authentik.sources.saml.processors.metadata

SAML Service Provider Metadata Processor

 1"""SAML Service Provider Metadata Processor"""
 2
 3from django.http import HttpRequest
 4from lxml.etree import Element, SubElement, tostring  # nosec
 5
 6from authentik.common.saml.constants import (
 7    NS_MAP,
 8    NS_SAML_METADATA,
 9    NS_SIGNATURE,
10    SAML_BINDING_POST,
11)
12from authentik.providers.saml.utils.encoding import strip_pem_header
13from authentik.sources.saml.models import SAMLSource
14
15
16class MetadataProcessor:
17    """SAML Service Provider Metadata Processor"""
18
19    source: SAMLSource
20    http_request: HttpRequest
21
22    def __init__(self, source: SAMLSource, request: HttpRequest):
23        self.source = source
24        self.http_request = request
25
26    # Using type unions doesn't work with cython types (which is what lxml is)
27    def get_signing_key_descriptor(self) -> Element | None:  # noqa: UP007
28        """Get Signing KeyDescriptor, if enabled for the source"""
29        if self.source.signing_kp:
30            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
31            key_descriptor.attrib["use"] = "signing"
32            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
33            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
34            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
35            x509_certificate.text = strip_pem_header(
36                self.source.signing_kp.certificate_data.replace("\r", "")
37            ).replace("\n", "")
38            return key_descriptor
39        return None
40
41    def get_encryption_key_descriptor(self) -> Element | None:  # noqa: UP007
42        """Get Encryption KeyDescriptor, if enabled for the source"""
43        if self.source.encryption_kp:
44            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
45            key_descriptor.attrib["use"] = "encryption"
46            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
47            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
48            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
49            x509_certificate.text = strip_pem_header(
50                self.source.encryption_kp.certificate_data.replace("\r", "")
51            ).replace("\n", "")
52            return key_descriptor
53        return None
54
55    def get_name_id_format(self) -> Element:
56        element = Element(f"{{{NS_SAML_METADATA}}}NameIDFormat")
57        element.text = self.source.name_id_policy
58        return element
59
60    def build_entity_descriptor(self) -> str:
61        """Build full EntityDescriptor"""
62        entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
63        entity_descriptor.attrib["entityID"] = self.source.get_issuer(self.http_request)
64
65        sp_sso_descriptor = SubElement(entity_descriptor, f"{{{NS_SAML_METADATA}}}SPSSODescriptor")
66        sp_sso_descriptor.attrib["protocolSupportEnumeration"] = (
67            "urn:oasis:names:tc:SAML:2.0:protocol"
68        )
69
70        signing_descriptor = self.get_signing_key_descriptor()
71        if signing_descriptor is not None:
72            sp_sso_descriptor.append(signing_descriptor)
73
74        encryption_descriptor = self.get_encryption_key_descriptor()
75        if encryption_descriptor is not None:
76            sp_sso_descriptor.append(encryption_descriptor)
77
78        sp_sso_descriptor.append(self.get_name_id_format())
79
80        assertion_consumer_service = SubElement(
81            sp_sso_descriptor, f"{{{NS_SAML_METADATA}}}AssertionConsumerService"
82        )
83        assertion_consumer_service.attrib["isDefault"] = "true"
84        assertion_consumer_service.attrib["index"] = "0"
85        assertion_consumer_service.attrib["Binding"] = SAML_BINDING_POST
86        assertion_consumer_service.attrib["Location"] = self.source.build_full_url(
87            self.http_request
88        )
89
90        return tostring(entity_descriptor).decode()
class MetadataProcessor:
17class MetadataProcessor:
18    """SAML Service Provider Metadata Processor"""
19
20    source: SAMLSource
21    http_request: HttpRequest
22
23    def __init__(self, source: SAMLSource, request: HttpRequest):
24        self.source = source
25        self.http_request = request
26
27    # Using type unions doesn't work with cython types (which is what lxml is)
28    def get_signing_key_descriptor(self) -> Element | None:  # noqa: UP007
29        """Get Signing KeyDescriptor, if enabled for the source"""
30        if self.source.signing_kp:
31            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
32            key_descriptor.attrib["use"] = "signing"
33            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
34            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
35            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
36            x509_certificate.text = strip_pem_header(
37                self.source.signing_kp.certificate_data.replace("\r", "")
38            ).replace("\n", "")
39            return key_descriptor
40        return None
41
42    def get_encryption_key_descriptor(self) -> Element | None:  # noqa: UP007
43        """Get Encryption KeyDescriptor, if enabled for the source"""
44        if self.source.encryption_kp:
45            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
46            key_descriptor.attrib["use"] = "encryption"
47            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
48            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
49            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
50            x509_certificate.text = strip_pem_header(
51                self.source.encryption_kp.certificate_data.replace("\r", "")
52            ).replace("\n", "")
53            return key_descriptor
54        return None
55
56    def get_name_id_format(self) -> Element:
57        element = Element(f"{{{NS_SAML_METADATA}}}NameIDFormat")
58        element.text = self.source.name_id_policy
59        return element
60
61    def build_entity_descriptor(self) -> str:
62        """Build full EntityDescriptor"""
63        entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
64        entity_descriptor.attrib["entityID"] = self.source.get_issuer(self.http_request)
65
66        sp_sso_descriptor = SubElement(entity_descriptor, f"{{{NS_SAML_METADATA}}}SPSSODescriptor")
67        sp_sso_descriptor.attrib["protocolSupportEnumeration"] = (
68            "urn:oasis:names:tc:SAML:2.0:protocol"
69        )
70
71        signing_descriptor = self.get_signing_key_descriptor()
72        if signing_descriptor is not None:
73            sp_sso_descriptor.append(signing_descriptor)
74
75        encryption_descriptor = self.get_encryption_key_descriptor()
76        if encryption_descriptor is not None:
77            sp_sso_descriptor.append(encryption_descriptor)
78
79        sp_sso_descriptor.append(self.get_name_id_format())
80
81        assertion_consumer_service = SubElement(
82            sp_sso_descriptor, f"{{{NS_SAML_METADATA}}}AssertionConsumerService"
83        )
84        assertion_consumer_service.attrib["isDefault"] = "true"
85        assertion_consumer_service.attrib["index"] = "0"
86        assertion_consumer_service.attrib["Binding"] = SAML_BINDING_POST
87        assertion_consumer_service.attrib["Location"] = self.source.build_full_url(
88            self.http_request
89        )
90
91        return tostring(entity_descriptor).decode()

SAML Service Provider Metadata Processor

MetadataProcessor( source: authentik.sources.saml.models.SAMLSource, request: django.http.request.HttpRequest)
23    def __init__(self, source: SAMLSource, request: HttpRequest):
24        self.source = source
25        self.http_request = request
http_request: django.http.request.HttpRequest
def get_signing_key_descriptor(self) -> lxml.etree.Element | None:
28    def get_signing_key_descriptor(self) -> Element | None:  # noqa: UP007
29        """Get Signing KeyDescriptor, if enabled for the source"""
30        if self.source.signing_kp:
31            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
32            key_descriptor.attrib["use"] = "signing"
33            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
34            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
35            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
36            x509_certificate.text = strip_pem_header(
37                self.source.signing_kp.certificate_data.replace("\r", "")
38            ).replace("\n", "")
39            return key_descriptor
40        return None

Get Signing KeyDescriptor, if enabled for the source

def get_encryption_key_descriptor(self) -> lxml.etree.Element | None:
42    def get_encryption_key_descriptor(self) -> Element | None:  # noqa: UP007
43        """Get Encryption KeyDescriptor, if enabled for the source"""
44        if self.source.encryption_kp:
45            key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
46            key_descriptor.attrib["use"] = "encryption"
47            key_info = SubElement(key_descriptor, f"{{{NS_SIGNATURE}}}KeyInfo")
48            x509_data = SubElement(key_info, f"{{{NS_SIGNATURE}}}X509Data")
49            x509_certificate = SubElement(x509_data, f"{{{NS_SIGNATURE}}}X509Certificate")
50            x509_certificate.text = strip_pem_header(
51                self.source.encryption_kp.certificate_data.replace("\r", "")
52            ).replace("\n", "")
53            return key_descriptor
54        return None

Get Encryption KeyDescriptor, if enabled for the source

def get_name_id_format(self) -> lxml.etree.Element:
56    def get_name_id_format(self) -> Element:
57        element = Element(f"{{{NS_SAML_METADATA}}}NameIDFormat")
58        element.text = self.source.name_id_policy
59        return element
def build_entity_descriptor(self) -> str:
61    def build_entity_descriptor(self) -> str:
62        """Build full EntityDescriptor"""
63        entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
64        entity_descriptor.attrib["entityID"] = self.source.get_issuer(self.http_request)
65
66        sp_sso_descriptor = SubElement(entity_descriptor, f"{{{NS_SAML_METADATA}}}SPSSODescriptor")
67        sp_sso_descriptor.attrib["protocolSupportEnumeration"] = (
68            "urn:oasis:names:tc:SAML:2.0:protocol"
69        )
70
71        signing_descriptor = self.get_signing_key_descriptor()
72        if signing_descriptor is not None:
73            sp_sso_descriptor.append(signing_descriptor)
74
75        encryption_descriptor = self.get_encryption_key_descriptor()
76        if encryption_descriptor is not None:
77            sp_sso_descriptor.append(encryption_descriptor)
78
79        sp_sso_descriptor.append(self.get_name_id_format())
80
81        assertion_consumer_service = SubElement(
82            sp_sso_descriptor, f"{{{NS_SAML_METADATA}}}AssertionConsumerService"
83        )
84        assertion_consumer_service.attrib["isDefault"] = "true"
85        assertion_consumer_service.attrib["index"] = "0"
86        assertion_consumer_service.attrib["Binding"] = SAML_BINDING_POST
87        assertion_consumer_service.attrib["Location"] = self.source.build_full_url(
88            self.http_request
89        )
90
91        return tostring(entity_descriptor).decode()

Build full EntityDescriptor