From b20a8b7c1796a42f9afff42dbc34ce55d880da35 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 16 Jun 2021 22:59:16 +0200 Subject: [PATCH] stages/authenticator_duo: fix error when enrolling an existing user Signed-off-by: Jens Langhammer --- authentik/flows/stage.py | 16 ---------------- authentik/flows/views.py | 10 +++++++++- authentik/stages/authenticator_duo/stage.py | 12 +++++++++++- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/authentik/flows/stage.py b/authentik/flows/stage.py index 3c32472c3..8502a42c6 100644 --- a/authentik/flows/stage.py +++ b/authentik/flows/stage.py @@ -18,27 +18,11 @@ from authentik.flows.challenge import ( ) from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.views import FlowExecutorView -from authentik.lib.sentry import SentryIgnoredException PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier" LOGGER = get_logger() -class InvalidChallengeError(SentryIgnoredException): - """Error raised when a challenge from a stage is not valid""" - - def __init__(self, errors, stage_view: View, challenge: Challenge) -> None: - super().__init__() - self.errors = errors - self.stage_view = stage_view - self.challenge = challenge - - def __str__(self) -> str: - return ( - f"Invalid challenge from {self.stage_view}: {self.errors}\n{self.challenge}" - ) - - class StageView(View): """Abstract Stage, inherits TemplateView but can be combined with FormView""" diff --git a/authentik/flows/views.py b/authentik/flows/views.py index c02396012..2cfcfc06b 100644 --- a/authentik/flows/views.py +++ b/authentik/flows/views.py @@ -44,6 +44,7 @@ from authentik.flows.planner import ( FlowPlan, FlowPlanner, ) +from authentik.lib.sentry import SentryIgnoredException from authentik.lib.utils.reflection import all_subclasses, class_to_path from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs from authentik.tenants.models import Tenant @@ -93,6 +94,10 @@ def challenge_response_types(): return Inner() +class InvalidStageError(SentryIgnoredException): + """Error raised when a challenge from a stage is not valid""" + + @method_decorator(xframe_options_sameorigin, name="dispatch") class FlowExecutorView(APIView): """Stage 1 Flow executor, passing requests to Stage Views""" @@ -173,7 +178,10 @@ class FlowExecutorView(APIView): self.current_stage_view.args = self.args self.current_stage_view.kwargs = self.kwargs self.current_stage_view.request = request - return super().dispatch(request) + try: + return super().dispatch(request) + except InvalidStageError as exc: + return self.stage_invalid(str(exc)) @extend_schema( responses={ diff --git a/authentik/stages/authenticator_duo/stage.py b/authentik/stages/authenticator_duo/stage.py index 999f5d82c..6007ad9c2 100644 --- a/authentik/stages/authenticator_duo/stage.py +++ b/authentik/stages/authenticator_duo/stage.py @@ -3,6 +3,7 @@ from django.http import HttpRequest, HttpResponse from rest_framework.fields import CharField from structlog.stdlib import get_logger +from authentik.events.models import Event, EventAction from authentik.flows.challenge import ( Challenge, ChallengeResponse, @@ -11,6 +12,7 @@ from authentik.flows.challenge import ( ) from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import ChallengeStageView +from authentik.flows.views import InvalidStageError from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice LOGGER = get_logger() @@ -42,7 +44,15 @@ class AuthenticatorDuoStageView(ChallengeStageView): def get_challenge(self, *args, **kwargs) -> Challenge: user = self.get_pending_user() stage: AuthenticatorDuoStage = self.executor.current_stage - enroll = stage.client.enroll(user.username) + try: + enroll = stage.client.enroll(user.username) + except RuntimeError as exc: + Event.new( + EventAction.CONFIGURATION_ERROR, + message=f"Failed to enroll user: {str(exc)}", + user=user, + ).from_http(self.request).set_user(user).save() + raise InvalidStageError(str(exc)) from exc user_id = enroll["user_id"] self.request.session[SESSION_KEY_DUO_USER_ID] = user_id self.request.session[SESSION_KEY_DUO_ACTIVATION_CODE] = enroll[