Mercurial > hg > orthanc
changeset 6240:a6c9451fbade
propagating the authentication payload to the REST handlers
line wrap: on
line diff
--- a/NEWS Thu Jul 10 18:36:36 2025 +0200 +++ b/NEWS Fri Jul 11 09:41:19 2025 +0200 @@ -31,6 +31,8 @@ DICOM resource from a plugin. - "OrthancPluginRegisterHttpAuthentication()" to install a custom callback to authenticate HTTP requests. +* The OrthancPluginHttpRequest structure provides the payload of + the possible HTTP authentication callback. * OrthancPluginCallRestApi() now also returns the body of DELETE requests: https://discourse.orthanc-server.org/t/response-to-plugin-from-orthanc-api-delete-endpoint/6022
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -128,7 +128,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& arguments, const void* /*bodyData*/, - size_t /*bodySize*/) + size_t /*bodySize*/, + const std::string& authenticationPayload /* ignored */) { if (!Toolbox::IsChildUri(pimpl_->baseUri_, uri)) {
--- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Fri Jul 11 09:41:19 2025 +0200 @@ -50,7 +50,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload /* ignored */) ORTHANC_OVERRIDE { return false; } @@ -64,7 +65,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& arguments, const void* /*bodyData*/, - size_t /*bodySize*/) ORTHANC_OVERRIDE; + size_t /*bodySize*/, + const std::string& authenticationPayload /* ignored */) ORTHANC_OVERRIDE; bool IsListDirectoryContent() const {
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -349,6 +349,7 @@ bool isJQueryUploadChunk_; std::string jqueryUploadFileName_; size_t jqueryUploadFileSize_; + const std::string& authenticationPayload_; void HandleInternal(const MultipartStreamReader::HttpHeaders& headers, const void* part, @@ -359,7 +360,7 @@ HttpToolbox::GetArguments getArguments; if (!handler_.Handle(fakeOutput, RequestOrigin_RestApi, remoteIp_.c_str(), username_.c_str(), - HttpMethod_Post, uri_, headers, getArguments, part, size)) + HttpMethod_Post, uri_, headers, getArguments, part, size, authenticationPayload_)) { throw OrthancException(ErrorCode_UnknownResource); } @@ -371,14 +372,16 @@ const std::string& remoteIp, const std::string& username, const UriComponents& uri, - const MultipartStreamReader::HttpHeaders& headers) : + const MultipartStreamReader::HttpHeaders& headers, + const std::string& authenticationPayload) : handler_(handler), chunkStore_(chunkStore), remoteIp_(remoteIp), username_(username), uri_(uri), isJQueryUploadChunk_(false), - jqueryUploadFileSize_(0) // Dummy initialization + jqueryUploadFileSize_(0), // Dummy initialization + authenticationPayload_(authenticationPayload) { typedef HttpToolbox::Arguments::const_iterator Iterator; @@ -471,9 +474,10 @@ const UriComponents& uri, const std::map<std::string, std::string>& headers, const std::string& body, - const std::string& boundary) + const std::string& boundary, + const std::string& authenticationPayload) { - MultipartFormDataHandler handler(GetHandler(), pimpl_->chunkStore_, remoteIp, username, uri, headers); + MultipartFormDataHandler handler(GetHandler(), pimpl_->chunkStore_, remoteIp, username, uri, headers, authenticationPayload); MultipartStreamReader reader(boundary); reader.SetHandler(handler); @@ -1269,7 +1273,7 @@ const IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter(); // Authenticate this connection - std::string customPayload; + std::string authenticationPayload; std::string redirection; IIncomingHttpRequestFilter::AuthenticationStatus status; @@ -1279,7 +1283,7 @@ } else { - status = filter->CheckAuthentication(customPayload, redirection, requestUri, headers); + status = filter->CheckAuthentication(authenticationPayload, redirection, requestUri, headers); } switch (status) @@ -1295,7 +1299,6 @@ break; case IIncomingHttpRequestFilter::AuthenticationStatus_Success: - printf("PAYLOAD: [%s]\n", customPayload.c_str()); break; case IIncomingHttpRequestFilter::AuthenticationStatus_Redirect: @@ -1434,7 +1437,7 @@ status = ReadBodyToString(body, connection, headers); if (status == PostDataStatus_Success) { - server.ProcessMultipartFormData(remoteIp, username, uri, headers, body, boundary); + server.ProcessMultipartFormData(remoteIp, username, uri, headers, body, boundary, authenticationPayload); output.SendStatus(HttpStatus_200_Ok); return; } @@ -1447,7 +1450,7 @@ if (server.HasHandler()) { found = server.GetHandler().CreateChunkedRequestReader - (stream, RequestOrigin_RestApi, remoteIp, username.c_str(), method, uri, headers); + (stream, RequestOrigin_RestApi, remoteIp, username.c_str(), method, uri, headers, authenticationPayload); } if (found) @@ -1496,7 +1499,7 @@ server.HasHandler()) { found = server.GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(), - method, uri, headers, argumentsGET, body.c_str(), body.size()); + method, uri, headers, argumentsGET, body.c_str(), body.size(), authenticationPayload); } if (!found)
--- a/OrthancFramework/Sources/HttpServer/HttpServer.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.h Fri Jul 11 09:41:19 2025 +0200 @@ -227,7 +227,8 @@ const UriComponents& uri, const std::map<std::string, std::string>& headers, const std::string& body, - const std::string& boundary); + const std::string& boundary, + const std::string& authenticationPayload); MetricsRegistry::SharedMetrics& GetAvailableHttpThreadsMetrics() {
--- a/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -49,7 +49,7 @@ HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Get, curi, - httpHeaders, getArguments, NULL /* no body for GET */, 0)) + httpHeaders, getArguments, NULL /* no body for GET */, 0, "" /* no authentication payload */)) { if (stream.GetStatus() == HttpStatus_200_Ok) { @@ -89,7 +89,7 @@ HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", method, curi, - httpHeaders, getArguments, bodyData, bodySize)) + httpHeaders, getArguments, bodyData, bodySize, "" /* no authentication payload */)) { stream.GetBody(answerBody); @@ -149,7 +149,7 @@ HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi, - httpHeaders, getArguments, NULL /* no body for DELETE */, 0)) + httpHeaders, getArguments, NULL /* no body for DELETE */, 0, "" /* no authentication payload */)) { stream.GetBody(answerBody);
--- a/OrthancFramework/Sources/HttpServer/IHttpHandler.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.h Fri Jul 11 09:41:19 2025 +0200 @@ -72,7 +72,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) = 0; + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) = 0; virtual bool Handle(HttpOutput& output, RequestOrigin origin, @@ -83,7 +84,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) = 0; + size_t bodySize, + const std::string& authenticationPayload) = 0; /**
--- a/OrthancFramework/Sources/RestApi/RestApi.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -775,7 +775,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) { return false; } @@ -790,7 +791,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) + size_t bodySize, + const std::string& authenticationPayload) { RestApiOutput wrappedOutput(output, method);
--- a/OrthancFramework/Sources/RestApi/RestApi.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.h Fri Jul 11 09:41:19 2025 +0200 @@ -46,7 +46,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE; + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; virtual bool Handle(HttpOutput& output, RequestOrigin origin, @@ -57,7 +58,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE; + size_t bodySize, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; void Register(const std::string& path, RestApiGetCall::Handler handler);
--- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -1290,7 +1290,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) ORTHANC_OVERRIDE { return false; } @@ -1304,7 +1305,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE + size_t bodySize, + const std::string& authenticationPayload) ORTHANC_OVERRIDE { printf("received %d\n", static_cast<int>(bodySize));
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -2459,7 +2459,8 @@ public: HttpRequestConverter(const RestCallbackMatcher& matcher, HttpMethod method, - const HttpToolbox::Arguments& headers) + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) { memset(&converted_, 0, sizeof(OrthancPluginHttpRequest)); @@ -2502,6 +2503,14 @@ converted_.headersKeys = &headersKeys_[0]; converted_.headersValues = &headersValues_[0]; } + + converted_.authenticationPayload = authenticationPayload.empty() ? NULL : authenticationPayload.c_str(); + converted_.authenticationPayloadSize = static_cast<uint32_t>(authenticationPayload.size()); + + if (converted_.authenticationPayloadSize != authenticationPayload.size()) + { + throw OrthancException(ErrorCode_NotEnoughMemory); + } } void SetGetArguments(const HttpToolbox::GetArguments& getArguments) @@ -2573,7 +2582,8 @@ HttpMethod method, const UriComponents& uri, const HttpToolbox::Arguments& headers, - const HttpToolbox::GetArguments& getArguments) + const HttpToolbox::GetArguments& getArguments, + const std::string& authenticationPayload) { RestCallbackMatcher matcher(uri); @@ -2622,7 +2632,7 @@ } else { - HttpRequestConverter converter(matcher, method, headers); + HttpRequestConverter converter(matcher, method, headers, authenticationPayload); converter.SetGetArguments(getArguments); PImpl::PluginHttpOutput pluginOutput(output); @@ -2648,7 +2658,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) + size_t bodySize, + const std::string& authenticationPayload) { RestCallbackMatcher matcher(uri); @@ -2669,12 +2680,12 @@ if (callback == NULL) { // Callback not found, try to find a chunked callback - return HandleChunkedGetDelete(output, method, uri, headers, getArguments); + return HandleChunkedGetDelete(output, method, uri, headers, getArguments, authenticationPayload); } CLOG(INFO, PLUGINS) << "Delegating HTTP request to plugin for URI: " << matcher.GetFlatUri(); - HttpRequestConverter converter(matcher, method, headers); + HttpRequestConverter converter(matcher, method, headers, authenticationPayload); converter.SetGetArguments(getArguments); converter.GetRequest().body = bodyData; converter.GetRequest().bodySize = bodySize; @@ -6662,7 +6673,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) { if (method != HttpMethod_Post && method != HttpMethod_Put) @@ -6718,7 +6730,7 @@ { CLOG(INFO, PLUGINS) << "Delegating chunked HTTP request to plugin for URI: " << matcher.GetFlatUri(); - HttpRequestConverter converter(matcher, method, headers); + HttpRequestConverter converter(matcher, method, headers, authenticationPayload); converter.GetRequest().body = NULL; converter.GetRequest().bodySize = 0;
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Fri Jul 11 09:41:19 2025 +0200 @@ -106,7 +106,8 @@ HttpMethod method, const UriComponents& uri, const HttpToolbox::Arguments& headers, - const HttpToolbox::GetArguments& getArguments); + const HttpToolbox::GetArguments& getArguments, + const std::string& authenticationPayload); void RegisterOnStoredInstanceCallback(const void* parameters); @@ -291,7 +292,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE; + size_t bodySize, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; virtual bool InvokeService(SharedLibrary& plugin, _OrthancPluginService service, @@ -399,7 +401,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE; + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; // New in Orthanc 1.6.0 IStorageCommitmentFactory::ILookupHandler* CreateStorageCommitment(
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Fri Jul 11 09:41:19 2025 +0200 @@ -419,6 +419,23 @@ **/ const char* const* headersValues; + + /* -------------------------------------------------- + New in version 1.12.9 + -------------------------------------------------- */ + + /** + * @brief If a HTTP authentication callback is registered, the + * content of the custom payload generated by the callback. + **/ + const void* authenticationPayload; + + /** + * @brief The size of the custom authentication payload (0 if no + * authentication callback is registered). + **/ + uint32_t authenticationPayloadSize; + } OrthancPluginHttpRequest; @@ -10398,26 +10415,27 @@ /** * @brief Register a callback to handle HTTP authentication. * - * This function installs a callback that is executed on each + * This function installs a callback that is executed for each * incoming HTTP request to handle HTTP authentication. At most one * plugin can register such a callback. This gives the opportunity * to one plugin to validate access tokens (such as a JWT), possibly - * redirecting the user to a login page. The callback can generate a - * custom payload that will be provided to the possible subsequent - * HTTP authorizer (cf. function XXX). - * - * If one plugin installs such a callback, the built-in HTTP - * authentication of Orthanc is disabled. This means that the - * "RegisteredUsers" and "AuthenticationEnabled" configuration - * options of Orthanc are totally ignored. In addition, tokens - * generated by OrthancPluginGenerateRestApiAuthorizationToken() - * become ineffective. + * redirecting the user to a login page. The authentication callback + * can generate a custom payload that will be provided to the + * subsequent REST handling callback. * * The HTTP authentication callback can notably be used if some * resource in the REST API must be available for public access, as * soon as the "RemoteAccessAllowed" configuration option is set to * "true". * + * If one plugin installs a HTTP authentication callback, the + * built-in HTTP authentication of Orthanc is disabled. This means + * that the "RegisteredUsers" and "AuthenticationEnabled" + * configuration options of Orthanc are totally ignored. In + * addition, tokens generated by + * OrthancPluginGenerateRestApiAuthorizationToken() become + * ineffective. + * * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). * @param callback The HTTP authentication callback. * @return 0 if success, other value if error.
--- a/OrthancServer/Sources/EmbeddedResourceHttpHandler.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/EmbeddedResourceHttpHandler.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -51,7 +51,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& arguments, const void* /*bodyData*/, - size_t /*bodySize*/) + size_t /*bodySize*/, + const std::string& /*authenticationPayload*/) { if (!Toolbox::IsChildUri(baseUri_, uri)) {
--- a/OrthancServer/Sources/EmbeddedResourceHttpHandler.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/EmbeddedResourceHttpHandler.h Fri Jul 11 09:41:19 2025 +0200 @@ -47,7 +47,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) ORTHANC_OVERRIDE { return false; } @@ -61,6 +62,7 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& arguments, const void* /*bodyData*/, - size_t /*bodySize*/) ORTHANC_OVERRIDE; + size_t /*bodySize*/, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Sources/OrthancHttpHandler.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/OrthancHttpHandler.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -36,7 +36,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) { if (method != HttpMethod_Post && method != HttpMethod_Put) @@ -47,7 +48,7 @@ for (Handlers::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) { if ((*it)->CreateChunkedRequestReader - (target, origin, remoteIp, username, method, uri, headers)) + (target, origin, remoteIp, username, method, uri, headers, authenticationPayload)) { if (target.get() == NULL) { @@ -71,12 +72,13 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) + size_t bodySize, + const std::string& authenticationPayload) { for (Handlers::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) { if ((*it)->Handle(output, origin, remoteIp, username, method, uri, - headers, getArguments, bodyData, bodySize)) + headers, getArguments, bodyData, bodySize, authenticationPayload)) { return true; }
--- a/OrthancServer/Sources/OrthancHttpHandler.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/OrthancHttpHandler.h Fri Jul 11 09:41:19 2025 +0200 @@ -46,7 +46,8 @@ const char* username, HttpMethod method, const UriComponents& uri, - const HttpToolbox::Arguments& headers) ORTHANC_OVERRIDE; + const HttpToolbox::Arguments& headers, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; virtual bool Handle(HttpOutput& output, RequestOrigin origin, @@ -57,7 +58,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE; + size_t bodySize, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; void Register(IHttpHandler& handler, bool isOrthancRestApi);
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp Fri Jul 11 09:41:19 2025 +0200 @@ -297,13 +297,14 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) + size_t bodySize, + const std::string& authenticationPayload) { MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_rest_api_duration_ms"); MetricsRegistry::ActiveCounter counter(activeRequests_); return RestApi::Handle(output, origin, remoteIp, username, method, - uri, headers, getArguments, bodyData, bodySize); + uri, headers, getArguments, bodyData, bodySize, authenticationPayload); }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h Thu Jul 10 18:36:36 2025 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h Fri Jul 11 09:41:19 2025 +0200 @@ -78,7 +78,8 @@ const HttpToolbox::Arguments& headers, const HttpToolbox::GetArguments& getArguments, const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE; + size_t bodySize, + const std::string& authenticationPayload) ORTHANC_OVERRIDE; const bool& LeaveBarrierFlag() const {