From c6bb6709fdd2d72ef504d38eb8b552d0fad3b88e Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 24 May 2021 20:04:56 +0200 Subject: [PATCH] flows: add default challenge response Signed-off-by: Jens Langhammer --- authentik/flows/challenge.py | 2 +- authentik/flows/views.py | 2 +- authentik/providers/saml/views/flows.py | 8 ++ authentik/sources/plex/models.py | 8 +- authentik/stages/authenticator_duo/stage.py | 8 ++ .../stages/authenticator_static/stage.py | 8 ++ schema.yml | 92 +++++++++++++------ tests/e2e/utils.py | 6 +- .../stages/autosubmit/AutosubmitStage.ts | 2 +- web/src/flows/stages/base.ts | 9 +- .../identification/IdentificationStage.ts | 6 +- web/src/flows/stages/prompt/PromptStage.ts | 4 +- 12 files changed, 109 insertions(+), 46 deletions(-) diff --git a/authentik/flows/challenge.py b/authentik/flows/challenge.py index 0dd8a9f3e..f353559b5 100644 --- a/authentik/flows/challenge.py +++ b/authentik/flows/challenge.py @@ -83,7 +83,7 @@ class ChallengeResponse(PassiveSerializer): """Base class for all challenge responses""" stage: Optional["StageView"] - component = CharField(default="") + component = CharField(default="xak-flow-response-default") def __init__(self, instance=None, data=None, **kwargs): self.stage = kwargs.pop("stage", None) diff --git a/authentik/flows/views.py b/authentik/flows/views.py index 9d7f50ec1..9035cb88e 100644 --- a/authentik/flows/views.py +++ b/authentik/flows/views.py @@ -215,7 +215,7 @@ class FlowExecutorView(APIView): ), }, request=PolymorphicProxySerializer( - component_name="ChallengeResponse", + component_name="FlowChallengeResponse", serializers=challenge_response_types(), resource_type_field_name="component", ), diff --git a/authentik/providers/saml/views/flows.py b/authentik/providers/saml/views/flows.py index 094fe2296..803ff6d19 100644 --- a/authentik/providers/saml/views/flows.py +++ b/authentik/providers/saml/views/flows.py @@ -37,12 +37,20 @@ class AutosubmitChallenge(Challenge): component = CharField(default="ak-stage-autosubmit") +class AutoSubmitChallengeResponse(ChallengeResponse): + """Pseudo class for autosubmit response""" + + component = CharField(default="ak-stage-autosubmit") + + # This View doesn't have a URL on purpose, as its called by the FlowExecutor class SAMLFlowFinalView(ChallengeStageView): """View used by FlowExecutor after all stages have passed. Logs the authorization, and redirects to the SP (if REDIRECT is configured) or shows an auto-submit element (if POST is configured).""" + response_class = AutoSubmitChallengeResponse + def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: application: Application = self.executor.plan.context[PLAN_CONTEXT_APPLICATION] provider: SAMLProvider = get_object_or_404( diff --git a/authentik/sources/plex/models.py b/authentik/sources/plex/models.py index c83483db3..fe215b467 100644 --- a/authentik/sources/plex/models.py +++ b/authentik/sources/plex/models.py @@ -8,7 +8,7 @@ from rest_framework.serializers import BaseSerializer from authentik.core.models import Source, UserSourceConnection from authentik.core.types import UILoginButton -from authentik.flows.challenge import Challenge, ChallengeTypes +from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes from authentik.providers.oauth2.generators import generate_client_id @@ -20,6 +20,12 @@ class PlexAuthenticationChallenge(Challenge): component = CharField(default="ak-flow-sources-plex") +class PlexAuthenticationChallengeResponse(ChallengeResponse): + """Pseudo class for plex response""" + + component = CharField(default="ak-flow-sources-plex") + + class PlexSource(Source): """Authenticate against plex.tv""" diff --git a/authentik/stages/authenticator_duo/stage.py b/authentik/stages/authenticator_duo/stage.py index 4bbc1b6fa..999f5d82c 100644 --- a/authentik/stages/authenticator_duo/stage.py +++ b/authentik/stages/authenticator_duo/stage.py @@ -28,9 +28,17 @@ class AuthenticatorDuoChallenge(WithUserInfoChallenge): component = CharField(default="ak-stage-authenticator-duo") +class AuthenticatorDuoChallengeResponse(ChallengeResponse): + """Pseudo class for duo response""" + + component = CharField(default="ak-stage-authenticator-duo") + + class AuthenticatorDuoStageView(ChallengeStageView): """Duo stage""" + response_class = AuthenticatorDuoChallengeResponse + def get_challenge(self, *args, **kwargs) -> Challenge: user = self.get_pending_user() stage: AuthenticatorDuoStage = self.executor.current_stage diff --git a/authentik/stages/authenticator_static/stage.py b/authentik/stages/authenticator_static/stage.py index 9212cb6c6..5f40a10e6 100644 --- a/authentik/stages/authenticator_static/stage.py +++ b/authentik/stages/authenticator_static/stage.py @@ -25,9 +25,17 @@ class AuthenticatorStaticChallenge(WithUserInfoChallenge): component = CharField(default="ak-stage-authenticator-static") +class AuthenticatorStaticChallengeResponse(ChallengeResponse): + """Pseudo class for static response""" + + component = CharField(default="ak-stage-authenticator-static") + + class AuthenticatorStaticStageView(ChallengeStageView): """Static OTP Setup stage""" + response_class = AuthenticatorStaticChallengeResponse + def get_challenge(self, *args, **kwargs) -> AuthenticatorStaticChallenge: tokens: list[StaticToken] = self.request.session[SESSION_STATIC_TOKENS] return AuthenticatorStaticChallenge( diff --git a/schema.yml b/schema.yml index 159f7a6c5..dd834649d 100644 --- a/schema.yml +++ b/schema.yml @@ -3550,13 +3550,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ChallengeResponseRequest' + $ref: '#/components/schemas/FlowChallengeResponseRequest' application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/ChallengeResponseRequest' + $ref: '#/components/schemas/FlowChallengeResponseRequest' multipart/form-data: schema: - $ref: '#/components/schemas/ChallengeResponseRequest' + $ref: '#/components/schemas/FlowChallengeResponseRequest' security: - authentik: [] - cookieAuth: [] @@ -15194,6 +15194,13 @@ components: - pending_user_avatar - stage_uuid - type + AuthenticatorDuoChallengeResponseRequest: + type: object + description: Pseudo class for duo response + properties: + component: + type: string + default: ak-stage-authenticator-duo AuthenticatorDuoStage: type: object description: AuthenticatorDuoStage Serializer @@ -15296,6 +15303,13 @@ components: - pending_user - pending_user_avatar - type + AuthenticatorStaticChallengeResponseRequest: + type: object + description: Pseudo class for static response + properties: + component: + type: string + default: ak-stage-authenticator-static AuthenticatorStaticStage: type: object description: AuthenticatorStaticStage Serializer @@ -15624,6 +15638,13 @@ components: additionalProperties: {} required: - response + AutoSubmitChallengeResponseRequest: + type: object + description: Pseudo class for autosubmit response + properties: + component: + type: string + default: ak-stage-autosubmit AutosubmitChallenge: type: object description: Autosubmit challenge used to send and navigate a POST request @@ -15889,31 +15910,6 @@ components: - shell - redirect type: string - ChallengeResponseRequest: - oneOf: - - $ref: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest' - - $ref: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest' - - $ref: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest' - - $ref: '#/components/schemas/CaptchaChallengeResponseRequest' - - $ref: '#/components/schemas/ConsentChallengeResponseRequest' - - $ref: '#/components/schemas/DummyChallengeResponseRequest' - - $ref: '#/components/schemas/EmailChallengeResponseRequest' - - $ref: '#/components/schemas/IdentificationChallengeResponseRequest' - - $ref: '#/components/schemas/PasswordChallengeResponseRequest' - - $ref: '#/components/schemas/PromptResponseChallengeRequest' - discriminator: - propertyName: component - mapping: - ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest' - ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest' - ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest' - ak-stage-captcha: '#/components/schemas/CaptchaChallengeResponseRequest' - ak-stage-consent: '#/components/schemas/ConsentChallengeResponseRequest' - ak-stage-dummy: '#/components/schemas/DummyChallengeResponseRequest' - ak-stage-email: '#/components/schemas/EmailChallengeResponseRequest' - ak-stage-identification: '#/components/schemas/IdentificationChallengeResponseRequest' - ak-stage-password: '#/components/schemas/PasswordChallengeResponseRequest' - ak-stage-prompt: '#/components/schemas/PromptResponseChallengeRequest' ClientTypeEnum: enum: - confidential @@ -16796,6 +16792,39 @@ components: - slug - stages - title + FlowChallengeResponseRequest: + oneOf: + - $ref: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest' + - $ref: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest' + - $ref: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest' + - $ref: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest' + - $ref: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest' + - $ref: '#/components/schemas/AutoSubmitChallengeResponseRequest' + - $ref: '#/components/schemas/CaptchaChallengeResponseRequest' + - $ref: '#/components/schemas/ConsentChallengeResponseRequest' + - $ref: '#/components/schemas/DummyChallengeResponseRequest' + - $ref: '#/components/schemas/EmailChallengeResponseRequest' + - $ref: '#/components/schemas/IdentificationChallengeResponseRequest' + - $ref: '#/components/schemas/PasswordChallengeResponseRequest' + - $ref: '#/components/schemas/PlexAuthenticationChallengeResponseRequest' + - $ref: '#/components/schemas/PromptResponseChallengeRequest' + discriminator: + propertyName: component + mapping: + ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest' + ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest' + ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest' + ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest' + ak-stage-authenticator-webauthn: '#/components/schemas/AuthenticatorWebAuthnChallengeResponseRequest' + ak-stage-autosubmit: '#/components/schemas/AutoSubmitChallengeResponseRequest' + ak-stage-captcha: '#/components/schemas/CaptchaChallengeResponseRequest' + ak-stage-consent: '#/components/schemas/ConsentChallengeResponseRequest' + ak-stage-dummy: '#/components/schemas/DummyChallengeResponseRequest' + ak-stage-email: '#/components/schemas/EmailChallengeResponseRequest' + ak-stage-identification: '#/components/schemas/IdentificationChallengeResponseRequest' + ak-stage-password: '#/components/schemas/PasswordChallengeResponseRequest' + ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallengeResponseRequest' + ak-stage-prompt: '#/components/schemas/PromptResponseChallengeRequest' FlowDesignationEnum: enum: - authentication @@ -22612,6 +22641,13 @@ components: - client_id - slug - type + PlexAuthenticationChallengeResponseRequest: + type: object + description: Pseudo class for plex response + properties: + component: + type: string + default: ak-flow-sources-plex PlexSource: type: object description: Plex Source Serializer diff --git a/tests/e2e/utils.py b/tests/e2e/utils.py index f326bdb25..735dc4fde 100644 --- a/tests/e2e/utils.py +++ b/tests/e2e/utils.py @@ -136,13 +136,13 @@ class SeleniumTestCase(StaticLiveServerTestCase): ) identification_stage.find_element( - By.CSS_SELECTOR, "input[name=uid_field]" + By.CSS_SELECTOR, "input[name=uidField]" ).click() identification_stage.find_element( - By.CSS_SELECTOR, "input[name=uid_field]" + By.CSS_SELECTOR, "input[name=uidField]" ).send_keys(USER().username) identification_stage.find_element( - By.CSS_SELECTOR, "input[name=uid_field]" + By.CSS_SELECTOR, "input[name=uidField]" ).send_keys(Keys.ENTER) flow_executor = self.get_shadow_root("ak-flow-executor") diff --git a/web/src/flows/stages/autosubmit/AutosubmitStage.ts b/web/src/flows/stages/autosubmit/AutosubmitStage.ts index c3e980582..b8e63f7e9 100644 --- a/web/src/flows/stages/autosubmit/AutosubmitStage.ts +++ b/web/src/flows/stages/autosubmit/AutosubmitStage.ts @@ -40,7 +40,7 @@ export class AutosubmitStage extends BaseStage {