Revize 5e31b492
Přidáno uživatelem David Friesecký před téměř 4 roky(ů)
src/controllers/certificates_controller.py | ||
---|---|---|
17 | 17 |
CertificateStatusInvalidException, CertificateNotFoundException, CertificateAlreadyRevokedException |
18 | 18 |
# responsibility. |
19 | 19 |
from src.services.key_service import KeyService |
20 |
from src.utils.logger import Logger |
|
21 |
from src.utils.util import dict_to_string |
|
20 | 22 |
|
21 | 23 |
TREE_NODE_TYPE_COUNT = 3 |
22 | 24 |
|
... | ... | |
67 | 69 |
|
68 | 70 |
:rtype: CreatedResponse |
69 | 71 |
""" |
72 |
|
|
73 |
Logger.info(f"\n\t{request.referrer}" |
|
74 |
f"\n\t{request.method} {request.path} {request.scheme}") |
|
75 |
|
|
70 | 76 |
required_keys = {SUBJECT, USAGE, VALIDITY_DAYS} # required fields of the POST req |
71 | 77 |
|
72 | 78 |
if request.is_json: # accept JSON only |
73 | 79 |
body = request.get_json() |
80 |
|
|
81 |
Logger.info(f"\n\tRequest body:" |
|
82 |
f"\n{dict_to_string(body)}") |
|
83 |
|
|
74 | 84 |
if not all(k in body for k in required_keys): # verify that all keys are present |
85 |
Logger.error(f"Invalid request, missing parameters") |
|
75 | 86 |
return E_MISSING_PARAMETERS, C_BAD_REQUEST |
76 | 87 |
|
77 | 88 |
if not isinstance(body[VALIDITY_DAYS], int): # type checking |
89 |
Logger.error(f"Invalid request, wrong parameter '{VALIDITY_DAYS}'.") |
|
78 | 90 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
79 | 91 |
|
80 | 92 |
subject = Subject.from_dict(body[SUBJECT]) # generate Subject from passed dict |
81 | 93 |
|
82 | 94 |
if subject is None: # if the format is incorrect |
95 |
Logger.error(f"Invalid request, wrong parameter '{SUBJECT}'.") |
|
83 | 96 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
84 | 97 |
|
85 | 98 |
usages_dict = {} |
86 | 99 |
|
87 | 100 |
if not isinstance(body[USAGE], dict): # type checking |
101 |
Logger.error(f"Invalid request, wrong parameter '{USAGE}'.") |
|
88 | 102 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
89 | 103 |
|
90 | 104 |
for k, v in body[USAGE].items(): # for each usage |
91 | 105 |
if k not in CertController.KEY_MAP: # check that it is a valid usage |
106 |
Logger.error(f"Invalid request, wrong parameter '{USAGE}'[{k}].") |
|
92 | 107 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST # and throw if it is not |
93 | 108 |
usages_dict[CertController.KEY_MAP[k]] = v # otherwise translate key and set |
94 | 109 |
|
... | ... | |
105 | 120 |
issuer = self.certificate_service.get_certificate(body[CA]) # get base issuer info |
106 | 121 |
|
107 | 122 |
if issuer is None: # if such issuer does not exist |
123 |
Logger.error(f"No certificate authority with such unique ID exists 'ID = {key.private_key_id}'.") |
|
108 | 124 |
self.key_service.delete_key(key.private_key_id) # free |
109 | 125 |
return E_NO_ISSUER_FOUND, C_BAD_REQUEST # and throw |
110 | 126 |
|
111 | 127 |
issuer_key = self.key_service.get_key(issuer.private_key_id) # get issuer's key, which must exist |
112 | 128 |
|
113 | 129 |
if issuer_key is None: # if it does not |
130 |
Logger.error(f"Internal server error (corrupted database).") |
|
114 | 131 |
self.key_service.delete_key(key.private_key_id) # free |
115 | 132 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR # and throw |
116 | 133 |
|
... | ... | |
131 | 148 |
return {"success": True, |
132 | 149 |
"data": cert.certificate_id}, C_CREATED_SUCCESSFULLY |
133 | 150 |
else: # if this fails, then |
151 |
Logger.error(f"Internal error: The certificate could not have been created.") |
|
134 | 152 |
self.key_service.delete_key(key.private_key_id) # free |
135 | 153 |
return {"success": False, # and wonder what the cause is, |
136 | 154 |
"data": "Internal error: The certificate could not have been created."}, C_BAD_REQUEST |
137 | 155 |
# as obj/None carries only one bit |
138 | 156 |
# of error information |
139 | 157 |
else: |
158 |
Logger.error(f"The request must be JSON-formatted.") |
|
140 | 159 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST # throw in case of non-JSON format |
141 | 160 |
|
142 | 161 |
def get_certificate_by_id(self, id): |
... | ... | |
149 | 168 |
|
150 | 169 |
:rtype: PemResponse |
151 | 170 |
""" |
171 |
|
|
172 |
Logger.info(f"\n\t{request.referrer}" |
|
173 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
174 |
f"\n\tCertificate ID = {id}") |
|
152 | 175 |
try: |
153 | 176 |
v = int(id) |
154 | 177 |
except ValueError: |
178 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
155 | 179 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
156 | 180 |
|
157 | 181 |
cert = self.certificate_service.get_certificate(v) |
158 | 182 |
|
159 | 183 |
if cert is None: |
184 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
160 | 185 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
161 | 186 |
else: |
162 | 187 |
return {"success": True, "data": cert.pem_data}, C_SUCCESS |
... | ... | |
171 | 196 |
|
172 | 197 |
:rtype: CertificateResponse |
173 | 198 |
""" |
199 |
|
|
200 |
Logger.info(f"\n\t{request.referrer}" |
|
201 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
202 |
f"\n\tCertificate ID = {id}") |
|
203 |
|
|
174 | 204 |
try: |
175 | 205 |
v = int(id) |
176 | 206 |
except ValueError: |
207 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
177 | 208 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
178 | 209 |
|
179 | 210 |
cert = self.certificate_service.get_certificate(v) |
180 | 211 |
|
181 | 212 |
if cert is None: |
213 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
182 | 214 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
183 | 215 |
else: |
184 | 216 |
data = self.cert_to_dict_full(cert) |
... | ... | |
196 | 228 |
|
197 | 229 |
:rtype: CertificateListResponse |
198 | 230 |
""" |
231 |
|
|
232 |
Logger.info(f"\n\t{request.referrer}" |
|
233 |
f"\n\t{request.method} {request.path} {request.scheme}") |
|
234 |
|
|
199 | 235 |
targets = {ROOT_CA_ID, INTERMEDIATE_CA_ID, CERTIFICATE_ID} # all targets |
200 | 236 |
issuer_id = -1 |
201 | 237 |
|
... | ... | |
207 | 243 |
try: |
208 | 244 |
data = {FILTERING: json.loads(request.args[FILTERING])} |
209 | 245 |
except JSONDecodeError: |
246 |
Logger.error(f"The request must be JSON-formatted.") |
|
210 | 247 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST |
211 | 248 |
|
249 |
Logger.info(f"\n\tRequest body:" |
|
250 |
f"\n{dict_to_string(data)}") |
|
251 |
|
|
212 | 252 |
if FILTERING in data: # if the 'filtering' field exists |
213 | 253 |
if isinstance(data[FILTERING], dict): # and it is also a 'dict' |
214 | 254 |
if CA in data[FILTERING]: # containing 'CA' |
... | ... | |
219 | 259 |
targets.remove(ROOT_CA_ID) |
220 | 260 |
targets.remove(INTERMEDIATE_CA_ID) |
221 | 261 |
else: |
262 |
Logger.error(f"Invalid request, wrong parameters '{FILTERING}.{CA}'.") |
|
222 | 263 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
223 | 264 |
if ISSUED_BY in data[FILTERING]: # containing 'issuedby' |
224 | 265 |
if isinstance(data[FILTERING][ISSUED_BY], int): # which is an 'int' |
225 | 266 |
issuer_id = data[FILTERING][ISSUED_BY] # then get its children only |
226 | 267 |
else: |
268 |
Logger.error(f"Invalid request, wrong parameters '{FILTERING}'.") |
|
227 | 269 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
228 | 270 |
if issuer_id >= 0: # if filtering by an issuer |
229 | 271 |
try: |
230 | 272 |
children = self.certificate_service.get_certificates_issued_by(issuer_id) # get his children |
231 | 273 |
except CertificateNotFoundException: # if id does not exist |
274 |
Logger.error(f"No such certificate found 'ID = {issuer_id}'.") |
|
232 | 275 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND # throw |
233 | 276 |
|
234 | 277 |
certs = [child for child in children if child.type_id in targets] |
... | ... | |
246 | 289 |
certs = self.certificate_service.get_certificates() # if no params, fetch everything |
247 | 290 |
|
248 | 291 |
if certs is None: |
292 |
Logger.error(f"Internal server error (unknown origin).") |
|
249 | 293 |
return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR |
250 | 294 |
elif len(certs) == 0: |
295 |
# TODO check log level |
|
296 |
Logger.warning(f"No such certificate found (empty list).") |
|
251 | 297 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
252 | 298 |
else: |
253 | 299 |
ret = [] |
254 | 300 |
for c in certs: |
255 | 301 |
data = self.cert_to_dict_partial(c) |
256 | 302 |
if data is None: |
303 |
Logger.error(f"Internal server error (corrupted database).") |
|
257 | 304 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR |
258 | 305 |
ret.append( |
259 | 306 |
data |
... | ... | |
270 | 317 |
|
271 | 318 |
:rtype: PemResponse |
272 | 319 |
""" |
320 |
|
|
321 |
Logger.info(f"\n\t{request.referrer}" |
|
322 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
323 |
f"\n\tCertificate ID = {id}") |
|
324 |
|
|
273 | 325 |
try: |
274 | 326 |
v = int(id) |
275 | 327 |
except ValueError: |
328 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
276 | 329 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
277 | 330 |
|
278 | 331 |
cert = self.certificate_service.get_certificate(v) |
279 | 332 |
|
280 | 333 |
if cert is None: |
334 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
281 | 335 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
282 | 336 |
|
283 | 337 |
trust_chain = self.certificate_service.get_chain_of_trust(cert.parent_id, exclude_root=False) |
284 | 338 |
if trust_chain is None or len(trust_chain) == 0: |
339 |
Logger.error(f"No such certificate found (empty list).") |
|
285 | 340 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
286 | 341 |
|
287 | 342 |
return {"success": True, "data": trust_chain[-1].pem_data}, C_SUCCESS |
... | ... | |
297 | 352 |
:rtype: PemResponse |
298 | 353 |
""" |
299 | 354 |
|
355 |
Logger.info(f"\n\t{request.referrer}" |
|
356 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
357 |
f"\n\tCertificate ID = {id}") |
|
358 |
|
|
300 | 359 |
try: |
301 | 360 |
v = int(id) |
302 | 361 |
except ValueError: |
362 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
303 | 363 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
304 | 364 |
|
305 | 365 |
cert = self.certificate_service.get_certificate(v) |
306 | 366 |
|
307 | 367 |
if cert is None: |
368 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
308 | 369 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
309 | 370 |
|
310 | 371 |
if cert.parent_id is None: |
372 |
Logger.error(f"Parent ID is empty in certificate 'ID = {v}'.") |
|
311 | 373 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA |
312 | 374 |
|
313 | 375 |
trust_chain = self.certificate_service.get_chain_of_trust(cert.parent_id) |
... | ... | |
329 | 391 |
|
330 | 392 |
:rtype: SuccessResponse | ErrorResponse (see OpenAPI definition) |
331 | 393 |
""" |
332 |
required_keys = {STATUS} # required keys |
|
333 | 394 |
|
334 |
# try to parse certificate identifier -> if it is not int return error 400
|
|
335 |
try:
|
|
336 |
identifier = int(id)
|
|
337 |
except ValueError: |
|
338 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
|
395 |
Logger.info(f"\n\t{request.referrer}"
|
|
396 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
397 |
f"\n\tCertificate ID = {id}")
|
|
398 |
|
|
399 |
required_keys = {STATUS} # required keys
|
|
339 | 400 |
|
340 | 401 |
# check if the request contains a JSON body |
341 | 402 |
if request.is_json: |
342 | 403 |
request_body = request.get_json() |
404 |
|
|
405 |
Logger.info(f"\n\tRequest body:" |
|
406 |
f"\n{dict_to_string(request_body)}") |
|
407 |
|
|
408 |
# try to parse certificate identifier -> if it is not int return error 400 |
|
409 |
try: |
|
410 |
identifier = int(id) |
|
411 |
except ValueError: |
|
412 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
413 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
|
414 |
|
|
343 | 415 |
# verify that all required keys are present |
344 | 416 |
if not all(k in request_body for k in required_keys): |
417 |
Logger.error(f"Invalid request, missing parameters.") |
|
345 | 418 |
return E_MISSING_PARAMETERS, C_BAD_REQUEST |
346 | 419 |
|
347 | 420 |
# get status and reason from the request |
... | ... | |
352 | 425 |
self.certificate_service.set_certificate_revocation_status(identifier, status, reason) |
353 | 426 |
except (RevocationReasonInvalidException, CertificateStatusInvalidException): |
354 | 427 |
# these exceptions are thrown in case invalid status or revocation reason is passed to the controller |
428 |
Logger.error(f"Invalid request, wrong parameters.") |
|
355 | 429 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
356 | 430 |
except CertificateAlreadyRevokedException: |
431 |
Logger.error(f"Certificate is already revoked 'ID = {identifier}'.") |
|
357 | 432 |
return E_NO_CERTIFICATE_ALREADY_REVOKED, C_BAD_REQUEST |
358 | 433 |
except CertificateNotFoundException: |
434 |
Logger.error(f"No such certificate found 'ID = {identifier}'.") |
|
359 | 435 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND |
360 | 436 |
return {"success": True, |
361 | 437 |
"data": "Certificate status updated successfully."}, C_SUCCESS |
362 | 438 |
# throw an error in case the request does not contain a json body |
363 | 439 |
else: |
440 |
Logger.error(f"The request must be JSON-formatted.") |
|
364 | 441 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST |
365 | 442 |
|
366 | 443 |
def cert_to_dict_partial(self, c): |
... | ... | |
369 | 446 |
:param c: target cert |
370 | 447 |
:return: certificate dict (compliant with some parts of the REST API) |
371 | 448 |
""" |
449 |
|
|
450 |
# TODO check log |
|
451 |
Logger.debug(f"Function launched.") |
|
452 |
|
|
372 | 453 |
c_issuer = self.certificate_service.get_certificate(c.parent_id) |
373 | 454 |
if c_issuer is None: |
374 | 455 |
return None |
... | ... | |
392 | 473 |
:param c: target cert |
393 | 474 |
:return: certificate dict (compliant with some parts of the REST API) |
394 | 475 |
""" |
476 |
|
|
477 |
Logger.info(f"Function launched.") |
|
478 |
|
|
395 | 479 |
subj = self.certificate_service.get_subject_from_certificate(c) |
396 | 480 |
c_issuer = self.certificate_service.get_certificate(c.parent_id) |
397 | 481 |
if c_issuer is None: |
... | ... | |
415 | 499 |
:rtype: PemResponse |
416 | 500 |
""" |
417 | 501 |
|
502 |
Logger.info(f"\n\t{request.referrer}" |
|
503 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
504 |
f"\n\tCertificate ID = {id}") |
|
505 |
|
|
418 | 506 |
# try to parse the supplied ID |
419 | 507 |
try: |
420 | 508 |
v = int(id) |
421 | 509 |
except ValueError: |
510 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
422 | 511 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
423 | 512 |
|
424 | 513 |
# find a certificate using the given ID |
425 | 514 |
cert = self.certificate_service.get_certificate(v) |
426 | 515 |
|
427 | 516 |
if cert is None: |
517 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
428 | 518 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND |
429 | 519 |
else: |
430 | 520 |
# certificate exists, fetch it's private key |
431 | 521 |
private_key = self.key_service.get_key(cert.private_key_id) |
432 | 522 |
if cert is None: |
523 |
Logger.error(f"Internal server error (certificate's private key cannot be found).") |
|
433 | 524 |
return E_NO_CERT_PRIVATE_KEY_FOUND, C_INTERNAL_SERVER_ERROR |
434 | 525 |
else: |
435 | 526 |
return {"success": True, "data": private_key.private_key}, C_SUCCESS |
... | ... | |
444 | 535 |
:rtype: PemResponse |
445 | 536 |
""" |
446 | 537 |
|
538 |
Logger.info(f"\n\t{request.referrer}" |
|
539 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
540 |
f"\n\tCertificate ID = {id}") |
|
541 |
|
|
447 | 542 |
# try to parse the supplied ID |
448 | 543 |
try: |
449 | 544 |
v = int(id) |
450 | 545 |
except ValueError: |
546 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
451 | 547 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
452 | 548 |
|
453 | 549 |
# find a certificate using the given ID |
454 | 550 |
cert = self.certificate_service.get_certificate(v) |
455 | 551 |
|
456 | 552 |
if cert is None: |
553 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
457 | 554 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND |
458 | 555 |
else: |
459 | 556 |
return {"success": True, "data": self.certificate_service.get_public_key_from_certificate(cert)}, C_SUCCESS |
... | ... | |
464 | 561 |
:param id: target certificate ID |
465 | 562 |
:rtype: DeleteResponse |
466 | 563 |
""" |
564 |
|
|
565 |
Logger.info(f"\n\t{request.referrer}" |
|
566 |
f"\n\t{request.method} {request.path} {request.scheme}" |
|
567 |
f"\n\tCertificate ID = {id}") |
|
568 |
|
|
467 | 569 |
try: |
468 | 570 |
v = int(id) |
469 | 571 |
except ValueError: |
572 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].") |
|
470 | 573 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST |
471 | 574 |
|
472 | 575 |
try: |
473 | 576 |
self.certificate_service.delete_certificate(v) |
474 | 577 |
except CertificateNotFoundException: |
578 |
Logger.error(f"No such certificate found 'ID = {v}'.") |
|
475 | 579 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND |
476 | 580 |
except DatabaseException: |
581 |
Logger.error(f"Internal server error (corrupted database).") |
|
477 | 582 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR |
478 | 583 |
except CertificateStatusInvalidException or RevocationReasonInvalidException or UnknownException: |
584 |
Logger.error(f"Internal server error (unknown origin).") |
|
479 | 585 |
return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR |
480 | 586 |
|
481 | 587 |
return {"success": True, "data": "The certificate and its descendants have been successfully deleted."} |
Také k dispozici: Unified diff
Re #8570 - Messages logging