From afa2afe1d4f945e631349ec3cca553d9eb69e6cd Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 24 Apr 2021 23:32:46 +0200 Subject: [PATCH 01/31] web/flows: include ShadyDOM, always enable ShadyDOM for flow interface improve compatibility with password managers and iOS Signed-off-by: Jens Langhammer --- authentik/core/templates/base/skeleton.html | 2 ++ authentik/core/templates/if/flow.html | 4 ++++ web/package-lock.json | 5 +++++ web/package.json | 1 + web/poly.ts | 2 ++ web/rollup.config.js | 4 +--- web/src/interfaces/flow/index.html | 1 + 7 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 web/poly.ts diff --git a/authentik/core/templates/base/skeleton.html b/authentik/core/templates/base/skeleton.html index 8e4e20ce5..125b531a3 100644 --- a/authentik/core/templates/base/skeleton.html +++ b/authentik/core/templates/base/skeleton.html @@ -15,6 +15,8 @@ + {% block head_before %} + {% endblock %} {% block head %} diff --git a/authentik/core/templates/if/flow.html b/authentik/core/templates/if/flow.html index 2156e8e9f..191be97ad 100644 --- a/authentik/core/templates/if/flow.html +++ b/authentik/core/templates/if/flow.html @@ -3,6 +3,10 @@ {% load static %} {% load i18n %} +{% block head_before %} + +{% endblock %} + {% block head %} {% endblock %} diff --git a/web/package-lock.json b/web/package-lock.json index 54017ddd0..410cbb9cc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2303,6 +2303,11 @@ "resolved": "https://registry.npmjs.org/@webcomponents/shadycss/-/shadycss-1.10.2.tgz", "integrity": "sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==" }, + "@webcomponents/webcomponentsjs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.5.0.tgz", + "integrity": "sha512-C0l51MWQZ9kLzcxOZtniOMohpIFdCLZum7/TEHv3XWFc1Fvt5HCpbSX84x8ltka/JuNKcuiDnxXFkiB2gaePcg==" + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", diff --git a/web/package.json b/web/package.json index f75c35cd8..79b59054c 100644 --- a/web/package.json +++ b/web/package.json @@ -57,6 +57,7 @@ "@types/grecaptcha": "^3.0.1", "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", + "@webcomponents/webcomponentsjs": "^2.5.0", "authentik-api": "file:api", "babel-plugin-macros": "^3.0.1", "base64-js": "^1.5.1", diff --git a/web/poly.ts b/web/poly.ts new file mode 100644 index 000000000..510032fcc --- /dev/null +++ b/web/poly.ts @@ -0,0 +1,2 @@ +import "construct-style-sheets-polyfill"; +import "@webcomponents/webcomponentsjs"; diff --git a/web/rollup.config.js b/web/rollup.config.js index c761f2bc9..001108d40 100644 --- a/web/rollup.config.js +++ b/web/rollup.config.js @@ -76,9 +76,7 @@ export default [ }, // Polyfills (imported first) { - input: [ - "construct-style-sheets-polyfill" - ], + input: "./poly.ts", output: [ { format: "iife", diff --git a/web/src/interfaces/flow/index.html b/web/src/interfaces/flow/index.html index 92121cbec..c990acb83 100644 --- a/web/src/interfaces/flow/index.html +++ b/web/src/interfaces/flow/index.html @@ -10,6 +10,7 @@ + From b2b9093c95c38f713144f33c93436f89b964903c Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 25 Apr 2021 01:29:01 +0200 Subject: [PATCH 02/31] web: don't enable ShadyDOM on selenium Signed-off-by: Jens Langhammer --- authentik/core/templates/if/flow.html | 2 +- web/src/interfaces/flow/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/authentik/core/templates/if/flow.html b/authentik/core/templates/if/flow.html index 191be97ad..e8fc13e1a 100644 --- a/authentik/core/templates/if/flow.html +++ b/authentik/core/templates/if/flow.html @@ -4,7 +4,7 @@ {% load i18n %} {% block head_before %} - + {% endblock %} {% block head %} diff --git a/web/src/interfaces/flow/index.html b/web/src/interfaces/flow/index.html index c990acb83..b03ab73b4 100644 --- a/web/src/interfaces/flow/index.html +++ b/web/src/interfaces/flow/index.html @@ -10,7 +10,7 @@ - + From 58712828a478a1d1bb1c4953049a587aafe386a4 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sun, 25 Apr 2021 18:50:19 +0200 Subject: [PATCH 03/31] web/flows/identification: fix phrasing account recovery Signed-off-by: Jens Langhammer --- web/src/elements/PageHeader.ts | 2 +- .../flows/stages/identification/IdentificationStage.ts | 1 - web/src/locales/en.po | 9 ++++----- web/src/locales/pseudo-LOCALE.po | 9 ++++----- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/web/src/elements/PageHeader.ts b/web/src/elements/PageHeader.ts index 7be03f728..e0aff235a 100644 --- a/web/src/elements/PageHeader.ts +++ b/web/src/elements/PageHeader.ts @@ -44,7 +44,7 @@ export class PageHeader extends LitElement { flex-direction: row; min-height: 114px; } - button.sidebar-trigger { + button.pf-c-button.pf-m-plain.sidebar-trigger { background-color: var(--pf-c-page__main-section--m-light--BackgroundColor); border-radius: 0px; } diff --git a/web/src/flows/stages/identification/IdentificationStage.ts b/web/src/flows/stages/identification/IdentificationStage.ts index c6fa5490c..c44511052 100644 --- a/web/src/flows/stages/identification/IdentificationStage.ts +++ b/web/src/flows/stages/identification/IdentificationStage.ts @@ -149,7 +149,6 @@ export class IdentificationStage extends BaseStage {

` : html``} ${this.challenge.recovery_url ? html` ` : html``} `; diff --git a/web/src/locales/en.po b/web/src/locales/en.po index aaa1f86a9..9825f5408 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -1079,7 +1079,7 @@ msgstr "Email" msgid "Email address" msgstr "Email address" -#: src/flows/stages/identification/IdentificationStage.ts:151 +#: src/flows/stages/identification/IdentificationStage.ts:150 msgid "Email or Username" msgstr "Email or Username" @@ -1382,7 +1382,7 @@ msgstr "Force the user to configure an authenticator" msgid "Forgot password?" msgstr "Forgot password?" -#: src/flows/stages/identification/IdentificationStage.ts:125 +#: src/flows/stages/identification/IdentificationStage.ts:124 msgid "Forgot username or password?" msgstr "Forgot username or password?" @@ -1677,7 +1677,7 @@ msgstr "Library" #: src/flows/stages/consent/ConsentStage.ts:28 #: src/flows/stages/dummy/DummyStage.ts:27 #: src/flows/stages/email/EmailStage.ts:26 -#: src/flows/stages/identification/IdentificationStage.ts:134 +#: src/flows/stages/identification/IdentificationStage.ts:133 #: src/flows/stages/password/PasswordStage.ts:31 #: src/flows/stages/prompt/PromptStage.ts:126 #: src/pages/applications/ApplicationViewPage.ts:43 @@ -1752,7 +1752,7 @@ msgstr "Log the currently pending user in." msgid "Login password is synced from LDAP into authentik automatically. Enable this option only to write password changes in authentik back to LDAP." msgstr "Login password is synced from LDAP into authentik automatically. Enable this option only to write password changes in authentik back to LDAP." -#: src/flows/stages/identification/IdentificationStage.ts:146 +#: src/flows/stages/identification/IdentificationStage.ts:145 msgid "Login to continue to {0}." msgstr "Login to continue to {0}." @@ -1930,7 +1930,6 @@ msgid "NameID Property Mapping" msgstr "NameID Property Mapping" #: src/flows/stages/identification/IdentificationStage.ts:119 -#: src/flows/stages/identification/IdentificationStage.ts:124 msgid "Need an account?" msgstr "Need an account?" diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index a346554c3..5ed3a220d 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -1071,7 +1071,7 @@ msgstr "" msgid "Email address" msgstr "" -#: src/flows/stages/identification/IdentificationStage.ts:151 +#: src/flows/stages/identification/IdentificationStage.ts:150 msgid "Email or Username" msgstr "" @@ -1374,7 +1374,7 @@ msgstr "" msgid "Forgot password?" msgstr "" -#: src/flows/stages/identification/IdentificationStage.ts:125 +#: src/flows/stages/identification/IdentificationStage.ts:124 msgid "Forgot username or password?" msgstr "" @@ -1669,7 +1669,7 @@ msgstr "" #: src/flows/stages/consent/ConsentStage.ts:28 #: src/flows/stages/dummy/DummyStage.ts:27 #: src/flows/stages/email/EmailStage.ts:26 -#: src/flows/stages/identification/IdentificationStage.ts:134 +#: src/flows/stages/identification/IdentificationStage.ts:133 #: src/flows/stages/password/PasswordStage.ts:31 #: src/flows/stages/prompt/PromptStage.ts:126 #: src/pages/applications/ApplicationViewPage.ts:43 @@ -1744,7 +1744,7 @@ msgstr "" msgid "Login password is synced from LDAP into authentik automatically. Enable this option only to write password changes in authentik back to LDAP." msgstr "" -#: src/flows/stages/identification/IdentificationStage.ts:146 +#: src/flows/stages/identification/IdentificationStage.ts:145 msgid "Login to continue to {0}." msgstr "" @@ -1922,7 +1922,6 @@ msgid "NameID Property Mapping" msgstr "" #: src/flows/stages/identification/IdentificationStage.ts:119 -#: src/flows/stages/identification/IdentificationStage.ts:124 msgid "Need an account?" msgstr "" From 50f0c11c0bdb4ccfddfd956ceab82fe331cad1d9 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 26 Apr 2021 17:45:09 +0200 Subject: [PATCH 04/31] web/flows: fix redirect loop when sentry is enabled Signed-off-by: Jens Langhammer --- web/src/api/Sentry.ts | 4 ++-- web/src/elements/sidebar/SidebarBrand.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/api/Sentry.ts b/web/src/api/Sentry.ts index ef7f9f2e4..e012bfd05 100644 --- a/web/src/api/Sentry.ts +++ b/web/src/api/Sentry.ts @@ -6,7 +6,7 @@ import { me } from "./Users"; import { config } from "./Config"; import { Config } from "authentik-api"; -export function configureSentry(): Promise { +export function configureSentry(canDoPpi: boolean = false): Promise { return config().then((config) => { if (config.errorReportingEnabled) { Sentry.init({ @@ -47,7 +47,7 @@ export function configureSentry(): Promise { }, }); console.debug("authentik/config: Sentry enabled."); - if (config.errorReportingSendPii) { + if (config.errorReportingSendPii && canDoPpi) { me().then(user => { Sentry.setUser({ email: user.user.email }); console.debug("authentik/config: Sentry with PII enabled."); diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index 63f8a2d6e..69873309d 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -41,7 +41,7 @@ export class SidebarBrand extends LitElement { } firstUpdated(): void { - configureSentry().then((c) => {this.config = c;}); + configureSentry(true).then((c) => {this.config = c;}); } render(): TemplateResult { From 378402fcf0eb430477be27c7f80d4db676568eb5 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 14:52:42 +0200 Subject: [PATCH 05/31] stages/user_login: add tests for explicit session length Signed-off-by: Jens Langhammer --- authentik/stages/user_login/tests.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/authentik/stages/user_login/tests.py b/authentik/stages/user_login/tests.py index 98da7ab45..33c921e17 100644 --- a/authentik/stages/user_login/tests.py +++ b/authentik/stages/user_login/tests.py @@ -1,4 +1,5 @@ """login tests""" +from time import sleep from unittest.mock import patch from django.test import Client, TestCase @@ -51,6 +52,31 @@ class TestUserLoginStage(TestCase): {"to": reverse("authentik_core:root-redirect"), "type": "redirect"}, ) + def test_expiry(self): + """Test with expiry""" + self.stage.session_duration = "seconds=2" + self.stage.save() + plan = FlowPlan( + flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] + ) + plan.context[PLAN_CONTEXT_PENDING_USER] = self.user + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + response = self.client.get( + reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}) + ) + self.assertEqual(response.status_code, 200) + self.assertJSONEqual( + force_str(response.content), + {"to": reverse("authentik_core:root-redirect"), "type": "redirect"}, + ) + self.assertNotEqual(list(self.client.session.keys()), []) + sleep(3) + self.client.session.clear_expired() + self.assertEqual(list(self.client.session.keys()), []) + @patch( "authentik.flows.views.to_stage_response", TO_STAGE_RESPONSE_MOCK, From ed49d7824e62df58e7b446afe2275b2f49bcc739 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 15:20:09 +0200 Subject: [PATCH 06/31] stages/email: catch ValueError when global email settings are invalid Signed-off-by: Jens Langhammer --- authentik/stages/email/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentik/stages/email/tasks.py b/authentik/stages/email/tasks.py index 38fafdeeb..462f3dae6 100644 --- a/authentik/stages/email/tasks.py +++ b/authentik/stages/email/tasks.py @@ -68,7 +68,7 @@ def send_mail( messages=["Successfully sent Mail."], ) ) - except (SMTPException, ConnectionError) as exc: + except (SMTPException, ConnectionError, ValueError) as exc: LOGGER.debug("Error sending email, retrying...", exc=exc) self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc)) raise exc From 1af3357826a1ca3e0ef4d999fffdc7e6b097931a Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 15:43:26 +0200 Subject: [PATCH 07/31] *: make logger not use .error Signed-off-by: Jens Langhammer --- authentik/flows/transfer/importer.py | 4 ++-- authentik/outposts/models.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/authentik/flows/transfer/importer.py b/authentik/flows/transfer/importer.py index 04ed65220..5c9fde10e 100644 --- a/authentik/flows/transfer/importer.py +++ b/authentik/flows/transfer/importer.py @@ -160,7 +160,7 @@ class FlowImporter: try: model: SerializerModel = apps.get_model(model_app_label, model_name) except LookupError: - self.logger.error( + self.logger.warning( "app or model does not exist", app=model_app_label, model=model_name ) return False @@ -168,7 +168,7 @@ class FlowImporter: try: serializer = self._validate_single(entry) except EntryInvalidError as exc: - self.logger.error("entry not valid", entry=entry, error=exc) + self.logger.warning("entry not valid", entry=entry, error=exc) return False model = serializer.save() diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index 33e653d5e..d8e75cdf4 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -201,7 +201,7 @@ class DockerServiceConnection(OutpostServiceConnection): ) client.containers.list() except DockerException as exc: - LOGGER.error(exc) + LOGGER.warning(exc) raise ServiceConnectionInvalid from exc return client From d82c01aa610e3a17c97d7a6f344a31e6e02f85e7 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 15:43:40 +0200 Subject: [PATCH 08/31] web/admin: don't show docker certs as required Signed-off-by: Jens Langhammer --- web/src/pages/outposts/ServiceConnectionDockerForm.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/src/pages/outposts/ServiceConnectionDockerForm.ts b/web/src/pages/outposts/ServiceConnectionDockerForm.ts index 584dd4513..db8ceafa8 100644 --- a/web/src/pages/outposts/ServiceConnectionDockerForm.ts +++ b/web/src/pages/outposts/ServiceConnectionDockerForm.ts @@ -70,7 +70,6 @@ export class ServiceConnectionDockerForm extends Form { From 580e88c6fc37124073e849902656339d9194eead Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 15:54:57 +0200 Subject: [PATCH 09/31] web: ignore network errors for sentry Signed-off-by: Jens Langhammer --- web/src/api/Sentry.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/src/api/Sentry.ts b/web/src/api/Sentry.ts index e012bfd05..7f0f39847 100644 --- a/web/src/api/Sentry.ts +++ b/web/src/api/Sentry.ts @@ -23,6 +23,11 @@ export function configureSentry(canDoPpi: boolean = false): Promise { if (hint.originalException instanceof SentryIgnoredError) { return null; } + if (hint.originalException instanceof Error) { + if (hint.originalException.name == 'NetworkError') { + return null; + } + } if (hint.originalException instanceof Response) { const response = hint.originalException as Response; // We only care about server errors From 2a9feafb903a364bdc15b057162e4d27d84cd1ff Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Tue, 27 Apr 2021 16:21:44 +0200 Subject: [PATCH 10/31] root: add middleware to properly report websocket connection to sentry Signed-off-by: Jens Langhammer --- authentik/lib/sentry.py | 17 +++++++++++++++++ authentik/root/websocket.py | 7 +++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/authentik/lib/sentry.py b/authentik/lib/sentry.py index df3704ba9..27c5bd020 100644 --- a/authentik/lib/sentry.py +++ b/authentik/lib/sentry.py @@ -5,6 +5,7 @@ from aioredis.errors import ConnectionClosedError, ReplyError from billiard.exceptions import WorkerLostError from botocore.client import ClientError from celery.exceptions import CeleryError +from channels.middleware import BaseMiddleware from channels_redis.core import ChannelFull from django.core.exceptions import SuspiciousOperation, ValidationError from django.db import InternalError, OperationalError, ProgrammingError @@ -14,12 +15,28 @@ from ldap3.core.exceptions import LDAPException from redis.exceptions import ConnectionError as RedisConnectionError from redis.exceptions import RedisError, ResponseError from rest_framework.exceptions import APIException +from sentry_sdk import Hub +from sentry_sdk.tracing import Transaction from structlog.stdlib import get_logger from websockets.exceptions import WebSocketException +from authentik.lib.utils.reflection import class_to_path + LOGGER = get_logger() +class SentryWSMiddleware(BaseMiddleware): + """Sentry Websocket middleweare to set the transaction name based on + consumer class path""" + + async def __call__(self, scope, receive, send): + transaction: Optional[Transaction] = Hub.current.scope.transaction + class_path = class_to_path(self.inner.consumer_class) + if transaction: + transaction.name = class_path + return await self.inner(scope, receive, send) + + class SentryIgnoredException(Exception): """Base Class for all errors that are suppressed, and not sent to sentry.""" diff --git a/authentik/root/websocket.py b/authentik/root/websocket.py index d53b52a12..398b47f62 100644 --- a/authentik/root/websocket.py +++ b/authentik/root/websocket.py @@ -2,10 +2,13 @@ from channels.auth import AuthMiddlewareStack from django.urls import path +from authentik.lib.sentry import SentryWSMiddleware from authentik.outposts.channels import OutpostConsumer from authentik.root.messages.consumer import MessageConsumer websocket_urlpatterns = [ - path("ws/outpost//", OutpostConsumer.as_asgi()), - path("ws/client/", AuthMiddlewareStack(MessageConsumer.as_asgi())), + path("ws/outpost//", SentryWSMiddleware(OutpostConsumer.as_asgi())), + path( + "ws/client/", AuthMiddlewareStack(SentryWSMiddleware(MessageConsumer.as_asgi())) + ), ] From 3dcd67c1a3d1f9d325c54185daf88de185e230f4 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 28 Apr 2021 18:32:16 +0200 Subject: [PATCH 11/31] outposts: only kill docker container if its running Signed-off-by: Jens Langhammer --- authentik/outposts/controllers/docker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/authentik/outposts/controllers/docker.py b/authentik/outposts/controllers/docker.py index d87b99656..0d7ea5630 100644 --- a/authentik/outposts/controllers/docker.py +++ b/authentik/outposts/controllers/docker.py @@ -134,7 +134,8 @@ class DockerController(BaseController): def down(self): try: container, _ = self._get_container() - container.kill() + if container.status == "running": + container.kill() container.remove() except DockerException as exc: raise ControllerException from exc From 8b3923200d3135cc09bc80584bc882c82999136b Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 28 Apr 2021 21:55:01 +0200 Subject: [PATCH 12/31] web: fix text-colour for form help text Signed-off-by: Jens Langhammer --- web/src/authentik.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/src/authentik.css b/web/src/authentik.css index b7b34e288..b6b2cbab0 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -100,6 +100,9 @@ body { .ak-initial-load h1 { color: var(--ak-dark-foreground); } +.form-help-text { + color: var(--pf-global--Color--100); +} @media (prefers-color-scheme: dark) { :root { @@ -239,6 +242,9 @@ body { .pf-c-check__label { color: var(--ak-dark-foreground); } + .form-help-text { + color: var(--ak-dark-foreground); + } /* inputs help text */ .pf-c-form__helper-text:not(.pf-m-error) { color: var(--ak-dark-foreground); From 07b9923bf67fd399777d983113ff94f977546c0c Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 28 Apr 2021 22:13:54 +0200 Subject: [PATCH 13/31] stages/invitation: fix token not being loaded correctly Signed-off-by: Jens Langhammer --- authentik/stages/invitation/stage.py | 5 +++-- authentik/stages/invitation/tests.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/authentik/stages/invitation/stage.py b/authentik/stages/invitation/stage.py index 77292d2eb..228be9699 100644 --- a/authentik/stages/invitation/stage.py +++ b/authentik/stages/invitation/stage.py @@ -3,6 +3,7 @@ from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404 from authentik.flows.stage import StageView +from authentik.flows.views import SESSION_KEY_GET from authentik.stages.invitation.models import Invitation, InvitationStage from authentik.stages.invitation.signals import invitation_used from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT @@ -17,13 +18,13 @@ class InvitationStageView(StageView): def get(self, request: HttpRequest) -> HttpResponse: """Apply data to the current flow based on a URL""" stage: InvitationStage = self.executor.current_stage - if INVITATION_TOKEN_KEY not in request.GET: + if INVITATION_TOKEN_KEY not in request.session.get(SESSION_KEY_GET, {}): # No Invitation was given, raise error or continue if stage.continue_flow_without_invitation: return self.executor.stage_ok() return self.executor.stage_invalid() - token = request.GET[INVITATION_TOKEN_KEY] + token = request.session[SESSION_KEY_GET][INVITATION_TOKEN_KEY] invite: Invitation = get_object_or_404(Invitation, pk=token) self.executor.plan.context[PLAN_CONTEXT_PROMPT] = invite.fixed_data self.executor.plan.context[INVITATION_IN_EFFECT] = True diff --git a/authentik/stages/invitation/tests.py b/authentik/stages/invitation/tests.py index 4dec9d12e..8394ab351 100644 --- a/authentik/stages/invitation/tests.py +++ b/authentik/stages/invitation/tests.py @@ -4,6 +4,7 @@ from unittest.mock import MagicMock, patch from django.test import Client, TestCase from django.urls import reverse from django.utils.encoding import force_str +from django.utils.http import urlencode from guardian.shortcuts import get_anonymous_user from rest_framework.test import APITestCase @@ -116,9 +117,8 @@ class TestUserLoginStage(TestCase): base_url = reverse( "authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug} ) - response = self.client.get( - base_url + f"?{INVITATION_TOKEN_KEY}={invite.pk.hex}" - ) + args = urlencode({INVITATION_TOKEN_KEY: invite.pk.hex}) + response = self.client.get(base_url + f"?query={args}") session = self.client.session plan: FlowPlan = session[SESSION_KEY_PLAN] From 2c70301f5676a993502f43d9132d453d76c77304 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 28 Apr 2021 22:20:54 +0200 Subject: [PATCH 14/31] stages/invitation: accept token from prompt_data Signed-off-by: Jens Langhammer --- authentik/stages/invitation/stage.py | 16 ++++++++++-- authentik/stages/invitation/tests.py | 37 ++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/authentik/stages/invitation/stage.py b/authentik/stages/invitation/stage.py index 228be9699..6ce02d2e3 100644 --- a/authentik/stages/invitation/stage.py +++ b/authentik/stages/invitation/stage.py @@ -1,4 +1,6 @@ """invitation stage logic""" +from typing import Optional + from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404 @@ -15,16 +17,26 @@ INVITATION_IN_EFFECT = "invitation_in_effect" class InvitationStageView(StageView): """Finalise Authentication flow by logging the user in""" + def get_token(self) -> Optional[str]: + """Get token from saved get-arguments or prompt_data""" + if INVITATION_TOKEN_KEY in self.request.session.get(SESSION_KEY_GET, {}): + return self.request.session[SESSION_KEY_GET][INVITATION_TOKEN_KEY] + if INVITATION_TOKEN_KEY in self.executor.plan.context.get( + PLAN_CONTEXT_PROMPT, {} + ): + return self.executor.plan.context[PLAN_CONTEXT_PROMPT][INVITATION_TOKEN_KEY] + return None + def get(self, request: HttpRequest) -> HttpResponse: """Apply data to the current flow based on a URL""" stage: InvitationStage = self.executor.current_stage - if INVITATION_TOKEN_KEY not in request.session.get(SESSION_KEY_GET, {}): + token = self.get_token() + if not token: # No Invitation was given, raise error or continue if stage.continue_flow_without_invitation: return self.executor.stage_ok() return self.executor.stage_invalid() - token = request.session[SESSION_KEY_GET][INVITATION_TOKEN_KEY] invite: Invitation = get_object_or_404(Invitation, pk=token) self.executor.plan.context[PLAN_CONTEXT_PROMPT] = invite.fixed_data self.executor.plan.context[INVITATION_IN_EFFECT] = True diff --git a/authentik/stages/invitation/tests.py b/authentik/stages/invitation/tests.py index 8394ab351..b556dab81 100644 --- a/authentik/stages/invitation/tests.py +++ b/authentik/stages/invitation/tests.py @@ -95,15 +95,11 @@ class TestUserLoginStage(TestCase): self.stage.continue_flow_without_invitation = False self.stage.save() - def test_with_invitation(self): + def test_with_invitation_get(self): """Test with invitation, check data in session""" plan = FlowPlan( flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] ) - plan.context[PLAN_CONTEXT_PENDING_USER] = self.user - plan.context[ - PLAN_CONTEXT_AUTHENTICATION_BACKEND - ] = "django.contrib.auth.backends.ModelBackend" session = self.client.session session[SESSION_KEY_PLAN] = plan session.save() @@ -130,6 +126,37 @@ class TestUserLoginStage(TestCase): {"to": reverse("authentik_core:root-redirect"), "type": "redirect"}, ) + def test_with_invitation_prompt_data(self): + """Test with invitation, check data in session""" + data = {"foo": "bar"} + invite = Invitation.objects.create( + created_by=get_anonymous_user(), fixed_data=data + ) + + plan = FlowPlan( + flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] + ) + plan.context[PLAN_CONTEXT_PROMPT] = {INVITATION_TOKEN_KEY: invite.pk.hex} + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + with patch("authentik.flows.views.FlowExecutorView.cancel", MagicMock()): + base_url = reverse( + "authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug} + ) + response = self.client.get(base_url) + + session = self.client.session + plan: FlowPlan = session[SESSION_KEY_PLAN] + self.assertEqual(plan.context[PLAN_CONTEXT_PROMPT], data) + + self.assertEqual(response.status_code, 200) + self.assertJSONEqual( + force_str(response.content), + {"to": reverse("authentik_core:root-redirect"), "type": "redirect"}, + ) + class TestInvitationsAPI(APITestCase): """Test Invitations API""" From a6e528d20996f24c6133b4c78183b4948c187251 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 29 Apr 2021 15:17:10 +0200 Subject: [PATCH 15/31] core: fix text color of error pages not being white Signed-off-by: Jens Langhammer --- authentik/core/templates/error/generic.html | 2 +- authentik/core/templates/if/admin.html | 2 +- authentik/core/templates/if/flow.html | 2 +- web/src/authentik.css | 2 +- web/src/interfaces/admin/index.html | 2 +- web/src/interfaces/flow/index.html | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/authentik/core/templates/error/generic.html b/authentik/core/templates/error/generic.html index a6bf253e0..4868f79d8 100644 --- a/authentik/core/templates/error/generic.html +++ b/authentik/core/templates/error/generic.html @@ -12,7 +12,7 @@ {% endblock %} {% block body %} -
+
diff --git a/authentik/core/templates/if/admin.html b/authentik/core/templates/if/admin.html index fa53c20f8..34679b1ae 100644 --- a/authentik/core/templates/if/admin.html +++ b/authentik/core/templates/if/admin.html @@ -10,7 +10,7 @@ {% block body %} -
+
diff --git a/authentik/core/templates/if/flow.html b/authentik/core/templates/if/flow.html index e8fc13e1a..35682d601 100644 --- a/authentik/core/templates/if/flow.html +++ b/authentik/core/templates/if/flow.html @@ -14,7 +14,7 @@ {% block body %} -
+
diff --git a/web/src/authentik.css b/web/src/authentik.css index b6b2cbab0..afcebb269 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -97,7 +97,7 @@ html > form > input { body { background-color: var(--ak-dark-background) !important; } -.ak-initial-load h1 { +.ak-static-page h1 { color: var(--ak-dark-foreground); } .form-help-text { diff --git a/web/src/interfaces/admin/index.html b/web/src/interfaces/admin/index.html index ec00e630f..0d068d06e 100644 --- a/web/src/interfaces/admin/index.html +++ b/web/src/interfaces/admin/index.html @@ -18,7 +18,7 @@ -
+
diff --git a/web/src/interfaces/flow/index.html b/web/src/interfaces/flow/index.html index b03ab73b4..cba81f5d7 100644 --- a/web/src/interfaces/flow/index.html +++ b/web/src/interfaces/flow/index.html @@ -19,7 +19,7 @@ -
+
From d1d28722d2d380c753daa1fa98a747e17e1458f9 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 29 Apr 2021 15:25:54 +0200 Subject: [PATCH 16/31] lib: don't send 404 errors to sentry Signed-off-by: Jens Langhammer --- authentik/lib/sentry.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/authentik/lib/sentry.py b/authentik/lib/sentry.py index 27c5bd020..79a7b0d53 100644 --- a/authentik/lib/sentry.py +++ b/authentik/lib/sentry.py @@ -9,6 +9,7 @@ from channels.middleware import BaseMiddleware from channels_redis.core import ChannelFull from django.core.exceptions import SuspiciousOperation, ValidationError from django.db import InternalError, OperationalError, ProgrammingError +from django.http.response import Http404 from django_redis.exceptions import ConnectionInterrupted from docker.errors import DockerException from ldap3.core.exceptions import LDAPException @@ -78,6 +79,8 @@ def before_send(event: dict, hint: dict) -> Optional[dict]: LDAPException, # Docker errors DockerException, + # End-user errors + Http404, ) if "exc_info" in hint: _, exc_value, _ = hint["exc_info"] From 4e5eeacf0a5d141a2eabac653dc6da0a7398a831 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 29 Apr 2021 23:03:09 +0200 Subject: [PATCH 17/31] release: 2021.4.5 --- .bumpversion.cfg | 2 +- .github/workflows/release.yml | 14 +++++++------- authentik/__init__.py | 2 +- docker-compose.yml | 6 +++--- helm/Chart.yaml | 2 +- helm/README.md | 2 +- helm/values.yaml | 2 +- outpost/pkg/version.go | 2 +- web/nginx.conf | 2 +- web/src/constants.ts | 2 +- website/docs/installation/docker-compose.md | 2 +- website/docs/installation/kubernetes.md | 2 +- .../docs/outposts/manual-deploy-docker-compose.md | 2 +- website/docs/outposts/manual-deploy-kubernetes.md | 14 +++++++------- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f30d7888d..0fc6c7c25 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2021.4.4 +current_version = 2021.4.5 tag = True commit = True parse = (?P\d+)\.(?P\d+)\.(?P\d+)\-?(?P.*) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 393c72c93..60091cf01 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,11 +18,11 @@ jobs: - name: Building Docker Image run: docker build --no-cache - -t beryju/authentik:2021.4.4 + -t beryju/authentik:2021.4.5 -t beryju/authentik:latest -f Dockerfile . - name: Push Docker Container to Registry (versioned) - run: docker push beryju/authentik:2021.4.4 + run: docker push beryju/authentik:2021.4.5 - name: Push Docker Container to Registry (latest) run: docker push beryju/authentik:latest build-proxy: @@ -48,11 +48,11 @@ jobs: cd outpost/ docker build \ --no-cache \ - -t beryju/authentik-proxy:2021.4.4 \ + -t beryju/authentik-proxy:2021.4.5 \ -t beryju/authentik-proxy:latest \ -f proxy.Dockerfile . - name: Push Docker Container to Registry (versioned) - run: docker push beryju/authentik-proxy:2021.4.4 + run: docker push beryju/authentik-proxy:2021.4.5 - name: Push Docker Container to Registry (latest) run: docker push beryju/authentik-proxy:latest build-static: @@ -72,11 +72,11 @@ jobs: cd web/ docker build \ --no-cache \ - -t beryju/authentik-static:2021.4.4 \ + -t beryju/authentik-static:2021.4.5 \ -t beryju/authentik-static:latest \ -f Dockerfile . - name: Push Docker Container to Registry (versioned) - run: docker push beryju/authentik-static:2021.4.4 + run: docker push beryju/authentik-static:2021.4.5 - name: Push Docker Container to Registry (latest) run: docker push beryju/authentik-static:latest test-release: @@ -110,5 +110,5 @@ jobs: SENTRY_PROJECT: authentik SENTRY_URL: https://sentry.beryju.org with: - tagName: 2021.4.4 + tagName: 2021.4.5 environment: beryjuorg-prod diff --git a/authentik/__init__.py b/authentik/__init__.py index 3a291052b..e89c3acb0 100644 --- a/authentik/__init__.py +++ b/authentik/__init__.py @@ -1,3 +1,3 @@ """authentik""" -__version__ = "2021.4.4" +__version__ = "2021.4.5" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" diff --git a/docker-compose.yml b/docker-compose.yml index 932e03d2d..98e9bb9d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: networks: - internal server: - image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.4} + image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.5} restart: unless-stopped command: server environment: @@ -48,7 +48,7 @@ services: env_file: - .env worker: - image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.4} + image: ${AUTHENTIK_IMAGE:-beryju/authentik}:${AUTHENTIK_TAG:-2021.4.5} restart: unless-stopped command: worker networks: @@ -68,7 +68,7 @@ services: env_file: - .env static: - image: ${AUTHENTIK_IMAGE_STATIC:-beryju/authentik-static}:${AUTHENTIK_TAG:-2021.4.4} + image: ${AUTHENTIK_IMAGE_STATIC:-beryju/authentik-static}:${AUTHENTIK_TAG:-2021.4.5} restart: unless-stopped networks: - internal diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 8507e293d..a2de4e14b 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -4,7 +4,7 @@ name: authentik home: https://goauthentik.io sources: - https://github.com/goauthentik/authentik -version: "2021.4.4" +version: "2021.4.5" icon: https://raw.githubusercontent.com/goauthentik/authentik/master/web/icons/icon.svg dependencies: - name: postgresql diff --git a/helm/README.md b/helm/README.md index fbb2aadb2..ae28206a1 100644 --- a/helm/README.md +++ b/helm/README.md @@ -4,7 +4,7 @@ |-----------------------------------|-------------------------|-------------| | image.name | beryju/authentik | Image used to run the authentik server and worker | | image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) | -| image.tag | 2021.4.4 | Image tag | +| image.tag | 2021.4.5 | Image tag | | image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments | | serverReplicas | 1 | Replicas for the Server deployment | | workerReplicas | 1 | Replicas for the Worker deployment | diff --git a/helm/values.yaml b/helm/values.yaml index 640cd8d83..ed5a59af9 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -5,7 +5,7 @@ image: name: beryju/authentik name_static: beryju/authentik-static name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended - tag: 2021.4.4 + tag: 2021.4.5 pullPolicy: IfNotPresent serverReplicas: 1 diff --git a/outpost/pkg/version.go b/outpost/pkg/version.go index 11d1a3651..3745556ef 100644 --- a/outpost/pkg/version.go +++ b/outpost/pkg/version.go @@ -1,3 +1,3 @@ package pkg -const VERSION = "2021.4.4" +const VERSION = "2021.4.5" diff --git a/web/nginx.conf b/web/nginx.conf index 39292954a..13085576e 100644 --- a/web/nginx.conf +++ b/web/nginx.conf @@ -81,7 +81,7 @@ http { location /static/ { expires 31d; add_header Cache-Control "public, no-transform"; - add_header X-authentik-version "2021.4.4"; + add_header X-authentik-version "2021.4.5"; add_header Vary X-authentik-version; } diff --git a/web/src/constants.ts b/web/src/constants.ts index 09c5208e8..601bd2231 100644 --- a/web/src/constants.ts +++ b/web/src/constants.ts @@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success"; export const ERROR_CLASS = "pf-m-danger"; export const PROGRESS_CLASS = "pf-m-in-progress"; export const CURRENT_CLASS = "pf-m-current"; -export const VERSION = "2021.4.4"; +export const VERSION = "2021.4.5"; export const PAGE_SIZE = 20; export const EVENT_REFRESH = "ak-refresh"; export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle"; diff --git a/website/docs/installation/docker-compose.md b/website/docs/installation/docker-compose.md index 417aa28d2..da808ebfc 100644 --- a/website/docs/installation/docker-compose.md +++ b/website/docs/installation/docker-compose.md @@ -16,7 +16,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env` -To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.4.4 >> .env` +To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.4.5 >> .env` If this is a fresh authentik install run the following commands to generate a password: diff --git a/website/docs/installation/kubernetes.md b/website/docs/installation/kubernetes.md index 90ff4978a..5cf91db90 100644 --- a/website/docs/installation/kubernetes.md +++ b/website/docs/installation/kubernetes.md @@ -38,7 +38,7 @@ image: name: beryju/authentik name_static: beryju/authentik-static name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended - tag: 2021.4.4 + tag: 2021.4.5 serverReplicas: 1 workerReplicas: 1 diff --git a/website/docs/outposts/manual-deploy-docker-compose.md b/website/docs/outposts/manual-deploy-docker-compose.md index 00f413acd..e46401882 100644 --- a/website/docs/outposts/manual-deploy-docker-compose.md +++ b/website/docs/outposts/manual-deploy-docker-compose.md @@ -11,7 +11,7 @@ version: "3.5" services: authentik_proxy: - image: beryju/authentik-proxy:2021.4.4 + image: beryju/authentik-proxy:2021.4.5 ports: - 4180:4180 - 4443:4443 diff --git a/website/docs/outposts/manual-deploy-kubernetes.md b/website/docs/outposts/manual-deploy-kubernetes.md index aff3b2745..f265db3b3 100644 --- a/website/docs/outposts/manual-deploy-kubernetes.md +++ b/website/docs/outposts/manual-deploy-kubernetes.md @@ -14,7 +14,7 @@ metadata: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 name: authentik-outpost-api stringData: authentik_host: "__AUTHENTIK_URL__" @@ -29,7 +29,7 @@ metadata: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 name: authentik-outpost spec: ports: @@ -54,7 +54,7 @@ metadata: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 name: authentik-outpost spec: selector: @@ -62,14 +62,14 @@ spec: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 template: metadata: labels: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 spec: containers: - env: @@ -88,7 +88,7 @@ spec: secretKeyRef: key: authentik_host_insecure name: authentik-outpost-api - image: beryju/authentik-proxy:2021.4.4 + image: beryju/authentik-proxy:2021.4.5 name: proxy ports: - containerPort: 4180 @@ -110,7 +110,7 @@ metadata: app.kubernetes.io/instance: __OUTPOST_NAME__ app.kubernetes.io/managed-by: goauthentik.io app.kubernetes.io/name: authentik-proxy - app.kubernetes.io/version: 2021.4.4 + app.kubernetes.io/version: 2021.4.5 name: authentik-outpost spec: rules: From 34c45900c2b153404e0adfb8672357c1b808aa55 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 30 Apr 2021 01:07:37 +0200 Subject: [PATCH 18/31] stages/identification: allow selection of no user fields to only allow login via sources Signed-off-by: Jens Langhammer --- ...8_alter_identificationstage_user_fields.py | 27 +++++++++ authentik/stages/identification/models.py | 1 + authentik/stages/identification/stage.py | 8 +-- swagger.yaml | 1 - .../identification/IdentificationStage.ts | 60 ++++++++++++------- web/src/locales/en.po | 48 ++++++++------- web/src/locales/pseudo-LOCALE.po | 44 ++++++++------ .../identification/IdentificationStageForm.ts | 3 +- 8 files changed, 123 insertions(+), 69 deletions(-) create mode 100644 authentik/stages/identification/migrations/0008_alter_identificationstage_user_fields.py diff --git a/authentik/stages/identification/migrations/0008_alter_identificationstage_user_fields.py b/authentik/stages/identification/migrations/0008_alter_identificationstage_user_fields.py new file mode 100644 index 000000000..d9a810e2b --- /dev/null +++ b/authentik/stages/identification/migrations/0008_alter_identificationstage_user_fields.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2 on 2021-04-29 22:56 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_stages_identification", "0007_remove_identificationstage_template"), + ] + + operations = [ + migrations.AlterField( + model_name="identificationstage", + name="user_fields", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField( + choices=[("email", "E Mail"), ("username", "Username")], + max_length=100, + ), + blank=True, + help_text="Fields of the user object to match against. (Hold shift to select multiple options)", + size=None, + ), + ), + ] diff --git a/authentik/stages/identification/models.py b/authentik/stages/identification/models.py index c00f3e2b8..db7b78e3d 100644 --- a/authentik/stages/identification/models.py +++ b/authentik/stages/identification/models.py @@ -22,6 +22,7 @@ class IdentificationStage(Stage): user_fields = ArrayField( models.CharField(max_length=100, choices=UserFields.choices), + blank=True, help_text=_( ( "Fields of the user object to match against. " diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index fb56cc21b..8a1b677c6 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -7,7 +7,7 @@ from django.db.models import Q from django.http import HttpResponse from django.urls import reverse from django.utils.translation import gettext as _ -from rest_framework.fields import CharField +from rest_framework.fields import CharField, ListField from rest_framework.serializers import ValidationError from structlog.stdlib import get_logger @@ -28,7 +28,7 @@ LOGGER = get_logger() class IdentificationChallenge(Challenge): """Identification challenges with all UI elements""" - input_type = CharField() + user_fields = ListField(CharField(), allow_empty=True, allow_null=True) application_pre = CharField(required=False) enroll_url = CharField(required=False) @@ -83,11 +83,9 @@ class IdentificationStageView(ChallengeStageView): "type": ChallengeTypes.NATIVE.value, "component": "ak-stage-identification", "primary_action": _("Log in"), - "input_type": "text", + "user_fields": current_stage.user_fields, } ) - if current_stage.user_fields == [UserFields.E_MAIL]: - challenge.initial_data["input_type"] = "email" # If the user has been redirected to us whilst trying to access an # application, SESSION_KEY_APPLICATION_PRE is set in the session if SESSION_KEY_APPLICATION_PRE in self.request.session: diff --git a/swagger.yaml b/swagger.yaml index 0269141a2..b5ee65cab 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -17950,7 +17950,6 @@ definitions: IdentificationStage: required: - name - - user_fields type: object properties: pk: diff --git a/web/src/flows/stages/identification/IdentificationStage.ts b/web/src/flows/stages/identification/IdentificationStage.ts index c44511052..8dc3035a6 100644 --- a/web/src/flows/stages/identification/IdentificationStage.ts +++ b/web/src/flows/stages/identification/IdentificationStage.ts @@ -22,7 +22,7 @@ export const PasswordManagerPrefill: { export interface IdentificationChallenge extends Challenge { - input_type: string; + user_fields?: string[]; primary_action: string; sources?: UILoginButton[]; @@ -154,6 +154,43 @@ export class IdentificationStage extends BaseStage {
`; } + renderInput(): TemplateResult { + let label = ""; + let type = "text"; + if (!this.challenge?.user_fields) { + return html`

+ ${t`Select one of the sources below to login.`} +

`; + } + if (this.challenge?.user_fields === ["email"]) { + label = t`Email`; + type = "email"; + } else if (this.challenge?.user_fields === ["username"]) { + label = t`Username`; + } else { + label = t`Email or username`; + } + return html` + + + +
+ +
`; + } + render(): TemplateResult { if (!this.challenge) { return html``: html``} - - - - - -
- -
+ ${this.renderInput()}