From f4bb22138c3eb4a61e360126d1e01d83a132ac40 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 28 Jan 2021 22:00:40 +0100 Subject: [PATCH] providers/saml: add support for WindowsDomainQualifiedName, add docs for NameID --- authentik/providers/saml/processors/assertion.py | 15 ++++++++++++--- website/docs/providers/saml.md | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/authentik/providers/saml/processors/assertion.py b/authentik/providers/saml/processors/assertion.py index 179a15ecf..9efaccc75 100644 --- a/authentik/providers/saml/processors/assertion.py +++ b/authentik/providers/saml/processors/assertion.py @@ -3,6 +3,7 @@ from hashlib import sha256 from types import GeneratorType import xmlsec +from django.conf import settings from django.http import HttpRequest from lxml import etree # nosec from lxml.etree import Element, SubElement # nosec @@ -23,6 +24,7 @@ from authentik.sources.saml.processors.constants import ( SAML_NAME_ID_FORMAT_EMAIL, SAML_NAME_ID_FORMAT_PERSISTENT, SAML_NAME_ID_FORMAT_TRANSIENT, + SAML_NAME_ID_FORMAT_WINDOWS, SAML_NAME_ID_FORMAT_X509, SIGN_ALGORITHM_TRANSFORM_MAP, ) @@ -141,20 +143,27 @@ class AssertionProcessor: """Get NameID Element""" name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID") name_id.attrib["Format"] = self.auth_n_request.name_id_policy + persistent = sha256( + f"{self.http_request.user.id}-{settings.SECRET_KEY}".encode("ascii") + ).hexdigest() if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_EMAIL: name_id.text = self.http_request.user.email return name_id if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_PERSISTENT: - name_id.text = self.http_request.user.username + name_id.text = persistent return name_id if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_X509: # This attribute is statically set by the LDAP source name_id.text = self.http_request.user.attributes.get( - "distinguishedName", "" + "distinguishedName", persistent ) return name_id - if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT: + if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_WINDOWS: # This attribute is statically set by the LDAP source + name_id.text = self.http_request.user.attributes.get("upn", persistent) + return name_id + if name_id.attrib["Format"] == SAML_NAME_ID_FORMAT_TRANSIENT: + # Use the hash of the user's session, which changes every session session_key: str = self.http_request.user.session.session_key name_id.text = sha256(session_key.encode()).hexdigest() return name_id diff --git a/website/docs/providers/saml.md b/website/docs/providers/saml.md index afe18e615..661e9570e 100644 --- a/website/docs/providers/saml.md +++ b/website/docs/providers/saml.md @@ -11,3 +11,13 @@ Default fields are exposed through auto-generated Property Mappings, which are p | SSO (POST binding) | `/application/saml//sso/binding/post/` | | IdP-initiated login | `/application/saml//sso/binding/init/` | | Metadata Download | `/application/saml//metadata/` | + +## Name ID + +You can select a custom SAML Property Mapping after which the NameID field will be generated. If left default, the following checks are done: + +- When the request asks for `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`, the NameID will be set to the user's email address. +- When the request asks for `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent`, the NameID will be set to the hashed user ID. +- When the request asks for `urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName`, the NameID will be set to the user's `distinguishedName` attribute. This attribute is set by the LDAP source by default. If the attribute does not exist, it will fall back the persistent identifier. +- When the request asks for `urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName`, the NameID will be set to the user's UPN. This is also set by the LDAP source, and also falls back to the persistent identifier. +- When the request asks for `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`, the NameID will be set based on the user's session ID.