from urllib.parse import unquote_to_bytes from cryptography import x509 from cryptography.x509 import load_pem_x509_certificate, SubjectAlternativeName from django.contrib.auth.backends import BaseBackend class ClientCertificateUser: def __init__(self, serial_number, issuer_name, subject_name, emails): self.serial_number = serial_number self.issuer_name = issuer_name self.subject_name = subject_name self.emails = emails def __str__(self): return (f"") class ClientCertificateBackend(BaseBackend): def authenticate(self, request, encoded_certificate=None): """ encoded_certificate is expected to be a URL encoded PEM certificate as sent by nginx when using the $ssl_client_escaped_cert """ if encoded_certificate is None: return None pem_data = unquote_to_bytes(encoded_certificate) certificate_data = load_pem_x509_certificate(pem_data) subject_alternative_name = certificate_data.extensions.get_extension_for_class(SubjectAlternativeName) emails = subject_alternative_name.value.get_values_for_type(x509.RFC822Name) serial_number = f"{certificate_data.serial_number:X}" if len(serial_number) % 2 == 1: serial_number = "0" + serial_number issuer_name = certificate_data.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value subject_name = certificate_data.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value return ClientCertificateUser(serial_number, issuer_name, subject_name, emails)