Mercurial > hg > orthanc-authorization
changeset 113:43154740ea2e
wip: checking labels
author | Alain Mazy <am@osimis.io> |
---|---|
date | Tue, 05 Sep 2023 12:48:20 +0200 |
parents | 572955904411 |
children | 546aea509427 |
files | Plugin/AuthorizationWebService.cpp Plugin/AuthorizationWebService.h Plugin/BaseAuthorizationService.h Plugin/CachedAuthorizationService.cpp Plugin/CachedAuthorizationService.h Plugin/Enumerations.h Plugin/IAuthorizationService.h Plugin/Plugin.cpp Plugin/Token.cpp Plugin/Token.h |
diffstat | 10 files changed, 154 insertions(+), 68 deletions(-) [+] |
line wrap: on
line diff
--- a/Plugin/AuthorizationWebService.cpp Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/AuthorizationWebService.cpp Tue Sep 05 12:48:20 2023 +0200 @@ -389,7 +389,10 @@ validity = jsonProfile[VALIDITY].asUInt(); profile.name = jsonProfile[USER_NAME].asString(); - + profile.tokenKey = token->GetKey(); + profile.tokenType = token->GetType(); + profile.tokenValue = tokenValue; + for (Json::ArrayIndex i = 0; i < jsonProfile[PERMISSIONS].size(); ++i) { profile.permissions.insert(jsonProfile[PERMISSIONS][i].asString()); @@ -414,21 +417,14 @@ bool AuthorizationWebService::HasUserPermissionInternal(unsigned int& validity, const std::string& permission, - const Token* token, - const std::string& tokenValue) + const UserProfile& profile) { - UserProfile profile; - - - if (GetUserProfileInternal(validity, profile, token, tokenValue)) + const std::set<std::string>& permissions = profile.permissions; + for (std::set<std::string>::const_iterator it = permissions.begin(); it != permissions.end(); ++it) { - std::set<std::string>& permissions = profile.permissions; - for (std::set<std::string>::const_iterator it = permissions.begin(); it != permissions.end(); ++it) + if (permission == *it) { - if (permission == *it) - { - return true; - } + return true; } }
--- a/Plugin/AuthorizationWebService.h Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/AuthorizationWebService.h Tue Sep 05 12:48:20 2023 +0200 @@ -42,14 +42,13 @@ const std::string& tokenValue) ORTHANC_OVERRIDE; virtual bool GetUserProfileInternal(unsigned int& validity, - UserProfile& profile /* out */, - const Token* token, - const std::string& tokenValue) ORTHANC_OVERRIDE; + UserProfile& profile /* out */, + const Token* token, + const std::string& tokenValue) ORTHANC_OVERRIDE; virtual bool HasUserPermissionInternal(unsigned int& validity, - const std::string& permission, - const Token* token, - const std::string& tokenValue) ORTHANC_OVERRIDE; + const std::string& permission, + const UserProfile& profile) ORTHANC_OVERRIDE; public: AuthorizationWebService(const std::string& tokenValidationUrl,
--- a/Plugin/BaseAuthorizationService.h Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/BaseAuthorizationService.h Tue Sep 05 12:48:20 2023 +0200 @@ -42,8 +42,7 @@ virtual bool HasUserPermissionInternal(unsigned int& validity, const std::string& permission, - const Token* token, - const std::string& tokenValue) = 0; + const UserProfile& profile) = 0; public: virtual ~BaseAuthorizationService() @@ -82,8 +81,7 @@ virtual bool HasUserPermission(unsigned int& validity /* out */, const std::set<std::string>& anyOfPermissions, - const Token& token, - const std::string& tokenValue) + const UserProfile& profile) { if (anyOfPermissions.size() == 0) { @@ -92,7 +90,7 @@ for (std::set<std::string>::const_iterator it = anyOfPermissions.begin(); it != anyOfPermissions.end(); ++it) { - if (HasUserPermissionInternal(validity, *it, &token, tokenValue)) + if (HasUserPermissionInternal(validity, *it, profile)) { return true; } @@ -108,9 +106,12 @@ 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, NULL, "")) + if (HasUserPermissionInternal(validity, *it, anonymousUserProfile)) { return true; }
--- a/Plugin/CachedAuthorizationService.cpp Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/CachedAuthorizationService.cpp Tue Sep 05 12:48:20 2023 +0200 @@ -123,12 +123,12 @@ bool CachedAuthorizationService::HasUserPermissionInternal(unsigned int& validity, const std::string& permission, - const Token* token, - const std::string& tokenValue) + const UserProfile& profile) { assert(decorated_.get() != NULL); - std::string key = ComputeKey(permission, token, tokenValue); + Token token(profile.tokenType, profile.tokenKey); + std::string key = ComputeKey(permission, &token, profile.tokenValue); std::string value; if (cache_->Retrieve(value, key)) @@ -137,7 +137,7 @@ return (value == "1"); } - bool granted = decorated_->HasUserPermissionInternal(validity, permission, token, tokenValue); + bool granted = decorated_->HasUserPermissionInternal(validity, permission, profile); if (granted) {
--- a/Plugin/CachedAuthorizationService.h Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/CachedAuthorizationService.h Tue Sep 05 12:48:20 2023 +0200 @@ -58,8 +58,7 @@ virtual bool HasUserPermissionInternal(unsigned int& validity, const std::string& permission, - const Token* token, - const std::string& tokenValue) ORTHANC_OVERRIDE; + const UserProfile& profile) ORTHANC_OVERRIDE; public:
--- a/Plugin/Enumerations.h Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/Enumerations.h Tue Sep 05 12:48:20 2023 +0200 @@ -25,7 +25,9 @@ enum TokenType { TokenType_HttpHeader, - TokenType_GetArgument + TokenType_GetArgument, + + TokenType_None };
--- a/Plugin/IAuthorizationService.h Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/IAuthorizationService.h Tue Sep 05 12:48:20 2023 +0200 @@ -58,6 +58,11 @@ std::string name; std::set<std::string> permissions; std::set<std::string> authorizedLabels; + + // the source token key/value that identified the user + TokenType tokenType; + std::string tokenKey; + std::string tokenValue; }; virtual ~IAuthorizationService() @@ -84,8 +89,7 @@ virtual bool HasUserPermission(unsigned int& validity /* out */, const std::set<std::string>& anyOfPermissions, - const Token& token, - const std::string& tokenValue) = 0; + const UserProfile& profile) = 0; virtual bool HasAnonymousUserPermission(unsigned int& validity /* out */, const std::set<std::string>& anyOfPermissions) = 0;
--- a/Plugin/Plugin.cpp Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/Plugin.cpp Tue Sep 05 12:48:20 2023 +0200 @@ -73,6 +73,71 @@ } }; +bool HasAccessToAllLabels(const OrthancPlugins::IAuthorizationService::UserProfile& profile) +{ + return (profile.authorizedLabels.find("*") != profile.authorizedLabels.end()); +} + +bool HasAccessToSomeLabels(const OrthancPlugins::IAuthorizationService::UserProfile& profile) +{ + return (profile.authorizedLabels.size() > 0); +} + + +static bool CheckAuthorizedLabelsForResource(const std::string& uri, + const OrthancPlugins::AssociativeArray& getArguments, + const OrthancPlugins::IAuthorizationService::UserProfile& profile) +{ + if (HasAccessToAllLabels(profile)) + { + return true; + } + + if (authorizationParser_.get() != NULL && + authorizationService_.get() != NULL) + { + // Parse the resources that are accessed through this URI + OrthancPlugins::IAuthorizationParser::AccessedResources accesses; + + if (!authorizationParser_->Parse(accesses, uri, getArguments.GetMap())) + { + return false; // Unable to parse this URI + } + + // Loop over all the accessed resources to ensure access is + // granted to each of them + for (OrthancPlugins::IAuthorizationParser::AccessedResources::const_iterator + access = accesses.begin(); access != accesses.end(); ++access) + { + // Ignored the access levels that are unchecked + // (cf. "UncheckedLevels" option) + if (uncheckedLevels_.find(access->GetLevel()) == uncheckedLevels_.end()) + { + std::string msg = std::string("Testing whether access to ") + OrthancPlugins::EnumerationToString(access->GetLevel()) + " \"" + access->GetOrthancId() + "\" is allowed wrt Labels for User '" + profile.name + "'"; + const std::set<std::string>& resourceLabels = access->GetLabels(); + std::set<std::string> authorizedResourceLabels; + + Orthanc::Toolbox::GetIntersection(authorizedResourceLabels, resourceLabels, profile.authorizedLabels); + + if (authorizedResourceLabels.size() == 0) + { + LOG(INFO) << msg << " -> not granted, no authorized labels"; + return false; + } + else + { + LOG(INFO) << msg << " -> granted, at least one authorized labels"; + return true; + } + } + } + + // Access is granted to all the resources that are 'unchecked' + return true; + } + + return false; // TODO or true ??? +} static int32_t FilterHttpRequests(OrthancPluginHttpMethod method, const char *uri, @@ -154,16 +219,26 @@ if (authTokens.empty()) { std::string msg = std::string("Testing whether anonymous user has any of the required permissions '") + JoinStrings(requiredPermissions) + "'"; - LOG(INFO) << msg; - if (authorizationService_->HasAnonymousUserPermission(validity, requiredPermissions)) - { - LOG(INFO) << msg << " -> granted"; - return 1; - } - else - { - LOG(INFO) << msg << " -> not granted"; - } + + // TODO: how to handle anonymous user ? + + // LOG(INFO) << msg; + // if (authorizationService_->HasAnonymousUserPermission(validity, requiredPermissions)) + // { + // // TODO: check labels permissions + // LOG(INFO) << msg << " -> granted"; + + // if (CheckAuthorizedLabelsForResource(uri, getArguments, profile)) + // { + // return 1; + // } + // } + // else + // { + // LOG(INFO) << msg << " -> not granted"; + // } + LOG(INFO) << msg << " -> not granted, TODO ????"; + return 0; } else { @@ -172,15 +247,25 @@ 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; - if (authorizationService_->HasUserPermission(validity, requiredPermissions, authTokens[i].GetToken(), authTokens[i].GetValue())) + + OrthancPlugins::IAuthorizationService::UserProfile profile; + unsigned int validityNotUsed; + authorizationService_->GetUserProfile(validityNotUsed, profile, authTokens[i].GetToken(), authTokens[i].GetValue()); + + if (authorizationService_->HasUserPermission(validity, requiredPermissions, profile)) { - // TODO: check labels permissions LOG(INFO) << msg << " -> granted"; - return 1; + + // check labels permissions + if (CheckAuthorizedLabelsForResource(uri, getArguments, profile)) + { + return 1; + } + // not granted, but continue and check if a resource tokens grant access } else { - LOG(INFO) << msg << " -> not granted"; + LOG(INFO) << msg << " -> not granted"; // but continue and check if a resource tokens grant access } } } @@ -388,16 +473,6 @@ return false; } -bool HasAccessToAllLabels(const OrthancPlugins::IAuthorizationService::UserProfile& profile) -{ - return (profile.authorizedLabels.find("*") != profile.authorizedLabels.end()); -} - -bool HasAccessToSomeLabels(const OrthancPlugins::IAuthorizationService::UserProfile& profile) -{ - return (profile.authorizedLabels.size() > 0); -} - void AdjustToolsFindQueryLabels(Json::Value& query, const OrthancPlugins::IAuthorizationService::UserProfile& profile) { std::set<std::string> labelsToFind; @@ -461,15 +536,11 @@ { if (profile.authorizedLabels.size() > 0) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Unauthorized, "Auth plugin: unable to transform tools/find query with 'None' labels constraint when the user only has authorized_labels."); + throw Orthanc::OrthancException(Orthanc::ErrorCode_Unauthorized, "Auth plugin: unable to transform tools/find query with 'None' labels constraint when the user only has authorized_labels."); } } } } - else - { - // TODO what shall we do if the user has no authorized_labels ??? - } } void ToolsFind(OrthancPluginRestOutput* output, @@ -507,7 +578,7 @@ } else { - OrthancPluginSendHttpStatusCode(context, output, 403); // TODO: check + throw Orthanc::OrthancException(Orthanc::ErrorCode_Unauthorized, "Auth plugin: no user profile found, access to tools/find is forbidden."); } } } @@ -556,10 +627,8 @@ } else { - OrthancPluginSendHttpStatusCode(context, output, 403); // TODO: check + throw Orthanc::OrthancException(Orthanc::ErrorCode_Unauthorized, "Auth plugin: no user profile found, access to tools/labels is forbidden."); } - - } } @@ -945,7 +1014,6 @@ if (!urlTokenCreationBase.empty()) { LOG(WARNING) << "Authorization plugin: base url defined for Token Creation : " << urlTokenCreationBase; - // TODO Token Creation } else { @@ -1012,24 +1080,28 @@ OrthancPlugins::AccessLevel checkedLevel = OrthancPlugins::StringToAccessLevel(checkedLevelString); if (checkedLevel == OrthancPlugins::AccessLevel_Instance) { + uncheckedLevels_.insert(OrthancPlugins::AccessLevel_System); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Patient); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Study); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Series); } else if (checkedLevel == OrthancPlugins::AccessLevel_Series) { + uncheckedLevels_.insert(OrthancPlugins::AccessLevel_System); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Patient); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Study); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Instance); } else if (checkedLevel == OrthancPlugins::AccessLevel_Study) { + uncheckedLevels_.insert(OrthancPlugins::AccessLevel_System); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Patient); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Series); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Instance); } else if (checkedLevel == OrthancPlugins::AccessLevel_Patient) { + uncheckedLevels_.insert(OrthancPlugins::AccessLevel_System); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Study); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Series); uncheckedLevels_.insert(OrthancPlugins::AccessLevel_Instance);
--- a/Plugin/Token.cpp Thu Aug 31 16:51:15 2023 +0200 +++ b/Plugin/Token.cpp Tue Sep 05 12:48:20 2023 +0200 @@ -32,4 +32,15 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } + + Token::Token(const Token& other) : + type_(other.GetType()), + key_(other.GetKey()) + { + if (key_.empty()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + } + }