stages/authenticator_validate: add Duo support
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		@ -11,12 +11,14 @@ import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage, StageHost } from "../base";
 | 
			
		||||
import "./AuthenticatorValidateStageWebAuthn";
 | 
			
		||||
import "./AuthenticatorValidateStageCode";
 | 
			
		||||
import "./AuthenticatorValidateStageDuo";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
 | 
			
		||||
export enum DeviceClasses {
 | 
			
		||||
    STATIC = "static",
 | 
			
		||||
    TOTP = "totp",
 | 
			
		||||
    WEBAUTHN = "webauthn",
 | 
			
		||||
    DUO = "duo",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DeviceChallenge {
 | 
			
		||||
@ -30,8 +32,9 @@ export interface AuthenticatorValidateStageChallenge extends WithUserInfoChallen
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorValidateStageChallengeResponse {
 | 
			
		||||
    code: string;
 | 
			
		||||
    webauthn: string;
 | 
			
		||||
    code?: string;
 | 
			
		||||
    webauthn?: string;
 | 
			
		||||
    duo?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate")
 | 
			
		||||
@ -77,6 +80,12 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
 | 
			
		||||
    renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
 | 
			
		||||
        switch (deviceChallenge.device_class) {
 | 
			
		||||
            case DeviceClasses.DUO:
 | 
			
		||||
                return html`<i class="fas fa-mobile-alt"></i>
 | 
			
		||||
                    <div class="right">
 | 
			
		||||
                        <p>${t`Duo push-notifications`}</p>
 | 
			
		||||
                        <small>${t`Receive a push notification on your phone to prove your identity.`}</small>
 | 
			
		||||
                    </div>`;
 | 
			
		||||
            case DeviceClasses.WEBAUTHN:
 | 
			
		||||
                return html`<i class="fas fa-mobile-alt"></i>
 | 
			
		||||
                    <div class="right">
 | 
			
		||||
@ -147,6 +156,13 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
                .deviceChallenge=${this.selectedDeviceChallenge}
 | 
			
		||||
                .showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
 | 
			
		||||
            </ak-stage-authenticator-validate-webauthn>`;
 | 
			
		||||
        case DeviceClasses.DUO:
 | 
			
		||||
            return html`<ak-stage-authenticator-validate-duo
 | 
			
		||||
                .host=${this}
 | 
			
		||||
                .challenge=${this.challenge}
 | 
			
		||||
                .deviceChallenge=${this.selectedDeviceChallenge}
 | 
			
		||||
                .showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
 | 
			
		||||
            </ak-stage-authenticator-validate-duo>`;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,81 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
 | 
			
		||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
 | 
			
		||||
import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate-duo")
 | 
			
		||||
export class AuthenticatorValidateStageWebDuo extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: AuthenticatorValidateStageChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    deviceChallenge?: DeviceChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({ type: Boolean })
 | 
			
		||||
    showBackButton = false;
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    firstUpdated(): void {
 | 
			
		||||
        this.host?.submit({
 | 
			
		||||
            "duo": this.deviceChallenge?.device_uid
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        if (!this.challenge) {
 | 
			
		||||
            return html`<ak-empty-state
 | 
			
		||||
                ?loading="${true}"
 | 
			
		||||
                header=${t`Loading`}>
 | 
			
		||||
            </ak-empty-state>`;
 | 
			
		||||
        }
 | 
			
		||||
        return html`<div class="pf-c-login__main-body">
 | 
			
		||||
            <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                <ak-form-static
 | 
			
		||||
                    class="pf-c-form__group"
 | 
			
		||||
                    userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                    user=${this.challenge.pending_user}>
 | 
			
		||||
                    <div slot="link">
 | 
			
		||||
                        <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </ak-form-static>
 | 
			
		||||
 | 
			
		||||
                <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                    <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
 | 
			
		||||
                        ${t`Continue`}
 | 
			
		||||
                    </button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <footer class="pf-c-login__main-footer">
 | 
			
		||||
            <ul class="pf-c-login__main-footer-links">
 | 
			
		||||
                ${this.showBackButton ?
 | 
			
		||||
                    html`<li class="pf-c-login__main-footer-links-item">
 | 
			
		||||
                        <button class="pf-c-button pf-m-secondary pf-m-block" @click=${() => {
 | 
			
		||||
                            if (!this.host) return;
 | 
			
		||||
                            (this.host as AuthenticatorValidateStage).selectedDeviceChallenge = undefined;
 | 
			
		||||
                        }}>
 | 
			
		||||
                            ${t`Return to device picker`}
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </li>`:
 | 
			
		||||
                    html``}
 | 
			
		||||
            </ul>
 | 
			
		||||
        </footer>`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user