Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 94f8d5cf

Přidáno uživatelem Jan Pašek před téměř 4 roky(ů)

Re #8700 - Implemented certificate revalidation check and fixed affected tests

Zobrazit rozdíly:

src/constants.py
59 59
                                  "CACompromise", "affiliationChanged",
60 60
                                  "superseded", "cessationOfOperation",
61 61
                                  "certificateHold", "removeFromCRL"}
62
CERTIFICATE_REVOCATION_REASON_HOLD = "certificateHold"
62 63

  
63 64

  
64 65
# Insert values into the template using % (index_file, serial_file)
src/controllers/certificates_controller.py
14 14
from src.exceptions.unknown_exception import UnknownException
15 15
from src.model.subject import Subject
16 16
from src.services.certificate_service import CertificateService, RevocationReasonInvalidException, \
17
    CertificateStatusInvalidException, CertificateNotFoundException, CertificateAlreadyRevokedException
17
    CertificateStatusInvalidException, CertificateNotFoundException, CertificateAlreadyRevokedException, \
18
    CertificateCannotBeSetToValid
18 19
#  responsibility.
19 20
from src.services.key_service import KeyService
20 21

  
......
357 358
                return E_NO_CERTIFICATE_ALREADY_REVOKED, C_BAD_REQUEST
358 359
            except CertificateNotFoundException:
359 360
                return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
361
            except CertificateCannotBeSetToValid as e:
362
                return {"success": False, "data": str(e)}, C_BAD_REQUEST
360 363
            return {"success": True,
361 364
                    "data": "Certificate status updated successfully."}, C_SUCCESS
362 365
        # throw an error in case the request does not contain a json body
src/services/certificate_service.py
4 4

  
5 5
from src.config.configuration import Configuration
6 6
from src.constants import ROOT_CA_ID, INTERMEDIATE_CA_ID, CA_ID, CERTIFICATE_ID, CERTIFICATE_STATES, \
7
    CERTIFICATE_REVOCATION_REASONS, SSL_ID, SIGNATURE_ID, AUTHENTICATION_ID
7
    CERTIFICATE_REVOCATION_REASONS, SSL_ID, SIGNATURE_ID, AUTHENTICATION_ID, CERTIFICATE_REVOCATION_REASON_HOLD
8 8
from src.dao.certificate_repository import CertificateRepository
9 9
from src.exceptions.certificate_not_found_exception import CertificateNotFoundException
10 10
from src.exceptions.database_exception import DatabaseException
......
326 326
        :param reason: reason for revocation
327 327
        :param id: identifier of the certificate whose status is to be changed
328 328
        :param status: new status of the certificate
329
        :raises CertificateStatusInvalidException: if status is not valid
330
        :raises RevocationReasonInvalidException: if reason is not valid
331
        :raises CertificateNotFoundException: if certificate with given id cannot be found
332
        :raises CertificateCannotBeSetToValid: if certificate was already revoked and not on hold,
333
                it cannot be set revalidated
334
        :raises CertificateAlreadyRevokedException: if caller tries to revoke a certificate that is already revoked
335
        :raises UnknownException: if the database is corrupted
329 336
        """
330 337
        if status not in CERTIFICATE_STATES:
331 338
            raise CertificateStatusInvalidException(status)
......
339 346

  
340 347
        updated = False
341 348
        if status == STATUS_VALID:
349
            # if the certificate is revoked but the reason is not certificateHold, it cannot be re-validated
350
            #    -> throw an exception
351
            if certificate.revocation_reason != "" and \
352
               certificate.revocation_reason != CERTIFICATE_REVOCATION_REASON_HOLD:
353
                raise CertificateCannotBeSetToValid(certificate.revocation_reason)
342 354
            updated = self.certificate_repository.clear_certificate_revocation(id)
343 355
        elif status == STATUS_REVOKED:
344 356
            # check if the certificate is not revoked already
......
430 442

  
431 443
    def __str__(self):
432 444
        return f"Certificate id '{self.id}' is already revoked."
445

  
446

  
447
class CertificateCannotBeSetToValid(Exception):
448
    """
449
    Exception that denotes that the caller was trying to
450
    set certificate to valid if the certificate was already
451
    revoked but not certificateHold.
452
    """
453

  
454
    def __init__(self, old_reason):
455
        self.old_state = old_reason
456

  
457
    def __str__(self):
458
        return "Cannot set revoked certificate back to valid when the certificate revocation reason is not " \
459
               "certificateHold. " \
460
               f"The revocation reason of the certificate is {self.old_state}"
tests/integration_tests/rest_api/certificates_test.py
639 639
    d = created_ret.json
640 640
    cert_id = d["data"]
641 641

  
642
    # hold certificate
643
    revocation_body = {
644
        "status": "revoked",
645
        "reason": "certificateHold"
646
    }
647
    revoke_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=revocation_body)
648

  
649
    assert revoke_ret.status_code == 200
650
    assert "data" in revoke_ret.json
651
    assert "success" in revoke_ret.json
652
    assert revoke_ret.json["success"]
653

  
654
    # set back to valid again
655
    valid_body = {
656
        "status": "valid"
657
    }
658
    valid_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=valid_body)
659

  
660
    assert valid_ret.status_code == 200
661
    assert "data" in valid_ret.json
662
    assert "success" in valid_ret.json
663
    assert valid_ret.json["success"]
664

  
642 665
    # revoke the certificate
643 666
    revocation_body = {
644 667
        "status": "revoked",
......
664 687
    }
665 688
    valid_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=valid_body)
666 689

  
667
    assert valid_ret.status_code == 200
690
    assert valid_ret.status_code == 400
668 691
    assert "data" in valid_ret.json
669 692
    assert "success" in valid_ret.json
670
    assert valid_ret.json["success"]
693
    assert not valid_ret.json["success"]
671 694

  
672 695
    # wrong status
673 696
    revocation_body = {
tests/integration_tests/services/certificate_service_test.py
5 5
from src.constants import SSL_ID, CA_ID, AUTHENTICATION_ID, INTERMEDIATE_CA_ID, ROOT_CA_ID, CERTIFICATE_ID, SIGNATURE_ID
6 6
from src.model.subject import Subject
7 7
from src.services.certificate_service import RevocationReasonInvalidException, CertificateStatusInvalidException, \
8
    CertificateNotFoundException, CertificateAlreadyRevokedException
8
    CertificateNotFoundException, CertificateAlreadyRevokedException, CertificateCannotBeSetToValid
9 9

  
10 10

  
11 11
def export_crt(crt):
......
318 318
                                                         root_ca_cert,
319 319
                                                         root_ca_private_key, usages={SSL_ID: True})
320 320

  
321
    certificate_service_unique.set_certificate_revocation_status(inter_ca_cert.certificate_id, "revoked", "unspecified")
321
    certificate_service_unique.set_certificate_revocation_status(inter_ca_cert.certificate_id, "revoked", "certificateHold")
322 322
    all_revoked = certificate_repository_unique.get_all_revoked_by(root_ca_cert.certificate_id)
323 323

  
324 324
    assert len(all_revoked) == 1
......
353 353
    with pytest.raises(CertificateAlreadyRevokedException) as e:
354 354
        certificate_service_unique.set_certificate_revocation_status(root_ca_cert.certificate_id, "revoked",
355 355
                                                                     "unspecified")
356

  
357
    with pytest.raises(CertificateCannotBeSetToValid) as e:
358
        certificate_service_unique.set_certificate_revocation_status(root_ca_cert.certificate_id, "valid")

Také k dispozici: Unified diff