We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add WantAuthnRequestsSigned Parameter to SAML Metadata Endpoint for Improved Integration with Spring Boot SAML Library
**Is your feature request related to a problem? Please describe.**
Yes, I consistently encounter an issue when integrating with the Spring Boot SAML Library. When the **WantAuthnRequestsSigned** parameter is missing in the SAML metadata endpoint within the XML file, the authentication page displays the message: "Verification Certificate configured, but request is not signed."

**Describe the solution you'd like**
I would like the **WantAuthnRequestsSigned="true"** parameter to be added to the XML file in the SAML metadata endpoint for the element **<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">**.

**Describe alternatives you've considered**
A potential alternative would be to modify the Spring Boot SAML Library to function even without the **WantAuthnRequestsSigned** parameter. However, this could lead to security concerns and is not the recommended approach.

**Additional context**
Adding this parameter is crucial for the correct functioning of authentication and the security of the system. It would be highly beneficial if this parameter were included in the XML file by default to prevent future integration issues.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `authentik/providers/saml/processors/metadata.py`
Content:
```
1 """SAML Identity Provider Metadata Processor"""
2 from hashlib import sha256
3 from typing import Iterator, Optional
4 
5 import xmlsec  # nosec
6 from django.http import HttpRequest
7 from django.urls import reverse
8 from lxml.etree import Element, SubElement, tostring  # nosec
9 
10 from authentik.providers.saml.models import SAMLProvider
11 from authentik.providers.saml.utils.encoding import strip_pem_header
12 from authentik.sources.saml.processors.constants import (
13     DIGEST_ALGORITHM_TRANSLATION_MAP,
14     NS_MAP,
15     NS_SAML_METADATA,
16     NS_SAML_PROTOCOL,
17     NS_SIGNATURE,
18     SAML_BINDING_POST,
19     SAML_BINDING_REDIRECT,
20     SAML_NAME_ID_FORMAT_EMAIL,
21     SAML_NAME_ID_FORMAT_PERSISTENT,
22     SAML_NAME_ID_FORMAT_TRANSIENT,
23     SAML_NAME_ID_FORMAT_X509,
24     SIGN_ALGORITHM_TRANSFORM_MAP,
25 )
26 
27 
28 class MetadataProcessor:
29     """SAML Identity Provider Metadata Processor"""
30 
31     provider: SAMLProvider
32     http_request: HttpRequest
33     force_binding: Optional[str]
34 
35     def __init__(self, provider: SAMLProvider, request: HttpRequest):
36         self.provider = provider
37         self.http_request = request
38         self.force_binding = None
39         self.xml_id = "_" + sha256(f"{provider.name}-{provider.pk}".encode("ascii")).hexdigest()
40 
41     def get_signing_key_descriptor(self) -> Optional[Element]:
42         """Get Signing KeyDescriptor, if enabled for the provider"""
43         if not self.provider.signing_kp:
44             return None
45         key_descriptor = Element(f"{{{NS_SAML_METADATA}}}KeyDescriptor")
46         key_descriptor.attrib["use"] = "signing"
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.provider.signing_kp.certificate_data.replace("\r", "")
52         )
53         return key_descriptor
54 
55     def get_name_id_formats(self) -> Iterator[Element]:
56         """Get compatible NameID Formats"""
57         formats = [
58             SAML_NAME_ID_FORMAT_EMAIL,
59             SAML_NAME_ID_FORMAT_PERSISTENT,
60             SAML_NAME_ID_FORMAT_X509,
61             SAML_NAME_ID_FORMAT_TRANSIENT,
62         ]
63         for name_id_format in formats:
64             element = Element(f"{{{NS_SAML_METADATA}}}NameIDFormat")
65             element.text = name_id_format
66             yield element
67 
68     def get_sso_bindings(self) -> Iterator[Element]:
69         """Get all Bindings supported"""
70         binding_url_map = {
71             (SAML_BINDING_REDIRECT, "SingleSignOnService"): self.http_request.build_absolute_uri(
72                 reverse(
73                     "authentik_providers_saml:sso-redirect",
74                     kwargs={"application_slug": self.provider.application.slug},
75                 )
76             ),
77             (SAML_BINDING_POST, "SingleSignOnService"): self.http_request.build_absolute_uri(
78                 reverse(
79                     "authentik_providers_saml:sso-post",
80                     kwargs={"application_slug": self.provider.application.slug},
81                 )
82             ),
83         }
84         for binding_svc, url in binding_url_map.items():
85             binding, svc = binding_svc
86             if self.force_binding and self.force_binding != binding:
87                 continue
88             element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
89             element.attrib["Binding"] = binding
90             element.attrib["Location"] = url
91             yield element
92 
93     def get_slo_bindings(self) -> Iterator[Element]:
94         """Get all Bindings supported"""
95         binding_url_map = {
96             (SAML_BINDING_REDIRECT, "SingleLogoutService"): self.http_request.build_absolute_uri(
97                 reverse(
98                     "authentik_providers_saml:slo-redirect",
99                     kwargs={"application_slug": self.provider.application.slug},
100                 )
101             ),
102             (SAML_BINDING_POST, "SingleLogoutService"): self.http_request.build_absolute_uri(
103                 reverse(
104                     "authentik_providers_saml:slo-post",
105                     kwargs={"application_slug": self.provider.application.slug},
106                 )
107             ),
108         }
109         for binding_svc, url in binding_url_map.items():
110             binding, svc = binding_svc
111             if self.force_binding and self.force_binding != binding:
112                 continue
113             element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
114             element.attrib["Binding"] = binding
115             element.attrib["Location"] = url
116             yield element
117 
118     def _prepare_signature(self, entity_descriptor: Element):
119         sign_algorithm_transform = SIGN_ALGORITHM_TRANSFORM_MAP.get(
120             self.provider.signature_algorithm, xmlsec.constants.TransformRsaSha1
121         )
122         signature = xmlsec.template.create(
123             entity_descriptor,
124             xmlsec.constants.TransformExclC14N,
125             sign_algorithm_transform,
126             ns="ds",  # type: ignore
127         )
128         entity_descriptor.append(signature)
129 
130     def _sign(self, entity_descriptor: Element):
131         digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(
132             self.provider.digest_algorithm, xmlsec.constants.TransformSha1
133         )
134         assertion = entity_descriptor.xpath("//md:EntityDescriptor", namespaces=NS_MAP)[0]
135         xmlsec.tree.add_ids(assertion, ["ID"])
136         signature_node = xmlsec.tree.find_node(assertion, xmlsec.constants.NodeSignature)
137         ref = xmlsec.template.add_reference(
138             signature_node,
139             digest_algorithm_transform,
140             uri="#" + self.xml_id,
141         )
142         xmlsec.template.add_transform(ref, xmlsec.constants.TransformEnveloped)
143         xmlsec.template.add_transform(ref, xmlsec.constants.TransformExclC14N)
144         key_info = xmlsec.template.ensure_key_info(signature_node)
145         xmlsec.template.add_x509_data(key_info)
146 
147         ctx = xmlsec.SignatureContext()
148 
149         key = xmlsec.Key.from_memory(
150             self.provider.signing_kp.key_data,
151             xmlsec.constants.KeyDataFormatPem,
152             None,
153         )
154         key.load_cert_from_memory(
155             self.provider.signing_kp.certificate_data,
156             xmlsec.constants.KeyDataFormatCertPem,
157         )
158         ctx.key = key
159         ctx.sign(signature_node)
160 
161     def build_entity_descriptor(self) -> str:
162         """Build full EntityDescriptor"""
163         entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
164         entity_descriptor.attrib["ID"] = self.xml_id
165         entity_descriptor.attrib["entityID"] = self.provider.issuer
166 
167         if self.provider.signing_kp:
168             self._prepare_signature(entity_descriptor)
169 
170         idp_sso_descriptor = SubElement(
171             entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor"
172         )
173         idp_sso_descriptor.attrib["protocolSupportEnumeration"] = NS_SAML_PROTOCOL
174 
175         signing_descriptor = self.get_signing_key_descriptor()
176         if signing_descriptor is not None:
177             idp_sso_descriptor.append(signing_descriptor)
178 
179         for binding in self.get_slo_bindings():
180             idp_sso_descriptor.append(binding)
181 
182         for name_id_format in self.get_name_id_formats():
183             idp_sso_descriptor.append(name_id_format)
184 
185         for binding in self.get_sso_bindings():
186             idp_sso_descriptor.append(binding)
187 
188         if self.provider.signing_kp:
189             self._sign(entity_descriptor)
190 
191         return tostring(entity_descriptor).decode()
192
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/authentik/providers/saml/processors/metadata.py b/authentik/providers/saml/processors/metadata.py
--- a/authentik/providers/saml/processors/metadata.py
+++ b/authentik/providers/saml/processors/metadata.py
@@ -171,6 +171,8 @@
             entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor"
         )
         idp_sso_descriptor.attrib["protocolSupportEnumeration"] = NS_SAML_PROTOCOL
+        if self.provider.verification_kp:
+            idp_sso_descriptor.attrib["WantAuthnRequestsSigned"] = "true"
 
         signing_descriptor = self.get_signing_key_descriptor()
         if signing_descriptor is not None:

{"golden_diff": "diff --git a/authentik/providers/saml/processors/metadata.py b/authentik/providers/saml/processors/metadata.py\n--- a/authentik/providers/saml/processors/metadata.py\n+++ b/authentik/providers/saml/processors/metadata.py\n@@ -171,6 +171,8 @@\n             entity_descriptor, f\"{{{NS_SAML_METADATA}}}IDPSSODescriptor\"\n         )\n         idp_sso_descriptor.attrib[\"protocolSupportEnumeration\"] = NS_SAML_PROTOCOL\n+        if self.provider.verification_kp:\n+            idp_sso_descriptor.attrib[\"WantAuthnRequestsSigned\"] = \"true\"\n \n         signing_descriptor = self.get_signing_key_descriptor()\n         if signing_descriptor is not None:\n", "issue": "Add WantAuthnRequestsSigned Parameter to SAML Metadata Endpoint for Improved Integration with Spring Boot SAML Library\n**Is your feature request related to a problem? Please describe.**\r\nYes, I consistently encounter an issue when integrating with the Spring Boot SAML Library. When the **WantAuthnRequestsSigned** parameter is missing in the SAML metadata endpoint within the XML file, the authentication page displays the message: \"Verification Certificate configured, but request is not signed.\"\r\n\r\n**Describe the solution you'd like**\r\nI would like the **WantAuthnRequestsSigned=\"true\"** parameter to be added to the XML file in the SAML metadata endpoint for the element **<md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">**.\r\n\r\n**Describe alternatives you've considered**\r\nA potential alternative would be to modify the Spring Boot SAML Library to function even without the **WantAuthnRequestsSigned** parameter. However, this could lead to security concerns and is not the recommended approach.\r\n\r\n**Additional context**\r\nAdding this parameter is crucial for the correct functioning of authentication and the security of the system. It would be highly beneficial if this parameter were included in the XML file by default to prevent future integration issues.\n", "before_files": [{"content": "\"\"\"SAML Identity Provider Metadata Processor\"\"\"\nfrom hashlib import sha256\nfrom typing import Iterator, Optional\n\nimport xmlsec  # nosec\nfrom django.http import HttpRequest\nfrom django.urls import reverse\nfrom lxml.etree import Element, SubElement, tostring  # nosec\n\nfrom authentik.providers.saml.models import SAMLProvider\nfrom authentik.providers.saml.utils.encoding import strip_pem_header\nfrom authentik.sources.saml.processors.constants import (\n    DIGEST_ALGORITHM_TRANSLATION_MAP,\n    NS_MAP,\n    NS_SAML_METADATA,\n    NS_SAML_PROTOCOL,\n    NS_SIGNATURE,\n    SAML_BINDING_POST,\n    SAML_BINDING_REDIRECT,\n    SAML_NAME_ID_FORMAT_EMAIL,\n    SAML_NAME_ID_FORMAT_PERSISTENT,\n    SAML_NAME_ID_FORMAT_TRANSIENT,\n    SAML_NAME_ID_FORMAT_X509,\n    SIGN_ALGORITHM_TRANSFORM_MAP,\n)\n\n\nclass MetadataProcessor:\n    \"\"\"SAML Identity Provider Metadata Processor\"\"\"\n\n    provider: SAMLProvider\n    http_request: HttpRequest\n    force_binding: Optional[str]\n\n    def __init__(self, provider: SAMLProvider, request: HttpRequest):\n        self.provider = provider\n        self.http_request = request\n        self.force_binding = None\n        self.xml_id = \"_\" + sha256(f\"{provider.name}-{provider.pk}\".encode(\"ascii\")).hexdigest()\n\n    def get_signing_key_descriptor(self) -> Optional[Element]:\n        \"\"\"Get Signing KeyDescriptor, if enabled for the provider\"\"\"\n        if not self.provider.signing_kp:\n            return None\n        key_descriptor = Element(f\"{{{NS_SAML_METADATA}}}KeyDescriptor\")\n        key_descriptor.attrib[\"use\"] = \"signing\"\n        key_info = SubElement(key_descriptor, f\"{{{NS_SIGNATURE}}}KeyInfo\")\n        x509_data = SubElement(key_info, f\"{{{NS_SIGNATURE}}}X509Data\")\n        x509_certificate = SubElement(x509_data, f\"{{{NS_SIGNATURE}}}X509Certificate\")\n        x509_certificate.text = strip_pem_header(\n            self.provider.signing_kp.certificate_data.replace(\"\\r\", \"\")\n        )\n        return key_descriptor\n\n    def get_name_id_formats(self) -> Iterator[Element]:\n        \"\"\"Get compatible NameID Formats\"\"\"\n        formats = [\n            SAML_NAME_ID_FORMAT_EMAIL,\n            SAML_NAME_ID_FORMAT_PERSISTENT,\n            SAML_NAME_ID_FORMAT_X509,\n            SAML_NAME_ID_FORMAT_TRANSIENT,\n        ]\n        for name_id_format in formats:\n            element = Element(f\"{{{NS_SAML_METADATA}}}NameIDFormat\")\n            element.text = name_id_format\n            yield element\n\n    def get_sso_bindings(self) -> Iterator[Element]:\n        \"\"\"Get all Bindings supported\"\"\"\n        binding_url_map = {\n            (SAML_BINDING_REDIRECT, \"SingleSignOnService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:sso-redirect\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n            (SAML_BINDING_POST, \"SingleSignOnService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:sso-post\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n        }\n        for binding_svc, url in binding_url_map.items():\n            binding, svc = binding_svc\n            if self.force_binding and self.force_binding != binding:\n                continue\n            element = Element(f\"{{{NS_SAML_METADATA}}}{svc}\")\n            element.attrib[\"Binding\"] = binding\n            element.attrib[\"Location\"] = url\n            yield element\n\n    def get_slo_bindings(self) -> Iterator[Element]:\n        \"\"\"Get all Bindings supported\"\"\"\n        binding_url_map = {\n            (SAML_BINDING_REDIRECT, \"SingleLogoutService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:slo-redirect\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n            (SAML_BINDING_POST, \"SingleLogoutService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:slo-post\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n        }\n        for binding_svc, url in binding_url_map.items():\n            binding, svc = binding_svc\n            if self.force_binding and self.force_binding != binding:\n                continue\n            element = Element(f\"{{{NS_SAML_METADATA}}}{svc}\")\n            element.attrib[\"Binding\"] = binding\n            element.attrib[\"Location\"] = url\n            yield element\n\n    def _prepare_signature(self, entity_descriptor: Element):\n        sign_algorithm_transform = SIGN_ALGORITHM_TRANSFORM_MAP.get(\n            self.provider.signature_algorithm, xmlsec.constants.TransformRsaSha1\n        )\n        signature = xmlsec.template.create(\n            entity_descriptor,\n            xmlsec.constants.TransformExclC14N,\n            sign_algorithm_transform,\n            ns=\"ds\",  # type: ignore\n        )\n        entity_descriptor.append(signature)\n\n    def _sign(self, entity_descriptor: Element):\n        digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(\n            self.provider.digest_algorithm, xmlsec.constants.TransformSha1\n        )\n        assertion = entity_descriptor.xpath(\"//md:EntityDescriptor\", namespaces=NS_MAP)[0]\n        xmlsec.tree.add_ids(assertion, [\"ID\"])\n        signature_node = xmlsec.tree.find_node(assertion, xmlsec.constants.NodeSignature)\n        ref = xmlsec.template.add_reference(\n            signature_node,\n            digest_algorithm_transform,\n            uri=\"#\" + self.xml_id,\n        )\n        xmlsec.template.add_transform(ref, xmlsec.constants.TransformEnveloped)\n        xmlsec.template.add_transform(ref, xmlsec.constants.TransformExclC14N)\n        key_info = xmlsec.template.ensure_key_info(signature_node)\n        xmlsec.template.add_x509_data(key_info)\n\n        ctx = xmlsec.SignatureContext()\n\n        key = xmlsec.Key.from_memory(\n            self.provider.signing_kp.key_data,\n            xmlsec.constants.KeyDataFormatPem,\n            None,\n        )\n        key.load_cert_from_memory(\n            self.provider.signing_kp.certificate_data,\n            xmlsec.constants.KeyDataFormatCertPem,\n        )\n        ctx.key = key\n        ctx.sign(signature_node)\n\n    def build_entity_descriptor(self) -> str:\n        \"\"\"Build full EntityDescriptor\"\"\"\n        entity_descriptor = Element(f\"{{{NS_SAML_METADATA}}}EntityDescriptor\", nsmap=NS_MAP)\n        entity_descriptor.attrib[\"ID\"] = self.xml_id\n        entity_descriptor.attrib[\"entityID\"] = self.provider.issuer\n\n        if self.provider.signing_kp:\n            self._prepare_signature(entity_descriptor)\n\n        idp_sso_descriptor = SubElement(\n            entity_descriptor, f\"{{{NS_SAML_METADATA}}}IDPSSODescriptor\"\n        )\n        idp_sso_descriptor.attrib[\"protocolSupportEnumeration\"] = NS_SAML_PROTOCOL\n\n        signing_descriptor = self.get_signing_key_descriptor()\n        if signing_descriptor is not None:\n            idp_sso_descriptor.append(signing_descriptor)\n\n        for binding in self.get_slo_bindings():\n            idp_sso_descriptor.append(binding)\n\n        for name_id_format in self.get_name_id_formats():\n            idp_sso_descriptor.append(name_id_format)\n\n        for binding in self.get_sso_bindings():\n            idp_sso_descriptor.append(binding)\n\n        if self.provider.signing_kp:\n            self._sign(entity_descriptor)\n\n        return tostring(entity_descriptor).decode()\n", "path": "authentik/providers/saml/processors/metadata.py"}], "after_files": [{"content": "\"\"\"SAML Identity Provider Metadata Processor\"\"\"\nfrom hashlib import sha256\nfrom typing import Iterator, Optional\n\nimport xmlsec  # nosec\nfrom django.http import HttpRequest\nfrom django.urls import reverse\nfrom lxml.etree import Element, SubElement, tostring  # nosec\n\nfrom authentik.providers.saml.models import SAMLProvider\nfrom authentik.providers.saml.utils.encoding import strip_pem_header\nfrom authentik.sources.saml.processors.constants import (\n    DIGEST_ALGORITHM_TRANSLATION_MAP,\n    NS_MAP,\n    NS_SAML_METADATA,\n    NS_SAML_PROTOCOL,\n    NS_SIGNATURE,\n    SAML_BINDING_POST,\n    SAML_BINDING_REDIRECT,\n    SAML_NAME_ID_FORMAT_EMAIL,\n    SAML_NAME_ID_FORMAT_PERSISTENT,\n    SAML_NAME_ID_FORMAT_TRANSIENT,\n    SAML_NAME_ID_FORMAT_X509,\n    SIGN_ALGORITHM_TRANSFORM_MAP,\n)\n\n\nclass MetadataProcessor:\n    \"\"\"SAML Identity Provider Metadata Processor\"\"\"\n\n    provider: SAMLProvider\n    http_request: HttpRequest\n    force_binding: Optional[str]\n\n    def __init__(self, provider: SAMLProvider, request: HttpRequest):\n        self.provider = provider\n        self.http_request = request\n        self.force_binding = None\n        self.xml_id = \"_\" + sha256(f\"{provider.name}-{provider.pk}\".encode(\"ascii\")).hexdigest()\n\n    def get_signing_key_descriptor(self) -> Optional[Element]:\n        \"\"\"Get Signing KeyDescriptor, if enabled for the provider\"\"\"\n        if not self.provider.signing_kp:\n            return None\n        key_descriptor = Element(f\"{{{NS_SAML_METADATA}}}KeyDescriptor\")\n        key_descriptor.attrib[\"use\"] = \"signing\"\n        key_info = SubElement(key_descriptor, f\"{{{NS_SIGNATURE}}}KeyInfo\")\n        x509_data = SubElement(key_info, f\"{{{NS_SIGNATURE}}}X509Data\")\n        x509_certificate = SubElement(x509_data, f\"{{{NS_SIGNATURE}}}X509Certificate\")\n        x509_certificate.text = strip_pem_header(\n            self.provider.signing_kp.certificate_data.replace(\"\\r\", \"\")\n        )\n        return key_descriptor\n\n    def get_name_id_formats(self) -> Iterator[Element]:\n        \"\"\"Get compatible NameID Formats\"\"\"\n        formats = [\n            SAML_NAME_ID_FORMAT_EMAIL,\n            SAML_NAME_ID_FORMAT_PERSISTENT,\n            SAML_NAME_ID_FORMAT_X509,\n            SAML_NAME_ID_FORMAT_TRANSIENT,\n        ]\n        for name_id_format in formats:\n            element = Element(f\"{{{NS_SAML_METADATA}}}NameIDFormat\")\n            element.text = name_id_format\n            yield element\n\n    def get_sso_bindings(self) -> Iterator[Element]:\n        \"\"\"Get all Bindings supported\"\"\"\n        binding_url_map = {\n            (SAML_BINDING_REDIRECT, \"SingleSignOnService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:sso-redirect\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n            (SAML_BINDING_POST, \"SingleSignOnService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:sso-post\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n        }\n        for binding_svc, url in binding_url_map.items():\n            binding, svc = binding_svc\n            if self.force_binding and self.force_binding != binding:\n                continue\n            element = Element(f\"{{{NS_SAML_METADATA}}}{svc}\")\n            element.attrib[\"Binding\"] = binding\n            element.attrib[\"Location\"] = url\n            yield element\n\n    def get_slo_bindings(self) -> Iterator[Element]:\n        \"\"\"Get all Bindings supported\"\"\"\n        binding_url_map = {\n            (SAML_BINDING_REDIRECT, \"SingleLogoutService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:slo-redirect\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n            (SAML_BINDING_POST, \"SingleLogoutService\"): self.http_request.build_absolute_uri(\n                reverse(\n                    \"authentik_providers_saml:slo-post\",\n                    kwargs={\"application_slug\": self.provider.application.slug},\n                )\n            ),\n        }\n        for binding_svc, url in binding_url_map.items():\n            binding, svc = binding_svc\n            if self.force_binding and self.force_binding != binding:\n                continue\n            element = Element(f\"{{{NS_SAML_METADATA}}}{svc}\")\n            element.attrib[\"Binding\"] = binding\n            element.attrib[\"Location\"] = url\n            yield element\n\n    def _prepare_signature(self, entity_descriptor: Element):\n        sign_algorithm_transform = SIGN_ALGORITHM_TRANSFORM_MAP.get(\n            self.provider.signature_algorithm, xmlsec.constants.TransformRsaSha1\n        )\n        signature = xmlsec.template.create(\n            entity_descriptor,\n            xmlsec.constants.TransformExclC14N,\n            sign_algorithm_transform,\n            ns=\"ds\",  # type: ignore\n        )\n        entity_descriptor.append(signature)\n\n    def _sign(self, entity_descriptor: Element):\n        digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(\n            self.provider.digest_algorithm, xmlsec.constants.TransformSha1\n        )\n        assertion = entity_descriptor.xpath(\"//md:EntityDescriptor\", namespaces=NS_MAP)[0]\n        xmlsec.tree.add_ids(assertion, [\"ID\"])\n        signature_node = xmlsec.tree.find_node(assertion, xmlsec.constants.NodeSignature)\n        ref = xmlsec.template.add_reference(\n            signature_node,\n            digest_algorithm_transform,\n            uri=\"#\" + self.xml_id,\n        )\n        xmlsec.template.add_transform(ref, xmlsec.constants.TransformEnveloped)\n        xmlsec.template.add_transform(ref, xmlsec.constants.TransformExclC14N)\n        key_info = xmlsec.template.ensure_key_info(signature_node)\n        xmlsec.template.add_x509_data(key_info)\n\n        ctx = xmlsec.SignatureContext()\n\n        key = xmlsec.Key.from_memory(\n            self.provider.signing_kp.key_data,\n            xmlsec.constants.KeyDataFormatPem,\n            None,\n        )\n        key.load_cert_from_memory(\n            self.provider.signing_kp.certificate_data,\n            xmlsec.constants.KeyDataFormatCertPem,\n        )\n        ctx.key = key\n        ctx.sign(signature_node)\n\n    def build_entity_descriptor(self) -> str:\n        \"\"\"Build full EntityDescriptor\"\"\"\n        entity_descriptor = Element(f\"{{{NS_SAML_METADATA}}}EntityDescriptor\", nsmap=NS_MAP)\n        entity_descriptor.attrib[\"ID\"] = self.xml_id\n        entity_descriptor.attrib[\"entityID\"] = self.provider.issuer\n\n        if self.provider.signing_kp:\n            self._prepare_signature(entity_descriptor)\n\n        idp_sso_descriptor = SubElement(\n            entity_descriptor, f\"{{{NS_SAML_METADATA}}}IDPSSODescriptor\"\n        )\n        idp_sso_descriptor.attrib[\"protocolSupportEnumeration\"] = NS_SAML_PROTOCOL\n        if self.provider.verification_kp:\n            idp_sso_descriptor.attrib[\"WantAuthnRequestsSigned\"] = \"true\"\n\n        signing_descriptor = self.get_signing_key_descriptor()\n        if signing_descriptor is not None:\n            idp_sso_descriptor.append(signing_descriptor)\n\n        for binding in self.get_slo_bindings():\n            idp_sso_descriptor.append(binding)\n\n        for name_id_format in self.get_name_id_formats():\n            idp_sso_descriptor.append(name_id_format)\n\n        for binding in self.get_sso_bindings():\n            idp_sso_descriptor.append(binding)\n\n        if self.provider.signing_kp:\n            self._sign(entity_descriptor)\n\n        return tostring(entity_descriptor).decode()\n", "path": "authentik/providers/saml/processors/metadata.py"}]}