web/sfe: downgrade bootstrap, add access denied test (#19763)

* web/sfe: downgrade bootstrap, add access denied test

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

* fix

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2026-01-26 16:14:12 +01:00
committed by GitHub
parent 03e16b3a14
commit cdd3fb7827
4 changed files with 84 additions and 33 deletions
+27
View File
@@ -8,6 +8,8 @@ from selenium.webdriver.remote.webdriver import WebDriver
from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import User
from authentik.flows.models import NotConfiguredAction
from authentik.stages.authenticator_validate.models import AuthenticatorValidateStage, DeviceClasses
from tests.e2e.utils import SeleniumTestCase, retry
@@ -50,3 +52,28 @@ class TestFlowsLoginSFE(SeleniumTestCase):
login_sfe(self.driver, self.user)
self.wait_for_url(self.if_user_url("/library"))
self.assert_user(self.user)
@retry()
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
"default/flow-default-invalidation-flow.yaml",
)
def test_login_mfa_static_deny(self):
"""test default login flow"""
mfa = AuthenticatorValidateStage.objects.get(
name="default-authentication-mfa-validation",
)
mfa.not_configured_action = NotConfiguredAction.DENY
mfa.device_classes = [DeviceClasses.STATIC]
mfa.save()
self.driver.get(
self.url(
"authentik_core:if-flow",
flow_slug="default-authentication-flow",
query={"sfe": True},
)
)
login_sfe(self.driver, self.user)
msg = self.driver.find_element(By.CSS_SELECTOR, "#access-denied > p")
self.assertEqual(msg.text, "No (allowed) MFA authenticator configured.")
+34 -31
View File
@@ -2636,17 +2636,6 @@
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
"license": "MIT"
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/plugin-commonjs": {
"version": "29.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz",
@@ -6119,25 +6108,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bootstrap": {
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
"integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
},
"node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
@@ -13707,6 +13677,18 @@
"points-on-curve": "0.2.0"
}
},
"node_modules/popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -17565,7 +17547,7 @@
"@swc/cli": "^0.7.10",
"@swc/core": "^1.15.10",
"base64-js": "^1.5.1",
"bootstrap": "^5.3.8",
"bootstrap": "^4.6.2",
"formdata-polyfill": "^2025.11.0",
"globby": "16.1.0",
"jquery": "^3.7.1",
@@ -17584,6 +17566,27 @@
"@swc/core-win32-ia32-msvc": "^1.15.3",
"@swc/core-win32-x64-msvc": "^1.15.3"
}
},
"packages/sfe/node_modules/bootstrap": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==",
"deprecated": "This version of Bootstrap is no longer supported. Please upgrade to the latest version.",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"jquery": "1.9.1 - 3",
"popper.js": "^1.16.1"
}
}
}
}
+1 -1
View File
@@ -22,7 +22,7 @@
"@swc/cli": "^0.7.10",
"@swc/core": "^1.15.10",
"base64-js": "^1.5.1",
"bootstrap": "^5.3.8",
"bootstrap": "^4.6.2",
"formdata-polyfill": "^2025.11.0",
"globby": "16.1.0",
"jquery": "^3.7.1",
+22 -1
View File
@@ -2,6 +2,7 @@ import "formdata-polyfill";
import "weakmap-polyfill";
import {
type AccessDeniedChallenge,
type AuthenticatorValidationChallenge,
type AutosubmitChallenge,
type ChallengeTypes,
@@ -113,8 +114,16 @@ class SimpleFlowExecutor {
case "ak-stage-authenticator-validate":
new AuthenticatorValidateStage(this, this.challenge).render();
return;
case "ak-stage-access-denied":
new AccessDeniedStage(this, this.challenge).render();
return;
default:
this.container.innerText = "Unsupported stage: " + this.challenge?.component;
new AccessDeniedStage(this, {
component: "ak-stage-access-denied",
errorMessage: "Unsupported stage: " + this.challenge?.component,
pendingUser: "",
pendingUserAvatar: "",
}).render();
return;
}
}
@@ -492,5 +501,17 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
}
}
class AccessDeniedStage extends Stage<AccessDeniedChallenge> {
render() {
this.html(`<form id="access-denied">
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
<h1 class="h3 mb-3 fw-normal text-center">${this.challenge?.flowInfo?.title}</h1>
<p>
${this.challenge.errorMessage ?? "Access denied."}
</p>
</form>`);
}
}
const sfe = new SimpleFlowExecutor($("#flow-sfe-container")[0] as HTMLDivElement);
sfe.start();