43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
|
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"<ClientCertificateUser[serial_number={self.serial_number}, issuer_name={self.issuer_name},"
|
||
|
f" subject_name={self.subject_name}, emails={self.emails}]>")
|
||
|
|
||
|
|
||
|
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)
|