changeset 243:3a6194f51293 inbox tip

new ExtraPermissions config + improved anonymous profiles
author Alain Mazy <am@orthanc.team>
date Thu, 12 Jun 2025 16:12:29 +0200 (4 days ago)
parents 1877694ab4f7
children
files NEWS Plugin/BaseAuthorizationService.h Plugin/IAuthorizationService.h Plugin/Plugin.cpp
diffstat 4 files changed, 82 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Jun 11 10:55:44 2025 +0200
+++ b/NEWS	Thu Jun 12 16:12:29 2025 +0200
@@ -1,3 +1,18 @@
+Pending changes in the mainline
+===============================
+
+=> Minimum Orthanc version: 1.11.3 <=
+=> Recommended SDK version: 1.12.4 <=
+=> Minimum SDK version: 1.11.3 <=
+
+* New configuration "ExtraPermissions" to ADD new permissions to
+  the default "Permissions" entries.
+* Improved handling of "Anonymous" user profiles (when no auth-tokens
+  are provided):  The plugin will now request the auth-service to
+  get an anonymous user profile even if there are no auth-tokens in the
+  HTTP request.
+
+
 2025-06-11 - v 0.9.3
 ====================
 
--- a/Plugin/BaseAuthorizationService.h	Wed Jun 11 10:55:44 2025 +0200
+++ b/Plugin/BaseAuthorizationService.h	Thu Jun 12 16:12:29 2025 +0200
@@ -102,25 +102,5 @@
       return false;
     }
 
-    virtual bool HasAnonymousUserPermission(unsigned int& validity /* out */,
-                                            const std::set<std::string>& anyOfPermissions) ORTHANC_OVERRIDE
-    {
-      if (anyOfPermissions.size() == 0)
-      {
-        return true;
-      }
-
-      UserProfile anonymousUserProfile;
-      anonymousUserProfile.tokenType = TokenType_None;
-
-      for (std::set<std::string>::const_iterator it = anyOfPermissions.begin(); it != anyOfPermissions.end(); ++it)
-      {
-        if (HasUserPermissionInternal(validity, *it, anonymousUserProfile))
-        {
-          return true;
-        }
-      }
-      return false;
-    }
   };
 }
--- a/Plugin/IAuthorizationService.h	Wed Jun 11 10:55:44 2025 +0200
+++ b/Plugin/IAuthorizationService.h	Thu Jun 12 16:12:29 2025 +0200
@@ -96,9 +96,6 @@
                                    const std::set<std::string>& anyOfPermissions,
                                    const UserProfile& profile) = 0;
 
-    virtual bool HasAnonymousUserPermission(unsigned int& validity /* out */,
-                                            const std::set<std::string>& anyOfPermissions) = 0;
-
     virtual bool CreateToken(CreatedToken& response,
                              const std::string& tokenType, 
                              const std::string& id, 
--- a/Plugin/Plugin.cpp	Wed Jun 11 10:55:44 2025 +0200
+++ b/Plugin/Plugin.cpp	Thu Jun 12 16:12:29 2025 +0200
@@ -273,6 +273,47 @@
   return false;
 }
 
+static bool TestRequiredPermissions(bool& hasUserRequiredPermissions, 
+                                    const std::set<std::string>& requiredPermissions, 
+                                    const OrthancPlugins::IAuthorizationService::UserProfile& profile,
+                                    const std::string& msg, 
+                                    const char* uri,
+                                    OrthancPluginHttpMethod method,
+                                    const OrthancPlugins::AssociativeArray& getArguments
+                                    )
+{
+  unsigned int validity;  // ignored
+  if (authorizationService_->HasUserPermission(validity, requiredPermissions, profile))
+  {
+    LOG(INFO) << msg << " -> granted";
+    hasUserRequiredPermissions = true;
+
+    // check labels permissions
+    std::string msg2 = std::string("Testing whether user has the authorized_labels to access '") + uri + "'";
+
+    bool hasAuthorizedLabelsForResource = false;
+    if (CheckAuthorizedLabelsForResource(hasAuthorizedLabelsForResource, uri, method, getArguments, profile))
+    {
+      if (hasAuthorizedLabelsForResource)
+      {
+        LOG(INFO) << msg2 << " -> granted";
+      }
+      else
+      {
+        LOG(INFO) << msg2 << " -> not granted";
+        return false; // the labels for this resource prevents access -> stop checking now !
+      }
+    }
+  }
+  else
+  {
+    LOG(INFO) << msg << " -> not granted";
+    hasUserRequiredPermissions = false;
+  }
+  
+  return true;
+}
+
 static int32_t FilterHttpRequests(OrthancPluginHttpMethod method,
                                   const char *uri,
                                   const char *ip,
@@ -323,22 +364,19 @@
       {
         if (authTokens.empty())
         {
-          std::string msg = std::string("Testing whether anonymous user has any of the required permissions '") + JoinStrings(requiredPermissions) + "'";
-          
+          std::string msg = std::string("Testing whether anonymous user has any of the required permissions '") + JoinStrings(requiredPermissions) + "' required to match '" + matchedPattern + "'";
+
+          OrthancPlugins::IAuthorizationService::UserProfile anonymousProfile;
+          unsigned int validityNotUsed;
+          authorizationService_->GetUserProfile(validityNotUsed, anonymousProfile, OrthancPlugins::Token(OrthancPlugins::TokenType_None, ""), "");
+
           LOG(INFO) << msg; 
-
-          unsigned int validity;  // ignored
-          if (authorizationService_->HasAnonymousUserPermission(validity, requiredPermissions))
+          if (!TestRequiredPermissions(hasUserRequiredPermissions, requiredPermissions, anonymousProfile, msg, uri, method, getArguments))
           {
-            LOG(INFO) << msg << " -> granted";
-            hasUserRequiredPermissions = true;
+            return 0; // the labels for this resource prevents access -> stop checking now !
           }
-          else
-          {
-            LOG(INFO) << msg << " -> not granted";
-            hasUserRequiredPermissions = false;
-            // continue in order to check if there is a resource token that could grant access to the resource
-          }
+
+          // continue in order to check if there is a resource token that could grant access to the resource
         }
         else
         {
@@ -346,39 +384,16 @@
           {
             std::string msg = std::string("Testing whether user has the required permissions '") + JoinStrings(requiredPermissions) + "' based on the HTTP header '" + authTokens[i].GetToken().GetKey() + "' required to match '" + matchedPattern + "'";
 
-            // LOG(INFO) << msg;
+            LOG(INFO) << msg;
             OrthancPlugins::IAuthorizationService::UserProfile profile;
             unsigned int validityNotUsed;
             authorizationService_->GetUserProfile(validityNotUsed, profile, authTokens[i].GetToken(), authTokens[i].GetValue());
 
-            unsigned int validity;  // ignored
-            if (authorizationService_->HasUserPermission(validity, requiredPermissions, profile))
+            if (!TestRequiredPermissions(hasUserRequiredPermissions, requiredPermissions, profile, msg, uri, method, getArguments))
             {
-              LOG(INFO) << msg << " -> granted";
-              hasUserRequiredPermissions = true;
-
-              // check labels permissions
-              msg = std::string("Testing whether user has the authorized_labels to access '") + uri + "' based on the HTTP header '" + authTokens[i].GetToken().GetKey() + "'";
+              return 0; // the labels for this resource prevents access -> stop checking now !
+            }
 
-              bool hasAuthorizedLabelsForResource = false;
-              if (CheckAuthorizedLabelsForResource(hasAuthorizedLabelsForResource, uri, method, getArguments, profile))
-              {
-                if (hasAuthorizedLabelsForResource)
-                {
-                  LOG(INFO) << msg << " -> granted";
-                }
-                else
-                {
-                  LOG(INFO) << msg << " -> not granted";
-                  return 0; // the labels for this resource prevents access -> stop checking now !
-                }
-              }
-            }
-            else
-            {
-              LOG(INFO) << msg << " -> not granted";
-              hasUserRequiredPermissions = false;
-            }
           }
         }
       }
@@ -546,30 +561,25 @@
     OrthancPlugins::IAuthorizationService::UserProfile tryProfile;
 
     std::string value;
-
-    bool hasValue = false;
     switch (token->GetType())
     {
       case OrthancPlugins::TokenType_HttpHeader:
-        hasValue = headers.GetValue(value, token->GetKey());
+        headers.GetValue(value, token->GetKey());
         break;
 
       case OrthancPlugins::TokenType_GetArgument:
-        hasValue = getArguments.GetValue(value, token->GetKey());
+        getArguments.GetValue(value, token->GetKey());
         break;
 
       default:
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
     
-    if (hasValue)
+    unsigned int validity; // not used
+    if (authorizationService_->GetUserProfile(validity, tryProfile, *token, value))
     {
-      unsigned int validity; // not used
-      if (authorizationService_->GetUserProfile(validity, tryProfile, *token, value))
-      {
-        profile = tryProfile;
-        return true;
-      }
+      profile = tryProfile;
+      return true;
     }
   }
 
@@ -1496,6 +1506,12 @@
             (new OrthancPlugins::PermissionParser(dicomWebRoot, oe2Root));
 
           permissionParser_->Add(pluginConfiguration.GetJson()[PERMISSIONS], authorizationParser_.get());
+
+          static const char* const EXTRA_PERMISSIONS = "ExtraPermissions";
+          if (pluginConfiguration.GetJson().isMember(EXTRA_PERMISSIONS))
+          {
+            permissionParser_->Add(pluginConfiguration.GetJson()[EXTRA_PERMISSIONS], authorizationParser_.get());
+          }
         }
         else
         {