authentik.providers.saml.processors.logout_request_parser

LogoutRequest parser

 1"""LogoutRequest parser"""
 2
 3from base64 import b64decode
 4from dataclasses import dataclass
 5
 6from defusedxml import ElementTree
 7
 8from authentik.common.saml.constants import NS_SAML_ASSERTION, NS_SAML_PROTOCOL
 9from authentik.providers.saml.exceptions import CannotHandleAssertion
10from authentik.providers.saml.models import SAMLProvider
11from authentik.providers.saml.processors.authn_request_parser import ERROR_CANNOT_DECODE_REQUEST
12from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
13
14
15@dataclass(slots=True)
16class LogoutRequest:
17    """Logout Request"""
18
19    id: str | None = None
20
21    issuer: str | None = None
22
23    name_id: str | None = None
24
25    name_id_format: str | None = None
26
27    session_index: str | None = None
28
29    relay_state: str | None = None
30
31
32class LogoutRequestParser:
33    """LogoutRequest Parser"""
34
35    provider: SAMLProvider
36
37    def __init__(self, provider: SAMLProvider):
38        self.provider = provider
39
40    def _parse_xml(self, decoded_xml: str | bytes, relay_state: str | None = None) -> LogoutRequest:
41        root = ElementTree.fromstring(decoded_xml)
42        request = LogoutRequest(
43            id=root.attrib["ID"],
44        )
45        # Try both namespaces for Issuer
46        issuers = root.findall(f"{{{NS_SAML_PROTOCOL}}}Issuer")
47        if not issuers:
48            issuers = root.findall(f"{{{NS_SAML_ASSERTION}}}Issuer")
49        if len(issuers) > 0:
50            request.issuer = issuers[0].text
51
52        # Extract NameID
53        name_ids = root.findall(f"{{{NS_SAML_ASSERTION}}}NameID")
54        if not name_ids:
55            name_ids = root.findall(f"{{{NS_SAML_PROTOCOL}}}NameID")
56        if len(name_ids) > 0:
57            request.name_id = name_ids[0].text
58            # Extract NameID Format if present
59            if "Format" in name_ids[0].attrib:
60                request.name_id_format = name_ids[0].attrib["Format"]
61
62        # Extract SessionIndex
63        session_indexes = root.findall(f"{{{NS_SAML_PROTOCOL}}}SessionIndex")
64        if not session_indexes:
65            session_indexes = root.findall(f"{{{NS_SAML_ASSERTION}}}SessionIndex")
66        if len(session_indexes) > 0:
67            request.session_index = session_indexes[0].text
68
69        request.relay_state = relay_state
70        return request
71
72    def parse(self, saml_request: str, relay_state: str | None = None) -> LogoutRequest:
73        """Validate and parse raw request with enveloped signautre."""
74        try:
75            decoded_xml = b64decode(saml_request.encode())
76        except UnicodeDecodeError:
77            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
78        return self._parse_xml(decoded_xml, relay_state)
79
80    def parse_detached(
81        self,
82        saml_request: str,
83        relay_state: str | None = None,
84    ) -> LogoutRequest:
85        """Validate and parse raw request with detached signature"""
86        try:
87            decoded_xml = decode_base64_and_inflate(saml_request)
88        except UnicodeDecodeError:
89            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
90
91        return self._parse_xml(decoded_xml, relay_state)
@dataclass(slots=True)
class LogoutRequest:
16@dataclass(slots=True)
17class LogoutRequest:
18    """Logout Request"""
19
20    id: str | None = None
21
22    issuer: str | None = None
23
24    name_id: str | None = None
25
26    name_id_format: str | None = None
27
28    session_index: str | None = None
29
30    relay_state: str | None = None

Logout Request

LogoutRequest( id: str | None = None, issuer: str | None = None, name_id: str | None = None, name_id_format: str | None = None, session_index: str | None = None, relay_state: str | None = None)
id: str | None
issuer: str | None
name_id: str | None
name_id_format: str | None
session_index: str | None
relay_state: str | None
class LogoutRequestParser:
33class LogoutRequestParser:
34    """LogoutRequest Parser"""
35
36    provider: SAMLProvider
37
38    def __init__(self, provider: SAMLProvider):
39        self.provider = provider
40
41    def _parse_xml(self, decoded_xml: str | bytes, relay_state: str | None = None) -> LogoutRequest:
42        root = ElementTree.fromstring(decoded_xml)
43        request = LogoutRequest(
44            id=root.attrib["ID"],
45        )
46        # Try both namespaces for Issuer
47        issuers = root.findall(f"{{{NS_SAML_PROTOCOL}}}Issuer")
48        if not issuers:
49            issuers = root.findall(f"{{{NS_SAML_ASSERTION}}}Issuer")
50        if len(issuers) > 0:
51            request.issuer = issuers[0].text
52
53        # Extract NameID
54        name_ids = root.findall(f"{{{NS_SAML_ASSERTION}}}NameID")
55        if not name_ids:
56            name_ids = root.findall(f"{{{NS_SAML_PROTOCOL}}}NameID")
57        if len(name_ids) > 0:
58            request.name_id = name_ids[0].text
59            # Extract NameID Format if present
60            if "Format" in name_ids[0].attrib:
61                request.name_id_format = name_ids[0].attrib["Format"]
62
63        # Extract SessionIndex
64        session_indexes = root.findall(f"{{{NS_SAML_PROTOCOL}}}SessionIndex")
65        if not session_indexes:
66            session_indexes = root.findall(f"{{{NS_SAML_ASSERTION}}}SessionIndex")
67        if len(session_indexes) > 0:
68            request.session_index = session_indexes[0].text
69
70        request.relay_state = relay_state
71        return request
72
73    def parse(self, saml_request: str, relay_state: str | None = None) -> LogoutRequest:
74        """Validate and parse raw request with enveloped signautre."""
75        try:
76            decoded_xml = b64decode(saml_request.encode())
77        except UnicodeDecodeError:
78            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
79        return self._parse_xml(decoded_xml, relay_state)
80
81    def parse_detached(
82        self,
83        saml_request: str,
84        relay_state: str | None = None,
85    ) -> LogoutRequest:
86        """Validate and parse raw request with detached signature"""
87        try:
88            decoded_xml = decode_base64_and_inflate(saml_request)
89        except UnicodeDecodeError:
90            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
91
92        return self._parse_xml(decoded_xml, relay_state)

LogoutRequest Parser

LogoutRequestParser(provider: authentik.providers.saml.models.SAMLProvider)
38    def __init__(self, provider: SAMLProvider):
39        self.provider = provider
def parse( self, saml_request: str, relay_state: str | None = None) -> LogoutRequest:
73    def parse(self, saml_request: str, relay_state: str | None = None) -> LogoutRequest:
74        """Validate and parse raw request with enveloped signautre."""
75        try:
76            decoded_xml = b64decode(saml_request.encode())
77        except UnicodeDecodeError:
78            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
79        return self._parse_xml(decoded_xml, relay_state)

Validate and parse raw request with enveloped signautre.

def parse_detached( self, saml_request: str, relay_state: str | None = None) -> LogoutRequest:
81    def parse_detached(
82        self,
83        saml_request: str,
84        relay_state: str | None = None,
85    ) -> LogoutRequest:
86        """Validate and parse raw request with detached signature"""
87        try:
88            decoded_xml = decode_base64_and_inflate(saml_request)
89        except UnicodeDecodeError:
90            raise CannotHandleAssertion(ERROR_CANNOT_DECODE_REQUEST) from None
91
92        return self._parse_xml(decoded_xml, relay_state)

Validate and parse raw request with detached signature