changeset 52:f65e4503cd67

added test_dicom_permissions
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 22 Oct 2025 12:05:32 +0200
parents 87429291063c
children a5d238852e69
files Resources/IntegrationTests/Run.py Sources/Plugin.cpp
diffstat 2 files changed, 136 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Resources/IntegrationTests/Run.py	Wed Oct 22 11:01:22 2025 +0200
+++ b/Resources/IntegrationTests/Run.py	Wed Oct 22 12:05:32 2025 +0200
@@ -840,6 +840,132 @@
         self.assertEqual(1, len(lst))
 
 
+    def test_dicom_permissions(self):
+        def CheckForbidden(path, headers = {}):
+            self.assertEqual(307, requests.get(URL + path, headers = headers, allow_redirects = False).status_code)
+
+        def CheckGranted(path, headers = {}):
+            self.assertEqual(200, requests.get(URL + path, headers = headers, allow_redirects = False).status_code)
+
+        def CheckPolicyPath(path):
+            requests.put(URL + '/education/api/projects/%s/instructors' % project, json.dumps([ ]),
+                         headers = AdministratorHeaders()).raise_for_status()
+            requests.put(URL + '/education/api/projects/%s/instructors' % project, json.dumps([ ]),
+                         headers = AdministratorHeaders()).raise_for_status()
+            requests.put(URL + '/education/api/projects/%s/policy' % project, json.dumps('hidden'),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckForbidden(path, headers = InstructorHeaders())
+            CheckForbidden(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+            requests.put(URL + '/education/api/projects/%s/policy' % project, json.dumps('public'),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckGranted(path, headers = InstructorHeaders())
+            CheckGranted(path, headers = LearnerHeaders())
+            CheckGranted(path, headers = GuestHeaders())
+
+            requests.put(URL + '/education/api/projects/%s/policy' % project, json.dumps('hidden'),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckForbidden(path, headers = InstructorHeaders())
+            CheckForbidden(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+            requests.put(URL + '/education/api/projects/%s/instructors' % project, json.dumps([ 'instructor@uclouvain.be' ]),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckGranted(path, headers = InstructorHeaders())
+            CheckForbidden(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+            requests.put(URL + '/education/api/projects/%s/learners' % project, json.dumps([ 'learner@uclouvain.be' ]),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckGranted(path, headers = InstructorHeaders())
+            CheckForbidden(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+            requests.put(URL + '/education/api/projects/%s/policy' % project, json.dumps('active'),
+                         headers = AdministratorHeaders()).raise_for_status()
+
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckGranted(path, headers = InstructorHeaders())
+            CheckGranted(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+        def CheckNoAccess(path):
+            CheckGranted(path, headers = AdministratorHeaders())
+            CheckForbidden(path, headers = InstructorHeaders())
+            CheckForbidden(path, headers = LearnerHeaders())
+            CheckForbidden(path, headers = GuestHeaders())
+
+        instance = self.create_test_instance_id()
+        study = requests.get(URL + '/instances/%s/study' % instance, headers = AdministratorHeaders()).json() ['ID']
+        series = requests.get(URL + '/instances/%s/series' % instance, headers = AdministratorHeaders()).json() ['ID']
+
+        project = requests.post(URL + '/education/api/projects', json.dumps({
+            'name' : 'Hello',
+            'description' : 'World',
+        }), headers = AdministratorHeaders()).json() ['id']
+
+        CheckNoAccess('/studies/%s/archive' % study)
+        CheckNoAccess('/series/%s/archive' % series)
+        CheckNoAccess('/instances/%s/file' % instance)
+
+        body = {
+            'resource' : {
+                'resource-id' : study,
+                'level' : 'Study',
+            },
+            'project' : project,
+        }
+
+        requests.post(URL + '/education/api/link', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+        CheckPolicyPath('/studies/%s/archive' % study)
+        CheckNoAccess('/series/%s/archive' % series)
+        CheckNoAccess('/instances/%s/file' % instance)
+        requests.post(URL + '/education/api/unlink', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+
+        body = {
+            'resource' : {
+                'resource-id' : series,
+                'level' : 'Series',
+            },
+            'project' : project,
+        }
+
+        requests.post(URL + '/education/api/link', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+        CheckNoAccess('/studies/%s/archive' % study)
+        CheckPolicyPath('/series/%s/archive' % series)
+        CheckNoAccess('/instances/%s/file' % instance)
+        requests.post(URL + '/education/api/unlink', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+
+        body = {
+            'resource' : {
+                'resource-id' : instance,
+                'level' : 'Instance',
+            },
+            'project' : project,
+        }
+
+        requests.post(URL + '/education/api/link', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+        CheckNoAccess('/studies/%s/archive' % study)
+        CheckNoAccess('/series/%s/archive' % series)
+        CheckPolicyPath('/instances/%s/file' % instance)
+        requests.post(URL + '/education/api/unlink', json.dumps(body), headers = AdministratorHeaders()).raise_for_status()
+
+        CheckNoAccess('/studies/%s/archive' % study)
+        CheckNoAccess('/series/%s/archive' % series)
+        CheckNoAccess('/instances/%s/file' % instance)
+
+
 try:
     print('\nStarting the tests...')
     unittest.main(argv = [ sys.argv[0] ] + args.options)
--- a/Sources/Plugin.cpp	Wed Oct 22 11:01:22 2025 +0200
+++ b/Sources/Plugin.cpp	Wed Oct 22 12:05:32 2025 +0200
@@ -185,6 +185,16 @@
             AuthorizationStatus_Forbidden);
   }
 
+  if (path.size() == 3 &&
+      path[0] == "instances" &&
+      path[2] == "file")
+  {
+    // For integration tests
+    return (OrthancDatabase::IsGrantedResource(granter, Orthanc::ResourceType_Instance, path[1]) ?
+            AuthorizationStatus_GrantedWithoutPayload :
+            AuthorizationStatus_Forbidden);
+  }
+
 
   /**
    * Checks related to the education plugin