diff --git a/authentik/stages/authenticator_validate/challenge.py b/authentik/stages/authenticator_validate/challenge.py index a8cf9b2b3..fabbddcd4 100644 --- a/authentik/stages/authenticator_validate/challenge.py +++ b/authentik/stages/authenticator_validate/challenge.py @@ -208,8 +208,7 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) -> stage=stage_view.executor.current_stage, device_class=DeviceClasses.DUO.value, ) - raise ValidationError("Duo denied access") - device.save() + raise ValidationError("Duo denied access", code="denied") return device except RuntimeError as exc: Event.new( @@ -217,4 +216,4 @@ def validate_challenge_duo(device_pk: int, stage_view: StageView, user: User) -> message=f"Failed to DUO authenticate user: {str(exc)}", user=user, ).from_http(stage_view.request, user) - raise ValidationError("Duo denied access") + raise ValidationError("Duo denied access", code="denied") diff --git a/authentik/stages/authenticator_validate/tests/test_duo.py b/authentik/stages/authenticator_validate/tests/test_duo.py index 4dfddaa52..6b779d6ce 100644 --- a/authentik/stages/authenticator_validate/tests/test_duo.py +++ b/authentik/stages/authenticator_validate/tests/test_duo.py @@ -73,7 +73,17 @@ class AuthenticatorValidateStageDuoTests(FlowTestCase): ) with patch( "authentik.stages.authenticator_duo.models.AuthenticatorDuoStage.auth_client", - MagicMock(return_value=MagicMock(auth=MagicMock(return_value={"result": "deny"}))), + MagicMock( + return_value=MagicMock( + auth=MagicMock( + return_value={ + "result": "deny", + "status": "deny", + "status_msg": "foo", + } + ) + ) + ), ): with self.assertRaises(ValidationError): validate_challenge_duo( diff --git a/web/src/flow/stages/access_denied/AccessDeniedStage.ts b/web/src/flow/stages/access_denied/AccessDeniedStage.ts index cb74205f8..c873a3a73 100644 --- a/web/src/flow/stages/access_denied/AccessDeniedStage.ts +++ b/web/src/flow/stages/access_denied/AccessDeniedStage.ts @@ -1,3 +1,4 @@ +import { AKElement } from "@goauthentik/elements/Base"; import "@goauthentik/elements/EmptyState"; import "@goauthentik/flow/FormStatic"; import { BaseStage } from "@goauthentik/flow/stages/base"; @@ -5,7 +6,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 } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import AKGlobal from "@goauthentik/common/styles/authentik.css"; @@ -18,18 +19,14 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { AccessDeniedChallenge, FlowChallengeResponseRequest } from "@goauthentik/api"; -@customElement("ak-stage-access-denied") -export class AccessDeniedStage extends BaseStage< - AccessDeniedChallenge, - FlowChallengeResponseRequest -> { +@customElement("ak-stage-access-denied-icon") +export class AccessDeniedIcon extends AKElement { + @property() + errorMessage?: string; + static get styles(): CSSResult[] { return [ PFBase, - PFLogin, - PFForm, - PFList, - PFFormControl, PFTitle, AKGlobal, css` @@ -50,6 +47,29 @@ export class AccessDeniedStage extends BaseStage< ]; } + render(): TemplateResult { + return html`
${this.errorMessage}
` + : html``} +${this.challenge.errorMessage}
`} -