changeset 6224:1c03790d9ff6

added OrthancPluginRedirectNotAuthenticatedToRoot()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 07 Jul 2025 17:16:55 +0200
parents 67dbb5004469
children 83e1282c5403
files NEWS OrthancFramework/Sources/HttpServer/HttpServer.cpp OrthancFramework/Sources/HttpServer/HttpServer.h OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Engine/OrthancPlugins.h OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Sources/main.cpp
diffstat 8 files changed, 92 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Jul 07 16:49:22 2025 +0200
+++ b/NEWS	Mon Jul 07 17:16:55 2025 +0200
@@ -4,31 +4,32 @@
 General
 -------
 
-* Lua: new "SetStableStatus" function.
+* Lua: new "SetStableStatus()" function.
 
 REST API
 --------
 
-* When creating a job, you can now add a "UserData" field in the payload.
-  This data will travel along with the job and will be available in the 
-  /jobs/{jobId} route.
-
+* When creating a job, a "UserData" field in the payload. This data
+  will travel along with the job and will be available in the
+  "/jobs/{jobId}" route.
 
 Plugin SDK
 ----------
 
-* Added new function OrthancPluginSetStableStatus to e.g force the 
-  stabilization of a study from a plugin.
-
+* Added new primitives:
+  - "OrthancPluginSetStableStatus()" to force the stabilization of a
+    DICOM resource from a plugin.
+  - "OrthancPluginRedirectNotAuthenticatedToRoot()" to allow a plugin
+    to redirect unauthenticated users to a login page.
 
 Plugins
 -------
 
 * Housekeeper plugin:
-  - new "ForceReconstructFiles": If "Force" is set to true, forces 
-    the "ReconstructFiles" option when reconstructing resources even 
-    if the plugin did not detect any changes in the configuration that 
-    should trigger a Reconstruct.
+  - new "ForceReconstructFiles" option: If set to true, forces the
+    "ReconstructFiles" option when reconstructing resources, even if
+    the plugin did not detect any changes in the configuration that
+    should trigger a reconstruct.
 
 
 
--- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp	Mon Jul 07 17:16:55 2025 +0200
@@ -1243,8 +1243,10 @@
     if (server.IsAuthenticationEnabled() &&
         accessMode == AccessMode_NotAuthenticated)
     {
-      if (server.IsRedirectNotAuthenticatedToRoot() &&
-          uri.size() > 0)
+      IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter();
+      if (uri.size() > 0 &&
+          filter != NULL &&
+          filter->IsRedirectNotAuthenticatedToRoot())
       {
         // This is new in Orthanc 1.12.9
         std::string redirectionToRoot;
@@ -1627,8 +1629,7 @@
     realm_(ORTHANC_REALM),
     threadsCount_(50),  // Default value in mongoose/civetweb
     tcpNoDelay_(true),
-    requestTimeout_(30),  // Default value in mongoose/civetweb (30 seconds)
-    redirectNotAuthenticatedToRoot_(false)
+    requestTimeout_(30)  // Default value in mongoose/civetweb (30 seconds)
   {
 #if ORTHANC_ENABLE_MONGOOSE == 1
     CLOG(INFO, HTTP) << "This Orthanc server uses Mongoose as its embedded HTTP server";
@@ -2231,17 +2232,4 @@
     }
   }
 #endif
-
-
-  bool HttpServer::IsRedirectNotAuthenticatedToRoot() const
-  {
-    return redirectNotAuthenticatedToRoot_;
-  }
-
-
-  void HttpServer::SetRedirectNotAuthenticatedToRoot(bool redirect)
-  {
-    Stop();
-    redirectNotAuthenticatedToRoot_ = redirect;
-  }
 }
--- a/OrthancFramework/Sources/HttpServer/HttpServer.h	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/HttpServer.h	Mon Jul 07 17:16:55 2025 +0200
@@ -114,7 +114,6 @@
     unsigned int threadsCount_;
     bool tcpNoDelay_;
     unsigned int requestTimeout_;  // In seconds
-    bool redirectNotAuthenticatedToRoot_;  // New in Orthanc 1.12.9
 
 #if ORTHANC_ENABLE_PUGIXML == 1
     WebDavBuckets webDavBuckets_;
@@ -227,9 +226,5 @@
                                   const std::map<std::string, std::string>& headers,
                                   const std::string& body,
                                   const std::string& boundary);
-
-    bool IsRedirectNotAuthenticatedToRoot() const;
-
-    void SetRedirectNotAuthenticatedToRoot(bool redirect);
   };
 }
--- a/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h	Mon Jul 07 17:16:55 2025 +0200
@@ -44,5 +44,7 @@
                            const char* username,
                            const HttpToolbox::Arguments& httpHeaders,
                            const HttpToolbox::GetArguments& getArguments) = 0;
+
+    virtual bool IsRedirectNotAuthenticatedToRoot() const = 0;
   };
 }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Mon Jul 07 17:16:55 2025 +0200
@@ -1763,6 +1763,7 @@
     std::string databaseServerIdentifier_;   // New in Orthanc 1.9.2
     unsigned int maxDatabaseRetries_;        // New in Orthanc 1.9.2
     bool hasStorageAreaCustomData_;          // New in Orthanc 1.12.8
+    bool redirectNotAuthenticatedToRoot_;    // New in Orthanc 1.12.9
 
     explicit PImpl(const std::string& databaseServerIdentifier) : 
       contextRefCount_(0),
@@ -1774,7 +1775,8 @@
       argv_(NULL),
       databaseServerIdentifier_(databaseServerIdentifier),
       maxDatabaseRetries_(0),
-      hasStorageAreaCustomData_(false)
+      hasStorageAreaCustomData_(false),
+      redirectNotAuthenticatedToRoot_(false)
     {
       memset(&moveCallbacks_, 0, sizeof(moveCallbacks_));
     }
@@ -5851,6 +5853,18 @@
         return true;
       }
 
+      case _OrthancPluginService_RedirectNotAuthenticatedToRoot:
+      {
+        const _OrthancPluginRedirectNotAuthenticatedToRoot& p = *reinterpret_cast<const _OrthancPluginRedirectNotAuthenticatedToRoot*>(parameters);
+
+        {
+          boost::unique_lock<boost::shared_mutex> lock(pimpl_->incomingHttpRequestFilterMutex_);
+          pimpl_->redirectNotAuthenticatedToRoot_ = (p.redirect == 1);
+        }
+
+        return true;
+      }
+
       default:
         return false;
     }
@@ -6816,4 +6830,11 @@
       pimpl_->webDavCollections_.pop_front();
     }
   }
+
+
+  bool OrthancPlugins::IsRedirectNotAuthenticatedToRoot() const
+  {
+    boost::shared_lock<boost::shared_mutex> lock(pimpl_->incomingHttpRequestFilterMutex_);
+    return pimpl_->redirectNotAuthenticatedToRoot_;
+  }
 }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h	Mon Jul 07 17:16:55 2025 +0200
@@ -414,6 +414,8 @@
     unsigned int GetMaxDatabaseRetries() const;
 
     void RegisterWebDavCollections(HttpServer& target);
+
+    bool IsRedirectNotAuthenticatedToRoot() const;
   };
 }
 
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Mon Jul 07 17:16:55 2025 +0200
@@ -484,6 +484,7 @@
     _OrthancPluginService_DequeueValue = 58,                        /* New in Orthanc 1.12.8 */
     _OrthancPluginService_GetQueueSize = 59,                        /* New in Orthanc 1.12.8 */
     _OrthancPluginService_SetStableStatus = 60,                     /* New in Orthanc 1.12.9 */
+    _OrthancPluginService_RedirectNotAuthenticatedToRoot = 61,      /* New in Orthanc 1.12.9 */
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -10339,10 +10340,44 @@
     return context->InvokeService(context, _OrthancPluginService_SetStableStatus, &params);
   }
 
+
+  typedef struct
+  {
+    uint8_t   redirect;
+  } _OrthancPluginRedirectNotAuthenticatedToRoot;
+
+  /**
+   * @brief Whether to redirect unauthorized requests to the root of the Web server.
+   *
+   * If a request is non-authenticated (e.g., because of bad HTTP
+   * basic authentication credentials, or because of a plugin
+   * implementing a filtering over incoming HTTP requests), Orthanc by
+   * default returns a 401 "Unauthorized" HTTP status code.
+   *
+   * However, an Orthanc plugin providing a custom user interface
+   * could want to redirect the user to a login page. In such a
+   * situation, plugins can invoke
+   * "OrthancPluginRedirectNotAuthenticatedToRoot(context, 1)". This
+   * allows the plugin to redirect the user to its login page by
+   * overriding the REST callback for the "/" path.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param redirect Whether to redirect unauthorized (non-authenticated) requests.
+   * @return 0 if success, other value if error.
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRedirectNotAuthenticatedToRoot(
+    OrthancPluginContext*  context,
+    uint8_t                redirect)
+  {
+    _OrthancPluginRedirectNotAuthenticatedToRoot params;
+    params.redirect = redirect;
+
+    return context->InvokeService(context, _OrthancPluginService_RedirectNotAuthenticatedToRoot, &params);
+  }
+
 #ifdef  __cplusplus
 }
 #endif
 
 
 /** @} */
-
--- a/OrthancServer/Sources/main.cpp	Mon Jul 07 16:49:22 2025 +0200
+++ b/OrthancServer/Sources/main.cpp	Mon Jul 07 17:16:55 2025 +0200
@@ -604,6 +604,18 @@
 
     return true;
   }
+
+  virtual bool IsRedirectNotAuthenticatedToRoot() const ORTHANC_OVERRIDE
+  {
+#if ORTHANC_ENABLE_PLUGINS == 1
+    if (plugins_ != NULL)
+    {
+      return plugins_->IsRedirectNotAuthenticatedToRoot();
+    }
+#endif
+
+    return false;
+  }
 };