# HG changeset patch # User Alain Mazy # Date 1748278400 -7200 # Node ID eb58d87936730e36532a7e66636cb11192900c33 # Parent f970d8d7012bf1337ca3757782c20e23842090dc /dicom-web/studies: complement query with the StudyInstanceUIDs from the resource token diff -r f970d8d7012b -r eb58d8793673 NEWS --- a/NEWS Fri May 16 11:57:35 2025 +0200 +++ b/NEWS Mon May 26 18:53:20 2025 +0200 @@ -8,6 +8,13 @@ * New default permissions to Q&R remote modalities * Maintenance: Use Orthanc SDK 1.12.4 by default to benefit from more detailed logging. * Fix default permission for /dicom-web/servers/../stow +* When calling /dicom-web/studies with a resource token when no StudyInstanceUID + is specified in the query args, the plugin now adds a filter on StudyInstanceUID=X|Y where + X & Y are the StudyInstanceUIDs of the resource token. + This will only work if the authorization service returns a "resources" field to the /tokens/decode route. + This notably prevents OHIF to display errors when requesting + prior studies while still preserving the security since only the authorized resources are returned. + 2025-04-29 - v 0.9.2 ==================== diff -r f970d8d7012b -r eb58d8793673 Plugin/AuthorizationWebService.cpp --- a/Plugin/AuthorizationWebService.cpp Fri May 16 11:57:35 2025 +0200 +++ b/Plugin/AuthorizationWebService.cpp Mon May 26 18:53:20 2025 +0200 @@ -221,6 +221,24 @@ response.tokenType = tokenResponse["token-type"].asString(); } + // LOG(INFO) << tokenResponse.toStyledString(); + + if (tokenResponse.isMember("resources") && tokenResponse["resources"].isArray()) + { + for (Json::ArrayIndex i = 0; i < tokenResponse["resources"].size(); ++i) + { + const Json::Value& resource = tokenResponse["resources"][i]; + if (resource.isMember("dicom-uid") && resource["dicom-uid"].isString() && !resource["dicom-uid"].asString().empty() ) + { + response.resourcesDicomIds.insert(resource["dicom-uid"].asString()); + } + if (resource.isMember("orthanc-id") && resource["orthanc-id"].isString() && !resource["orthanc-id"].asString().empty() ) + { + response.resourcesOrthancIds.insert(resource["orthanc-id"].asString()); + } + } + } + return true; } catch (Orthanc::OrthancException& ex) diff -r f970d8d7012b -r eb58d8793673 Plugin/IAuthorizationService.h --- a/Plugin/IAuthorizationService.h Fri May 16 11:57:35 2025 +0200 +++ b/Plugin/IAuthorizationService.h Mon May 26 18:53:20 2025 +0200 @@ -53,6 +53,9 @@ std::string redirectUrl; std::string errorCode; std::string tokenType; + + std::set resourcesDicomIds; + std::set resourcesOrthancIds; }; struct UserProfile diff -r f970d8d7012b -r eb58d8793673 Plugin/Plugin.cpp --- a/Plugin/Plugin.cpp Fri May 16 11:57:35 2025 +0200 +++ b/Plugin/Plugin.cpp Mon May 26 18:53:20 2025 +0200 @@ -820,13 +820,41 @@ if (!GetStudyInstanceUIDFromQuery(studyInstanceUID, query)) { // If there is no StudyInstaceUID, this might still be a call to /dicom-web/studies?PatientID=... e.g. from OHIF - // in this case, let's return an empty list. TODO: in the future, we may get the StudyInstanceUIDs from the resource token and + // in this case, let's complement the query to filter against the StudyInstanceUIDs from the resource token and // "add" &StudyInstanceUID=1.2|1.3|1.4 in the query if there are multiple studies in the resource token - Json::Value emptyArray = Json::arrayValue; - OrthancPlugins::AnswerJson(emptyArray, output); - return; + + std::vector authTokens; // the tokens that are set in this request + GetAuthTokens(authTokens, request->headersCount, request->headersKeys, request->headersValues, request->getCount, request->getKeys, request->getValues); - // old code prior to 0.9.2: throw Orthanc::OrthancException(Orthanc::ErrorCode_ForbiddenAccess, "Auth plugin: unable to call tools/find when the user does not have access to any labels and if there is no StudyInstanceUID in the query."); + for (std::vector::const_iterator it = authTokens.begin(); it != authTokens.end(); ++it) + { + OrthancPlugins::IAuthorizationService::DecodedToken decodedToken; + if (authorizationService_->DecodeToken(decodedToken, + it->GetToken().GetKey(), + it->GetValue())) + { + if (decodedToken.resourcesDicomIds.size() > 0) + { + std::string joinedStudyInstanceUids; + Orthanc::Toolbox::JoinStrings(joinedStudyInstanceUids, decodedToken.resourcesDicomIds, "|"); + + LOG(WARNING) << "Auth plugin: adding StudyInstanceUID constrains based on the resources/dicom-uid in the token."; + // LOG(INFO) << joinedStudyInstanceUids; + + query["StudyInstanceUID"] = joinedStudyInstanceUids; + + Json::Value result; + if (OrthancPlugins::RestApiPost(result, nativeUrl, query, false)) + { + OrthancPlugins::AnswerJson(result, output); + return; + } + } + } + } + + // old code prior to 0.9.2: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ForbiddenAccess, "Auth plugin: unable to call tools/find when the user does not have access to any labels and if there is no StudyInstanceUID in the query or in the resource token."); } std::vector studyOrthancIds;