core: show success message when authenticating/enrolling after flow is finished
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
2206b71f6f
commit
dd65862bf2
|
@ -5,7 +5,7 @@ from typing import Any, Optional
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.db.models.query_utils import Q
|
from django.db.models.query_utils import Q
|
||||||
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
@ -23,8 +23,10 @@ from authentik.flows.planner import (
|
||||||
PLAN_CONTEXT_SSO,
|
PLAN_CONTEXT_SSO,
|
||||||
FlowPlanner,
|
FlowPlanner,
|
||||||
)
|
)
|
||||||
|
from authentik.flows.stage import StageView
|
||||||
from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
|
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.lib.utils.urls import redirect_with_qs
|
||||||
|
from authentik.lib.views import bad_request_message
|
||||||
from authentik.policies.denied import AccessDeniedResponse
|
from authentik.policies.denied import AccessDeniedResponse
|
||||||
from authentik.policies.utils import delete_none_keys
|
from authentik.policies.utils import delete_none_keys
|
||||||
from authentik.stages.password import BACKEND_INBUILT
|
from authentik.stages.password import BACKEND_INBUILT
|
||||||
|
@ -43,6 +45,34 @@ class Action(Enum):
|
||||||
DENY = "deny"
|
DENY = "deny"
|
||||||
|
|
||||||
|
|
||||||
|
def message_stage(message: str, level: int) -> StageView:
|
||||||
|
"""Show a pre-configured message after the flow is done"""
|
||||||
|
|
||||||
|
class MessageStage(StageView):
|
||||||
|
"""Show a pre-configured message after the flow is done"""
|
||||||
|
|
||||||
|
message: str
|
||||||
|
level: int
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
"""Show a pre-configured message after the flow is done"""
|
||||||
|
messages.add_message(
|
||||||
|
self.request,
|
||||||
|
self.level,
|
||||||
|
self.message,
|
||||||
|
)
|
||||||
|
return self.executor.stage_ok()
|
||||||
|
|
||||||
|
def post(self, request: HttpRequest) -> HttpResponse:
|
||||||
|
"""Wrapper for post requests"""
|
||||||
|
return self.get(request)
|
||||||
|
|
||||||
|
MessageStage.message = message
|
||||||
|
MessageStage.level = level
|
||||||
|
return MessageStage
|
||||||
|
|
||||||
|
|
||||||
class SourceFlowManager:
|
class SourceFlowManager:
|
||||||
"""Help sources decide what they should do after authorization. Based on source settings and
|
"""Help sources decide what they should do after authorization. Based on source settings and
|
||||||
previous connections, authenticate the user, enroll a new user, link to an existing user
|
previous connections, authenticate the user, enroll a new user, link to an existing user
|
||||||
|
@ -156,10 +186,10 @@ class SourceFlowManager:
|
||||||
if connection:
|
if connection:
|
||||||
if action == Action.LINK:
|
if action == Action.LINK:
|
||||||
self._logger.debug("Linking existing user")
|
self._logger.debug("Linking existing user")
|
||||||
return self.handle_existing_user_link(connection)
|
return self.handle_existing_link(connection)
|
||||||
if action == Action.AUTH:
|
if action == Action.AUTH:
|
||||||
self._logger.debug("Handling auth user")
|
self._logger.debug("Handling auth user")
|
||||||
return self.handle_auth_user(connection)
|
return self.handle_auth(connection)
|
||||||
if action == Action.ENROLL:
|
if action == Action.ENROLL:
|
||||||
self._logger.debug("Handling enrollment of new user")
|
self._logger.debug("Handling enrollment of new user")
|
||||||
return self.handle_enroll(connection)
|
return self.handle_enroll(connection)
|
||||||
|
@ -199,7 +229,11 @@ class SourceFlowManager:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _handle_login_flow(
|
def _handle_login_flow(
|
||||||
self, flow: Flow, connection: UserSourceConnection, **kwargs
|
self,
|
||||||
|
flow: Flow,
|
||||||
|
connection: UserSourceConnection,
|
||||||
|
stages: Optional[list[StageView]] = None,
|
||||||
|
**kwargs,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
"""Prepare Authentication Plan, redirect user FlowExecutor"""
|
"""Prepare Authentication Plan, redirect user FlowExecutor"""
|
||||||
# Ensure redirect is carried through when user was trying to
|
# Ensure redirect is carried through when user was trying to
|
||||||
|
@ -219,12 +253,18 @@ class SourceFlowManager:
|
||||||
)
|
)
|
||||||
kwargs.update(self.policy_context)
|
kwargs.update(self.policy_context)
|
||||||
if not flow:
|
if not flow:
|
||||||
return HttpResponseBadRequest()
|
return bad_request_message(
|
||||||
|
self.request,
|
||||||
|
_("Configured flow does not exist."),
|
||||||
|
)
|
||||||
# We run the Flow planner here so we can pass the Pending user in the context
|
# We run the Flow planner here so we can pass the Pending user in the context
|
||||||
planner = FlowPlanner(flow)
|
planner = FlowPlanner(flow)
|
||||||
plan = planner.plan(self.request, kwargs)
|
plan = planner.plan(self.request, kwargs)
|
||||||
for stage in self.get_stages_to_append(flow):
|
for stage in self.get_stages_to_append(flow):
|
||||||
plan.append_stage(stage=stage)
|
plan.append_stage(stage)
|
||||||
|
if stages:
|
||||||
|
for stage in stages:
|
||||||
|
plan.append_stage(stage)
|
||||||
self.request.session[SESSION_KEY_PLAN] = plan
|
self.request.session[SESSION_KEY_PLAN] = plan
|
||||||
return redirect_with_qs(
|
return redirect_with_qs(
|
||||||
"authentik_core:if-flow",
|
"authentik_core:if-flow",
|
||||||
|
@ -233,19 +273,30 @@ class SourceFlowManager:
|
||||||
)
|
)
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def handle_auth_user(
|
def handle_auth(
|
||||||
self,
|
self,
|
||||||
connection: UserSourceConnection,
|
connection: UserSourceConnection,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
"""Login user and redirect."""
|
"""Login user and redirect."""
|
||||||
messages.success(
|
|
||||||
self.request,
|
|
||||||
_("Successfully authenticated with %(source)s!" % {"source": self.source.name}),
|
|
||||||
)
|
|
||||||
flow_kwargs = {PLAN_CONTEXT_PENDING_USER: connection.user}
|
flow_kwargs = {PLAN_CONTEXT_PENDING_USER: connection.user}
|
||||||
return self._handle_login_flow(self.source.authentication_flow, connection, **flow_kwargs)
|
return self._handle_login_flow(
|
||||||
|
self.source.authentication_flow,
|
||||||
|
connection,
|
||||||
|
stages=[
|
||||||
|
in_memory_stage(
|
||||||
|
message_stage(
|
||||||
|
messages.SUCCESS,
|
||||||
|
_(
|
||||||
|
"Successfully authenticated with %(source)s!"
|
||||||
|
% {"source": self.source.name}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
**flow_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def handle_existing_user_link(
|
def handle_existing_link(
|
||||||
self,
|
self,
|
||||||
connection: UserSourceConnection,
|
connection: UserSourceConnection,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
|
@ -263,7 +314,7 @@ class SourceFlowManager:
|
||||||
)
|
)
|
||||||
# When request isn't authenticated we jump straight to auth
|
# When request isn't authenticated we jump straight to auth
|
||||||
if not self.request.user.is_authenticated:
|
if not self.request.user.is_authenticated:
|
||||||
return self.handle_auth_user(connection)
|
return self.handle_auth(connection)
|
||||||
return redirect(
|
return redirect(
|
||||||
reverse(
|
reverse(
|
||||||
"authentik_core:if-user",
|
"authentik_core:if-user",
|
||||||
|
@ -276,18 +327,27 @@ class SourceFlowManager:
|
||||||
connection: UserSourceConnection,
|
connection: UserSourceConnection,
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
"""User was not authenticated and previous request was not authenticated."""
|
"""User was not authenticated and previous request was not authenticated."""
|
||||||
messages.success(
|
|
||||||
self.request,
|
|
||||||
_("Successfully authenticated with %(source)s!" % {"source": self.source.name}),
|
|
||||||
)
|
|
||||||
|
|
||||||
# We run the Flow planner here so we can pass the Pending user in the context
|
# We run the Flow planner here so we can pass the Pending user in the context
|
||||||
if not self.source.enrollment_flow:
|
if not self.source.enrollment_flow:
|
||||||
self._logger.warning("source has no enrollment flow")
|
self._logger.warning("source has no enrollment flow")
|
||||||
return HttpResponseBadRequest()
|
return bad_request_message(
|
||||||
|
self.request,
|
||||||
|
_("Source is not configured for enrollment."),
|
||||||
|
)
|
||||||
return self._handle_login_flow(
|
return self._handle_login_flow(
|
||||||
self.source.enrollment_flow,
|
self.source.enrollment_flow,
|
||||||
connection,
|
connection,
|
||||||
|
stages=[
|
||||||
|
in_memory_stage(
|
||||||
|
message_stage(
|
||||||
|
messages.SUCCESS,
|
||||||
|
_(
|
||||||
|
"Successfully authenticated with %(source)s!"
|
||||||
|
% {"source": self.source.name}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
**{
|
**{
|
||||||
PLAN_CONTEXT_PROMPT: delete_none_keys(self.enroll_info),
|
PLAN_CONTEXT_PROMPT: delete_none_keys(self.enroll_info),
|
||||||
PLAN_CONTEXT_USER_PATH: self.source.get_user_path(),
|
PLAN_CONTEXT_USER_PATH: self.source.get_user_path(),
|
||||||
|
|
Reference in New Issue