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

View File

@ -4,11 +4,11 @@ import {
transformCredentialCreateOptions,
transformNewAssertionForServer,
} from "@goauthentik/common/helpers/webauthn";
import { PFSize } from "@goauthentik/elements/Spinner";
import "@goauthentik/elements/EmptyState";
import { BaseStage } from "@goauthentik/flow/stages/base";
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 PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -41,7 +41,24 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
publicKeyCredentialCreateOptions?: PublicKeyCredentialCreationOptions;
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> {
@ -69,9 +86,14 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
// post the transformed credential data to the server for validation
// and storing the public key
try {
await this.host?.submit({
response: newAssertionForServer,
});
await this.host?.submit(
{
response: newAssertionForServer,
},
{
invisible: true,
},
);
} catch (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.register()
.catch((e) => {
console.error(e);
this.registerMessage = e.toString();
console.warn("authentik/flows/authenticator_webauthn: failed to register", e);
this.registerMessage = msg("Failed to register. Please try again.");
})
.finally(() => {
this.registerRunning = false;
@ -104,42 +126,37 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
render(): TemplateResult {
return html`<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl">
${this.challenge?.flowInfo?.title}
</h1>
<h1 class="pf-c-title pf-m-3xl">${this.challenge?.flowInfo?.title}</h1>
</header>
<div class="pf-c-login__main-body">
${
this.registerRunning
? html`<div class="pf-c-empty-state__content">
<div class="pf-l-bullseye">
<div class="pf-l-bullseye__item">
<ak-spinner size="${PFSize.XLarge}"></ak-spinner>
</div>
</div>
</div>`
: html` <div class="pf-c-form__group pf-m-action">
${this.challenge?.responseErrors
? html`<p class="pf-m-block">
${this.challenge.responseErrors["response"][0].string}
</p>`
: html``}
<p class="pf-m-block">${this.registerMessage}</p>
<button
<form class="pf-c-form">
<ak-empty-state
?loading="${this.registerRunning}"
header=${this.registerRunning
? msg("Registering...")
: this.registerMessage || msg("Failed to register")}
icon="fa-times"
>
</ak-empty-state>
${this.challenge?.responseErrors
? html`<p class="pf-m-block">
${this.challenge.responseErrors["response"][0].string}
</p>`
: html``}
<div class="pf-c-form__group pf-m-action">
${!this.registerRunning
? html` <button
class="pf-c-button pf-m-primary pf-m-block"
@click=${() => {
this.registerWrapper();
}}
type="button"
>
${msg("Register device")}
</button>
</div>`
}
</div>
</div>
<footer class="pf-c-login__main-footer">
<ul class="pf-c-login__main-footer-links">
</ul>
</footer>`;
${msg("Retry registration")}
</button>`
: nothing}
</div>
</form>
</div>`;
}
}