comparison Tests/CheckDicomTls.py @ 658:31a7e52b3da6

split DICOM TLS in 2: check-client and no-check-client
author Alain Mazy <am@orthanc.team>
date Mon, 17 Jun 2024 18:25:18 +0200
parents 5d7b6e43ab7d
children
comparison
equal deleted inserted replaced
657:9582c37652f4 658:31a7e52b3da6
59 parser.add_argument('--password', 59 parser.add_argument('--password',
60 default = 'orthanctest', 60 default = 'orthanctest',
61 help = 'Password to the REST API') 61 help = 'Password to the REST API')
62 parser.add_argument('--force', help = 'Do not warn the user', 62 parser.add_argument('--force', help = 'Do not warn the user',
63 action = 'store_true') 63 action = 'store_true')
64 parser.add_argument('--config', help = 'Create the configuration files for this test in the current folder', 64 parser.add_argument('--config-no-check-client', help = 'Create the configuration files for the "no-check-client" tests in the current folder',
65 action = 'store_true')
66 parser.add_argument('--config-check-client', help = 'Create the configuration files for the "check-client" tests test in the current folder',
65 action = 'store_true') 67 action = 'store_true')
66 parser.add_argument('options', metavar = 'N', nargs = '*', 68 parser.add_argument('options', metavar = 'N', nargs = '*',
67 help='Arguments to Python unittest') 69 help='Arguments to Python unittest')
68 70
69 args = parser.parse_args() 71 args = parser.parse_args()
72 ## 74 ##
73 ## Configure the testing context 75 ## Configure the testing context
74 ## 76 ##
75 77
76 78
77 if args.config: 79 if args.config_no_check_client or args.config_check_client:
78 def CreateCertificate(name): 80 def CreateCertificate(name):
79 subprocess.check_call([ 'openssl', 'req', '-x509', '-nodes', '-days', '365', '-newkey', 'rsa:2048', 81 subprocess.check_call([ 'openssl', 'req', '-x509', '-nodes', '-days', '365', '-newkey', 'rsa:2048',
80 '-keyout', '%s.key' % name, 82 '-keyout', '%s.key' % name,
81 '-out', '%s.crt' % name, 83 '-out', '%s.crt' % name,
82 '-subj', '/C=BE/CN=localhost' ]) 84 '-subj', '/C=BE/CN=localhost' ])
83 85
84 print('Writing configuration to folder: %s' % args.config) 86 print('Writing configuration for the %s tests to current folder' % ('no-check-client' if args.config_no_check_client else 'check-client'))
85 CreateCertificate('dicom-tls-a') 87 CreateCertificate('dicom-tls-a')
86 CreateCertificate('dicom-tls-b') 88 CreateCertificate('dicom-tls-b')
87 CreateCertificate('dicom-tls-c') # Not trusted by Orthanc 89 CreateCertificate('dicom-tls-c') # Not trusted by Orthanc
88 90
89 with open('dicom-tls-trusted.crt', 'w') as f: 91 with open('dicom-tls-trusted.crt', 'w') as f:
100 'ExecuteLuaEnabled' : True, 102 'ExecuteLuaEnabled' : True,
101 'RemoteAccessAllowed' : True, 103 'RemoteAccessAllowed' : True,
102 'RegisteredUsers' : { 104 'RegisteredUsers' : {
103 'alice' : 'orthanctest' 105 'alice' : 'orthanctest'
104 }, 106 },
105 'DicomTlsRemoteCertificateRequired' : False, # New in Orthanc 1.9.3 107 'DicomTlsRemoteCertificateRequired' : args.config_check_client, # New in Orthanc 1.9.3
106 })) 108 }))
107 109
108 exit(0) 110 exit(0)
109 111
110 112
134 136
135 137
136 FNULL = open(os.devnull, 'w') # Emulates "subprocess.DEVNULL" on Python 2.7 138 FNULL = open(os.devnull, 'w') # Emulates "subprocess.DEVNULL" on Python 2.7
137 139
138 140
139 class Orthanc(unittest.TestCase): 141 # in these tests, Orthanc does not check client certificates
142 class OrthancNoCheckClient(unittest.TestCase):
140 def setUp(self): 143 def setUp(self):
141 if (sys.version_info >= (3, 0)): 144 if (sys.version_info >= (3, 0)):
142 # Remove annoying warnings about unclosed socket in Python 3 145 # Remove annoying warnings about unclosed socket in Python 3
143 import warnings 146 import warnings
144 warnings.simplefilter('ignore', ResourceWarning) 147 warnings.simplefilter('ignore', ResourceWarning)
145 148
146 DropOrthanc(ORTHANC) 149 DropOrthanc(ORTHANC)
147 150
148 151
149 def test_incoming(self): 152 def test_incoming(self):
150 # No certificate 153 # No client certificate provided and client does not check server cert -> raise
151 self.assertRaises(Exception, lambda: subprocess.check_call([ 154 self.assertRaises(Exception, lambda: subprocess.check_call([
152 FindExecutable('echoscu'), 155 FindExecutable('echoscu'),
153 ORTHANC['Server'], 156 ORTHANC['Server'],
154 str(ORTHANC['DicomPort']), 157 str(ORTHANC['DicomPort']),
155 '-aec', 'ORTHANC', 158 '-aec', 'ORTHANC',
156 ], stderr = FNULL)) 159 ], stderr = FNULL))
157 160
161 # No client certificate provided and client does check server cert -> no raise
162 self.assertRaises(Exception, lambda: subprocess.check_call([
163 FindExecutable('echoscu'),
164 ORTHANC['Server'],
165 str(ORTHANC['DicomPort']),
166 '-aec', 'ORTHANC',
167 '+cf', 'dicom-tls-a.crt'
168 ], stderr = FNULL))
169
170 # random client certificate provided and client does check server cert -> no raise since Orthanc does not check the client cert
158 subprocess.check_call([ 171 subprocess.check_call([
159 FindExecutable('echoscu'), 172 FindExecutable('echoscu'),
160 ORTHANC['Server'], 173 ORTHANC['Server'],
161 str(ORTHANC['DicomPort']), 174 str(ORTHANC['DicomPort']),
162 '-aec', 'ORTHANC', 175 '-aec', 'ORTHANC',
163 '+tls', 'dicom-tls-b.key', 'dicom-tls-b.crt', 176 '+tls', 'dicom-tls-b.key', 'dicom-tls-b.crt',
164 '+cf', 'dicom-tls-a.crt', 177 '+cf', 'dicom-tls-a.crt',
165 ], stderr = FNULL) 178 ], stderr = FNULL)
166 179
167 self.assertRaises(Exception, lambda: subprocess.check_call([
168 FindExecutable('echoscu'),
169 ORTHANC['Server'],
170 str(ORTHANC['DicomPort']),
171 '-aec', 'ORTHANC',
172 '+tls', 'dicom-tls-c.key', 'dicom-tls-c.crt', # Not trusted by Orthanc
173 '+cf', 'dicom-tls-a.crt',
174 ], stderr = FNULL))
175
176 self.assertRaises(Exception, lambda: subprocess.check_call([
177 FindExecutable('echoscu'),
178 ORTHANC['Server'],
179 str(ORTHANC['DicomPort']),
180 '-aec', 'ORTHANC',
181 '+tls', 'dicom-tls-b.key', 'dicom-tls-b.crt',
182 '+cf', 'dicom-tls-b.crt', # Not the certificate of Orthanc
183 ], stderr = FNULL))
184 180
185 181
186 def test_outgoing_to_self(self): 182 def test_outgoing_to_self(self):
187 u = UploadInstance(ORTHANC, 'DummyCT.dcm') ['ID'] 183 u = UploadInstance(ORTHANC, 'DummyCT.dcm') ['ID']
188 184
216 '-aec', 'ORTHANC', 212 '-aec', 'ORTHANC',
217 '--anonymous-tls', 213 '--anonymous-tls',
218 '+cf', 'dicom-tls-a.crt', 214 '+cf', 'dicom-tls-a.crt',
219 ], stderr = FNULL) 215 ], stderr = FNULL)
220 216
221 217
218 # in these tests, Orthanc do checks client certificates
219 class OrthancCheckClient(unittest.TestCase):
220 def setUp(self):
221 if (sys.version_info >= (3, 0)):
222 # Remove annoying warnings about unclosed socket in Python 3
223 import warnings
224 warnings.simplefilter('ignore', ResourceWarning)
225
226 DropOrthanc(ORTHANC)
227
228
229 def test_check_client_incoming(self):
230 # client provides an untrusted certificate -> Orthanc will complain -> raise
231 self.assertRaises(Exception, lambda: subprocess.check_call([
232 FindExecutable('echoscu'),
233 ORTHANC['Server'],
234 str(ORTHANC['DicomPort']),
235 '-aec', 'ORTHANC',
236 '+tls', 'dicom-tls-c.key', 'dicom-tls-c.crt', # Not trusted by Orthanc
237 '+cf', 'dicom-tls-a.crt',
238 ], stderr = FNULL))
239
240 # client provides a trusted certificate but expects another cert from Orthanc -> raise
241 self.assertRaises(Exception, lambda: subprocess.check_call([
242 FindExecutable('echoscu'),
243 ORTHANC['Server'],
244 str(ORTHANC['DicomPort']),
245 '-aec', 'ORTHANC',
246 '+tls', 'dicom-tls-b.key', 'dicom-tls-b.crt',
247 '+cf', 'dicom-tls-b.crt', # Not the certificate of Orthanc
248 ], stderr = FNULL))
249
250
222 try: 251 try:
223 print('\nStarting the tests...') 252 print('\nStarting the tests...')
224 unittest.main(argv = [ sys.argv[0] ] + args.options) 253 unittest.main(argv = [ sys.argv[0] ] + args.options)
225 254
226 finally: 255 finally: