web/flows: rework redirect logic (#5498)
* web/flows: rework redirect logic always use redirect stage, remove special logic from flow executor show better message when redirect target URL isn't http or https (show notice to close the page) Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update strings Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -37,7 +37,6 @@ import {
|
||||
FlowErrorChallenge,
|
||||
FlowsApi,
|
||||
LayoutEnum,
|
||||
RedirectChallenge,
|
||||
ResponseError,
|
||||
ShellChallenge,
|
||||
UiThemeEnum,
|
||||
@ -52,18 +51,6 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
@property({ attribute: false })
|
||||
set challenge(value: ChallengeTypes | undefined) {
|
||||
this._challenge = value;
|
||||
// Assign the location as soon as we get the challenge and *not* in the render function
|
||||
// as the render function might be called multiple times, which will navigate multiple
|
||||
// times and can invalidate oauth codes
|
||||
// Also only auto-redirect when the inspector is open, so that a user can inspect the
|
||||
// redirect in the inspector
|
||||
if (value?.type === ChallengeChoices.Redirect && !this.inspectorOpen) {
|
||||
console.debug(
|
||||
"authentik/flows: redirecting to url from server",
|
||||
(value as RedirectChallenge).to,
|
||||
);
|
||||
window.location.assign((value as RedirectChallenge).to);
|
||||
}
|
||||
if (value?.flowInfo?.title) {
|
||||
document.title = `${value.flowInfo?.title} - ${this.tenant?.brandingTitle}`;
|
||||
} else {
|
||||
@ -407,15 +394,12 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
switch (this.challenge.type) {
|
||||
case ChallengeChoices.Redirect:
|
||||
if (this.inspectorOpen) {
|
||||
return html`<ak-stage-redirect
|
||||
.host=${this as StageHost}
|
||||
.challenge=${this.challenge}
|
||||
>
|
||||
</ak-stage-redirect>`;
|
||||
}
|
||||
return html`<ak-empty-state ?loading=${true} header=${t`Loading`}>
|
||||
</ak-empty-state>`;
|
||||
return html`<ak-stage-redirect
|
||||
.host=${this as StageHost}
|
||||
.challenge=${this.challenge}
|
||||
?promptUser=${this.inspectorOpen}
|
||||
>
|
||||
</ak-stage-redirect>`;
|
||||
case ChallengeChoices.Shell:
|
||||
return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`;
|
||||
case ChallengeChoices.Native:
|
||||
|
||||
@ -3,7 +3,7 @@ import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||
@ -16,6 +16,12 @@ import { FlowChallengeResponseRequest, RedirectChallenge } from "@goauthentik/ap
|
||||
|
||||
@customElement("ak-stage-redirect")
|
||||
export class RedirectStage extends BaseStage<RedirectChallenge, FlowChallengeResponseRequest> {
|
||||
@property({ type: Boolean })
|
||||
promptUser = false;
|
||||
|
||||
@state()
|
||||
startedRedirect = false;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
PFBase,
|
||||
@ -39,12 +45,46 @@ export class RedirectStage extends BaseStage<RedirectChallenge, FlowChallengeRes
|
||||
return this.challenge.to;
|
||||
}
|
||||
|
||||
firstUpdated(): void {
|
||||
if (this.promptUser) {
|
||||
return;
|
||||
}
|
||||
console.debug(
|
||||
"authentik/stages/redirect: redirecting to url from server",
|
||||
this.challenge.to,
|
||||
);
|
||||
window.location.assign(this.challenge.to);
|
||||
this.startedRedirect = true;
|
||||
}
|
||||
|
||||
renderLoading(): TemplateResult {
|
||||
const url = new URL(this.challenge.to);
|
||||
// If the protocol isn't http or https assume a custom protocol, that has an OS-level
|
||||
// handler, which the browser will show a popup for.
|
||||
// As this wouldn't really be a redirect, show a message that the page can be closed
|
||||
// and try to close it ourselves
|
||||
if (!url.protocol.startsWith("http")) {
|
||||
setTimeout(() => {
|
||||
window.close();
|
||||
}, 500);
|
||||
return html`<ak-empty-state
|
||||
icon="fas fa-check"
|
||||
header=${t`You may close this page now.`}
|
||||
>
|
||||
</ak-empty-state>`;
|
||||
}
|
||||
return html`<ak-empty-state ?loading=${true} header=${t`Loading`}> </ak-empty-state>`;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
if (this.startedRedirect || !this.promptUser) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
return html`<header class="pf-c-login__main-header">
|
||||
<h1 class="pf-c-title pf-m-3xl">${t`Redirect`}</h1>
|
||||
</header>
|
||||
<div class="pf-c-login__main-body">
|
||||
<form method="POST" class="pf-c-form">
|
||||
<form class="pf-c-form">
|
||||
<div class="pf-c-form__group">
|
||||
<p>${t`You're about to be redirect to the following URL.`}</p>
|
||||
<code>${this.renderURL()}</code>
|
||||
@ -54,6 +94,9 @@ export class RedirectStage extends BaseStage<RedirectChallenge, FlowChallengeRes
|
||||
type="submit"
|
||||
class="pf-c-button pf-m-primary pf-m-block"
|
||||
href=${this.challenge.to}
|
||||
@click=${() => {
|
||||
this.startedRedirect = true;
|
||||
}}
|
||||
>
|
||||
${t`Follow redirect`}
|
||||
</a>
|
||||
|
||||
@ -49,7 +49,9 @@ export class AuthenticatorDuoStage extends BaseStage<
|
||||
).stagesAuthenticatorDuoEnrollmentStatusCreate({
|
||||
stageUuid: this.challenge?.stageUuid || "",
|
||||
});
|
||||
console.debug(`authentik/flows/duo: Enrollment status: ${status.duoResponse}`);
|
||||
console.debug(
|
||||
`authentik/stages/authenticator_duo: Enrollment status: ${status.duoResponse}`,
|
||||
);
|
||||
switch (status.duoResponse) {
|
||||
case DuoResponseEnum.Success:
|
||||
this.host?.submit({});
|
||||
|
||||
Reference in New Issue
Block a user