web/flows: fix webauthn retry (#8599)

* web/flows: fix retry button on webauthn device stage

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* web/flows: rework webauth register design to match

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L
2024-02-20 22:50:48 +01:00
committed by GitHub
parent f6f997525f
commit 042fae143d
2 changed files with 59 additions and 41 deletions

View File

@ -89,8 +89,8 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
this.authenticating = true; this.authenticating = true;
this.authenticate() this.authenticate()
.catch((e: Error) => { .catch((e: Error) => {
console.warn(`authentik/flows/authenticator_validate/webauthn: ${e.toString()}`); console.warn("authentik/flows/authenticator_validate/webauthn: failed to auth", e);
this.errorMessage = msg("Authentication failed."); this.errorMessage = msg("Authentication failed. Please try again.");
}) })
.finally(() => { .finally(() => {
this.authenticating = false; this.authenticating = false;
@ -110,12 +110,13 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
> >
</ak-empty-state> </ak-empty-state>
<div class="pf-c-form__group pf-m-action"> <div class="pf-c-form__group pf-m-action">
${this.errorMessage ${!this.authenticating
? html` <button ? html` <button
class="pf-c-button pf-m-primary pf-m-block" class="pf-c-button pf-m-primary pf-m-block"
@click=${() => { @click=${() => {
this.authenticateWrapper(); this.authenticateWrapper();
}} }}
type="button"
> >
${msg("Retry authentication")} ${msg("Retry authentication")}
</button>` </button>`

View File

@ -4,11 +4,11 @@ import {
transformCredentialCreateOptions, transformCredentialCreateOptions,
transformNewAssertionForServer, transformNewAssertionForServer,
} from "@goauthentik/common/helpers/webauthn"; } from "@goauthentik/common/helpers/webauthn";
import { PFSize } from "@goauthentik/elements/Spinner"; import "@goauthentik/elements/EmptyState";
import { BaseStage } from "@goauthentik/flow/stages/base"; import { BaseStage } from "@goauthentik/flow/stages/base";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -41,7 +41,24 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
publicKeyCredentialCreateOptions?: PublicKeyCredentialCreationOptions; publicKeyCredentialCreateOptions?: PublicKeyCredentialCreationOptions;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFFormControl, PFForm, PFTitle, PFButton]; return [
PFBase,
PFLogin,
PFFormControl,
PFForm,
PFTitle,
PFButton,
// FIXME: this is technically duplicate with ../authenticator_validate/base.ts
css`
.pf-c-form__group.pf-m-action {
display: flex;
gap: 16px;
margin-top: 0;
margin-bottom: calc(var(--pf-c-form__group--m-action--MarginTop) / 2);
flex-direction: column;
}
`,
];
} }
async register(): Promise<void> { async register(): Promise<void> {
@ -69,9 +86,14 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
// post the transformed credential data to the server for validation // post the transformed credential data to the server for validation
// and storing the public key // and storing the public key
try { try {
await this.host?.submit({ await this.host?.submit(
{
response: newAssertionForServer, response: newAssertionForServer,
}); },
{
invisible: true,
},
);
} catch (err) { } catch (err) {
throw new Error(msg(str`Server validation of credential failed: ${err}`)); throw new Error(msg(str`Server validation of credential failed: ${err}`));
} }
@ -84,8 +106,8 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
this.registerRunning = true; this.registerRunning = true;
this.register() this.register()
.catch((e) => { .catch((e) => {
console.error(e); console.warn("authentik/flows/authenticator_webauthn: failed to register", e);
this.registerMessage = e.toString(); this.registerMessage = msg("Failed to register. Please try again.");
}) })
.finally(() => { .finally(() => {
this.registerRunning = false; this.registerRunning = false;
@ -104,42 +126,37 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
render(): TemplateResult { render(): TemplateResult {
return html`<header class="pf-c-login__main-header"> return html`<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl"> <h1 class="pf-c-title pf-m-3xl">${this.challenge?.flowInfo?.title}</h1>
${this.challenge?.flowInfo?.title}
</h1>
</header> </header>
<div class="pf-c-login__main-body"> <div class="pf-c-login__main-body">
${ <form class="pf-c-form">
this.registerRunning <ak-empty-state
? html`<div class="pf-c-empty-state__content"> ?loading="${this.registerRunning}"
<div class="pf-l-bullseye"> header=${this.registerRunning
<div class="pf-l-bullseye__item"> ? msg("Registering...")
<ak-spinner size="${PFSize.XLarge}"></ak-spinner> : this.registerMessage || msg("Failed to register")}
</div> icon="fa-times"
</div> >
</div>` </ak-empty-state>
: html` <div class="pf-c-form__group pf-m-action">
${this.challenge?.responseErrors ${this.challenge?.responseErrors
? html`<p class="pf-m-block"> ? html`<p class="pf-m-block">
${this.challenge.responseErrors["response"][0].string} ${this.challenge.responseErrors["response"][0].string}
</p>` </p>`
: html``} : html``}
<p class="pf-m-block">${this.registerMessage}</p> <div class="pf-c-form__group pf-m-action">
<button ${!this.registerRunning
? html` <button
class="pf-c-button pf-m-primary pf-m-block" class="pf-c-button pf-m-primary pf-m-block"
@click=${() => { @click=${() => {
this.registerWrapper(); this.registerWrapper();
}} }}
type="button"
> >
${msg("Register device")} ${msg("Retry registration")}
</button> </button>`
</div>` : nothing}
}
</div> </div>
</div> </form>
<footer class="pf-c-login__main-footer"> </div>`;
<ul class="pf-c-login__main-footer-links">
</ul>
</footer>`;
} }
} }