Sonador ACL MS1: Orthanc "acl" permission functional tests
Parent tracking issue: #55 (closed) — see that issue for overall test coverage status and gap priorities. This issue contains the full specification for the acl permission test cases.
✅ Complete (2026-07-09): All 11 test cases below are implemented intests/tests_sonadoracl_manage.py(SonadorAclPermissionTests) and merged tomastervia sonador-ftests!13 (merged), passing 11/11 live against dev01 (verified twice, including against a rebuilt environment). The precursor enforcement fix landed across oak-tree/medical-imaging/sonador!91, orthanc-sonador!56 (merged), and orthanc-authorization!2 (merged) (deployed together). The suite caught two real bugs on the way in: themodify=True, acl=Falsepolicy-creation vulnerability (Negative TC2, confirmed live pre-fix) and an indentation bug in theacl_traversebuilder that a static trace missed (fixed in orthanc-sonador!56 (merged), commit 917bb51). Full test-by-test trace: #55 (closed) §"ACL Policy Management"; deliverable → MR trace: oak-tree/medical-imaging/sonador#64 close-out comment. Known follow-up (non-blocking, tracked in #55 (closed) Priority 2): a positive-grant DICOMweb acl case.
Update (July 2026): implementation review and detailed technical notes for the coding agent are in this comment. Key finding: the permission semantics below are correct, but the
aclflag is not yet enforced on the Sonador side (ACL-management requests are currently authorized via a temporaryquery-permission shim /modifyfall-through). An enforcement fix MR insonador(and possiblyorthanc-sonador) is a precursor to these tests passing. Negative/regression test cases added to the checklist below. (Resolved — see completion note above.)Design decision (note):
acldoes not implyview— a principal may manage access to a resource without being able to retrieve its data. Ancestor traversal for ACL-management requests must therefore use a dedicated signal (action token oracl_traverse), notview; a separation test case (Negative TC4) pins this behavior.
Background. Sonador implements an access control (ACL) system which ensures that imaging resources can only be accessed by users who have received permission in a policy. The "ACL engine" in Sonador builds on top of the Orthanc Advanced Authorization Plugin, and is implemented in the visionaire.auth (located in apps) and orthancapi (located in lib) modules of the Django web application.
Resources in the Orthanc authorization plugin are identified by URL, which means that if the Sonador auth engine does not include an implementation than requests for that resource made by "limited" accounts will fail. The default response for any Orthanc endpoint is "deny." This makes it important to have complete API coverage for all endpoints within the access control system.
Within Sonador, there are two types of permissions:
- "server" permissions (
queryandupload) which provide access to server wide operations - "resource" permissions (
view,modify,remove,manage_comments,view_comments, andacl) which provide access to specific resources
Description. Create functional tests which test the acl permissions for Sonador. Both "global" and "local" tests are required. Refer to "Managing Resource Access" for details about the distinction between global and local tests.
The acl permission allows users to create policies related to a particular resource so that it can be shared with other users or groups in the platform.
- Global policy: if a user is a member of a global policy with the
aclpermission, she should be able to create local policies which authorize other users or groups to view and interact with the resource.- A wild card policy (
*) permission allows the user to create local policies for any resource in the platform (patient, study, or series). - A scoped policy (example 1:
patient={patient-uid}, example 2:study={study-uid}) allows for the user to create local policies for resources which are included in the scope.- A patient scope should grant permissions for the user to create local policies related to studies or series associated with the patient.
- A study scope should grant permissions for the user to create local policies associated with the series belonging to a study.
- A series scope should grant permissions for the user to create local policies for an individual series.
- A wild card policy (
- Local policy: if a user is a member of local policy that includes the
aclpermission, she should be able to create additional local policies for that resource and its children,.- Having a
patient(user or group) policy with theaclpermission allows for the creation of study or series policies. - A
studypolicy authorizes the creation of additional policies related to the study or to series which are members of the study. - A
seriespolicy authorizes the creation of policies for ONLY the series with which it is associated.
- Having a
- The
aclpermission is independent ofview: it authorizes managing (creating, reading, revoking) policies for a resource but does not authorize retrieving the resource data itself. Components that only manage access (e.g. service accounts) may holdaclwithoutview.
Test cases: (all 11 implemented and passing live against dev01 — sonador-ftests!13 (merged), tests/tests_sonadoracl_manage.py; merged to master 2026-07-09, commit ebb06327)
-
Global
-
Test case 1 (wild card): create global wild card (
*) permission policy for a group that a test user is a member of; upload a test resource; ensure that a limited user is able to create resource policies for patient, study, and series; check that the policies work as expected and allow the user to view/modify the resource. -
Test case 2 (scoped patient): create a scoped (
patient={uid}) permission policy for a group that a test user is a member of; upload a test resource; ensure that a limited user is able to create resource policies for patient, study, and series; check that the policies work as expected. -
Test case 3 (scoped study): similar to test case 2, but using a
study={uid}permission policy- Authorization provided by a study permission policy ALLOWS for policies to be created for child series.
-
Test case 4 (scoped series): similar to test case 3, but using a
series={uid}permission policy- When authorization is provided by a series permission policy, it SHOULD NOT be possible to create policies impacting the parent study (or sibling series)
-
Test case 1 (wild card): create global wild card (
-
Local
- Test case 1 (scoped patient): upload a resource to the server, create a local policy for the patient which includes the test user, ensure that the local user can create policies for studies and series belonging to the patient, and that the policies work as expected.
- Test case 2 (scoped study): similar to test case 1, policy created for study
- Test case 3 (scoped series): similar to test case 2, policy created for series
-
Negative / regression (added July 2026 — guards the interim enforcement shims and the acl/view separation, see technical note and design decision)
-
Test case 1 (
acl=False,query=True): a user whose global policy grantsquerybut notaclmust receive a 403 when attempting to create a resource policy via the DICOMweb (resource-acl) route. -
Test case 2 (
acl=False,modify=True): a user whose global policy grantsmodifybut notaclmust receive a 403 when attempting to create a resource policy via the internal (/{resource}/{uid}/acl/{user|group}) route. -
Test case 3 (revocation): after the creator's
aclgrant is revoked (global and local variants), further policy creation attempts must receive a 403. -
Test case 4 (
acl=True,view=False— separation): a principal whose policy grantsaclbut notviewmust be able to create and enumerate resource policies but must receive a 403 when attemptingview-mediated retrieval of the same resource (e.g.get_series, DICOMweb metadata/pixel routes). Confirmsacldoes not implyview.
-
Test case 1 (
References:
- "Managing Resource Access". Sonador Technical Reference. Jupyter Notebook describing the ACL control system within Sonador/Orthanc, how policies are created, and examples showing how they mediate interactions with resources.
- "Resource Authorization in Sonador". Sonador Documentation. ACL page within the Sonador documentation describing the architecture, components, and permissions of the system.
- orthanc-sonador!24 (merged): provides an overview of the access control endpoints that will need to be covered by the test cases.
-
oak-tree/medical-imaging/sonador!88 / orthanc-sonador!53 (merged): June 2026 ACL enforcement fixes (traversal signals, comment permissions) — establishes the leaf/ancestor pattern the
aclenforcement fix should follow. -
oak-tree/medical-imaging/sonador!91 / orthanc-sonador!56 (merged) / orthanc-authorization!2 (merged): July 2026
aclenforcement fix trio (merged 2026-07-09; deploy together). - sonador-ftests!8 (merged): ACL functional test matrix — conventions and base classes the new tests must follow.
-
oak-tree/medical-imaging/sonador-client!74: shared
assertRejected/assertDeniedhelpers the suite depends on.
Project Planning
OP#41 OP#74 OP#75