diff --git a/authentik/interfaces/views.py b/authentik/interfaces/views.py index a0d096276..ce1f25603 100644 --- a/authentik/interfaces/views.py +++ b/authentik/interfaces/views.py @@ -3,7 +3,7 @@ from json import dumps from typing import Any, Optional from urllib.parse import urlencode -from django.http import Http404, HttpRequest, HttpResponse +from django.http import Http404, HttpRequest, HttpResponse, QueryDict from django.shortcuts import get_object_or_404, redirect from django.template import Template, TemplateSyntaxError, engines from django.template.response import TemplateResponse @@ -19,7 +19,7 @@ from authentik.admin.tasks import LOCAL_VERSION from authentik.api.v3.config import ConfigView from authentik.flows.models import Flow from authentik.interfaces.models import Interface, InterfaceType -from authentik.lib.utils.urls import redirect_with_qs +from authentik.lib.utils.urls import reverse_with_qs from authentik.tenants.api import CurrentTenantSerializer from authentik.tenants.models import Tenant @@ -42,7 +42,9 @@ def redirect_to_default_interface(request: HttpRequest, interface_type: Interfac return RedirectToInterface.as_view(type=interface_type)(request, **kwargs) -def reverse_interface(request: HttpRequest, interface_type: InterfaceType, **kwargs): +def reverse_interface( + request: HttpRequest, interface_type: InterfaceType, query: Optional[QueryDict] = None, **kwargs +): """Reverse URL to configured default interface""" tenant: Tenant = request.tenant interface: Interface = None @@ -57,8 +59,9 @@ def reverse_interface(request: HttpRequest, interface_type: InterfaceType, **kwa if not interface: raise Http404() kwargs["if_name"] = interface.url_name - return reverse( + return reverse_with_qs( "authentik_interfaces:if", + query=query or request.GET, kwargs=kwargs, ) diff --git a/authentik/providers/oauth2/views/authorize.py b/authentik/providers/oauth2/views/authorize.py index 32850b5ea..b4b725464 100644 --- a/authentik/providers/oauth2/views/authorize.py +++ b/authentik/providers/oauth2/views/authorize.py @@ -29,8 +29,9 @@ from authentik.flows.models import in_memory_stage from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner from authentik.flows.stage import StageView from authentik.flows.views.executor import SESSION_KEY_PLAN +from authentik.interfaces.models import InterfaceType +from authentik.interfaces.views import redirect_to_default_interface from authentik.lib.utils.time import timedelta_from_string -from authentik.lib.utils.urls import redirect_with_qs from authentik.lib.views import bad_request_message from authentik.policies.types import PolicyRequest from authentik.policies.views import PolicyAccessView, RequestValidationError @@ -404,9 +405,9 @@ class AuthorizationFlowInitView(PolicyAccessView): plan.append_stage(in_memory_stage(OAuthFulfillmentStage)) self.request.session[SESSION_KEY_PLAN] = plan - return redirect_with_qs( - "authentik_core:if-flow", - self.request.GET, + return redirect_to_default_interface( + self.request, + InterfaceType.FLOW, flow_slug=self.provider.authorization_flow.slug, ) diff --git a/authentik/providers/oauth2/views/device_init.py b/authentik/providers/oauth2/views/device_init.py index c9f240661..7b17cac5c 100644 --- a/authentik/providers/oauth2/views/device_init.py +++ b/authentik/providers/oauth2/views/device_init.py @@ -15,7 +15,8 @@ from authentik.flows.models import in_memory_stage from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner from authentik.flows.stage import ChallengeStageView from authentik.flows.views.executor import SESSION_KEY_PLAN -from authentik.lib.utils.urls import redirect_with_qs +from authentik.interfaces.models import InterfaceType +from authentik.interfaces.views import redirect_to_default_interface from authentik.providers.oauth2.models import DeviceToken, OAuth2Provider from authentik.providers.oauth2.views.device_finish import ( PLAN_CONTEXT_DEVICE, @@ -77,9 +78,9 @@ def validate_code(code: int, request: HttpRequest) -> Optional[HttpResponse]: return None plan.insert_stage(in_memory_stage(OAuthDeviceCodeFinishStage)) request.session[SESSION_KEY_PLAN] = plan - return redirect_with_qs( - "authentik_core:if-flow", - request.GET, + return redirect_to_default_interface( + request, + InterfaceType.FLOW, flow_slug=token.provider.authorization_flow.slug, ) @@ -110,9 +111,9 @@ class DeviceEntryView(View): plan.append_stage(in_memory_stage(OAuthDeviceCodeStage)) self.request.session[SESSION_KEY_PLAN] = plan - return redirect_with_qs( - "authentik_core:if-flow", - self.request.GET, + return redirect_to_default_interface( + self.request, + InterfaceType.FLOW, flow_slug=device_flow.slug, ) diff --git a/authentik/providers/saml/views/sso.py b/authentik/providers/saml/views/sso.py index 99844150a..fe49e777e 100644 --- a/authentik/providers/saml/views/sso.py +++ b/authentik/providers/saml/views/sso.py @@ -15,7 +15,8 @@ from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.models import in_memory_stage from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner from authentik.flows.views.executor import SESSION_KEY_PLAN, SESSION_KEY_POST -from authentik.lib.utils.urls import redirect_with_qs +from authentik.interfaces.models import InterfaceType +from authentik.interfaces.views import redirect_to_default_interface from authentik.lib.views import bad_request_message from authentik.policies.views import PolicyAccessView from authentik.providers.saml.exceptions import CannotHandleAssertion @@ -76,9 +77,9 @@ class SAMLSSOView(PolicyAccessView): raise Http404 plan.append_stage(in_memory_stage(SAMLFlowFinalView)) request.session[SESSION_KEY_PLAN] = plan - return redirect_with_qs( - "authentik_core:if-flow", - request.GET, + return redirect_to_default_interface( + request, + InterfaceType.FLOW, flow_slug=self.provider.authorization_flow.slug, ) diff --git a/authentik/sources/saml/views.py b/authentik/sources/saml/views.py index a34985947..f84c0072b 100644 --- a/authentik/sources/saml/views.py +++ b/authentik/sources/saml/views.py @@ -32,7 +32,8 @@ from authentik.flows.planner import ( ) from authentik.flows.stage import ChallengeStageView from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN -from authentik.lib.utils.urls import redirect_with_qs +from authentik.interfaces.models import InterfaceType +from authentik.interfaces.views import redirect_to_default_interface from authentik.lib.views import bad_request_message from authentik.providers.saml.utils.encoding import nice64 from authentik.sources.saml.exceptions import MissingSAMLResponse, UnsupportedNameIDFormat @@ -91,9 +92,9 @@ class InitiateView(View): for stage in stages_to_append: plan.append_stage(stage) self.request.session[SESSION_KEY_PLAN] = plan - return redirect_with_qs( - "authentik_core:if-flow", - self.request.GET, + return redirect_to_default_interface( + self.request, + InterfaceType.FLOW, flow_slug=source.pre_authentication_flow.slug, ) diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index a54de07d9..8ad9b09cc 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -26,6 +26,8 @@ from authentik.flows.models import FlowDesignation from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, ChallengeStageView from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE, SESSION_KEY_GET +from authentik.interfaces.models import InterfaceType +from authentik.interfaces.views import reverse_interface from authentik.lib.utils.http import get_client_ip from authentik.lib.utils.urls import reverse_with_qs from authentik.sources.oauth.types.apple import AppleLoginChallenge @@ -205,22 +207,25 @@ class IdentificationStageView(ChallengeStageView): get_qs = self.request.session.get(SESSION_KEY_GET, self.request.GET) # Check for related enrollment and recovery flow, add URL to view if current_stage.enrollment_flow: - challenge.initial_data["enroll_url"] = reverse_with_qs( - "authentik_core:if-flow", + challenge.initial_data["enroll_url"] = reverse_interface( + self.request, + InterfaceType.FLOW, query=get_qs, - kwargs={"flow_slug": current_stage.enrollment_flow.slug}, + flow_slug=current_stage.enrollment_flow.slug, ) if current_stage.recovery_flow: - challenge.initial_data["recovery_url"] = reverse_with_qs( - "authentik_core:if-flow", + challenge.initial_data["recovery_url"] = reverse_interface( + self.request, + InterfaceType.FLOW, query=get_qs, - kwargs={"flow_slug": current_stage.recovery_flow.slug}, + flow_slug=current_stage.recovery_flow.slug, ) if current_stage.passwordless_flow: - challenge.initial_data["passwordless_url"] = reverse_with_qs( - "authentik_core:if-flow", + challenge.initial_data["passwordless_url"] = reverse_interface( + self.request, + InterfaceType.FLOW, query=get_qs, - kwargs={"flow_slug": current_stage.passwordless_flow.slug}, + flow_slug=current_stage.passwordless_flow.slug, ) # Check all enabled source, add them if they have a UI Login button.