From 16b8edd0825eaea83bcdcb01cc81110fdb07ab2b Mon Sep 17 00:00:00 2001 From: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com> Date: Mon, 8 Apr 2024 09:30:40 -0700 Subject: [PATCH 1/8] web: fix application library list display length and capability (#9094) * web: fix esbuild issue with style sheets Getting ESBuild, Lit, and Storybook to all agree on how to read and parse stylesheets is a serious pain. This fix better identifies the value types (instances) being passed from various sources in the repo to the three *different* kinds of style processors we're using (the native one, the polyfill one, and whatever the heck Storybook does internally). Falling back to using older CSS instantiating techniques one era at a time seems to do the trick. It's ugly, but in the face of the aggressive styling we use to avoid Flashes of Unstyled Content (FLoUC), it's the logic with which we're left. In standard mode, the following warning appears on the console when running a Flow: ``` Autofocus processing was blocked because a document already has a focused element. ``` In compatibility mode, the following **error** appears on the console when running a Flow: ``` crawler-inject.js:1106 Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'. at initDomMutationObservers (crawler-inject.js:1106:18) at crawler-inject.js:1114:24 at Array.forEach () at initDomMutationObservers (crawler-inject.js:1114:10) at crawler-inject.js:1549:1 initDomMutationObservers @ crawler-inject.js:1106 (anonymous) @ crawler-inject.js:1114 initDomMutationObservers @ crawler-inject.js:1114 (anonymous) @ crawler-inject.js:1549 ``` Despite this error, nothing seems to be broken and flows work as anticipated. * web: fix application display length and capability The User Application Library only shows the top 100 applications. This patch strips what is passed out of the API fetch down to the bare minimum: the list of applications. No pagination, no search strings, none of the items returned by the API other than the application. It then fetches multiple pages of 100 until the user's Application list is exhausted, presenting the entire list to the user. The fetches are done simultaneously; a user with a thousand applications, if one should exist, would start 9 downloads in parallel. The first fetch analyzes the page count to determine how many *more* must be started, then starts them. This should make an interesting stress-test. Failures at the Django end are not well-handled, but then they have never been well-handled. At best, the page is blank and the browser console will contain a cryptic error message. That isn't fixed this time around, but it probably should be. This patch will have no effect until the [application pagination bug](https://github.com/goauthentik/authentik/issues/9093) is fixed. * Prettier has opinions. * attempt to fix backend pagination Signed-off-by: Jens Langhammer * make page_number optional Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Co-authored-by: Jens Langhammer --- authentik/core/api/applications.py | 19 +++++--- web/src/user/LibraryPage/LibraryPage.ts | 54 ++++++++++++++------- web/src/user/LibraryPage/LibraryPageImpl.ts | 11 ++--- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/authentik/core/api/applications.py b/authentik/core/api/applications.py index 413e7777a9..eddad64bf8 100644 --- a/authentik/core/api/applications.py +++ b/authentik/core/api/applications.py @@ -22,6 +22,7 @@ from rest_framework.viewsets import ModelViewSet from structlog.stdlib import get_logger from authentik.admin.api.metrics import CoordinateSerializer +from authentik.api.pagination import Pagination from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT from authentik.core.api.providers import ProviderSerializer from authentik.core.api.used_by import UsedByMixin @@ -43,9 +44,12 @@ from authentik.rbac.filters import ObjectFilter LOGGER = get_logger() -def user_app_cache_key(user_pk: str) -> str: +def user_app_cache_key(user_pk: str, page_number: int | None = None) -> str: """Cache key where application list for user is saved""" - return f"{CACHE_PREFIX}/app_access/{user_pk}" + key = f"{CACHE_PREFIX}/app_access/{user_pk}" + if page_number: + key += f"/{page_number}" + return key class ApplicationSerializer(ModelSerializer): @@ -213,7 +217,8 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet): return super().list(request) queryset = self._filter_queryset_for_list(self.get_queryset()) - paginated_apps = self.paginate_queryset(queryset) + paginator: Pagination = self.paginator + paginated_apps = paginator.paginate_queryset(queryset, request) if "for_user" in request.query_params: try: @@ -235,12 +240,14 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet): if not should_cache: allowed_applications = self._get_allowed_applications(paginated_apps) if should_cache: - allowed_applications = cache.get(user_app_cache_key(self.request.user.pk)) + allowed_applications = cache.get( + user_app_cache_key(self.request.user.pk, paginator.page.number) + ) if not allowed_applications: - LOGGER.debug("Caching allowed application list") + LOGGER.debug("Caching allowed application list", page=paginator.page.number) allowed_applications = self._get_allowed_applications(paginated_apps) cache.set( - user_app_cache_key(self.request.user.pk), + user_app_cache_key(self.request.user.pk, paginator.page.number), allowed_applications, timeout=86400, ) diff --git a/web/src/user/LibraryPage/LibraryPage.ts b/web/src/user/LibraryPage/LibraryPage.ts index cdd54f8f72..01ab26c718 100644 --- a/web/src/user/LibraryPage/LibraryPage.ts +++ b/web/src/user/LibraryPage/LibraryPage.ts @@ -2,7 +2,6 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { me } from "@goauthentik/common/users"; import { AKElement, rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/EmptyState"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; import { localized, msg } from "@lit/localize"; import { html } from "lit"; @@ -25,6 +24,8 @@ import type { PageUIConfig } from "./types"; * */ +const coreApi = () => new CoreApi(DEFAULT_CONFIG); + @localized() @customElement("ak-library") export class LibraryPage extends AKElement { @@ -35,15 +36,13 @@ export class LibraryPage extends AKElement { isAdmin = false; @state() - apps!: PaginatedResponse; + apps: Application[] = []; @state() uiConfig: PageUIConfig; constructor() { super(); - const applicationListFetch = new CoreApi(DEFAULT_CONFIG).coreApplicationsList({}); - const meFetch = me(); const uiConfig = rootInterface()?.uiConfig; if (!uiConfig) { throw new Error("Could not retrieve uiConfig. Reason: unknown. Check logs."); @@ -55,22 +54,41 @@ export class LibraryPage extends AKElement { searchEnabled: uiConfig.enabledFeatures.search, }; - Promise.allSettled([applicationListFetch, meFetch]).then( - ([applicationListStatus, meStatus]) => { - if (meStatus.status === "rejected") { - throw new Error( - `Could not determine status of user. Reason: ${meStatus.reason}`, - ); + Promise.all([this.fetchApplications(), me()]).then(([applications, meStatus]) => { + this.isAdmin = meStatus.user.isSuperuser; + this.apps = applications; + this.ready = true; + }); + } + + async fetchApplications(): Promise { + const applicationListParams = (page = 1) => ({ + ordering: "name", + page, + pageSize: 100, + }); + + const applicationListFetch = await coreApi().coreApplicationsList(applicationListParams(1)); + const pageCount = applicationListFetch.pagination.totalPages; + if (pageCount === 1) { + return applicationListFetch.results; + } + + const applicationLaterPages = await Promise.allSettled( + Array.from({ length: pageCount - 1 }).map((_a, idx) => + coreApi().coreApplicationsList(applicationListParams(idx + 2)), + ), + ); + + return applicationLaterPages.reduce( + function (acc, result) { + if (result.status === "rejected") { + const reason = JSON.stringify(result.reason, null, 2); + throw new Error(`Could not retrieve list of applications. Reason: ${reason}`); } - if (applicationListStatus.status === "rejected") { - throw new Error( - `Could not retrieve list of applications. Reason: ${applicationListStatus.reason}`, - ); - } - this.isAdmin = meStatus.value.user.isSuperuser; - this.apps = applicationListStatus.value; - this.ready = true; + return [...acc, ...result.value.results]; }, + [...applicationListFetch.results], ); } diff --git a/web/src/user/LibraryPage/LibraryPageImpl.ts b/web/src/user/LibraryPage/LibraryPageImpl.ts index 76d82793c1..1892e499f9 100644 --- a/web/src/user/LibraryPage/LibraryPageImpl.ts +++ b/web/src/user/LibraryPage/LibraryPageImpl.ts @@ -1,7 +1,6 @@ import { groupBy } from "@goauthentik/common/utils"; import { AKElement } from "@goauthentik/elements/Base"; import "@goauthentik/elements/EmptyState"; -import { PaginatedResponse } from "@goauthentik/elements/table/Table"; import "@goauthentik/user/LibraryApplication"; import { msg } from "@lit/localize"; @@ -42,8 +41,8 @@ export class LibraryPage extends AKElement { @property({ attribute: "isadmin", type: Boolean }) isAdmin = false; - @property({ attribute: false }) - apps!: PaginatedResponse; + @property({ attribute: false, type: Array }) + apps!: Application[]; @property({ attribute: false }) uiConfig!: PageUIConfig; @@ -66,7 +65,7 @@ export class LibraryPage extends AKElement { connectedCallback() { super.connectedCallback(); - this.filteredApps = this.apps?.results; + this.filteredApps = this.apps; if (this.filteredApps === undefined) { throw new Error( "Application.results should never be undefined when passed to the Library Page.", @@ -89,7 +88,7 @@ export class LibraryPage extends AKElement { event.stopPropagation(); const apps = event.detail.apps; this.selectedApp = undefined; - this.filteredApps = this.apps.results; + this.filteredApps = this.apps; if (apps.length > 0) { this.selectedApp = apps[0]; this.filteredApps = event.detail.apps; @@ -132,7 +131,7 @@ export class LibraryPage extends AKElement { } renderSearch() { - return html``; + return html``; } render() { From 2ec8a445c3010d0a60a109de4d03760b750ce359 Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 9 Apr 2024 01:42:36 +0200 Subject: [PATCH 2/8] events: add context manager to ignore/modify audit events being written (#9181) --- authentik/events/middleware.py | 39 +++++++++++++ authentik/events/tests/test_middleware.py | 57 ++++++++++++++++--- authentik/providers/oauth2/views/token.py | 34 ++++++----- .../authenticator_validate/challenge.py | 4 +- 4 files changed, 110 insertions(+), 24 deletions(-) diff --git a/authentik/events/middleware.py b/authentik/events/middleware.py index 2b4705f3a3..eec473202a 100644 --- a/authentik/events/middleware.py +++ b/authentik/events/middleware.py @@ -1,6 +1,8 @@ """Events middleware""" from collections.abc import Callable +from contextlib import contextmanager +from contextvars import ContextVar from functools import partial from threading import Thread from typing import Any @@ -31,6 +33,9 @@ IGNORED_MODELS = tuple( ) ) +_CTX_OVERWRITE_USER = ContextVar[User | None]("authentik_events_log_overwrite_user", default=None) +_CTX_IGNORE = ContextVar[bool]("authentik_events_log_ignore", default=False) + def should_log_model(model: Model) -> bool: """Return true if operation on `model` should be logged""" @@ -44,6 +49,28 @@ def should_log_m2m(model: Model) -> bool: return False +@contextmanager +def audit_overwrite_user(user: User): + """Overwrite user being logged for model AuditMiddleware. Commonly used + for example in flows where a pending user is given, but the request is not authenticated yet""" + _CTX_OVERWRITE_USER.set(user) + try: + yield + finally: + _CTX_OVERWRITE_USER.set(None) + + +@contextmanager +def audit_ignore(): + """Ignore model operations in the block. Useful for objects which need to be modified + but are not excluded (e.g. WebAuthn devices)""" + _CTX_IGNORE.set(True) + try: + yield + finally: + _CTX_IGNORE.set(False) + + class EventNewThread(Thread): """Create Event in background thread""" @@ -158,6 +185,10 @@ class AuditMiddleware: """Signal handler for all object's post_save""" if not should_log_model(instance): return + if _CTX_IGNORE.get(): + return + if _new_user := _CTX_OVERWRITE_USER.get(): + user = _new_user action = EventAction.MODEL_CREATED if created else EventAction.MODEL_UPDATED thread = EventNewThread(action, request, user=user, model=model_to_dict(instance)) @@ -168,6 +199,10 @@ class AuditMiddleware: """Signal handler for all object's pre_delete""" if not should_log_model(instance): # pragma: no cover return + if _CTX_IGNORE.get(): + return + if _new_user := _CTX_OVERWRITE_USER.get(): + user = _new_user EventNewThread( EventAction.MODEL_DELETED, @@ -184,6 +219,10 @@ class AuditMiddleware: return if not should_log_m2m(instance): return + if _CTX_IGNORE.get(): + return + if _new_user := _CTX_OVERWRITE_USER.get(): + user = _new_user EventNewThread( EventAction.MODEL_UPDATED, diff --git a/authentik/events/tests/test_middleware.py b/authentik/events/tests/test_middleware.py index 1bd667d06e..906deb030d 100644 --- a/authentik/events/tests/test_middleware.py +++ b/authentik/events/tests/test_middleware.py @@ -5,7 +5,9 @@ from rest_framework.test import APITestCase from authentik.core.models import Application from authentik.core.tests.utils import create_test_admin_user +from authentik.events.middleware import audit_ignore, audit_overwrite_user from authentik.events.models import Event, EventAction +from authentik.lib.generators import generate_id class TestEventsMiddleware(APITestCase): @@ -15,35 +17,74 @@ class TestEventsMiddleware(APITestCase): super().setUp() self.user = create_test_admin_user() self.client.force_login(self.user) + Event.objects.all().delete() def test_create(self): """Test model creation event""" + uid = generate_id() self.client.post( reverse("authentik_api:application-list"), - data={"name": "test-create", "slug": "test-create"}, + data={"name": uid, "slug": uid}, ) - self.assertTrue(Application.objects.filter(name="test-create").exists()) + self.assertTrue(Application.objects.filter(name=uid).exists()) self.assertTrue( Event.objects.filter( action=EventAction.MODEL_CREATED, context__model__model_name="application", context__model__app="authentik_core", - context__model__name="test-create", + context__model__name=uid, ).exists() ) def test_delete(self): """Test model creation event""" - Application.objects.create(name="test-delete", slug="test-delete") - self.client.delete( - reverse("authentik_api:application-detail", kwargs={"slug": "test-delete"}) - ) + uid = generate_id() + Application.objects.create(name=uid, slug=uid) + self.client.delete(reverse("authentik_api:application-detail", kwargs={"slug": uid})) self.assertFalse(Application.objects.filter(name="test").exists()) self.assertTrue( Event.objects.filter( action=EventAction.MODEL_DELETED, context__model__model_name="application", context__model__app="authentik_core", - context__model__name="test-delete", + context__model__name=uid, + ).exists() + ) + + def test_audit_ignore(self): + """Test audit_ignore context manager""" + uid = generate_id() + with audit_ignore(): + self.client.post( + reverse("authentik_api:application-list"), + data={"name": uid, "slug": uid}, + ) + self.assertTrue(Application.objects.filter(name=uid).exists()) + self.assertFalse( + Event.objects.filter( + action=EventAction.MODEL_CREATED, + context__model__model_name="application", + context__model__app="authentik_core", + context__model__name=uid, + ).exists() + ) + + def test_audit_overwrite_user(self): + """Test audit_overwrite_user context manager""" + uid = generate_id() + new_user = create_test_admin_user() + with audit_overwrite_user(new_user): + self.client.post( + reverse("authentik_api:application-list"), + data={"name": uid, "slug": uid}, + ) + self.assertTrue(Application.objects.filter(name=uid).exists()) + self.assertTrue( + Event.objects.filter( + action=EventAction.MODEL_CREATED, + context__model__model_name="application", + context__model__app="authentik_core", + context__model__name=uid, + user__username=new_user.username, ).exists() ) diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index 464df72636..ce535f9905 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -31,6 +31,7 @@ from authentik.core.models import ( User, UserTypes, ) +from authentik.events.middleware import audit_ignore from authentik.events.models import Event, EventAction from authentik.events.signals import get_login_event from authentik.flows.planner import PLAN_CONTEXT_APPLICATION @@ -465,22 +466,25 @@ class TokenParams: def __create_user_from_jwt(self, token: dict[str, Any], app: Application, source: OAuthSource): """Create user from JWT""" - self.user, created = User.objects.update_or_create( - username=f"{self.provider.name}-{token.get('sub')}", - defaults={ - "attributes": { - USER_ATTRIBUTE_GENERATED: True, + with audit_ignore(): + self.user, created = User.objects.update_or_create( + username=f"{self.provider.name}-{token.get('sub')}", + defaults={ + "attributes": { + USER_ATTRIBUTE_GENERATED: True, + }, + "last_login": timezone.now(), + "name": ( + f"Autogenerated user from application {app.name} (client credentials JWT)" + ), + "path": source.get_user_path(), + "type": UserTypes.SERVICE_ACCOUNT, }, - "last_login": timezone.now(), - "name": f"Autogenerated user from application {app.name} (client credentials JWT)", - "path": source.get_user_path(), - "type": UserTypes.SERVICE_ACCOUNT, - }, - ) - exp = token.get("exp") - if created and exp: - self.user.attributes[USER_ATTRIBUTE_EXPIRES] = exp - self.user.save() + ) + exp = token.get("exp") + if created and exp: + self.user.attributes[USER_ATTRIBUTE_EXPIRES] = exp + self.user.save() @method_decorator(csrf_exempt, name="dispatch") diff --git a/authentik/stages/authenticator_validate/challenge.py b/authentik/stages/authenticator_validate/challenge.py index 38c7bb28ae..60a6786c52 100644 --- a/authentik/stages/authenticator_validate/challenge.py +++ b/authentik/stages/authenticator_validate/challenge.py @@ -21,6 +21,7 @@ from webauthn.helpers.structs import UserVerificationRequirement from authentik.core.api.utils import JSONDictField, PassiveSerializer from authentik.core.models import Application, User from authentik.core.signals import login_failed +from authentik.events.middleware import audit_ignore from authentik.events.models import Event, EventAction from authentik.flows.stage import StageView from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE @@ -167,7 +168,8 @@ def validate_challenge_webauthn(data: dict, stage_view: StageView, user: User) - ) raise ValidationError("Assertion failed") from exc - device.set_sign_count(authentication_verification.new_sign_count) + with audit_ignore(): + device.set_sign_count(authentication_verification.new_sign_count) return device From 284904a02a85f7d4e0804c1fcf1c27b07d724f6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:47:46 +0200 Subject: [PATCH 3/8] core: bump maxmind/geoipupdate from v6.1 to v7.0 (#9186) Bumps maxmind/geoipupdate from v6.1 to v7.0. --- updated-dependencies: - dependency-name: maxmind/geoipupdate dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d00c03b90f..eaf287b807 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,7 +70,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \ GOARM="${TARGETVARIANT#v}" go build -o /go/authentik ./cmd/server # Stage 4: MaxMind GeoIP -FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.1 as geoip +FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.0 as geoip ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN" ENV GEOIPUPDATE_VERBOSE="true" From 728b64ffc3030d725c63c9900e49ac78449acaa2 Mon Sep 17 00:00:00 2001 From: pgumpoldsberger <60177408+pgumpoldsberger@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:46:30 +0200 Subject: [PATCH 4/8] website/docs: update Postgresql username (#9190) Update Username Signed-off-by: pgumpoldsberger <60177408+pgumpoldsberger@users.noreply.github.com> --- website/docs/troubleshooting/postgres/upgrade_kubernetes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/troubleshooting/postgres/upgrade_kubernetes.md b/website/docs/troubleshooting/postgres/upgrade_kubernetes.md index 5aac942357..be47140813 100644 --- a/website/docs/troubleshooting/postgres/upgrade_kubernetes.md +++ b/website/docs/troubleshooting/postgres/upgrade_kubernetes.md @@ -27,7 +27,7 @@ cd /bitnami/postgresql/ # Set the postgres password based on the `POSTGRES_POSTGRES_PASSWORD` environment variable export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD # Dump the authentik database into an sql file -pg_dump -U postgres $POSTGRES_DB > dump-11.sql +pg_dump -U $POSTGRES_USER $POSTGRES_DB > dump-11.sql ``` ### Stop PostgreSQL and start the upgrade @@ -88,7 +88,7 @@ Run the following commands to restore the data: cd /bitnami/postgresql/ # Set the Postgres password based on the `POSTGRES_POSTGRES_PASSWORD` environment variable. export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD -psql -U postgres $POSTGRES_DB < dump-11.sql +psql -U $POSTGRES_USER $POSTGRES_DB < dump-11.sql ``` After the last command finishes, all of the data is restored, and you can restart authentik. From 9d6e58b3d8fbd2bab088e9e1af84ad12d67a96c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:47:00 +0200 Subject: [PATCH 5/8] website: bump @types/react from 18.2.74 to 18.2.75 in /website (#9185) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.74 to 18.2.75. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 2d0930f652..6785cab4d6 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -33,7 +33,7 @@ "@docusaurus/module-type-aliases": "3.2.1", "@docusaurus/tsconfig": "3.2.1", "@docusaurus/types": "3.2.1", - "@types/react": "^18.2.74", + "@types/react": "^18.2.75", "prettier": "3.2.5", "typescript": "~5.4.4" }, @@ -3902,9 +3902,9 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" }, "node_modules/@types/react": { - "version": "18.2.74", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.74.tgz", - "integrity": "sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==", + "version": "18.2.75", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.75.tgz", + "integrity": "sha512-+DNnF7yc5y0bHkBTiLKqXFe+L4B3nvOphiMY3tuA5X10esmjqk7smyBZzbGTy2vsiy/Bnzj8yFIBL8xhRacoOg==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" diff --git a/website/package.json b/website/package.json index 4bcd7a969c..fa41024f33 100644 --- a/website/package.json +++ b/website/package.json @@ -52,7 +52,7 @@ "@docusaurus/module-type-aliases": "3.2.1", "@docusaurus/tsconfig": "3.2.1", "@docusaurus/types": "3.2.1", - "@types/react": "^18.2.74", + "@types/react": "^18.2.75", "prettier": "3.2.5", "typescript": "~5.4.4" }, From a030f04ccbe1bedee14dce50bcda0a0f6d39f661 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:47:12 +0200 Subject: [PATCH 6/8] web: bump chromedriver from 123.0.1 to 123.0.2 in /tests/wdio (#9188) Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 123.0.1 to 123.0.2. - [Commits](https://github.com/giggio/node-chromedriver/compare/123.0.1...123.0.2) --- updated-dependencies: - dependency-name: chromedriver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 8 ++++---- tests/wdio/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index da6633335a..84a8e87697 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "@goauthentik/web-tests", "dependencies": { - "chromedriver": "^123.0.1" + "chromedriver": "^123.0.2" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", @@ -2084,9 +2084,9 @@ } }, "node_modules/chromedriver": { - "version": "123.0.1", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.1.tgz", - "integrity": "sha512-YQUIP/zdlzDIRCZNCv6rEVDSY4RAxo/tDL0OiGPPuai+z8unRNqJr/9V6XTBypVFyDheXNalKt9QxEqdMPuLAQ==", + "version": "123.0.2", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-123.0.2.tgz", + "integrity": "sha512-Kx0r/IGULm7eciaUtX/OKaFbdBdHRDSguiV1Q4zuQncz11gvymDdMtELa7ppk+kTL5113NLPud92nuIMNTRhww==", "hasInstallScript": true, "dependencies": { "@testim/chrome-version": "^1.1.4", diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 8f7d3c6996..cd29c85cca 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -32,6 +32,6 @@ "node": ">=20" }, "dependencies": { - "chromedriver": "^123.0.1" + "chromedriver": "^123.0.2" } } From e1fd6cbd3118eb058162309b3d676937c332161c Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:47:22 +0200 Subject: [PATCH 7/8] core, web: update translations (#9183) Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: rissson <18313093+rissson@users.noreply.github.com> --- locale/en/LC_MESSAGES/django.po | 15 ++++++++- web/xliff/de.xlf | 12 +++++++ web/xliff/en.xlf | 12 +++++++ web/xliff/es.xlf | 12 +++++++ web/xliff/fr.xlf | 12 +++++++ web/xliff/ko.xlf | 12 +++++++ web/xliff/nl.xlf | 12 +++++++ web/xliff/pl.xlf | 12 +++++++ web/xliff/pseudo-LOCALE.xlf | 12 +++++++ web/xliff/tr.xlf | 12 +++++++ web/xliff/zh-CN.xlf | 12 +++++++ web/xliff/zh-Hans.xlf | 56 ++++++++++++++++++++------------- web/xliff/zh-Hant.xlf | 12 +++++++ web/xliff/zh_TW.xlf | 12 +++++++ 14 files changed, 192 insertions(+), 23 deletions(-) diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 67c78e425a..904bd1d24f 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-01 23:02+0000\n" +"POT-Creation-Date: 2024-04-09 00:08+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -2251,6 +2251,19 @@ msgstr "" msgid "WebAuthn Devices" msgstr "" +#: authentik/stages/authenticator_webauthn/models.py +msgid "WebAuthn Device type" +msgstr "" + +#: authentik/stages/authenticator_webauthn/models.py +msgid "WebAuthn Device types" +msgstr "" + +#: authentik/stages/authenticator_webauthn/stage.py +#, python-brace-format +msgid "Invalid device type. Contact your {brand} administrator for help." +msgstr "" + #: authentik/stages/captcha/models.py msgid "Public key, acquired your captcha Provider." msgstr "" diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index cacbd40d1e..429b65cb92 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -6475,6 +6475,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index 478b61a68c..9f6d9bcd30 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6744,6 +6744,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index 8a2023d6e5..6afd3320ef 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -6391,6 +6391,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index dd8cb6180b..03c309e551 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -8504,6 +8504,18 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/ko.xlf b/web/xliff/ko.xlf index ff2c9d0a7d..e66fb6f61b 100644 --- a/web/xliff/ko.xlf +++ b/web/xliff/ko.xlf @@ -8332,6 +8332,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/nl.xlf b/web/xliff/nl.xlf index e11d30ad21..6d58c2bcf6 100644 --- a/web/xliff/nl.xlf +++ b/web/xliff/nl.xlf @@ -8175,6 +8175,18 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index 009cdc4ff7..b5ff9a6e5f 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -6596,6 +6596,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index a5d785d1b0..5a7cc37552 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -8448,4 +8448,16 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. + diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 8f8e18bfed..80ba4a88b1 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -6384,6 +6384,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/zh-CN.xlf b/web/xliff/zh-CN.xlf index f25b697682..ffe8205a8e 100644 --- a/web/xliff/zh-CN.xlf +++ b/web/xliff/zh-CN.xlf @@ -5302,6 +5302,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. + diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 682abe4ad2..53bc5d6bb9 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -596,9 +596,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1040,8 +1040,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1782,8 +1782,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2961,8 +2961,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3739,8 +3739,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3916,10 +3916,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5000,7 +5000,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5335,10 +5335,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5387,7 +5387,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7839,7 +7839,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8523,7 +8523,19 @@ Bindings to groups/users are checked against the user of the event. A selection is required 需要进行选择 + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. - \ No newline at end of file + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 3acef706ff..917771ecd6 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -6432,6 +6432,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 62695991c3..398cc40220 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -8293,6 +8293,18 @@ Bindings to groups/users are checked against the user of the event. A selection is required + + + Device type restrictions + + + Available Device types + + + Selected Device types + + + Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. From 54387a7ab8f42bc0a1ebbd236bae9be0bf50106e Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 9 Apr 2024 15:26:48 +0200 Subject: [PATCH 8/8] web/admin: fix SAML Provider preview (#9192) Signed-off-by: Jens Langhammer --- web/src/admin/providers/saml/SAMLProviderViewPage.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/src/admin/providers/saml/SAMLProviderViewPage.ts b/web/src/admin/providers/saml/SAMLProviderViewPage.ts index dd00547b12..df9f16ef96 100644 --- a/web/src/admin/providers/saml/SAMLProviderViewPage.ts +++ b/web/src/admin/providers/saml/SAMLProviderViewPage.ts @@ -575,7 +575,11 @@ export class SAMLProviderViewPage extends AKElement {
-
    +
      + ${attr.Value.map((value) => { + return html`
    • ${value}
    • `; + })} +
    `;