flows: add get_pending_user() for WithUserInfoChallenge
This commit is contained in:
parent
27cd10e072
commit
88e5b22d16
|
@ -1,6 +1,5 @@
|
||||||
"""authentik stage Base view"""
|
"""authentik stage Base view"""
|
||||||
from collections import namedtuple
|
from typing import Any, Optional
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http.request import QueryDict
|
from django.http.request import QueryDict
|
||||||
|
@ -9,6 +8,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.core.models import User
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
Challenge,
|
Challenge,
|
||||||
ChallengeResponse,
|
ChallengeResponse,
|
||||||
|
@ -20,8 +20,6 @@ from authentik.flows.views import FlowExecutorView
|
||||||
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
|
PLAN_CONTEXT_PENDING_USER_IDENTIFIER = "pending_user_identifier"
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
FakeUser = namedtuple("User", ["username", "email"])
|
|
||||||
|
|
||||||
|
|
||||||
class StageView(TemplateView):
|
class StageView(TemplateView):
|
||||||
"""Abstract Stage, inherits TemplateView but can be combined with FormView"""
|
"""Abstract Stage, inherits TemplateView but can be combined with FormView"""
|
||||||
|
@ -44,7 +42,7 @@ class StageView(TemplateView):
|
||||||
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
||||||
kwargs["user"] = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
kwargs["user"] = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||||
if PLAN_CONTEXT_PENDING_USER_IDENTIFIER in self.executor.plan.context:
|
if PLAN_CONTEXT_PENDING_USER_IDENTIFIER in self.executor.plan.context:
|
||||||
kwargs["user"] = FakeUser(
|
kwargs["user"] = User(
|
||||||
username=self.executor.plan.context.get(
|
username=self.executor.plan.context.get(
|
||||||
PLAN_CONTEXT_PENDING_USER_IDENTIFIER
|
PLAN_CONTEXT_PENDING_USER_IDENTIFIER
|
||||||
),
|
),
|
||||||
|
@ -59,6 +57,22 @@ class ChallengeStageView(StageView):
|
||||||
|
|
||||||
response_class = ChallengeResponse
|
response_class = ChallengeResponse
|
||||||
|
|
||||||
|
def get_pending_user(self) -> Optional[User]:
|
||||||
|
"""Either show the matched User object or show what the user entered,
|
||||||
|
based on what the earlier stage (mostly IdentificationStage) set.
|
||||||
|
_USER_IDENTIFIER overrides the first User, as PENDING_USER is used for
|
||||||
|
other things besides the form display"""
|
||||||
|
if PLAN_CONTEXT_PENDING_USER_IDENTIFIER in self.executor.plan.context:
|
||||||
|
return User(
|
||||||
|
username=self.executor.plan.context.get(
|
||||||
|
PLAN_CONTEXT_PENDING_USER_IDENTIFIER
|
||||||
|
),
|
||||||
|
email="",
|
||||||
|
)
|
||||||
|
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
||||||
|
return self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
||||||
|
return None
|
||||||
|
|
||||||
def get_response_instance(self, data: QueryDict) -> ChallengeResponse:
|
def get_response_instance(self, data: QueryDict) -> ChallengeResponse:
|
||||||
"""Return the response class type"""
|
"""Return the response class type"""
|
||||||
return self.response_class(None, data=data, stage=self)
|
return self.response_class(None, data=data, stage=self)
|
||||||
|
|
|
@ -3,7 +3,6 @@ from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
|
|
||||||
from authentik.core.models import User
|
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
Challenge,
|
Challenge,
|
||||||
ChallengeResponse,
|
ChallengeResponse,
|
||||||
|
@ -55,10 +54,9 @@ class ConsentStageView(ChallengeStageView):
|
||||||
# If there's a pending user, update the `username` field
|
# If there's a pending user, update the `username` field
|
||||||
# this field is only used by password managers.
|
# this field is only used by password managers.
|
||||||
# If there's no user set, an error is raised later.
|
# If there's no user set, an error is raised later.
|
||||||
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
if user := self.get_pending_user():
|
||||||
pending_user: User = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
challenge.initial_data["pending_user"] = user.username
|
||||||
challenge.initial_data["pending_user"] = pending_user.username
|
challenge.initial_data["pending_user_avatar"] = avatar(user)
|
||||||
challenge.initial_data["pending_user_avatar"] = avatar(pending_user)
|
|
||||||
return challenge
|
return challenge
|
||||||
|
|
||||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
|
|
@ -86,10 +86,9 @@ class PasswordStageView(ChallengeStageView):
|
||||||
# If there's a pending user, update the `username` field
|
# If there's a pending user, update the `username` field
|
||||||
# this field is only used by password managers.
|
# this field is only used by password managers.
|
||||||
# If there's no user set, an error is raised later.
|
# If there's no user set, an error is raised later.
|
||||||
if PLAN_CONTEXT_PENDING_USER in self.executor.plan.context:
|
if user := self.get_pending_user():
|
||||||
pending_user: User = self.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
|
challenge.initial_data["pending_user"] = user.username
|
||||||
challenge.initial_data["pending_user"] = pending_user.username
|
challenge.initial_data["pending_user_avatar"] = avatar(user)
|
||||||
challenge.initial_data["pending_user_avatar"] = avatar(pending_user)
|
|
||||||
|
|
||||||
recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY)
|
recovery_flow = Flow.objects.filter(designation=FlowDesignation.RECOVERY)
|
||||||
if recovery_flow.exists():
|
if recovery_flow.exists():
|
||||||
|
|
26
swagger.yaml
26
swagger.yaml
|
@ -9657,22 +9657,22 @@ definitions:
|
||||||
- authentik.sources.ldap
|
- authentik.sources.ldap
|
||||||
- authentik.sources.oauth
|
- authentik.sources.oauth
|
||||||
- authentik.sources.saml
|
- authentik.sources.saml
|
||||||
- authentik.stages.captcha
|
|
||||||
- authentik.stages.consent
|
|
||||||
- authentik.stages.dummy
|
|
||||||
- authentik.stages.email
|
|
||||||
- authentik.stages.prompt
|
|
||||||
- authentik.stages.identification
|
|
||||||
- authentik.stages.invitation
|
|
||||||
- authentik.stages.user_delete
|
|
||||||
- authentik.stages.user_login
|
|
||||||
- authentik.stages.user_logout
|
|
||||||
- authentik.stages.user_write
|
|
||||||
- authentik.stages.authenticator_static
|
- authentik.stages.authenticator_static
|
||||||
- authentik.stages.authenticator_totp
|
- authentik.stages.authenticator_totp
|
||||||
- authentik.stages.authenticator_validate
|
- authentik.stages.authenticator_validate
|
||||||
- authentik.stages.authenticator_webauthn
|
- authentik.stages.authenticator_webauthn
|
||||||
|
- authentik.stages.captcha
|
||||||
|
- authentik.stages.consent
|
||||||
|
- authentik.stages.dummy
|
||||||
|
- authentik.stages.email
|
||||||
|
- authentik.stages.identification
|
||||||
|
- authentik.stages.invitation
|
||||||
- authentik.stages.password
|
- authentik.stages.password
|
||||||
|
- authentik.stages.prompt
|
||||||
|
- authentik.stages.user_delete
|
||||||
|
- authentik.stages.user_login
|
||||||
|
- authentik.stages.user_logout
|
||||||
|
- authentik.stages.user_write
|
||||||
- authentik.managed
|
- authentik.managed
|
||||||
- authentik.core
|
- authentik.core
|
||||||
ExpressionPolicy:
|
ExpressionPolicy:
|
||||||
|
@ -11742,8 +11742,8 @@ definitions:
|
||||||
- password
|
- password
|
||||||
- number
|
- number
|
||||||
- checkbox
|
- checkbox
|
||||||
- data
|
- date
|
||||||
- data-time
|
- date-time
|
||||||
- separator
|
- separator
|
||||||
- hidden
|
- hidden
|
||||||
- static
|
- static
|
||||||
|
|
Reference in a new issue