class CertUtilsTest(TestCase): """ Tests to exercise splice.common.certs.CertUtils """ def setUp(self): super(CertUtilsTest, self).setUp() # Test Certificate Data # invalid cert, signed by a CA other than 'root_ca_pem' self.invalid_key_path = os.path.join(TEST_DATA_DIR, 'invalid_cert', 'invalid.key') self.invalid_identity_cert_path = os.path.join(TEST_DATA_DIR, "invalid_cert", "invalid.cert") self.invalid_identity_cert_pem = open(self.invalid_identity_cert_path, "r").read() # a valid cert, signed by the below CA, 'root_ca_pem' self.valid_identity_cert_path = os.path.join(TEST_DATA_DIR, "valid_cert", "valid.cert") self.valid_identity_cert_pem = open(self.valid_identity_cert_path, "r").read() # CA self.root_ca_crt_path = os.path.join(TEST_DATA_DIR, 'ca', 'ca.crt') self.root_ca_key_path = os.path.join(TEST_DATA_DIR, 'ca', 'ca.key') self.root_ca_srl_path = os.path.join(TEST_DATA_DIR, 'ca', 'ca.srl') self.root_ca_crt = open(self.root_ca_crt_path).read() self.root_ca_key = open(self.root_ca_key_path).read() self.root_ca_pem = open(self.root_ca_srl_path).read() self.root_ca_pem = self.root_ca_crt + self.root_ca_key self.expected_valid_identity_uuid = "fb647f68-aa01-4171-b62b-35c2984a5328" self.cert_utils = CertUtils() def tearDown(self): super(CertUtilsTest, self).tearDown() def test_validate_certificate_pem_valid(self): self.assertTrue(self.cert_utils.validate_certificate( self.valid_identity_cert_pem, self.root_ca_pem)) def test_validate_certificate_pem_invalid(self): self.assertFalse(self.cert_utils.validate_certificate( self.invalid_identity_cert_pem, self.root_ca_pem)) def test_get_subject_pieces(self): pieces = self.cert_utils.get_subject_pieces(self.valid_identity_cert_pem) self.assertTrue(pieces["CN"]) self.assertEquals(pieces["CN"], self.expected_valid_identity_uuid) def test_get_subject_pieces_with_filepath(self): caught = False try: pieces = self.cert_utils.get_subject_pieces(self.valid_identity_cert_path) except CertificateParseException, e: caught = True self.assertTrue(caught)
class X509CertificateAuthentication(Authentication): """ Class will perform authentication based on the X509 certificate used to form the SSL connection. The certificate will be found from the context of the request. If the certificate has been signed by the configured CA and it is valid the request will be authenticated. """ def __init__(self, verification_ca): """ @param verification_ca: CA to be used in verifying client certificates were signed correctly. This is the actual string PEM encoded certificate, not a path to a file @type verification_ca: str, contents in PEM encoded format @return: """ super(X509CertificateAuthentication, self).__init__(require_active=False) self.verification_ca = verification_ca self.cert_utils = CertUtils() def is_authenticated(self, request, **kwargs): """ Verify that the SSL client certificate used to form this SSL Connection has been signed by the configured CA. @param request: @type django.http.HttpRequest @param kwargs: @return: """ x509_cert_from_request = get_client_cert_from_request(request) if x509_cert_from_request: if self.cert_utils.validate_certificate(x509_cert_from_request, self.verification_ca): return True return HttpResponse( content="Unable to verify SSL client's identity certificate was signed by configured CA", status=httplib.UNAUTHORIZED) # Optional but recommended def get_identifier(self, request): """ Return the UUID and Account number embedded in the certificate @param request: @return: (CN, O) corresponds to CN being the UUID of the certificate and O being the account number """ x509_cert_from_request = get_client_cert_from_request(request) return get_identifier_from_cert(x509_cert_from_request)