diff --git a/authentik/flows/challenge.py b/authentik/flows/challenge.py index 62887c2b7..cc7401b9c 100644 --- a/authentik/flows/challenge.py +++ b/authentik/flows/challenge.py @@ -28,6 +28,14 @@ class ErrorDetailSerializer(PassiveSerializer): code = CharField() +class ContextualFlowInfo(PassiveSerializer): + """Contextual flow information for a challenge""" + + title = CharField(required=False, allow_blank=True) + background = CharField(required=False) + cancel_url = CharField() + + class Challenge(PassiveSerializer): """Challenge that gets sent to the client based on which stage is currently active""" @@ -35,8 +43,7 @@ class Challenge(PassiveSerializer): type = ChoiceField( choices=[(x.value, x.name) for x in ChallengeTypes], ) - title = CharField(required=False, allow_blank=True) - background = CharField(required=False) + flow_info = ContextualFlowInfo() component = CharField(default="") response_errors = DictField( diff --git a/authentik/flows/stage.py b/authentik/flows/stage.py index ad484a3bf..968c1b876 100644 --- a/authentik/flows/stage.py +++ b/authentik/flows/stage.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import AnonymousUser from django.http import HttpRequest from django.http.request import QueryDict from django.http.response import HttpResponse +from django.urls import reverse from django.views.generic.base import View from rest_framework.request import Request from structlog.stdlib import get_logger @@ -11,6 +12,7 @@ from authentik.core.models import DEFAULT_AVATAR, User from authentik.flows.challenge import ( Challenge, ChallengeResponse, + ContextualFlowInfo, HttpChallengeResponse, WithUserInfoChallenge, ) @@ -93,10 +95,16 @@ class ChallengeStageView(StageView): def _get_challenge(self, *args, **kwargs) -> Challenge: challenge = self.get_challenge(*args, **kwargs) - if "title" not in challenge.initial_data: - challenge.initial_data["title"] = self.executor.flow.title - if "background" not in challenge.initial_data: - challenge.initial_data["background"] = self.executor.flow.background_url + if "flow_info" not in challenge.initial_data: + flow_info = ContextualFlowInfo( + data={ + "title": self.executor.flow.title, + "background": self.executor.flow.background_url, + "cancel_url": reverse("authentik_flows:cancel"), + } + ) + flow_info.is_valid() + challenge.initial_data["flow_info"] = flow_info.data if isinstance(challenge, WithUserInfoChallenge): # If there's a pending user, update the `username` field # this field is only used by password managers. diff --git a/schema.yml b/schema.yml index 4600f7a56..a41aebd15 100644 --- a/schema.yml +++ b/schema.yml @@ -15347,10 +15347,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-access-denied @@ -15363,6 +15361,7 @@ components: error_message: type: string required: + - flow_info - type ActionEnum: enum: @@ -15669,10 +15668,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-authenticator-duo @@ -15695,6 +15692,7 @@ components: required: - activation_barcode - activation_code + - flow_info - pending_user - pending_user_avatar - stage_uuid @@ -15782,10 +15780,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-authenticator-static @@ -15805,6 +15801,7 @@ components: type: string required: - codes + - flow_info - pending_user - pending_user_avatar - type @@ -15883,10 +15880,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-authenticator-totp @@ -15904,6 +15899,7 @@ components: type: string required: - config_url + - flow_info - pending_user - pending_user_avatar - type @@ -16060,10 +16056,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-authenticator-validate @@ -16083,6 +16077,7 @@ components: $ref: '#/components/schemas/DeviceChallenge' required: - device_challenges + - flow_info - pending_user - pending_user_avatar - type @@ -16106,10 +16101,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-authenticator-webauthn @@ -16127,6 +16120,7 @@ components: type: object additionalProperties: {} required: + - flow_info - pending_user - pending_user_avatar - registration @@ -16156,10 +16150,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-autosubmit @@ -16177,6 +16169,7 @@ components: type: string required: - attrs + - flow_info - type - url BackendsEnum: @@ -16211,10 +16204,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-captcha @@ -16231,6 +16222,7 @@ components: site_key: type: string required: + - flow_info - pending_user - pending_user_avatar - site_key @@ -16416,10 +16408,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-consent @@ -16440,6 +16430,7 @@ components: items: $ref: '#/components/schemas/Permission' required: + - flow_info - header_text - pending_user - pending_user_avatar @@ -16512,6 +16503,18 @@ components: description: 'Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3).' required: - name + ContextualFlowInfo: + type: object + description: Contextual flow information for a challenge + properties: + title: + type: string + background: + type: string + cancel_url: + type: string + required: + - cancel_url Coordinate: type: object description: Coordinates for diagrams @@ -16715,10 +16718,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-dummy @@ -16729,6 +16730,7 @@ components: items: $ref: '#/components/schemas/ErrorDetail' required: + - flow_info - type DummyChallengeResponseRequest: type: object @@ -16875,10 +16877,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-email @@ -16889,6 +16889,7 @@ components: items: $ref: '#/components/schemas/ErrorDetail' required: + - flow_info - type EmailChallengeResponseRequest: type: object @@ -17668,10 +17669,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-identification @@ -17701,6 +17700,7 @@ components: items: $ref: '#/components/schemas/UILoginButton' required: + - flow_info - password_fields - primary_action - type @@ -21626,10 +21626,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-password @@ -21646,6 +21644,7 @@ components: recovery_url: type: string required: + - flow_info - pending_user - pending_user_avatar - type @@ -23378,10 +23377,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-flow-sources-plex @@ -23397,6 +23394,7 @@ components: type: string required: - client_id + - flow_info - slug - type PlexAuthenticationChallengeResponseRequest: @@ -23739,10 +23737,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: ak-stage-prompt @@ -23758,6 +23754,7 @@ components: $ref: '#/components/schemas/StagePrompt' required: - fields + - flow_info - type PromptChallengeResponseRequest: type: object @@ -24199,10 +24196,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: xak-flow-redirect @@ -24215,6 +24210,7 @@ components: to: type: string required: + - flow_info - to - type RefreshTokenModel: @@ -24912,10 +24908,8 @@ components: properties: type: $ref: '#/components/schemas/ChallengeChoices' - title: - type: string - background: - type: string + flow_info: + $ref: '#/components/schemas/ContextualFlowInfo' component: type: string default: xak-flow-shell @@ -24929,6 +24923,7 @@ components: type: string required: - body + - flow_info - type SignatureAlgorithmEnum: enum: diff --git a/web/src/api/legacy.ts b/web/src/api/legacy.ts index 75af21a6a..e0d458bcf 100644 --- a/web/src/api/legacy.ts +++ b/web/src/api/legacy.ts @@ -15,8 +15,4 @@ export class FlowURLManager { return `/flows/-/configure/${stageUuid}/${rest}`; } - static cancel(): string { - return "/flows/-/cancel/"; - } - } diff --git a/web/src/flows/FlowExecutor.ts b/web/src/flows/FlowExecutor.ts index 0154f5f94..f191e96c4 100644 --- a/web/src/flows/FlowExecutor.ts +++ b/web/src/flows/FlowExecutor.ts @@ -86,8 +86,8 @@ export class FlowExecutor extends LitElement implements StageHost { private postUpdate(): void { tenant().then(tenant => { - if (this.challenge?.title) { - document.title = `${this.challenge.title} - ${tenant.brandingTitle}`; + if (this.challenge?.flowInfo.title) { + document.title = `${this.challenge.flowInfo.title} - ${tenant.brandingTitle}`; } else { document.title = tenant.brandingTitle || TITLE_DEFAULT; } @@ -124,8 +124,8 @@ export class FlowExecutor extends LitElement implements StageHost { }).then((challenge) => { this.challenge = challenge; // Only set background on first update, flow won't change throughout execution - if (this.challenge?.background) { - this.setBackground(this.challenge.background); + if (this.challenge?.flowInfo.background) { + this.setBackground(this.challenge.flowInfo.background); } this.postUpdate(); }).catch((e: Error) => { @@ -271,7 +271,7 @@ export class FlowExecutor extends LitElement implements StageHost { ${this.tenant?.brandingTitle != "authentik" ? html`
  • ${t`Powered by authentik`}
  • ` : html``} - ${this.challenge?.background?.startsWith("/static") ? html` + ${this.challenge?.flowInfo.background?.startsWith("/static") ? html`
  • ${t`Background image`}
  • ` : html``} diff --git a/web/src/flows/access_denied/FlowAccessDenied.ts b/web/src/flows/access_denied/FlowAccessDenied.ts index 9b8cae20a..a49294a62 100644 --- a/web/src/flows/access_denied/FlowAccessDenied.ts +++ b/web/src/flows/access_denied/FlowAccessDenied.ts @@ -28,7 +28,7 @@ export class FlowAccessDenied extends BaseStage

    - ${this.challenge.title} + ${this.challenge.flowInfo.title}

    diff --git a/web/src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts b/web/src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts index cf95dc2b7..442dca75b 100644 --- a/web/src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts +++ b/web/src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts @@ -11,7 +11,6 @@ import { BaseStage } from "../base"; import "../../../elements/forms/FormElement"; import "../../../elements/EmptyState"; import "../../FormStatic"; -import { FlowURLManager } from "../../../api/legacy"; import { AuthenticatorDuoChallenge, StagesApi } from "authentik-api"; import { DEFAULT_CONFIG } from "../../../api/Config"; import { AuthenticatorDuoChallengeResponseRequest } from "authentik-api/dist/models/AuthenticatorDuoChallengeResponseRequest"; @@ -50,7 +49,7 @@ export class AuthenticatorDuoStage extends BaseStage