diff --git a/GenerateConfigurationForTests.py b/GenerateConfigurationForTests.py index c3bd266..c39ac62 100755 --- a/GenerateConfigurationForTests.py +++ b/GenerateConfigurationForTests.py @@ -127,6 +127,17 @@ config['DicomModalities'] = { 'Host': ip, 'Port': 5001, 'LocalAet': 'OT-FROM-CONFIG' + }, + # This is a Modality used to test if queries such as `find-worklist` use + # the configured `LocalAet` of ths modality configuration. This modality + # configuration will allow `find-worklist` queries to succeed if the calling + # (LocalAet) is `FAKE_SELF_AET` + 'self-with-fake-local-aet': { + 'AET': 'FAKE_SELF_AET', + 'Host': '127.0.0.1', + 'Port': 4242, + 'LocalAet': 'FAKE_SELF_AET', + 'AllowFindWorklist': True } } config['DicomPort'] = args.dicom diff --git a/Tests/Tests.py b/Tests/Tests.py index 4d7291a..47e290d 100644 --- a/Tests/Tests.py +++ b/Tests/Tests.py @@ -4425,6 +4425,50 @@ class Orthanc(unittest.TestCase): self.assertEqual('OT-FROM-CONFIG', DoGet(_REMOTE, '/jobs/%s' % allJobs[0]['ID'])['Content']['LocalAet']) + def test_find_worklist_local_aet(self): + # Purpose: "/modalities/{id}/find-worklist" (and the REST handlers that + # share its SCU connection setup: the deprecated "/find", "/find-patient", + # "/find-study", "/find-series", "/find-instance", and "/echo") must use + # the "LocalAet" configured on the target modality as the calling AE + # title for the outgoing DICOM association, instead of always falling + # back to the global "DicomAet". + # + # How this test works: Orthanc is made to query a worklist/find SCP that + # is itself (a "self-loop", as used e.g. for periodic health checks), + # through the "self-with-fake-local-aet" modality, whose "LocalAet" + # ("FAKE_SELF_AET") is deliberately distinct from the global AET + # ("ORTHANC") and from every other modality's AET in this test + # configuration. The calling AE title is exactly what the SCP-side + # authorization check ("OrthancApplicationEntityFilter::IsAllowedRequest" + # in main.cpp) looks up in its own "DicomModalities" to decide whether to + # accept the incoming association: + # - If "LocalAet" is honored, Orthanc presents "FAKE_SELF_AET" to itself, + # which matches this very "DicomModalities" entry, so the association + # is authorized and the C-FIND succeeds. + # - If "LocalAet" is ignored, Orthanc presents its own global AET + # ("ORTHANC") instead, which isn't declared as any known modality's AET + # here, so the association is rejected and the REST call fails with a + # 500 error ("Peer aborted Association"). + # + # Note: this only works for request types whose "DicomAlwaysAllow*" + # option defaults to false, since otherwise an unrecognized calling AET + # is accepted anyway. This covers "FindWorklist" and the plain "Find" + # family (deprecated "/find*"), but not "Echo" or "Store" (both default + # to true, so they can't be checked this way, regardless of whether + # "LocalAet" is honored). + + answers = DoPost(_REMOTE, '/modalities/self-with-fake-local-aet/find-worklist', { + 'Query' : { 'PatientID' : '' } + }) + self.assertTrue(isinstance(answers, list)) + + # Same underlying helper, different DICOM request type ("Find" instead + # of "FindWorklist"): catches a fix narrowly scoped to "find-worklist" + # alone that would still leave the deprecated "find" family broken. + answers = DoPost(_REMOTE, '/modalities/self-with-fake-local-aet/find-patient', {}) + self.assertTrue(isinstance(answers, list)) + + def test_reconstruct_json(self): self.assertEqual(0, len(DoGet(_REMOTE, '/patients')))