providers/saml: fix NameIDPolicy not being parsed correctly, improve error handling
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
14c70b3e4a
commit
fcb795c273
|
@ -69,7 +69,7 @@ class AuthNRequestParser:
|
||||||
auth_n_request = AuthNRequest(id=root.attrib["ID"], relay_state=relay_state)
|
auth_n_request = AuthNRequest(id=root.attrib["ID"], relay_state=relay_state)
|
||||||
|
|
||||||
# Check if AuthnRequest has a NameID Policy object
|
# Check if AuthnRequest has a NameID Policy object
|
||||||
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}:NameIDPolicy")
|
name_id_policies = root.findall(f"{{{NS_SAML_PROTOCOL}}}NameIDPolicy")
|
||||||
if len(name_id_policies) > 0:
|
if len(name_id_policies) > 0:
|
||||||
name_id_policy = name_id_policies[0]
|
name_id_policy = name_id_policies[0]
|
||||||
auth_n_request.name_id_policy = name_id_policy.attrib["Format"]
|
auth_n_request.name_id_policy = name_id_policy.attrib["Format"]
|
||||||
|
|
|
@ -17,6 +17,7 @@ from authentik.providers.saml.models import SAMLBindings, SAMLProvider
|
||||||
from authentik.providers.saml.processors.assertion import AssertionProcessor
|
from authentik.providers.saml.processors.assertion import AssertionProcessor
|
||||||
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
from authentik.providers.saml.processors.request_parser import AuthNRequest
|
||||||
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode, nice64
|
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode, nice64
|
||||||
|
from authentik.sources.saml.exceptions import SAMLException
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
||||||
|
@ -56,22 +57,30 @@ class SAMLFlowFinalView(ChallengeStageView):
|
||||||
provider: SAMLProvider = get_object_or_404(
|
provider: SAMLProvider = get_object_or_404(
|
||||||
SAMLProvider, pk=application.provider_id
|
SAMLProvider, pk=application.provider_id
|
||||||
)
|
)
|
||||||
# Log Application Authorization
|
|
||||||
Event.new(
|
|
||||||
EventAction.AUTHORIZE_APPLICATION,
|
|
||||||
authorized_application=application,
|
|
||||||
flow=self.executor.plan.flow_pk,
|
|
||||||
).from_http(self.request)
|
|
||||||
|
|
||||||
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
|
if SESSION_KEY_AUTH_N_REQUEST not in self.request.session:
|
||||||
return self.executor.stage_invalid()
|
return self.executor.stage_invalid()
|
||||||
|
|
||||||
auth_n_request: AuthNRequest = self.request.session.pop(
|
auth_n_request: AuthNRequest = self.request.session.pop(
|
||||||
SESSION_KEY_AUTH_N_REQUEST
|
SESSION_KEY_AUTH_N_REQUEST
|
||||||
)
|
)
|
||||||
response = AssertionProcessor(
|
try:
|
||||||
provider, request, auth_n_request
|
response = AssertionProcessor(
|
||||||
).build_response()
|
provider, request, auth_n_request
|
||||||
|
).build_response()
|
||||||
|
except SAMLException as exc:
|
||||||
|
Event.new(
|
||||||
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
message=f"Failed to process SAML assertion: {str(exc)}",
|
||||||
|
provider=provider,
|
||||||
|
).from_http(self.request)
|
||||||
|
return self.executor.stage_invalid()
|
||||||
|
|
||||||
|
# Log Application Authorization
|
||||||
|
Event.new(
|
||||||
|
EventAction.AUTHORIZE_APPLICATION,
|
||||||
|
authorized_application=application,
|
||||||
|
flow=self.executor.plan.flow_pk,
|
||||||
|
).from_http(self.request)
|
||||||
|
|
||||||
if provider.sp_binding == SAMLBindings.POST:
|
if provider.sp_binding == SAMLBindings.POST:
|
||||||
form_attrs = {
|
form_attrs = {
|
||||||
|
|
|
@ -2,17 +2,21 @@
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
|
|
||||||
|
|
||||||
class MissingSAMLResponse(SentryIgnoredException):
|
class SAMLException(SentryIgnoredException):
|
||||||
|
"""Base SAML Exception"""
|
||||||
|
|
||||||
|
|
||||||
|
class MissingSAMLResponse(SAMLException):
|
||||||
"""Exception raised when request does not contain SAML Response."""
|
"""Exception raised when request does not contain SAML Response."""
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedNameIDFormat(SentryIgnoredException):
|
class UnsupportedNameIDFormat(SAMLException):
|
||||||
"""Exception raised when SAML Response contains NameID Format not supported."""
|
"""Exception raised when SAML Response contains NameID Format not supported."""
|
||||||
|
|
||||||
|
|
||||||
class MismatchedRequestID(SentryIgnoredException):
|
class MismatchedRequestID(SAMLException):
|
||||||
"""Exception raised when the returned request ID doesn't match the saved ID."""
|
"""Exception raised when the returned request ID doesn't match the saved ID."""
|
||||||
|
|
||||||
|
|
||||||
class InvalidSignature(SentryIgnoredException):
|
class InvalidSignature(SAMLException):
|
||||||
"""Signature of XML Object is either missing or invalid"""
|
"""Signature of XML Object is either missing or invalid"""
|
||||||
|
|
|
@ -51,7 +51,7 @@ class AuthenticatorDuoStageView(ChallengeStageView):
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
message=f"Failed to enroll user: {str(exc)}",
|
message=f"Failed to enroll user: {str(exc)}",
|
||||||
user=user,
|
user=user,
|
||||||
).from_http(self.request).set_user(user).save()
|
).from_http(self.request, user)
|
||||||
raise InvalidStageError(str(exc)) from exc
|
raise InvalidStageError(str(exc)) from exc
|
||||||
user_id = enroll["user_id"]
|
user_id = enroll["user_id"]
|
||||||
self.request.session[SESSION_KEY_DUO_USER_ID] = user_id
|
self.request.session[SESSION_KEY_DUO_USER_ID] = user_id
|
||||||
|
|
Reference in New Issue