authentik.core.views.apps

app views

 1"""app views"""
 2
 3from django.http import Http404, HttpRequest, HttpResponse, HttpResponseRedirect
 4from django.shortcuts import get_object_or_404
 5from django.utils.translation import gettext_lazy as _
 6from django.views import View
 7
 8from authentik.core.models import Application
 9from authentik.flows.challenge import (
10    ChallengeResponse,
11    HttpChallengeResponse,
12    RedirectChallenge,
13)
14from authentik.flows.exceptions import FlowNonApplicableException
15from authentik.flows.models import FlowDesignation, in_memory_stage
16from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
17from authentik.flows.stage import ChallengeStageView
18from authentik.flows.views.executor import (
19    ToDefaultFlow,
20)
21from authentik.stages.consent.stage import (
22    PLAN_CONTEXT_CONSENT_HEADER,
23    PLAN_CONTEXT_CONSENT_PERMISSIONS,
24)
25
26
27class RedirectToAppLaunch(View):
28    """Application launch view, redirect to the launch URL"""
29
30    def dispatch(self, request: HttpRequest, application_slug: str) -> HttpResponse:
31        app = get_object_or_404(Application, slug=application_slug)
32        # Check here if the application has any launch URL set, if not 404
33        launch = app.get_launch_url()
34        if not launch:
35            raise Http404
36        # Check if we're authenticated already, saves us the flow run
37        if request.user.is_authenticated:
38            return HttpResponseRedirect(app.get_launch_url(request.user))
39        # otherwise, do a custom flow plan that includes the application that's
40        # being accessed, to improve usability
41        if app and app.provider and app.provider.authentication_flow:
42            flow = app.provider.authentication_flow
43        else:
44            flow = ToDefaultFlow.get_flow(
45                request=request, designation=FlowDesignation.AUTHENTICATION
46            )
47        planner = FlowPlanner(flow)
48        planner.allow_empty_flows = True
49        try:
50            plan = planner.plan(
51                request,
52                {
53                    PLAN_CONTEXT_APPLICATION: app,
54                    PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.")
55                    % {"application": app.name},
56                    PLAN_CONTEXT_CONSENT_PERMISSIONS: [],
57                },
58            )
59        except FlowNonApplicableException:
60            raise Http404 from None
61        # We redirect with an in_memory stage instead of `?next=...` as the launch URL
62        # might be formatted with the user, which hasn't logged in yet
63        plan.append_stage(in_memory_stage(RedirectToAppStage))
64        return plan.to_redirect(request, flow)
65
66
67class RedirectToAppStage(ChallengeStageView):
68    """Final stage to be inserted after the user logs in"""
69
70    def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
71        app = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
72        launch = app.get_launch_url(self.get_pending_user())
73        # sanity check to ensure launch is still set
74        if not launch:
75            raise Http404
76        return RedirectChallenge(
77            instance={
78                "to": launch,
79            }
80        )
81
82    def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
83        return HttpChallengeResponse(self.get_challenge())
class RedirectToAppLaunch(django.views.generic.base.View):
28class RedirectToAppLaunch(View):
29    """Application launch view, redirect to the launch URL"""
30
31    def dispatch(self, request: HttpRequest, application_slug: str) -> HttpResponse:
32        app = get_object_or_404(Application, slug=application_slug)
33        # Check here if the application has any launch URL set, if not 404
34        launch = app.get_launch_url()
35        if not launch:
36            raise Http404
37        # Check if we're authenticated already, saves us the flow run
38        if request.user.is_authenticated:
39            return HttpResponseRedirect(app.get_launch_url(request.user))
40        # otherwise, do a custom flow plan that includes the application that's
41        # being accessed, to improve usability
42        if app and app.provider and app.provider.authentication_flow:
43            flow = app.provider.authentication_flow
44        else:
45            flow = ToDefaultFlow.get_flow(
46                request=request, designation=FlowDesignation.AUTHENTICATION
47            )
48        planner = FlowPlanner(flow)
49        planner.allow_empty_flows = True
50        try:
51            plan = planner.plan(
52                request,
53                {
54                    PLAN_CONTEXT_APPLICATION: app,
55                    PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.")
56                    % {"application": app.name},
57                    PLAN_CONTEXT_CONSENT_PERMISSIONS: [],
58                },
59            )
60        except FlowNonApplicableException:
61            raise Http404 from None
62        # We redirect with an in_memory stage instead of `?next=...` as the launch URL
63        # might be formatted with the user, which hasn't logged in yet
64        plan.append_stage(in_memory_stage(RedirectToAppStage))
65        return plan.to_redirect(request, flow)

Application launch view, redirect to the launch URL

def dispatch( self, request: django.http.request.HttpRequest, application_slug: str) -> django.http.response.HttpResponse:
31    def dispatch(self, request: HttpRequest, application_slug: str) -> HttpResponse:
32        app = get_object_or_404(Application, slug=application_slug)
33        # Check here if the application has any launch URL set, if not 404
34        launch = app.get_launch_url()
35        if not launch:
36            raise Http404
37        # Check if we're authenticated already, saves us the flow run
38        if request.user.is_authenticated:
39            return HttpResponseRedirect(app.get_launch_url(request.user))
40        # otherwise, do a custom flow plan that includes the application that's
41        # being accessed, to improve usability
42        if app and app.provider and app.provider.authentication_flow:
43            flow = app.provider.authentication_flow
44        else:
45            flow = ToDefaultFlow.get_flow(
46                request=request, designation=FlowDesignation.AUTHENTICATION
47            )
48        planner = FlowPlanner(flow)
49        planner.allow_empty_flows = True
50        try:
51            plan = planner.plan(
52                request,
53                {
54                    PLAN_CONTEXT_APPLICATION: app,
55                    PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.")
56                    % {"application": app.name},
57                    PLAN_CONTEXT_CONSENT_PERMISSIONS: [],
58                },
59            )
60        except FlowNonApplicableException:
61            raise Http404 from None
62        # We redirect with an in_memory stage instead of `?next=...` as the launch URL
63        # might be formatted with the user, which hasn't logged in yet
64        plan.append_stage(in_memory_stage(RedirectToAppStage))
65        return plan.to_redirect(request, flow)
class RedirectToAppStage(authentik.flows.stage.ChallengeStageView):
68class RedirectToAppStage(ChallengeStageView):
69    """Final stage to be inserted after the user logs in"""
70
71    def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
72        app = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
73        launch = app.get_launch_url(self.get_pending_user())
74        # sanity check to ensure launch is still set
75        if not launch:
76            raise Http404
77        return RedirectChallenge(
78            instance={
79                "to": launch,
80            }
81        )
82
83    def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
84        return HttpChallengeResponse(self.get_challenge())

Final stage to be inserted after the user logs in

def get_challenge(self, *args, **kwargs) -> authentik.flows.challenge.RedirectChallenge:
71    def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
72        app = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
73        launch = app.get_launch_url(self.get_pending_user())
74        # sanity check to ensure launch is still set
75        if not launch:
76            raise Http404
77        return RedirectChallenge(
78            instance={
79                "to": launch,
80            }
81        )

Return the challenge that the client should solve

def challenge_valid( self, response: authentik.flows.challenge.ChallengeResponse) -> django.http.response.HttpResponse:
83    def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
84        return HttpChallengeResponse(self.get_challenge())

Callback when the challenge has the correct format