From afbdc84f84e63b3714e257153335114c59e4c1f4 Mon Sep 17 00:00:00 2001 From: Captain_Trojan <sejakm@students.zcu.cz> Date: Fri, 16 Apr 2021 22:06:28 +0200 Subject: [PATCH 1/3] Re #8574 - Extended the `get_certificate_list` method of CertificateController to reflect the filtering query 'issuedby' update. --- src/controllers/certificates_controller.py | 34 +++++++++++++++------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/controllers/certificates_controller.py b/src/controllers/certificates_controller.py index 932c745..67b5004 100644 --- a/src/controllers/certificates_controller.py +++ b/src/controllers/certificates_controller.py @@ -29,6 +29,7 @@ USAGE = "usage" SUBJECT = "subject" VALIDITY_DAYS = "validityDays" CA = "CA" +ISSUED_BY = "issuedby" STATUS = "status" REASON = "reason" REASON_UNDEFINED = "unspecified" @@ -161,7 +162,7 @@ class CertController: cert = self.certificate_service.get_certificate(v) if cert is None: - return E_NO_CERTIFICATES_FOUND, C_NO_DATA + return E_NO_CERTIFICATES_FOUND, C_NO_DATA else: return {"success": True, "data": cert.pem_data}, C_SUCCESS @@ -183,7 +184,7 @@ class CertController: cert = self.certificate_service.get_certificate(v) if cert is None: - return E_NO_CERTIFICATES_FOUND, C_NO_DATA + return E_NO_CERTIFICATES_FOUND, C_NO_DATA else: data = self.cert_to_dict_full(cert) if data is None: @@ -201,14 +202,15 @@ class CertController: :rtype: CertificateListResponse """ targets = {ROOT_CA_ID, INTERMEDIATE_CA_ID, CERTIFICATE_ID} # all targets + issuer_id = -1 # the filtering parameter can be read as URL argument or as a request body - if request.is_json or "filtering" in request.args.keys(): # if the request carries JSON data + if request.is_json or FILTERING in request.args.keys(): # if the request carries JSON data if request.is_json: data = request.get_json() # get it else: try: - data = {"filtering": json.loads(request.args["filtering"])} + data = {FILTERING: json.loads(request.args[FILTERING])} except JSONDecodeError: return E_NOT_JSON_FORMAT, C_BAD_REQUEST @@ -223,23 +225,33 @@ class CertController: targets.remove(INTERMEDIATE_CA_ID) else: return E_WRONG_PARAMETERS, C_BAD_REQUEST + if ISSUED_BY in data[FILTERING]: # containing 'issuedby' + if isinstance(data[FILTERING][ISSUED_BY], int): # which is an 'int' + issuer_id = data[FILTERING][ISSUED_BY] # then get its children only else: return E_WRONG_PARAMETERS, C_BAD_REQUEST + if issuer_id >= 0: # if filtering by an issuer + try: + children = self.certificate_service.get_certificates_issued_by(issuer_id) # get his children + except CertificateNotFoundException: # if id does not exist + return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND # throw - if len(targets) == TREE_NODE_TYPE_COUNT: # = 3 -> root node, + certs = [child for child in children if child.type_id in targets] + + elif len(targets) == TREE_NODE_TYPE_COUNT: # = 3 -> root node, # intermediate node, # or leaf node # if filtering did not change the # targets, - certs = self.certificate_service.get_certificates() # fetch everything - else: # otherwise fetch targets only - certs = list(chain(*(self.certificate_service.get_certificates(target) for target in targets))) + certs = self.certificate_service.get_certificates() # fetch everything + else: # otherwise fetch targets only + certs = list(chain(*(self.certificate_service.get_certificates(target) for target in targets))) + else: + certs = self.certificate_service.get_certificates() # if no params, fetch everything if certs is None: return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR - elif len(certs) == 0: - return E_NO_CERTIFICATES_FOUND, C_NO_DATA else: ret = [] for c in certs: @@ -296,7 +308,7 @@ class CertController: cert = self.certificate_service.get_certificate(v) if cert is None: - return E_NO_CERTIFICATES_FOUND, C_NO_DATA + return E_NO_CERTIFICATES_FOUND, C_NO_DATA if cert.parent_id is None: return E_NO_CERTIFICATES_FOUND, C_NO_DATA -- GitLab From 485913d0a75f4e733b19be3e542939919f0bd81b Mon Sep 17 00:00:00 2001 From: Captain_Trojan <sejakm@students.zcu.cz> Date: Fri, 16 Apr 2021 22:08:43 +0200 Subject: [PATCH 2/3] Re #8574 - Added the `get_certificates_issued_by(id)` method to the CertificateService (just calling the homonymous CryptoService method). --- src/services/certificate_service.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/services/certificate_service.py b/src/services/certificate_service.py index a609443..5dd997d 100644 --- a/src/services/certificate_service.py +++ b/src/services/certificate_service.py @@ -6,6 +6,7 @@ from src.config.configuration import Configuration from src.constants import ROOT_CA_ID, INTERMEDIATE_CA_ID, CA_ID, CERTIFICATE_ID, CERTIFICATE_STATES, \ CERTIFICATE_REVOCATION_REASONS from src.dao.certificate_repository import CertificateRepository +from src.exceptions.database_exception import DatabaseException from src.exceptions.unknown_exception import UnknownException from src.model.certificate import Certificate from src.model.private_key import PrivateKey @@ -267,6 +268,21 @@ class CertificateService: # TODO delete children? return self.certificate_repository.delete(unique_id) + def get_certificates_issued_by(self, unique_id): + """ + Returns a list of all children of a certificate identified by an unique_id. + Raises a DatabaseException should any unexpected behavior occur. + :param unique_id: target certificate ID + :return: children of unique_id + """ + try: + if self.certificate_repository.read(unique_id) is None: + raise CertificateNotFoundException(unique_id) + except DatabaseException: + raise CertificateNotFoundException(unique_id) + + return self.certificate_repository.get_all_issued_by(unique_id) + def set_certificate_revocation_status(self, id, status, reason="unspecified"): """ Set certificate status to 'valid' or 'revoked'. -- GitLab From 5aa1b47663ba8591f85be7637d149ecb4521f18a Mon Sep 17 00:00:00 2001 From: Captain_Trojan <sejakm@students.zcu.cz> Date: Fri, 16 Apr 2021 22:09:31 +0200 Subject: [PATCH 3/3] Re #8574 - Added tests for the new filtering functionality. --- .../rest_api/certificates_test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/integration_tests/rest_api/certificates_test.py b/tests/integration_tests/rest_api/certificates_test.py index a63dad1..9d68c62 100644 --- a/tests/integration_tests/rest_api/certificates_test.py +++ b/tests/integration_tests/rest_api/certificates_test.py @@ -399,6 +399,24 @@ def test_filtering(server): assert len(all_certs_actual) == len(all_certs_expected) # TODO assert set(all_certs_expected) == set(all_certs_actual) or something like that instead + ret = server.get("/api/certificates", json={"filtering": {"issuedby": 2}}) + assert ret.status_code == 200 + assert "data" in ret.json + assert "success" in ret.json + assert ret.json["success"] + issued_by_2 = ret.json["data"] + assert len(issued_by_2) == 2 + assert set(issued_by_2[i]["id"] for i in range(2)) == {3, 8} + + ret = server.get("/api/certificates", json={"filtering": {"issuedby": 2, "CA": True}}) + assert ret.status_code == 200 + assert "data" in ret.json + assert "success" in ret.json + assert ret.json["success"] + issued_by_2 = ret.json["data"] + assert len(issued_by_2) == 1 + assert issued_by_2[0]["id"] == 3 + def test_get_one(server): ret = server.get("/api/certificates/1") -- GitLab