web/flows: update types

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-05-24 20:52:12 +02:00
parent c6bb6709fd
commit 716923e17a
23 changed files with 93 additions and 142 deletions

View file

@ -44,7 +44,7 @@ class PromptChallenge(Challenge):
component = CharField(default="ak-stage-prompt") component = CharField(default="ak-stage-prompt")
class PromptResponseChallenge(ChallengeResponse): class PromptChallengeResponse(ChallengeResponse):
"""Validate response, fields are dynamically created based """Validate response, fields are dynamically created based
on the stage""" on the stage"""
@ -159,7 +159,7 @@ class ListPolicyEngine(PolicyEngine):
class PromptStageView(ChallengeStageView): class PromptStageView(ChallengeStageView):
"""Prompt Stage, save form data in plan context.""" """Prompt Stage, save form data in plan context."""
response_class = PromptResponseChallenge response_class = PromptChallengeResponse
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
fields = list(self.executor.current_stage.fields.all().order_by("order")) fields = list(self.executor.current_stage.fields.all().order_by("order"))
@ -174,7 +174,7 @@ class PromptStageView(ChallengeStageView):
def get_response_instance(self, data: QueryDict) -> ChallengeResponse: def get_response_instance(self, data: QueryDict) -> ChallengeResponse:
if not self.executor.plan: if not self.executor.plan:
raise ValueError raise ValueError
return PromptResponseChallenge( return PromptChallengeResponse(
instance=None, instance=None,
data=data, data=data,
stage=self.executor.current_stage, stage=self.executor.current_stage,

View file

@ -13,7 +13,7 @@ from authentik.flows.planner import FlowPlan
from authentik.flows.views import SESSION_KEY_PLAN from authentik.flows.views import SESSION_KEY_PLAN
from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.expression.models import ExpressionPolicy
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptResponseChallenge from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT, PromptChallengeResponse
class TestPromptStage(TestCase): class TestPromptStage(TestCase):
@ -112,7 +112,7 @@ class TestPromptStage(TestCase):
self.assertIn(prompt.label, force_str(response.content)) self.assertIn(prompt.label, force_str(response.content))
self.assertIn(prompt.placeholder, force_str(response.content)) self.assertIn(prompt.placeholder, force_str(response.content))
def test_valid_challenge_with_policy(self) -> PromptResponseChallenge: def test_valid_challenge_with_policy(self) -> PromptChallengeResponse:
"""Test challenge_response validation""" """Test challenge_response validation"""
plan = FlowPlan( plan = FlowPlan(
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
@ -123,13 +123,13 @@ class TestPromptStage(TestCase):
) )
self.stage.validation_policies.set([expr_policy]) self.stage.validation_policies.set([expr_policy])
self.stage.save() self.stage.save()
challenge_response = PromptResponseChallenge( challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data None, stage=self.stage, plan=plan, data=self.prompt_data
) )
self.assertEqual(challenge_response.is_valid(), True) self.assertEqual(challenge_response.is_valid(), True)
return challenge_response return challenge_response
def test_invalid_challenge(self) -> PromptResponseChallenge: def test_invalid_challenge(self) -> PromptChallengeResponse:
"""Test challenge_response validation""" """Test challenge_response validation"""
plan = FlowPlan( plan = FlowPlan(
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
@ -140,7 +140,7 @@ class TestPromptStage(TestCase):
) )
self.stage.validation_policies.set([expr_policy]) self.stage.validation_policies.set([expr_policy])
self.stage.save() self.stage.save()
challenge_response = PromptResponseChallenge( challenge_response = PromptChallengeResponse(
None, stage=self.stage, plan=plan, data=self.prompt_data None, stage=self.stage, plan=plan, data=self.prompt_data
) )
self.assertEqual(challenge_response.is_valid(), False) self.assertEqual(challenge_response.is_valid(), False)

View file

@ -16807,7 +16807,7 @@ components:
- $ref: '#/components/schemas/IdentificationChallengeResponseRequest' - $ref: '#/components/schemas/IdentificationChallengeResponseRequest'
- $ref: '#/components/schemas/PasswordChallengeResponseRequest' - $ref: '#/components/schemas/PasswordChallengeResponseRequest'
- $ref: '#/components/schemas/PlexAuthenticationChallengeResponseRequest' - $ref: '#/components/schemas/PlexAuthenticationChallengeResponseRequest'
- $ref: '#/components/schemas/PromptResponseChallengeRequest' - $ref: '#/components/schemas/PromptChallengeResponseRequest'
discriminator: discriminator:
propertyName: component propertyName: component
mapping: mapping:
@ -16824,7 +16824,7 @@ components:
ak-stage-identification: '#/components/schemas/IdentificationChallengeResponseRequest' ak-stage-identification: '#/components/schemas/IdentificationChallengeResponseRequest'
ak-stage-password: '#/components/schemas/PasswordChallengeResponseRequest' ak-stage-password: '#/components/schemas/PasswordChallengeResponseRequest'
ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallengeResponseRequest' ak-flow-sources-plex: '#/components/schemas/PlexAuthenticationChallengeResponseRequest'
ak-stage-prompt: '#/components/schemas/PromptResponseChallengeRequest' ak-stage-prompt: '#/components/schemas/PromptChallengeResponseRequest'
FlowDesignationEnum: FlowDesignationEnum:
enum: enum:
- authentication - authentication
@ -22995,6 +22995,15 @@ components:
required: required:
- fields - fields
- type - type
PromptChallengeResponseRequest:
type: object
description: |-
Validate response, fields are dynamically created based
on the stage
properties:
component:
type: string
default: ak-stage-prompt
PromptRequest: PromptRequest:
type: object type: object
description: Prompt Serializer description: Prompt Serializer
@ -23024,15 +23033,6 @@ components:
- field_key - field_key
- label - label
- type - type
PromptResponseChallengeRequest:
type: object
description: |-
Validate response, fields are dynamically created based
on the stage
properties:
component:
type: string
default: ak-stage-prompt
PromptStage: PromptStage:
type: object type: object
description: PromptStage Serializer description: PromptStage Serializer

View file

@ -34,6 +34,7 @@ import { PFSize } from "../elements/Spinner";
import { TITLE_DEFAULT } from "../constants"; import { TITLE_DEFAULT } from "../constants";
import { configureSentry } from "../api/Sentry"; import { configureSentry } from "../api/Sentry";
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest"; import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
import { FlowChallengeResponseRequest } from "authentik-api/src";
@customElement("ak-flow-executor") @customElement("ak-flow-executor")
@ -77,9 +78,6 @@ export class FlowExecutor extends LitElement implements StageHost {
constructor() { constructor() {
super(); super();
this.addEventListener("ak-flow-submit", () => {
this.submit();
});
this.flowSlug = window.location.pathname.split("/")[3]; this.flowSlug = window.location.pathname.split("/")[3];
} }
@ -100,12 +98,14 @@ export class FlowExecutor extends LitElement implements StageHost {
} }
submit(payload: ChallengeResponseRequest): Promise<void> { submit(payload: ChallengeResponseRequest): Promise<void> {
payload.component = this.challenge.component; // @ts-ignore
payload.component = this.challenge?.component;
console.log(payload);
this.loading = true; this.loading = true;
return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({ return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
flowSlug: this.flowSlug, flowSlug: this.flowSlug,
query: window.location.search.substring(1), query: window.location.search.substring(1),
challengeResponseRequest: payload, flowChallengeResponseRequest: payload as FlowChallengeResponseRequest,
}).then((data) => { }).then((data) => {
this.challenge = data; this.challenge = data;
this.postUpdate(); this.postUpdate();
@ -142,7 +142,7 @@ export class FlowExecutor extends LitElement implements StageHost {
} }
errorMessage(error: string): void { errorMessage(error: string): void {
this.challenge = <ShellChallenge>{ this.challenge = {
type: ChallengeChoices.Shell, type: ChallengeChoices.Shell,
body: `<header class="pf-c-login__main-header"> body: `<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl"> <h1 class="pf-c-title pf-m-3xl">
@ -162,7 +162,7 @@ export class FlowExecutor extends LitElement implements StageHost {
</li> </li>
</ul> </ul>
</footer>` </footer>`
}; } as Challenge;
} }
renderLoading(): TemplateResult { renderLoading(): TemplateResult {

View file

@ -1,5 +1,5 @@
import { AccessDeniedChallenge } from "authentik-api"; import { AccessDeniedChallenge } from "authentik-api";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import { BaseStage } from "../stages/base"; import { BaseStage } from "../stages/base";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css"; import PFTitle from "@patternfly/patternfly/components/Title/title.css";
@ -11,12 +11,10 @@ import AKGlobal from "../../authentik.css";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import "../../elements/EmptyState"; import "../../elements/EmptyState";
import { FlowChallengeResponseRequest } from "authentik-api/src";
@customElement("ak-stage-access-denied") @customElement("ak-stage-access-denied")
export class FlowAccessDenied extends BaseStage { export class FlowAccessDenied extends BaseStage<AccessDeniedChallenge, FlowChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AccessDeniedChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFList, PFFormControl, PFTitle, AKGlobal]; return [PFBase, PFLogin, PFForm, PFList, PFFormControl, PFTitle, AKGlobal];

View file

@ -7,7 +7,7 @@ import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
import AKGlobal from "../../../authentik.css"; import AKGlobal from "../../../authentik.css";
import { CSSResult, customElement, property } from "lit-element"; import { CSSResult, customElement } from "lit-element";
import { html, TemplateResult } from "lit-html"; import { html, TemplateResult } from "lit-html";
import { BaseStage } from "../../stages/base"; import { BaseStage } from "../../stages/base";
import { PlexAPIClient, popupCenterScreen } from "./API"; import { PlexAPIClient, popupCenterScreen } from "./API";
@ -15,13 +15,11 @@ import { DEFAULT_CONFIG } from "../../../api/Config";
import { SourcesApi } from "authentik-api"; import { SourcesApi } from "authentik-api";
import { showMessage } from "../../../elements/messages/MessageContainer"; import { showMessage } from "../../../elements/messages/MessageContainer";
import { MessageLevel } from "../../../elements/messages/Message"; import { MessageLevel } from "../../../elements/messages/Message";
import { PlexAuthenticationChallengeResponseRequest } from "authentik-api/dist/models/PlexAuthenticationChallengeResponseRequest";
@customElement("ak-flow-sources-plex") @customElement("ak-flow-sources-plex")
export class PlexLoginInit extends BaseStage { export class PlexLoginInit extends BaseStage<PlexAuthenticationChallenge, PlexAuthenticationChallengeResponseRequest> {
@property({ attribute: false })
challenge?: PlexAuthenticationChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -14,12 +14,10 @@ import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { AuthenticatorDuoChallenge, StagesApi } from "authentik-api"; import { AuthenticatorDuoChallenge, StagesApi } from "authentik-api";
import { DEFAULT_CONFIG } from "../../../api/Config"; import { DEFAULT_CONFIG } from "../../../api/Config";
import { AuthenticatorDuoChallengeResponseRequest } from "authentik-api/dist/models/AuthenticatorDuoChallengeResponseRequest";
@customElement("ak-stage-authenticator-duo") @customElement("ak-stage-authenticator-duo")
export class AuthenticatorDuoStage extends BaseStage { export class AuthenticatorDuoStage extends BaseStage<AuthenticatorDuoChallenge, AuthenticatorDuoChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorDuoChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { css, CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -13,6 +13,7 @@ import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { AuthenticatorStaticChallenge } from "authentik-api"; import { AuthenticatorStaticChallenge } from "authentik-api";
import { AuthenticatorStaticChallengeResponseRequest } from "authentik-api/dist/models/AuthenticatorStaticChallengeResponseRequest";
export const STATIC_TOKEN_STYLE = css` export const STATIC_TOKEN_STYLE = css`
/* Static OTP Tokens */ /* Static OTP Tokens */
@ -31,10 +32,7 @@ export const STATIC_TOKEN_STYLE = css`
@customElement("ak-stage-authenticator-static") @customElement("ak-stage-authenticator-static")
export class AuthenticatorStaticStage extends BaseStage { export class AuthenticatorStaticStage extends BaseStage<AuthenticatorStaticChallenge, AuthenticatorStaticChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorStaticChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal, STATIC_TOKEN_STYLE]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal, STATIC_TOKEN_STYLE];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -15,14 +15,11 @@ import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { MessageLevel } from "../../../elements/messages/Message"; import { MessageLevel } from "../../../elements/messages/Message";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { AuthenticatorTOTPChallenge } from "authentik-api"; import { AuthenticatorTOTPChallenge, AuthenticatorTOTPChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-authenticator-totp") @customElement("ak-stage-authenticator-totp")
export class AuthenticatorTOTPStage extends BaseStage { export class AuthenticatorTOTPStage extends BaseStage<AuthenticatorTOTPChallenge, AuthenticatorTOTPChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorTOTPChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];

View file

@ -12,9 +12,8 @@ import "./AuthenticatorValidateStageWebAuthn";
import "./AuthenticatorValidateStageCode"; import "./AuthenticatorValidateStageCode";
import "./AuthenticatorValidateStageDuo"; import "./AuthenticatorValidateStageDuo";
import { PasswordManagerPrefill } from "../identification/IdentificationStage"; import { PasswordManagerPrefill } from "../identification/IdentificationStage";
import { DeviceChallenge } from "authentik-api"; import { AuthenticatorValidationChallengeResponseRequest, DeviceChallenge } from "authentik-api";
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge"; import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
export enum DeviceClasses { export enum DeviceClasses {
STATIC = "static", STATIC = "static",
@ -24,15 +23,12 @@ export enum DeviceClasses {
} }
@customElement("ak-stage-authenticator-validate") @customElement("ak-stage-authenticator-validate")
export class AuthenticatorValidateStage extends BaseStage implements StageHost { export class AuthenticatorValidateStage extends BaseStage<AuthenticatorValidationChallenge, AuthenticatorValidationChallengeResponseRequest> implements StageHost {
@property({ attribute: false })
challenge?: AuthenticatorValidationChallenge;
@property({attribute: false}) @property({attribute: false})
selectedDeviceChallenge?: DeviceChallenge; selectedDeviceChallenge?: DeviceChallenge;
submit(payload: ChallengeResponseRequest): Promise<void> { submit(payload: AuthenticatorValidationChallengeResponseRequest): Promise<void> {
return this.host?.submit(payload) || Promise.resolve(); return this.host?.submit(payload) || Promise.resolve();
} }
@ -130,21 +126,21 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
case DeviceClasses.STATIC: case DeviceClasses.STATIC:
case DeviceClasses.TOTP: case DeviceClasses.TOTP:
return html`<ak-stage-authenticator-validate-code return html`<ak-stage-authenticator-validate-code
.host=${this as StageHost} .host=${this}
.challenge=${this.challenge} .challenge=${this.challenge}
.deviceChallenge=${this.selectedDeviceChallenge} .deviceChallenge=${this.selectedDeviceChallenge}
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}> .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
</ak-stage-authenticator-validate-code>`; </ak-stage-authenticator-validate-code>`;
case DeviceClasses.WEBAUTHN: case DeviceClasses.WEBAUTHN:
return html`<ak-stage-authenticator-validate-webauthn return html`<ak-stage-authenticator-validate-webauthn
.host=${this as StageHost} .host=${this}
.challenge=${this.challenge} .challenge=${this.challenge}
.deviceChallenge=${this.selectedDeviceChallenge} .deviceChallenge=${this.selectedDeviceChallenge}
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}> .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
</ak-stage-authenticator-validate-webauthn>`; </ak-stage-authenticator-validate-webauthn>`;
case DeviceClasses.DUO: case DeviceClasses.DUO:
return html`<ak-stage-authenticator-validate-duo return html`<ak-stage-authenticator-validate-duo
.host=${this as StageHost} .host=${this}
.challenge=${this.challenge} .challenge=${this.challenge}
.deviceChallenge=${this.selectedDeviceChallenge} .deviceChallenge=${this.selectedDeviceChallenge}
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}> .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>

View file

@ -15,13 +15,10 @@ import { PasswordManagerPrefill } from "../identification/IdentificationStage";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge"; import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
import { DeviceChallenge } from "authentik-api"; import { AuthenticatorValidationChallengeResponseRequest, DeviceChallenge } from "authentik-api";
@customElement("ak-stage-authenticator-validate-code") @customElement("ak-stage-authenticator-validate-code")
export class AuthenticatorValidateStageWebCode extends BaseStage { export class AuthenticatorValidateStageWebCode extends BaseStage<AuthenticatorValidationChallenge, AuthenticatorValidationChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorValidationChallenge;
@property({ attribute: false }) @property({ attribute: false })
deviceChallenge?: DeviceChallenge; deviceChallenge?: DeviceChallenge;

View file

@ -14,13 +14,10 @@ import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge"; import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
import { DeviceChallenge } from "authentik-api"; import { AuthenticatorValidationChallengeResponseRequest, DeviceChallenge } from "authentik-api";
@customElement("ak-stage-authenticator-validate-duo") @customElement("ak-stage-authenticator-validate-duo")
export class AuthenticatorValidateStageWebDuo extends BaseStage { export class AuthenticatorValidateStageWebDuo extends BaseStage<AuthenticatorValidationChallenge, AuthenticatorValidationChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorValidationChallenge;
@property({ attribute: false }) @property({ attribute: false })
deviceChallenge?: DeviceChallenge; deviceChallenge?: DeviceChallenge;

View file

@ -12,13 +12,10 @@ import { transformAssertionForServer, transformCredentialRequestOptions } from "
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage"; import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge"; import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
import { DeviceChallenge } from "authentik-api"; import { AuthenticatorValidationChallengeResponseRequest, DeviceChallenge } from "authentik-api";
@customElement("ak-stage-authenticator-validate-webauthn") @customElement("ak-stage-authenticator-validate-webauthn")
export class AuthenticatorValidateStageWebAuthn extends BaseStage { export class AuthenticatorValidateStageWebAuthn extends BaseStage<AuthenticatorValidationChallenge, AuthenticatorValidationChallengeResponseRequest> {
@property({attribute: false})
challenge?: AuthenticatorValidationChallenge;
@property({attribute: false}) @property({attribute: false})
deviceChallenge?: DeviceChallenge; deviceChallenge?: DeviceChallenge;
@ -62,9 +59,9 @@ export class AuthenticatorValidateStageWebAuthn extends BaseStage {
// post the assertion to the server for verification. // post the assertion to the server for verification.
try { try {
const formData = new FormData(); await this.host?.submit({
formData.set("webauthn", JSON.stringify(transformedAssertionForServer)); webauthn: transformedAssertionForServer
await this.host?.submit(formData); });
} catch (err) { } catch (err) {
throw new Error(t`Error when validating assertion on server: ${err}`); throw new Error(t`Error when validating assertion on server: ${err}`);
} }

View file

@ -10,17 +10,14 @@ import AKGlobal from "../../../authentik.css";
import { PFSize } from "../../../elements/Spinner"; import { PFSize } from "../../../elements/Spinner";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import { Assertion, transformCredentialCreateOptions, transformNewAssertionForServer } from "./utils"; import { Assertion, transformCredentialCreateOptions, transformNewAssertionForServer } from "./utils";
import { AuthenticatorWebAuthnChallenge } from "authentik-api"; import { AuthenticatorWebAuthnChallenge, AuthenticatorWebAuthnChallengeResponseRequest } from "authentik-api";
export interface WebAuthnAuthenticatorRegisterChallengeResponse { export interface WebAuthnAuthenticatorRegisterChallengeResponse {
response: Assertion; response: Assertion;
} }
@customElement("ak-stage-authenticator-webauthn") @customElement("ak-stage-authenticator-webauthn")
export class WebAuthnAuthenticatorRegisterStage extends BaseStage { export class WebAuthnAuthenticatorRegisterStage extends BaseStage<AuthenticatorWebAuthnChallenge, AuthenticatorWebAuthnChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AuthenticatorWebAuthnChallenge;
@property({type: Boolean}) @property({type: Boolean})
registerRunning = false; registerRunning = false;

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -10,12 +10,10 @@ import AKGlobal from "../../../authentik.css";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import { AutosubmitChallenge } from "authentik-api"; import { AutosubmitChallenge } from "authentik-api";
import { AutoSubmitChallengeResponseRequest } from "authentik-api/dist/models/AutoSubmitChallengeResponseRequest";
@customElement("ak-stage-autosubmit") @customElement("ak-stage-autosubmit")
export class AutosubmitStage extends BaseStage { export class AutosubmitStage extends BaseStage<AutosubmitChallenge, AutoSubmitChallengeResponseRequest> {
@property({ attribute: false })
challenge?: AutosubmitChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal];

View file

@ -1,16 +1,16 @@
import { Challenge } from "authentik-api"; import { LitElement, property } from "lit-element";
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
import { LitElement } from "lit-element";
export interface StageHost { export interface StageHost {
challenge?: Challenge; challenge?: unknown;
submit(payload: ChallengeResponseRequest): Promise<void>; submit(payload: unknown): Promise<void>;
} }
export class BaseStage extends LitElement { export class BaseStage<Tin, Tout> extends LitElement {
host?: StageHost; host!: StageHost;
challenge!: Challenge;
@property({ attribute: false })
challenge!: Tin;
submitForm(e: Event): void { submitForm(e: Event): void {
e.preventDefault(); e.preventDefault();
@ -19,7 +19,7 @@ export class BaseStage extends LitElement {
} = {}; } = {};
const form = new FormData(this.shadowRoot?.querySelector("form") || undefined); const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
form.forEach((value, key) => object[key] = value); form.forEach((value, key) => object[key] = value);
this.host?.submit(object as unknown as ChallengeResponseRequest); this.host?.submit(object as unknown as Tout);
} }
} }

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -13,13 +13,10 @@ import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { CaptchaChallenge } from "authentik-api"; import { CaptchaChallenge, CaptchaChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-captcha") @customElement("ak-stage-captcha")
export class CaptchaStage extends BaseStage { export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeResponseRequest> {
@property({ attribute: false })
challenge?: CaptchaChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -11,14 +11,11 @@ import { BaseStage } from "../base";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { ConsentChallenge } from "authentik-api"; import { ConsentChallenge, ConsentChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-consent") @customElement("ak-stage-consent")
export class ConsentStage extends BaseStage { export class ConsentStage extends BaseStage<ConsentChallenge, ConsentChallengeResponseRequest> {
@property({ attribute: false })
challenge?: ConsentChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -10,13 +10,10 @@ import AKGlobal from "../../../authentik.css";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import "../../FormStatic"; import "../../FormStatic";
import { DummyChallenge } from "authentik-api"; import { DummyChallenge, DummyChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-dummy") @customElement("ak-stage-dummy")
export class DummyStage extends BaseStage { export class DummyStage extends BaseStage<DummyChallenge, DummyChallengeResponseRequest> {
@property({ attribute: false })
challenge?: DummyChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -9,13 +9,10 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import AKGlobal from "../../../authentik.css"; import AKGlobal from "../../../authentik.css";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import { EmailChallenge } from "authentik-api"; import { EmailChallenge, EmailChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-email") @customElement("ak-stage-email")
export class EmailStage extends BaseStage { export class EmailStage extends BaseStage<EmailChallenge, EmailChallengeResponseRequest> {
@property({ attribute: false })
challenge?: EmailChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { css, CSSResult, customElement, html, TemplateResult } from "lit-element";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
@ -10,7 +10,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import AKGlobal from "../../../authentik.css"; import AKGlobal from "../../../authentik.css";
import "../../../elements/forms/FormElement"; import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import { IdentificationChallenge, UILoginButton } from "authentik-api"; import { Challenge, IdentificationChallenge, IdentificationChallengeResponseRequest, UILoginButton } from "authentik-api";
export const PasswordManagerPrefill: { export const PasswordManagerPrefill: {
password: string | undefined; password: string | undefined;
@ -22,10 +22,7 @@ export const PasswordManagerPrefill: {
@customElement("ak-stage-identification") @customElement("ak-stage-identification")
export class IdentificationStage extends BaseStage { export class IdentificationStage extends BaseStage<IdentificationChallenge, IdentificationChallengeResponseRequest> {
@property({attribute: false})
challenge?: IdentificationChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal].concat( return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal].concat(
@ -119,7 +116,7 @@ export class IdentificationStage extends BaseStage {
return html`<li class="pf-c-login__main-footer-links-item"> return html`<li class="pf-c-login__main-footer-links-item">
<button type="button" @click=${() => { <button type="button" @click=${() => {
if (!this.host) return; if (!this.host) return;
this.host.challenge = source.challenge; this.host.challenge = source.challenge as Challenge;
}}> }}>
${icon} ${icon}
</button> </button>

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
@ -13,13 +13,10 @@ import "../../../elements/EmptyState";
import { PasswordManagerPrefill } from "../identification/IdentificationStage"; import { PasswordManagerPrefill } from "../identification/IdentificationStage";
import "../../FormStatic"; import "../../FormStatic";
import { FlowURLManager } from "../../../api/legacy"; import { FlowURLManager } from "../../../api/legacy";
import { PasswordChallenge } from "authentik-api"; import { PasswordChallenge, PasswordChallengeResponseRequest } from "authentik-api";
@customElement("ak-stage-password") @customElement("ak-stage-password")
export class PasswordStage extends BaseStage { export class PasswordStage extends BaseStage<PasswordChallenge, PasswordChallengeResponseRequest> {
@property({attribute: false})
challenge?: PasswordChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal]; return [PFBase, PFLogin, PFForm, PFFormControl, PFButton, PFTitle, AKGlobal];

View file

@ -1,5 +1,5 @@
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element"; import { CSSResult, customElement, html, TemplateResult } from "lit-element";
import { unsafeHTML } from "lit-html/directives/unsafe-html"; import { unsafeHTML } from "lit-html/directives/unsafe-html";
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFForm from "@patternfly/patternfly/components/Form/form.css";
@ -14,14 +14,12 @@ import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import "../../../elements/Divider"; import "../../../elements/Divider";
import { Error } from "../../../api/Flows"; import { Error } from "../../../api/Flows";
import { Prompt, PromptChallenge, StagePrompt } from "authentik-api"; import { PromptChallenge, StagePrompt } from "authentik-api";
import { PromptChallengeResponseRequest } from "authentik-api/src/models/PromptChallengeResponseRequest";
@customElement("ak-stage-prompt") @customElement("ak-stage-prompt")
export class PromptStage extends BaseStage { export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeResponseRequest> {
@property({attribute: false})
challenge?: PromptChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFAlert, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFAlert, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];