From 430678326d22f2adc1bfad9ddc1bfc20cff7e5c7 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 13 Jun 2025 16:05:52 +0200 Subject: [PATCH] switch saml to flow context Signed-off-by: Jens Langhammer --- authentik/providers/saml/views/flows.py | 12 +++++------- authentik/providers/saml/views/slo.py | 11 ++++++++--- authentik/providers/saml/views/sso.py | 13 +++++++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/authentik/providers/saml/views/flows.py b/authentik/providers/saml/views/flows.py index 5a89d3e8c5..ba0311af00 100644 --- a/authentik/providers/saml/views/flows.py +++ b/authentik/providers/saml/views/flows.py @@ -35,8 +35,8 @@ REQUEST_KEY_SAML_SIG_ALG = "SigAlg" REQUEST_KEY_SAML_RESPONSE = "SAMLResponse" REQUEST_KEY_RELAY_STATE = "RelayState" -SESSION_KEY_AUTH_N_REQUEST = "authentik/providers/saml/authn_request" -SESSION_KEY_LOGOUT_REQUEST = "authentik/providers/saml/logout_request" +PLAN_CONTEXT_SAML_AUTH_N_REQUEST = "authentik/providers/saml/authn_request" +PLAN_CONTEXT_SAML_LOGOUT_REQUEST = "authentik/providers/saml/logout_request" # This View doesn't have a URL on purpose, as its called by the FlowExecutor @@ -50,10 +50,11 @@ class SAMLFlowFinalView(ChallengeStageView): def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: application: Application = self.executor.plan.context[PLAN_CONTEXT_APPLICATION] provider: SAMLProvider = get_object_or_404(SAMLProvider, pk=application.provider_id) - if SESSION_KEY_AUTH_N_REQUEST not in self.request.session: + if PLAN_CONTEXT_SAML_AUTH_N_REQUEST not in self.executor.plan.context: + self.logger.warning("No AuthNRequest in context") return self.executor.stage_invalid() - auth_n_request: AuthNRequest = self.request.session.pop(SESSION_KEY_AUTH_N_REQUEST) + auth_n_request: AuthNRequest = self.executor.plan.context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] try: response = AssertionProcessor(provider, request, auth_n_request).build_response() except SAMLException as exc: @@ -106,6 +107,3 @@ class SAMLFlowFinalView(ChallengeStageView): def challenge_valid(self, response: ChallengeResponse) -> HttpResponse: # We'll never get here since the challenge redirects to the SP return HttpResponseBadRequest() - - def cleanup(self): - self.request.session.pop(SESSION_KEY_AUTH_N_REQUEST, None) diff --git a/authentik/providers/saml/views/slo.py b/authentik/providers/saml/views/slo.py index 2a205b73aa..7e4a9ab935 100644 --- a/authentik/providers/saml/views/slo.py +++ b/authentik/providers/saml/views/slo.py @@ -19,9 +19,9 @@ from authentik.providers.saml.exceptions import CannotHandleAssertion from authentik.providers.saml.models import SAMLProvider from authentik.providers.saml.processors.logout_request_parser import LogoutRequestParser from authentik.providers.saml.views.flows import ( + PLAN_CONTEXT_SAML_LOGOUT_REQUEST, REQUEST_KEY_RELAY_STATE, REQUEST_KEY_SAML_REQUEST, - SESSION_KEY_LOGOUT_REQUEST, ) LOGGER = get_logger() @@ -33,6 +33,10 @@ class SAMLSLOView(PolicyAccessView): flow: Flow + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.plan_context = {} + def resolve_provider_application(self): self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"]) self.provider: SAMLProvider = get_object_or_404( @@ -59,6 +63,7 @@ class SAMLSLOView(PolicyAccessView): request, { PLAN_CONTEXT_APPLICATION: self.application, + **self.plan_context, }, ) plan.append_stage(in_memory_stage(SessionEndStage)) @@ -83,7 +88,7 @@ class SAMLSLOBindingRedirectView(SAMLSLOView): self.request.GET[REQUEST_KEY_SAML_REQUEST], relay_state=self.request.GET.get(REQUEST_KEY_RELAY_STATE, None), ) - self.request.session[SESSION_KEY_LOGOUT_REQUEST] = logout_request + self.plan_context[PLAN_CONTEXT_SAML_LOGOUT_REQUEST] = logout_request except CannotHandleAssertion as exc: Event.new( EventAction.CONFIGURATION_ERROR, @@ -111,7 +116,7 @@ class SAMLSLOBindingPOSTView(SAMLSLOView): payload[REQUEST_KEY_SAML_REQUEST], relay_state=payload.get(REQUEST_KEY_RELAY_STATE, None), ) - self.request.session[SESSION_KEY_LOGOUT_REQUEST] = logout_request + self.plan_context[PLAN_CONTEXT_SAML_LOGOUT_REQUEST] = logout_request except CannotHandleAssertion as exc: LOGGER.info(str(exc)) return bad_request_message(self.request, str(exc)) diff --git a/authentik/providers/saml/views/sso.py b/authentik/providers/saml/views/sso.py index 8d7c6e0272..076fb68706 100644 --- a/authentik/providers/saml/views/sso.py +++ b/authentik/providers/saml/views/sso.py @@ -20,11 +20,11 @@ from authentik.providers.saml.exceptions import CannotHandleAssertion from authentik.providers.saml.models import SAMLBindings, SAMLProvider from authentik.providers.saml.processors.authn_request_parser import AuthNRequestParser from authentik.providers.saml.views.flows import ( + PLAN_CONTEXT_SAML_AUTH_N_REQUEST, REQUEST_KEY_RELAY_STATE, REQUEST_KEY_SAML_REQUEST, REQUEST_KEY_SAML_SIG_ALG, REQUEST_KEY_SAML_SIGNATURE, - SESSION_KEY_AUTH_N_REQUEST, SAMLFlowFinalView, ) from authentik.stages.consent.stage import ( @@ -39,6 +39,10 @@ class SAMLSSOView(BufferedPolicyAccessView): """SAML SSO Base View, which plans a flow and injects our final stage. Calls get/post handler.""" + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.plan_context = {} + def resolve_provider_application(self): self.application = get_object_or_404(Application, slug=self.kwargs["application_slug"]) self.provider: SAMLProvider = get_object_or_404( @@ -68,6 +72,7 @@ class SAMLSSOView(BufferedPolicyAccessView): PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.") % {"application": self.application.name}, PLAN_CONTEXT_CONSENT_PERMISSIONS: [], + **self.plan_context, }, ) except FlowNonApplicableException: @@ -103,7 +108,7 @@ class SAMLSSOBindingRedirectView(SAMLSSOView): self.request.GET.get(REQUEST_KEY_SAML_SIGNATURE), self.request.GET.get(REQUEST_KEY_SAML_SIG_ALG), ) - self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request + self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request except CannotHandleAssertion as exc: Event.new( EventAction.CONFIGURATION_ERROR, @@ -137,7 +142,7 @@ class SAMLSSOBindingPOSTView(SAMLSSOView): payload[REQUEST_KEY_SAML_REQUEST], payload.get(REQUEST_KEY_RELAY_STATE), ) - self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request + self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request except CannotHandleAssertion as exc: LOGGER.info(str(exc)) return bad_request_message(self.request, str(exc)) @@ -151,4 +156,4 @@ class SAMLSSOBindingInitView(SAMLSSOView): """Create SAML Response from scratch""" LOGGER.debug("No SAML Request, using IdP-initiated flow.") auth_n_request = AuthNRequestParser(self.provider).idp_initiated() - self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request + self.plan_context[PLAN_CONTEXT_SAML_AUTH_N_REQUEST] = auth_n_request