From 83f9eae6549a5cedfb590025f1ab86ab20556a68 Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 5 Oct 2023 01:04:55 +0200 Subject: [PATCH 01/41] root: extended flow and policy metrics (#7067) --- Makefile | 2 +- authentik/events/monitored_tasks.py | 4 +-- authentik/flows/apps.py | 5 ++++ authentik/flows/views/executor.py | 25 +++++++++++----- authentik/policies/apps.py | 7 ++++- authentik/policies/engine.py | 45 ++++++++++++++++++++++------- authentik/policies/process.py | 6 ++-- 7 files changed, 69 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 8a122b7e1..bb7f70a43 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ dev-drop-db: dropdb -U ${pg_user} -h ${pg_host} ${pg_name} # Also remove the test-db if it exists dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true - echo redis-cli -n 0 flushall + redis-cli -n 0 flushall dev-create-db: createdb -U ${pg_user} -h ${pg_host} ${pg_name} diff --git a/authentik/events/monitored_tasks.py b/authentik/events/monitored_tasks.py index 9acee40b6..70f59f610 100644 --- a/authentik/events/monitored_tasks.py +++ b/authentik/events/monitored_tasks.py @@ -206,8 +206,8 @@ def prefill_task(func): task_call_module=func.__module__, task_call_func=func.__name__, # We don't have real values for these attributes but they cannot be null - start_timestamp=default_timer(), - finish_timestamp=default_timer(), + start_timestamp=0, + finish_timestamp=0, finish_time=datetime.now(), ).save(86400) LOGGER.debug("prefilled task", task_name=func.__name__) diff --git a/authentik/flows/apps.py b/authentik/flows/apps.py index e01640bfc..45ebb8489 100644 --- a/authentik/flows/apps.py +++ b/authentik/flows/apps.py @@ -8,6 +8,11 @@ GAUGE_FLOWS_CACHED = Gauge( "authentik_flows_cached", "Cached flows", ) +HIST_FLOW_EXECUTION_STAGE_TIME = Histogram( + "authentik_flows_execution_stage_time", + "Duration each stage took to execute.", + ["stage_type", "method"], +) HIST_FLOWS_PLAN_TIME = Histogram( "authentik_flows_plan_time", "Duration to build a plan for a flow", diff --git a/authentik/flows/views/executor.py b/authentik/flows/views/executor.py index 92b944670..773650c00 100644 --- a/authentik/flows/views/executor.py +++ b/authentik/flows/views/executor.py @@ -24,6 +24,7 @@ from structlog.stdlib import BoundLogger, get_logger from authentik.core.models import Application from authentik.events.models import Event, EventAction, cleanse_dict +from authentik.flows.apps import HIST_FLOW_EXECUTION_STAGE_TIME from authentik.flows.challenge import ( Challenge, ChallengeResponse, @@ -266,17 +267,21 @@ class FlowExecutorView(APIView): ) def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: """Get the next pending challenge from the currently active flow.""" + class_path = class_to_path(self.current_stage_view.__class__) self._logger.debug( "f(exec): Passing GET", - view_class=class_to_path(self.current_stage_view.__class__), + view_class=class_path, stage=self.current_stage, ) try: with Hub.current.start_span( op="authentik.flow.executor.stage", - description=class_to_path(self.current_stage_view.__class__), - ) as span: - span.set_data("Method", "GET") + description=class_path, + ) as span, HIST_FLOW_EXECUTION_STAGE_TIME.labels( + method=request.method.upper(), + stage_type=class_path, + ).time(): + span.set_data("Method", request.method.upper()) span.set_data("authentik Stage", self.current_stage_view) span.set_data("authentik Flow", self.flow.slug) stage_response = self.current_stage_view.dispatch(request) @@ -310,17 +315,21 @@ class FlowExecutorView(APIView): ) def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: """Solve the previously retrieved challenge and advanced to the next stage.""" + class_path = class_to_path(self.current_stage_view.__class__) self._logger.debug( "f(exec): Passing POST", - view_class=class_to_path(self.current_stage_view.__class__), + view_class=class_path, stage=self.current_stage, ) try: with Hub.current.start_span( op="authentik.flow.executor.stage", - description=class_to_path(self.current_stage_view.__class__), - ) as span: - span.set_data("Method", "POST") + description=class_path, + ) as span, HIST_FLOW_EXECUTION_STAGE_TIME.labels( + method=request.method.upper(), + stage_type=class_path, + ).time(): + span.set_data("Method", request.method.upper()) span.set_data("authentik Stage", self.current_stage_view) span.set_data("authentik Flow", self.flow.slug) stage_response = self.current_stage_view.dispatch(request) diff --git a/authentik/policies/apps.py b/authentik/policies/apps.py index 17ef4a3a4..d66b77487 100644 --- a/authentik/policies/apps.py +++ b/authentik/policies/apps.py @@ -7,7 +7,11 @@ GAUGE_POLICIES_CACHED = Gauge( "authentik_policies_cached", "Cached Policies", ) - +HIST_POLICIES_ENGINE_TOTAL_TIME = Histogram( + "authentik_policies_engine_time_total_seconds", + "(Total) Duration the policy engine took to evaluate a result.", + ["obj_type", "obj_pk"], +) HIST_POLICIES_EXECUTION_TIME = Histogram( "authentik_policies_execution_time", "Execution times for single policies", @@ -17,6 +21,7 @@ HIST_POLICIES_EXECUTION_TIME = Histogram( "binding_target_name", "object_pk", "object_type", + "mode", ], ) diff --git a/authentik/policies/engine.py b/authentik/policies/engine.py index a3d8a3191..58295f321 100644 --- a/authentik/policies/engine.py +++ b/authentik/policies/engine.py @@ -1,6 +1,7 @@ """authentik policy engine""" from multiprocessing import Pipe, current_process from multiprocessing.connection import Connection +from timeit import default_timer from typing import Iterator, Optional from django.core.cache import cache @@ -10,6 +11,8 @@ from sentry_sdk.tracing import Span from structlog.stdlib import BoundLogger, get_logger from authentik.core.models import User +from authentik.lib.utils.reflection import class_to_path +from authentik.policies.apps import HIST_POLICIES_ENGINE_TOTAL_TIME, HIST_POLICIES_EXECUTION_TIME from authentik.policies.exceptions import PolicyEngineException from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel, PolicyEngineMode from authentik.policies.process import PolicyProcess, cache_key @@ -77,6 +80,33 @@ class PolicyEngine: if binding.policy is not None and binding.policy.__class__ == Policy: raise PolicyEngineException(f"Policy '{binding.policy}' is root type") + def _check_cache(self, binding: PolicyBinding): + if not self.use_cache: + return False + before = default_timer() + key = cache_key(binding, self.request) + cached_policy = cache.get(key, None) + duration = max(default_timer() - before, 0) + if not cached_policy: + return False + self.logger.debug( + "P_ENG: Taking result from cache", + binding=binding, + cache_key=key, + request=self.request, + ) + HIST_POLICIES_EXECUTION_TIME.labels( + binding_order=binding.order, + binding_target_type=binding.target_type, + binding_target_name=binding.target_name, + object_pk=str(self.request.obj.pk), + object_type=class_to_path(self.request.obj.__class__), + mode="cache_retrieve", + ).observe(duration) + # It's a bit silly to time this, but + self.__cached_policies.append(cached_policy) + return True + def build(self) -> "PolicyEngine": """Build wrapper which monitors performance""" with ( @@ -84,6 +114,10 @@ class PolicyEngine: op="authentik.policy.engine.build", description=self.__pbm, ) as span, + HIST_POLICIES_ENGINE_TOTAL_TIME.labels( + obj_type=class_to_path(self.__pbm.__class__), + obj_pk=str(self.__pbm.pk), + ).time(), ): span: Span span.set_data("pbm", self.__pbm) @@ -92,16 +126,7 @@ class PolicyEngine: self.__expected_result_count += 1 self._check_policy_type(binding) - key = cache_key(binding, self.request) - cached_policy = cache.get(key, None) - if cached_policy and self.use_cache: - self.logger.debug( - "P_ENG: Taking result from cache", - binding=binding, - cache_key=key, - request=self.request, - ) - self.__cached_policies.append(cached_policy) + if self._check_cache(binding): continue self.logger.debug("P_ENG: Evaluating policy", binding=binding, request=self.request) our_end, task_end = Pipe(False) diff --git a/authentik/policies/process.py b/authentik/policies/process.py index 89dc548da..aa3ed9ff5 100644 --- a/authentik/policies/process.py +++ b/authentik/policies/process.py @@ -11,6 +11,7 @@ from structlog.stdlib import get_logger from authentik.events.models import Event, EventAction from authentik.lib.config import CONFIG from authentik.lib.utils.errors import exception_to_string +from authentik.lib.utils.reflection import class_to_path from authentik.policies.apps import HIST_POLICIES_EXECUTION_TIME from authentik.policies.exceptions import PolicyException from authentik.policies.models import PolicyBinding @@ -128,9 +129,8 @@ class PolicyProcess(PROCESS_CLASS): binding_target_type=self.binding.target_type, binding_target_name=self.binding.target_name, object_pk=str(self.request.obj.pk), - object_type=( - f"{self.request.obj._meta.app_label}.{self.request.obj._meta.model_name}" - ), + object_type=class_to_path(self.request.obj.__class__), + mode="execute_process", ).time(), ): span: Span From f28f30186537153fecd0975258dad28954f7765e Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 5 Oct 2023 02:05:01 +0200 Subject: [PATCH 02/41] policies: fix cached policy metric (#7068) --- authentik/policies/signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentik/policies/signals.py b/authentik/policies/signals.py index 52c5ec767..d7949330f 100644 --- a/authentik/policies/signals.py +++ b/authentik/policies/signals.py @@ -17,7 +17,7 @@ LOGGER = get_logger() @receiver(monitoring_set) def monitoring_set_policies(sender, **kwargs): """set policy gauges""" - GAUGE_POLICIES_CACHED.set(len(cache.keys(f"{CACHE_PREFIX}_*") or [])) + GAUGE_POLICIES_CACHED.set(len(cache.keys(f"{CACHE_PREFIX}*") or [])) @receiver(post_save, sender=Policy) From 96c669803cfbb6e4326590c91a1dbca4d32f3368 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:39:03 +0200 Subject: [PATCH 03/41] core: bump github.com/getsentry/sentry-go from 0.24.1 to 0.25.0 (#7070) Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.24.1 to 0.25.0. - [Release notes](https://github.com/getsentry/sentry-go/releases) - [Changelog](https://github.com/getsentry/sentry-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-go/compare/v0.24.1...v0.25.0) --- updated-dependencies: - dependency-name: github.com/getsentry/sentry-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a154977b2..49e1f00e7 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( beryju.io/ldap v0.1.0 github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb github.com/coreos/go-oidc v2.2.1+incompatible - github.com/getsentry/sentry-go v0.24.1 + github.com/getsentry/sentry-go v0.25.0 github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/runtime v0.26.0 diff --git a/go.sum b/go.sum index d5a3b1b62..9d1d6e789 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk= -github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI= +github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= From 87fa313d444a67ef1d652d1cfde0788cb8ca9c09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:39:21 +0200 Subject: [PATCH 04/41] web: bump the wdio group in /tests/wdio with 2 updates (#7069) Bumps the wdio group in /tests/wdio with 2 updates: [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli) and [@wdio/local-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-local-runner). Updates `@wdio/cli` from 8.16.19 to 8.16.20 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.20/packages/wdio-cli) Updates `@wdio/local-runner` from 8.16.19 to 8.16.20 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.20/packages/wdio-local-runner) --- updated-dependencies: - dependency-name: "@wdio/cli" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio - dependency-name: "@wdio/local-runner" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 85 +++++++++++++++++------------------- tests/wdio/package.json | 4 +- 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 78a562d24..22492829e 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -9,8 +9,8 @@ "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", - "@wdio/cli": "^8.16.19", - "@wdio/local-runner": "^8.16.19", + "@wdio/cli": "^8.16.20", + "@wdio/local-runner": "^8.16.20", "@wdio/mocha-framework": "^8.16.17", "@wdio/spec-reporter": "^8.16.17", "eslint": "^8.49.0", @@ -1067,14 +1067,14 @@ } }, "node_modules/@wdio/cli": { - "version": "8.16.19", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.19.tgz", - "integrity": "sha512-MGpRrb56kp0n+r/Z0KMe0o4O1dFgBhhjt/O4HC5l0WcPuf5Ew19w1Nr8PoSZ5XqXklGJi0woFh68YZA1MziInA==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.20.tgz", + "integrity": "sha512-FYd5b2PhlCccC/Sn9D3ZG4/8NGGCLGijbNS1DJLkvYp/XJFqcf1kz0gdum2ct9IVEuFhgRdjqOlRPD3fUa7fDA==", "dev": true, "dependencies": { "@types/node": "^20.1.1", - "@wdio/config": "8.16.17", - "@wdio/globals": "8.16.19", + "@wdio/config": "8.16.20", + "@wdio/globals": "8.16.20", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", "@wdio/types": "8.16.12", @@ -1093,7 +1093,7 @@ "lodash.union": "^4.6.0", "read-pkg-up": "10.1.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.16.19", + "webdriverio": "8.16.20", "yargs": "^17.7.2", "yarn-install": "^1.0.0" }, @@ -1117,9 +1117,9 @@ } }, "node_modules/@wdio/config": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.17.tgz", - "integrity": "sha512-9+AY73Dp6N/CHzUYe4KbYV8wcKh3mpzBsMKieNlwXi1bQ3AAirTjOXzQ2BoQn6fg/Yd1GxmT3F0YsVS+bF1PmQ==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.20.tgz", + "integrity": "sha512-JFD7aYs3nGF2kNhc0eV03mWFQMJku42NCBl+aedb1jzP3z6tBWV3n1a0ETS4MTLps8lFXBDZWvWEnl+ZvVrHZw==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", @@ -1136,28 +1136,28 @@ } }, "node_modules/@wdio/globals": { - "version": "8.16.19", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.19.tgz", - "integrity": "sha512-KziZCYLcEvcsESJm2STkCEUKq2rhIbAP+1lyksULUdMsLoKhqW3yPrb8g6z3qj8G7yAYF8xWpKID0yQejl3UXA==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.20.tgz", + "integrity": "sha512-4MG2E7t1z6IGq6ycGnumLj853n4KVRaS4njlRT74jtamFij0OluyV/e0CHf8Tc0r+ePwD7+UqACFxgwb5KIz6Q==", "dev": true, "engines": { "node": "^16.13 || >=18" }, "optionalDependencies": { "expect-webdriverio": "^4.2.5", - "webdriverio": "8.16.19" + "webdriverio": "8.16.20" } }, "node_modules/@wdio/local-runner": { - "version": "8.16.19", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.19.tgz", - "integrity": "sha512-YUGF+7JCWoziFRW9/L+JSxuGKLgRiRXkRJ39iKaW97qS3MckBxLtuB4IY7gt3WJ80iDYo6IWLllRZfWtpvAT/A==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.20.tgz", + "integrity": "sha512-jPhm4fdPpae3RlM1OEPOZQa+fPLXhkDHBsGOHY2FWerNPF/kkHutjBE1OTRS4I7Tn8Ou0644kggB56GcGVWRcw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.16.17", "@wdio/repl": "8.10.1", - "@wdio/runner": "8.16.19", + "@wdio/runner": "8.16.20", "@wdio/types": "8.16.12", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", @@ -1246,22 +1246,22 @@ } }, "node_modules/@wdio/runner": { - "version": "8.16.19", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.19.tgz", - "integrity": "sha512-CzLxlxcRfIVzTKGeo+TO5rUmmWHjUUdRaM6/6UGNFhFCcYW5rLvfHd1ojpU7ZKxBIc/bz2RGw2/cQ8KgQbFR3g==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.20.tgz", + "integrity": "sha512-egNa/pR7NpU/Ocy+txBnezxE8zE8ghNM6z5WTYBZ2uA1jmwcqR6GFUyZWQmhfkqdVltOnWVa9eRvMb25wqhGtw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.17", - "@wdio/globals": "8.16.19", + "@wdio/config": "8.16.20", + "@wdio/globals": "8.16.20", "@wdio/logger": "8.16.17", "@wdio/types": "8.16.12", "@wdio/utils": "8.16.17", "deepmerge-ts": "^5.0.0", "expect-webdriverio": "^4.2.5", "gaze": "^1.1.2", - "webdriver": "8.16.17", - "webdriverio": "8.16.19" + "webdriver": "8.16.20", + "webdriverio": "8.16.20" }, "engines": { "node": "^16.13 || >=18" @@ -2595,11 +2595,10 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1188743", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1188743.tgz", - "integrity": "sha512-FZDQC58vLiGR2mjSgsMzU8aEJieovMonIyxf38b775eYdIfAYgSzyAWnDf0Eq6ouF/L9qcbqR8jcQeIC34jp/w==", - "dev": true, - "peer": true + "version": "0.0.1203626", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz", + "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==", + "dev": true }, "node_modules/diff": { "version": "5.1.0", @@ -8694,14 +8693,14 @@ } }, "node_modules/webdriver": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.17.tgz", - "integrity": "sha512-pG5aEqK6odI9Tr9pr0+1mN6iGqUu5uc5HTVbqbEM6CSX2g035JRVQ/tavFTegCF1HI6yIquHiwAqsfPgLciAnQ==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.20.tgz", + "integrity": "sha512-3Dynj9pfTqmbDadqmMmD/sQgGFwho92zQPGgpAqLUMebE/qEkraoIfRWdbi2tw1ityiThOJVPTXfwsY/bpvknw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.16.17", + "@wdio/config": "8.16.20", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", "@wdio/types": "8.16.12", @@ -8753,13 +8752,13 @@ } }, "node_modules/webdriverio": { - "version": "8.16.19", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.19.tgz", - "integrity": "sha512-b63vRWWuLq7OKYTLMdCn+uvTW48sMFepEyrv8MKFJproaSOCcokw7sqJ/EcQFmqIgrZxKL/mDch+QKjxlW0ORw==", + "version": "8.16.20", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.20.tgz", + "integrity": "sha512-2xSJDrMxwPF1kucB/r7Wc8yF689GGi7iSKrog7vkkoIiRY25vd3U129iN2mTYgNDyM6SM0kw+GP5W1s73khpYw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.17", + "@wdio/config": "8.16.20", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", "@wdio/repl": "8.10.1", @@ -8781,7 +8780,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.16.17" + "webdriver": "8.16.20" }, "engines": { "node": "^16.13 || >=18" @@ -8804,12 +8803,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/webdriverio/node_modules/devtools-protocol": { - "version": "0.0.1203626", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz", - "integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==", - "dev": true - }, "node_modules/webdriverio/node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 2770bcca1..84f70256a 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -6,8 +6,8 @@ "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", - "@wdio/cli": "^8.16.19", - "@wdio/local-runner": "^8.16.19", + "@wdio/cli": "^8.16.20", + "@wdio/local-runner": "^8.16.20", "@wdio/mocha-framework": "^8.16.17", "@wdio/spec-reporter": "^8.16.17", "eslint": "^8.49.0", From 36c10c74e4f5990286b8cf3ea382675250e9da43 Mon Sep 17 00:00:00 2001 From: Tana M Berry Date: Thu, 5 Oct 2023 11:08:38 -0500 Subject: [PATCH 05/41] website/blog: SCIM blog (#7072) * blog about SCIM * ready for review * Optimised images with calibre/image-actions * minor changes Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Co-authored-by: Tana Berry Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> Co-authored-by: Jens Langhammer --- .../image1.png | Bin 0 -> 84913 bytes .../2023-10-05-SCIMs-many-deviations/item.md | 81 ++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 website/blog/2023-10-05-SCIMs-many-deviations/image1.png create mode 100644 website/blog/2023-10-05-SCIMs-many-deviations/item.md diff --git a/website/blog/2023-10-05-SCIMs-many-deviations/image1.png b/website/blog/2023-10-05-SCIMs-many-deviations/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..cea8ca3406543c14c4254c85ca9d27011b503c1e GIT binary patch literal 84913 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 literal 0 HcmV?d00001 diff --git a/website/blog/2023-10-05-SCIMs-many-deviations/item.md b/website/blog/2023-10-05-SCIMs-many-deviations/item.md new file mode 100644 index 000000000..5b6656675 --- /dev/null +++ b/website/blog/2023-10-05-SCIMs-many-deviations/item.md @@ -0,0 +1,81 @@ +--- +title: "We need to talk about SCIM: More deviation than standard" +description: "SCIM’s many deviations, undocumented edge cases, and lack of official test coverage make it an especially complex protocol to implement." +slug: 2023-10-05-SCIMs-many-deviations +authors: + - name: Jens Langhammer + title: CTO at Authentik Security Inc + url: https://github.com/BeryJu + image_url: https://github.com/BeryJu.png +tags: + - SCIM + - SSO + - open source + - community + - identity provider + - security + - authentication +hide_table_of_contents: false +image: ./image1.png +--- + +> **_authentik is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and auth0. Authentik Security is a [public benefit company](https://github.com/OpenCoreVentures/ocv-public-benefit-company/blob/main/ocv-public-benefit-company-charter.md) building on top of the open source project._** + +--- + +As a young security company, we’ve been working on our implementation of SCIM (System for Cross-domain Identity Management), which I’ll share more about below. SCIM is in many ways a great improvement on LDAP, but we’ve run into challenges in implementation and some things just seem to be harder than they need to be. Is it just us? + +!["authentik admin interface"](./image1.png) + + + +# Improvements on LDAP + +From a security standpoint, it’s wise not to expose LDAP (Lightweight Directory Access Protocol) to the internet if you’re using Active Directory, OpenLDAP, FreeIPA or anything similar as your source of truth for authentication. SCIM fills a need for directory synchronization in a cloud-native world in which many companies aren’t hosting the software they use on their own servers. + +SCIM, being an HTTP API specification, is much simpler and (in theory) gives you less to worry about than LDAP (being its own specific protocol). SCIM also offers time- and cost-saving advantages over Just in Time provisioning, especially for scaling companies. SCIM can save hours of company time for IT admins who no longer have to manually create individual accounts across multiple applications for new team members. Offboarding is also streamlined as departing team members can be deprovisioned automatically, preventing unauthorized access. + +Most modern SaaS applications support SCIM, making it essential for security vendors to support the protocol, but it does come with its drawbacks. + +# Growing pains + +authentik currently supports SCIM going outwards; which means is that authentik is your source of truth/central directory, and you can use authentik together with a tool like [Sentry](https://sentry.io) that supports SCIM. In this case all your users or employees in authentik automatically get created in Sentry, with their correct group assignment, and they can just log in. + +Most of the information and commentary I see about SCIM focuses on the advantages described above, but I don’t see a lot of talk about the pitfalls of SCIM. I’m sharing our experiences here and am curious if others have found the same or can tell me how they’re avoiding these (I would love to hear that we’re doing this wrong actually!). + +## Deviation from standards isn’t well documented + +Implementing a protocol based on reading the RFCs and then writing the code is in itself not fun (to be fair, this is true for implementing any protocol based on a standard). Having implemented SCIM in line with the specification though, once we actually started testing with different solutions that can receive SCIM, we discovered a lot of quirks along the lines of x solution doesn’t do y (which the documentation says they should) or they do it slightly differently, and so on. + +This leads to a lot of workarounds which shouldn’t be necessary or things that simply don’t work without a clear cause. For example, when we started testing SCIM with Sentry, we ran into a lot of deviations (to their credit these were mostly listed in their [documentation](https://docs.sentry.io/product/accounts/sso/#scim-provisioning)). One of the issues I ran into when testing locally was when we created a user with SCIM, it just returned an error saying, “Please enter a valid email address” even though we _had_ sent it a valid email address. At least Sentry has the advantage of being open source, so we can just go and look at the code and see what’s happening, but this is still no small effort and you don’t have that option with closed source solutions. + +You can see other examples of confusing/unexpected behavior from SCIM [here](https://github.com/goauthentik/authentik/issues/5396) and [here](https://github.com/goauthentik/authentik/issues/6695). + +## Testing isn’t built out + +Some protocols make a big effort to uphold the adherence to the standard. OpenID Connect is another standard that’s well defined by multiple RFCs, but also has a lot of room for vendor-specific quirks. However, with OpenID we have the reassurance that the [OpenID Foundation](https://openid.net/foundation/) is behind it. + +The OpenID Foundation is a non-profit standards body of which Authentik Security is a member, but anyone can join to contribute to working groups that support implementation. OpenID Connect offers an [entire test suite](https://openid.net/certification/about-conformance-suite/) made up of hundreds of tests that you can run against your implementation, testing for edge cases and all the behaviors that they define. If you pass all the required tests you can send them the test results and get a [certification](https://openid.net/certification/) (which we are also working on) that your software adheres to the standards. + +Instead of working in the dark and trying to make sure you’ve interpreted the specs correctly (while testing with vendors who might have their own interpretations), you have some reassurance that you’re doing the right things when developing with OpenID Connect. + +To my knowledge there isn’t an official equivalent for SCIM—there are some smaller community projects that try to do something similar, but again, then you have to rely on someone’s interpretation of the standard. Even the [SCIM website’s overview page](https://scim.cloud/) says, “Information on this overview page is not normative.” + +## Updating a user is unnecessarily complex + +As mentioned above, authentik currently supports SCIM in one direction, but we are [working on making it so that another application can send SCIM to authentik](https://github.com/goauthentik/authentik/pull/3051), to create users in it. In this process we’ve discovered that updating a user is surprisingly annoying to implement. With SCIM [you have two options to update a user](https://datatracker.ietf.org/doc/html/rfc7644#autoid-22): + +- You can either send a request to replace the user (for which you have to send _all_ the user’s data), or +- You can send a patch request + +A lot of vendors use the patch request option to update group membership: they send a patch request for a user and just say, for example, “Add that group,” or “Remove that group.” This approach makes more sense in the case of an advanced user with tons of groups, as you’re not replacing everything, just making adjustments to their membership. However, this patch request is done with a custom filtering expression language which is extremely and needlessly complex. + +My first thought when I encountered this was, “Okay, can I just parse this with RegEx?” but it’s not possible. The correct way to parse it is with [ANTLR](https://www.antlr.org/), a parser generator for different kinds of grammars. The thing about ANTLR is that it’s a type of tool usually used to build a compiler: it allows you to define a grammar for which it generates a parser that can then parse things in said grammar. It’s not typically used for filtering language for directories and there are a lot of existing syntaxes that could have been used for this purpose. While luckily some people have written a full grammar for this, I was hoping that there would at least be an official definition for an ANTLR grammar. + +# Immaturity bites + +LDAP, being the more mature protocol (introduced in the ‘90s), has the advantage that deviations have been well documented and kinks ironed out. There are a handful of “standard” implementations like Active Directory, FreeIPA and some others. Similar to SAML support—there’s just been a lot more time to document edge cases and workarounds. + +SCIM, despite being around since 2015, is still subject to a lot of different interpretations of the standard, which leads to varying implementations and quirks with how vendors do SCIM. There’s a maturity challenge at work here in both senses—from the vendors but also from ourselves. Since we’ve added SCIM to our product a lot later than LDAP, there’s still a lot of room for us to catch up and make our implementation better. + +_Have you worked on SCIM implementation? Got advice for us? We’d love to hear from you in the comments._ From 205d3d10e38c62a3366d382439d8a7ab040f9c98 Mon Sep 17 00:00:00 2001 From: Philipp Kolberg <39984529+PKizzle@users.noreply.github.com> Date: Thu, 5 Oct 2023 20:13:38 +0200 Subject: [PATCH 06/41] root: Support PyCharm's test runner (#7074) * Initial commit. * Use Django's test runner as basis * Skip already correctly formatted test labels --- authentik/root/test_runner.py | 61 ++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/authentik/root/test_runner.py b/authentik/root/test_runner.py index 5141613b0..02425f016 100644 --- a/authentik/root/test_runner.py +++ b/authentik/root/test_runner.py @@ -1,8 +1,10 @@ """Integrate ./manage.py test with pytest""" +import os from argparse import ArgumentParser from unittest import TestCase from django.conf import settings +from django.test.runner import DiscoverRunner from authentik.lib.config import CONFIG from authentik.lib.sentry import sentry_init @@ -12,13 +14,11 @@ from tests.e2e.utils import get_docker_tag TestCase.maxDiff = None -class PytestTestRunner: # pragma: no cover +class PytestTestRunner(DiscoverRunner): # pragma: no cover """Runs pytest to discover and run tests.""" def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs): - self.verbosity = verbosity - self.failfast = failfast - self.keepdb = keepdb + super().__init__(verbosity, failfast, keepdb, **kwargs) self.args = [] if self.failfast: @@ -47,16 +47,61 @@ class PytestTestRunner: # pragma: no cover @classmethod def add_arguments(cls, parser: ArgumentParser): """Add more pytest-specific arguments""" - parser.add_argument("--randomly-seed", type=int) - parser.add_argument("--keepdb", action="store_true") + parser.add_argument( + "--randomly-seed", + type=int, + help="Set the seed that pytest-randomly uses (int), or pass the special value 'last'" + "to reuse the seed from the previous run." + "Default behaviour: use random.Random().getrandbits(32), so the seed is" + "different on each run.", + ) + parser.add_argument( + "--keepdb", action="store_true", help="Preserves the test DB between runs." + ) - def run_tests(self, test_labels): + def run_tests(self, test_labels, extra_tests=None, **kwargs): """Run pytest and return the exitcode. It translates some of Django's test command option to pytest's. + It is supported to only run specific classes and methods using + a dotted module name i.e. foo.bar[.Class[.method]] + + The extra_tests argument has been deprecated since Django 5.x + It is kept for compatibility with PyCharm's Django test runner. """ + for label in test_labels: + valid_label_found = False + label_as_path = os.path.abspath(label) + # File path has been specified + if os.path.exists(label_as_path): + self.args.append(label_as_path) + valid_label_found = True + else: + # Already correctly formatted test found (file_path::class::method) + if "::" in label: + self.args.append(label) + valid_label_found = True + # Convert dotted module path to file_path::class::method + else: + path_pieces = label.split(".") + # Check whether only class or class and method are specified + for i in range(-1, -3, -1): + path = os.path.join(*path_pieces[:i]) + ".py" + label_as_path = os.path.abspath(path) + if os.path.exists(label_as_path): + path_method = label_as_path + "::" + "::".join(path_pieces[i:]) + self.args.append(path_method) + valid_label_found = True + break + + if not valid_label_found: + raise RuntimeError( + f"One of the test labels: {label!r}, " + f"is not supported. Use a dotted module name or " + f"path instead." + ) + import pytest - self.args.extend(test_labels) return pytest.main(self.args) From 279d54f8002db623af2ca99a023c81b2d9ed43e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:47:07 +0200 Subject: [PATCH 07/41] core: bump golang from 1.21.1-bookworm to 1.21.2-bookworm (#7085) Bumps golang from 1.21.1-bookworm to 1.21.2-bookworm. --- updated-dependencies: - dependency-name: golang 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> --- Dockerfile | 2 +- ldap.Dockerfile | 2 +- proxy.Dockerfile | 2 +- radius.Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 95d20d999..6556ed3a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api RUN npm run build # Stage 3: Build go proxy -FROM docker.io/golang:1.21.1-bookworm AS go-builder +FROM docker.io/golang:1.21.2-bookworm AS go-builder WORKDIR /go/src/goauthentik.io diff --git a/ldap.Dockerfile b/ldap.Dockerfile index 576a840ea..c43a2a77c 100644 --- a/ldap.Dockerfile +++ b/ldap.Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build -FROM docker.io/golang:1.21.1-bookworm AS builder +FROM docker.io/golang:1.21.2-bookworm AS builder WORKDIR /go/src/goauthentik.io diff --git a/proxy.Dockerfile b/proxy.Dockerfile index f6a226956..ffcde9122 100644 --- a/proxy.Dockerfile +++ b/proxy.Dockerfile @@ -15,7 +15,7 @@ COPY web . RUN npm run build-proxy # Stage 2: Build -FROM docker.io/golang:1.21.1-bookworm AS builder +FROM docker.io/golang:1.21.2-bookworm AS builder WORKDIR /go/src/goauthentik.io diff --git a/radius.Dockerfile b/radius.Dockerfile index 8b6d84900..d2faf4829 100644 --- a/radius.Dockerfile +++ b/radius.Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build -FROM docker.io/golang:1.21.1-bookworm AS builder +FROM docker.io/golang:1.21.2-bookworm AS builder WORKDIR /go/src/goauthentik.io From 241a77040c2aa06544561804277150544da69268 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:47:21 +0200 Subject: [PATCH 08/41] core: bump golang.org/x/sync from 0.3.0 to 0.4.0 (#7086) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.3.0 to 0.4.0. - [Commits](https://github.com/golang/sync/compare/v0.3.0...v0.4.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 49e1f00e7..cc8e33016 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( goauthentik.io/api/v3 v3.2023083.4 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.12.0 - golang.org/x/sync v0.3.0 + golang.org/x/sync v0.4.0 gopkg.in/yaml.v2 v2.4.0 layeh.com/radius v0.0.0-20210819152912-ad72663a72ab ) diff --git a/go.sum b/go.sum index 9d1d6e789..0d025a2c4 100644 --- a/go.sum +++ b/go.sum @@ -449,8 +449,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From de50f45295e87aefa24241f1decee9130d7b859e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:47:33 +0200 Subject: [PATCH 09/41] core: bump twilio from 8.9.0 to 8.9.1 (#7087) Bumps [twilio](https://github.com/twilio/twilio-python) from 8.9.0 to 8.9.1. - [Release notes](https://github.com/twilio/twilio-python/releases) - [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md) - [Commits](https://github.com/twilio/twilio-python/compare/8.9.0...8.9.1) --- updated-dependencies: - dependency-name: twilio 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> --- poetry.lock | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index eabcf4729..78d92b40f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3723,20 +3723,19 @@ wsproto = ">=0.14" [[package]] name = "twilio" -version = "8.9.0" +version = "8.9.1" description = "Twilio API client and TwiML generator" optional = false python-versions = ">=3.7.0" files = [ - {file = "twilio-8.9.0-py2.py3-none-any.whl", hash = "sha256:d2f71060575432f73ed73f7cfc33259c53c96b92aa969d2910dacc8da1d1a5d9"}, - {file = "twilio-8.9.0.tar.gz", hash = "sha256:e711b5ea89694cb58a55a6b69f6190ea4c8499a1d6d68eb6a03c9840bb78fbb3"}, + {file = "twilio-8.9.1-py2.py3-none-any.whl", hash = "sha256:3edc0bcde7320b5ae5f516484af9092bc4df2f5a3b1d4d94a66c29310adb924c"}, + {file = "twilio-8.9.1.tar.gz", hash = "sha256:7bca5dc476d4d15e89e41d3074f8a265bd61445d1de9e8a697ca96cd8399eda6"}, ] [package.dependencies] aiohttp = ">=3.8.4" aiohttp-retry = ">=2.8.3" PyJWT = ">=2.0.0,<3.0.0" -pytz = "*" requests = ">=2.0.0" [[package]] From f71dbf2df3b02bbe50ba83a442257915588db18b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:48:54 +0200 Subject: [PATCH 10/41] web: bump @rollup/plugin-terser from 0.4.3 to 0.4.4 in /web (#7084) Bumps [@rollup/plugin-terser](https://github.com/rollup/plugins/tree/HEAD/packages/terser) from 0.4.3 to 0.4.4. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/terser/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/HEAD/packages/terser) --- updated-dependencies: - dependency-name: "@rollup/plugin-terser" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 19405122f..7a6cbcc6c 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -59,7 +59,7 @@ "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-terser": "^0.4.3", + "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.4", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", @@ -4442,9 +4442,9 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz", - "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "dev": true, "dependencies": { "serialize-javascript": "^6.0.1", @@ -4455,7 +4455,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.x || ^3.x" + "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { diff --git a/web/package.json b/web/package.json index 856e6d98b..eae09eee5 100644 --- a/web/package.json +++ b/web/package.json @@ -77,7 +77,7 @@ "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-terser": "^0.4.3", + "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.4", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", From 4b2359ffa82154f8f6644b4acad6d8a50b9254fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:49:21 +0200 Subject: [PATCH 11/41] web: bump @rollup/plugin-babel from 6.0.3 to 6.0.4 in /web (#7083) Bumps [@rollup/plugin-babel](https://github.com/rollup/plugins/tree/HEAD/packages/babel) from 6.0.3 to 6.0.4. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/babel/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/HEAD/packages/babel) --- updated-dependencies: - dependency-name: "@rollup/plugin-babel" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 7a6cbcc6c..62a5760d7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -55,7 +55,7 @@ "@jackfranklin/rollup-plugin-markdown": "^0.4.0", "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.10", - "@rollup/plugin-babel": "^6.0.3", + "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-replace": "^5.0.2", @@ -4345,9 +4345,9 @@ } }, "node_modules/@rollup/plugin-babel": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.3.tgz", - "integrity": "sha512-fKImZKppa1A/gX73eg4JGo+8kQr/q1HBQaCGKECZ0v4YBBv3lFqi14+7xyApECzvkLTHCifx+7ntcrvtBIRcpg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.18.6", @@ -4359,7 +4359,7 @@ "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "@types/babel__core": { diff --git a/web/package.json b/web/package.json index eae09eee5..b20d3830b 100644 --- a/web/package.json +++ b/web/package.json @@ -73,7 +73,7 @@ "@jackfranklin/rollup-plugin-markdown": "^0.4.0", "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.10", - "@rollup/plugin-babel": "^6.0.3", + "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-replace": "^5.0.2", From 1351bfc6e9a014f732138dd92658e47bebf73562 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:49:58 +0200 Subject: [PATCH 12/41] web: bump @rollup/plugin-node-resolve from 15.2.1 to 15.2.2 in /web (#7079) Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 15.2.1 to 15.2.2. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/HEAD/packages/node-resolve) --- updated-dependencies: - dependency-name: "@rollup/plugin-node-resolve" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 62a5760d7..6a5496e1b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -57,7 +57,7 @@ "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", - "@rollup/plugin-node-resolve": "^15.2.1", + "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.4", @@ -4396,9 +4396,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.1.tgz", - "integrity": "sha512-nsbUg588+GDSu8/NS8T4UAshO6xeaOfINNuXeVHcKV02LJtoRaM1SiOacClw4kws1SFiNhdLGxlbMY9ga/zs/w==", + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.2.tgz", + "integrity": "sha512-f64bU4OKqV0yihtxFemmuf0oj37pToCFMISCA+sJbbIAl5wcpbRO9XgWNWb1tDiWQJUcPxo6V0l59hcuZOQ3kw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -4412,7 +4412,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { diff --git a/web/package.json b/web/package.json index b20d3830b..1962feb75 100644 --- a/web/package.json +++ b/web/package.json @@ -75,7 +75,7 @@ "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", - "@rollup/plugin-node-resolve": "^15.2.1", + "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.4", From 58f52f92f841a9acd16cfaa8786336e154eb8085 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:50:11 +0200 Subject: [PATCH 13/41] web: bump rollup from 3.29.4 to 4.0.0 in /web (#7080) Bumps [rollup](https://github.com/rollup/rollup) from 3.29.4 to 4.0.0. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v3.29.4...v4.0.0) --- updated-dependencies: - dependency-name: rollup dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 205 ++++++++++++++++++++++++++++++++++++++++-- web/package.json | 2 +- 2 files changed, 197 insertions(+), 10 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 6a5496e1b..dd45d818b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -87,7 +87,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^3.29.4", + "rollup": "^4.0.0", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", @@ -4490,9 +4490,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", - "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", + "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -4503,7 +4503,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -4511,6 +4511,149 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.0.tgz", + "integrity": "sha512-rN3qt1JzOx0v7JWyK68zkb3yf1k1f1OhhHR0i7vLlGlediTtM3FKsOkestQN6HwJ9nEaP3KxPHxH5Xv7yr6f4w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.0.tgz", + "integrity": "sha512-dcdg6Zp2bqIS/+2FHhdSS+lbcySufP2fYYoXkDa4W6uHE22L15psftdQZtFhxvvqRWPD1HsK0xIj5f07zuujkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.0.tgz", + "integrity": "sha512-mOz75DpOOHGk4+xYbh1E23vmSOrOqskTwq9s/e2Z46eYbTZ0+s/UVoS42cLG8dUe6enF2Xh3hTtiIEzLhO9kmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.0.tgz", + "integrity": "sha512-rEBuHQ2ejl9gb0//19F88gR7Z9HY2kcCX8jT5LhCHqGqAvlloETXO1FD7DKEdqGz98UtJy6pVAxxeVBN4tlWag==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.0.tgz", + "integrity": "sha512-W4Elp0SGWqWOkdgoYniOp6ERrhHYRfMPikUZmnU/kAdLXQ9p0M0meF648Z6Y7ClHJr8pIQpcCdmr7E2h8Kn7Fw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.0.tgz", + "integrity": "sha512-/BTevM/UKprMJgFse0nm+YXQ83iDqArru+k3kZtQlvaNMWdkLcyscOP8SwWPpR0CJuLlXr8Gtpps+EgH3TUqLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.0.tgz", + "integrity": "sha512-Pz2FD/4FUZM98+rcpuGAJgatW5/dW/pXXrbanjtir38EYqqmdVc0odHwqlQ+KFY2C5P+B6PJO5vom8PmJQLdug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.0.tgz", + "integrity": "sha512-Xs2tOshU5MD7nK5WnaSBUwiFdBlMtyKdXOOnBno4IRbDIyrjLtx9lnSIO47FNP0LtpGfyOcsK/lE/ZsLlnXyIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.0.tgz", + "integrity": "sha512-h2r04SsqVMbmaIRSMN3HKQLYpKewJ7rWQx1SwEZQMeXRkecWFBBNOfoB3iMlvvUfc3VUOonR/3Dm/Op6yOD2Lg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.0.tgz", + "integrity": "sha512-1pl05L51RbVLnqZTEpbgG2RxeS7VLysF7vhU8v1EOAMqbLzko64r8+S2SxsNDKODsgusFqHO8rc3w+G9VUjodw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.0.tgz", + "integrity": "sha512-GDi4TkL95/J0ven1wt+q2cfdg1k9UEIQiF58lSC36KUdA0xtlqgLPEDlNAhu6NTXJ491eiZ71lQbLu1D7hlz9w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sentry-internal/tracing": { "version": "7.73.0", "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.73.0.tgz", @@ -7500,6 +7643,22 @@ "node": ">=12" } }, + "node_modules/@storybook/builder-vite/node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/@storybook/channels": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.4.1.tgz", @@ -20233,18 +20392,29 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.0.tgz", + "integrity": "sha512-dtlkoIdp/g2glVlQb6FzhMAMzhMYVIJ3KLGjhWKkwz/ambEuHeVZ7Eg6GALhHZOsDRD+ZWSjnUikZXPyb22puQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.0.0", + "@rollup/rollup-android-arm64": "4.0.0", + "@rollup/rollup-darwin-arm64": "4.0.0", + "@rollup/rollup-darwin-x64": "4.0.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.0.0", + "@rollup/rollup-linux-arm64-gnu": "4.0.0", + "@rollup/rollup-linux-x64-gnu": "4.0.0", + "@rollup/rollup-linux-x64-musl": "4.0.0", + "@rollup/rollup-win32-arm64-msvc": "4.0.0", + "@rollup/rollup-win32-ia32-msvc": "4.0.0", + "@rollup/rollup-win32-x64-msvc": "4.0.0", "fsevents": "~2.3.2" } }, @@ -23000,6 +23170,23 @@ } } }, + "node_modules/vite/node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/vscode-css-languageservice": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-4.3.0.tgz", diff --git a/web/package.json b/web/package.json index 1962feb75..756cc9a04 100644 --- a/web/package.json +++ b/web/package.json @@ -105,7 +105,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^3.29.4", + "rollup": "^4.0.0", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", From 802d19729b0a4432689e1d921ba1dcd8418f8ddd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:50:47 +0200 Subject: [PATCH 14/41] web: bump @rollup/plugin-typescript from 11.1.4 to 11.1.5 in /web (#7078) Bumps [@rollup/plugin-typescript](https://github.com/rollup/plugins/tree/HEAD/packages/typescript) from 11.1.4 to 11.1.5. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/typescript/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/HEAD/packages/typescript) --- updated-dependencies: - dependency-name: "@rollup/plugin-typescript" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index dd45d818b..320f62794 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -60,7 +60,7 @@ "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^11.1.4", + "@rollup/plugin-typescript": "^11.1.5", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", "@storybook/blocks": "^7.1.1", @@ -4464,9 +4464,9 @@ } }, "node_modules/@rollup/plugin-typescript": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.4.tgz", - "integrity": "sha512-WZRh5LBVLQXdKFICUId5J3eIpmjGURaBqntfg3GSZACgeOAFS+lOSMGTwfzDkELTaZVp/lWdMVNU3UkwCUBg/Q==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.5.tgz", + "integrity": "sha512-rnMHrGBB0IUEv69Q8/JGRD/n4/n6b3nfpufUu26axhUcboUzv/twfZU8fIBbTOphRAe0v8EyxzeDpKXqGHfyDA==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -4476,7 +4476,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.14.0||^3.0.0", + "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" }, diff --git a/web/package.json b/web/package.json index 756cc9a04..182c9cc88 100644 --- a/web/package.json +++ b/web/package.json @@ -78,7 +78,7 @@ "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^11.1.4", + "@rollup/plugin-typescript": "^11.1.5", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", "@storybook/blocks": "^7.1.1", From cb2f06b6c16b629a14adc883b6f3d56f1d04aaed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:51:30 +0200 Subject: [PATCH 15/41] web: bump @rollup/plugin-replace from 5.0.2 to 5.0.3 in /web (#7082) Bumps [@rollup/plugin-replace](https://github.com/rollup/plugins/tree/HEAD/packages/replace) from 5.0.2 to 5.0.3. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/replace/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/babel-v5.0.3/packages/replace) --- updated-dependencies: - dependency-name: "@rollup/plugin-replace" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 320f62794..e17b89eeb 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -58,7 +58,7 @@ "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.2", - "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@storybook/addon-essentials": "^7.4.6", @@ -4421,9 +4421,9 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", - "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.3.tgz", + "integrity": "sha512-je7fu05B800IrMlWjb2wzJcdXzHYW46iTipfChnBDbIbDXhASZs27W1B58T2Yf45jZtJUONegpbce+9Ut2Ti/Q==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -4433,7 +4433,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { diff --git a/web/package.json b/web/package.json index 182c9cc88..9f4f63ed1 100644 --- a/web/package.json +++ b/web/package.json @@ -76,7 +76,7 @@ "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.2", - "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@storybook/addon-essentials": "^7.4.6", From 9050759f6b470853fda143c7b8724425d8d90f02 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:51:46 +0200 Subject: [PATCH 16/41] web: bump @rollup/plugin-commonjs from 25.0.4 to 25.0.5 in /web (#7081) Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 25.0.4 to 25.0.5. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/commonjs/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/HEAD/packages/commonjs) --- updated-dependencies: - dependency-name: "@rollup/plugin-commonjs" 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> --- web/package-lock.json | 10 +++++----- web/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index e17b89eeb..b3a355a3c 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -56,7 +56,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-commonjs": "^25.0.4", + "@rollup/plugin-commonjs": "^25.0.5", "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", @@ -4371,9 +4371,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "25.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.4.tgz", - "integrity": "sha512-L92Vz9WUZXDnlQQl3EwbypJR4+DM2EbsO+/KOcEkP4Mc6Ct453EeDB2uH9lgRwj4w5yflgNpq9pHOiY8aoUXBQ==", + "version": "25.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.5.tgz", + "integrity": "sha512-xY8r/A9oisSeSuLCTfhssyDjo9Vp/eDiRLXkg1MXCcEEgEjPmLU+ZyDB20OOD0NlyDa/8SGbK5uIggF5XTx77w==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -4387,7 +4387,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" + "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { diff --git a/web/package.json b/web/package.json index 9f4f63ed1..e9b59fd6a 100644 --- a/web/package.json +++ b/web/package.json @@ -74,7 +74,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-commonjs": "^25.0.4", + "@rollup/plugin-commonjs": "^25.0.5", "@rollup/plugin-node-resolve": "^15.2.2", "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", From 3b8b307c4ddc86cd8d16ac53d2d7f798baf73691 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 6 Oct 2023 13:51:23 +0200 Subject: [PATCH 17/41] lifecycle: improve reliability of system migrations better transaction handling which allows for re-trying migrations without needing manual intervention Signed-off-by: Jens Langhammer --- lifecycle/migrate.py | 21 ++++++--- lifecycle/system_migrations/install_id.py | 33 +++++++------- lifecycle/system_migrations/otp_merge.py | 44 +++++++++---------- lifecycle/system_migrations/to_0_10.py | 28 +++++------- .../system_migrations/to_0_13_authentik.py | 35 +++++++-------- .../system_migrations/to_0_14_events..py | 11 ++--- .../to_2021_3_authenticator.py | 9 ++-- .../to_2023_1_hibp_remove.py | 10 ++--- 8 files changed, 93 insertions(+), 98 deletions(-) diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 8eee74adb..978455cf7 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -1,12 +1,12 @@ #!/usr/bin/env python """System Migration handler""" -import os from importlib.util import module_from_spec, spec_from_file_location from inspect import getmembers, isclass +from os import environ, system from pathlib import Path from typing import Any -from psycopg import connect +from psycopg import Connection, Cursor, connect from structlog.stdlib import get_logger from authentik.lib.config import CONFIG @@ -19,13 +19,24 @@ LOCKED = False class BaseMigration: """Base System Migration""" - cur: Any - con: Any + cur: Cursor + con: Connection def __init__(self, cur: Any, con: Any): self.cur = cur self.con = con + def system_crit(self, command: str): + """Run system command""" + LOGGER.debug("Running system_crit command", command=command) + retval = system(command) # nosec + if retval != 0: + raise Exception("Migration error") + + def fake_migration(self, *app_migration: tuple[str, str]): + for app, migration in app_migration: + self.system_crit(f"./manage.py migrate {app} {migration} --fake") + def needs_migration(self) -> bool: """Return true if Migration needs to be run""" return False @@ -82,7 +93,7 @@ if __name__ == "__main__": LOGGER.info("Migration finished applying", migration=sub) release_lock() LOGGER.info("applying django migrations") - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") + environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") wait_for_lock() try: from django.core.management import execute_from_command_line diff --git a/lifecycle/system_migrations/install_id.py b/lifecycle/system_migrations/install_id.py index 28867d8fa..3a4f8e8c2 100644 --- a/lifecycle/system_migrations/install_id.py +++ b/lifecycle/system_migrations/install_id.py @@ -4,11 +4,9 @@ from uuid import uuid4 from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -CREATE TABLE IF NOT EXISTS authentik_install_id ( +SQL_STATEMENT = """CREATE TABLE IF NOT EXISTS authentik_install_id ( id TEXT NOT NULL -); -COMMIT;""" +);""" class Migration(BaseMigration): @@ -19,19 +17,20 @@ class Migration(BaseMigration): return not bool(self.cur.rowcount) def upgrade(self, migrate=False): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - if migrate: - # If we already have migrations in the database, assume we're upgrading an existing install - # and set the install id to the secret key - self.cur.execute( - "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) - ) - else: - # Otherwise assume a new install, generate an install ID based on a UUID - install_id = str(uuid4()) - self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + self.con.commit() + if migrate: + # If we already have migrations in the database, assume we're upgrading an existing install + # and set the install id to the secret key + self.cur.execute( + "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) + ) + else: + # Otherwise assume a new install, generate an install ID based on a UUID + install_id = str(uuid4()) + self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) + self.con.commit() def run(self): self.cur.execute( diff --git a/lifecycle/system_migrations/otp_merge.py b/lifecycle/system_migrations/otp_merge.py index c3908bffa..7561f0df7 100644 --- a/lifecycle/system_migrations/otp_merge.py +++ b/lifecycle/system_migrations/otp_merge.py @@ -1,10 +1,7 @@ # flake8: noqa -from os import system - from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ -BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'otp_static'; DELETE FROM django_migrations WHERE app = 'otp_totp'; -- Rename tables (static) @@ -15,7 +12,7 @@ ALTER SEQUENCE otp_static_staticdevice_id_seq RENAME TO authentik_stages_authent -- Rename tables (totp) ALTER TABLE otp_totp_totpdevice RENAME TO authentik_stages_authenticator_totp_totpdevice; ALTER SEQUENCE otp_totp_totpdevice_id_seq RENAME TO authentik_stages_authenticator_totp_totpdevice_id_seq; -COMMIT;""" +""" class Migration(BaseMigration): @@ -25,23 +22,24 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) - def system_crit(self, command): - retval = system(command) # nosec - if retval != 0: - raise Exception("Migration error") - def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_static 0008_initial --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_static 0009_throttling --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_totp 0008_initial --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_totp 0009_auto_20190420_0723 --fake" - ) + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + self.fake_migration( + ( + "authentik_stages_authenticator_static", + "0008_initial", + ), + ( + "authentik_stages_authenticator_static", + "0009_throttling", + ), + ( + "authentik_stages_authenticator_totp", + "0008_initial", + ), + ( + "authentik_stages_authenticator_totp", + "0009_auto_20190420_0723", + ), + ) diff --git a/lifecycle/system_migrations/to_0_10.py b/lifecycle/system_migrations/to_0_10.py index 77ff3f69c..84ab45b39 100644 --- a/lifecycle/system_migrations/to_0_10.py +++ b/lifecycle/system_migrations/to_0_10.py @@ -1,10 +1,7 @@ # flake8: noqa -from os import system - from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ -BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'passbook_stages_prompt'; DROP TABLE passbook_stages_prompt_prompt cascade; DROP TABLE passbook_stages_prompt_promptstage cascade; @@ -25,7 +22,7 @@ DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0008_defa DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0009_source_flows'; DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0010_provider_flows'; DELETE FROM django_migrations WHERE app = 'passbook_stages_password' AND name = '0002_passwordstage_change_flow'; -COMMIT;""" +""" class Migration(BaseMigration): @@ -35,17 +32,14 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) - def system_crit(self, command): - retval = system(command) # nosec - if retval != 0: - raise Exception("Migration error") - def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - self.system_crit("./manage.py migrate passbook_stages_prompt") - self.system_crit("./manage.py migrate passbook_flows 0008_default_flows --fake") - self.system_crit("./manage.py migrate passbook_flows 0009_source_flows --fake") - self.system_crit("./manage.py migrate passbook_flows 0010_provider_flows --fake") - self.system_crit("./manage.py migrate passbook_flows") - self.system_crit("./manage.py migrate passbook_stages_password --fake") + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + self.system_crit("./manage.py migrate passbook_stages_prompt") + self.fake_migration( + ("passbook_flows", "0008_default_flows"), + ("passbook_flows", "0009_source_flows"), + ("passbook_flows", "0010_provider_flows"), + ) + self.system_crit("./manage.py migrate passbook_flows") + self.fake_migration(("passbook_stages_password", "")) diff --git a/lifecycle/system_migrations/to_0_13_authentik.py b/lifecycle/system_migrations/to_0_13_authentik.py index ff2088349..8ba702132 100644 --- a/lifecycle/system_migrations/to_0_13_authentik.py +++ b/lifecycle/system_migrations/to_0_13_authentik.py @@ -4,7 +4,7 @@ from redis import Redis from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; +SQL_STATEMENT = """ ALTER TABLE passbook_audit_event RENAME TO authentik_audit_event; ALTER TABLE passbook_core_application RENAME TO authentik_core_application; ALTER TABLE passbook_core_group RENAME TO authentik_core_group; @@ -92,8 +92,7 @@ ALTER SEQUENCE passbook_stages_prompt_promptstage_validation_policies_id_seq REN UPDATE django_migrations SET app = replace(app, 'passbook', 'authentik'); UPDATE django_content_type SET app_label = replace(app_label, 'passbook', 'authentik'); - -END TRANSACTION;""" +""" class Migration(BaseMigration): @@ -104,18 +103,18 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - # We also need to clean the cache to make sure no pickeled objects still exist - for db in [ - CONFIG.get("redis.message_queue_db"), - CONFIG.get("redis.cache_db"), - CONFIG.get("redis.ws_db"), - ]: - redis = Redis( - host=CONFIG.get("redis.host"), - port=6379, - db=db, - password=CONFIG.get("redis.password"), - ) - redis.flushall() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + # We also need to clean the cache to make sure no pickeled objects still exist + for db in [ + CONFIG.get("redis.message_queue_db"), + CONFIG.get("redis.cache_db"), + CONFIG.get("redis.ws_db"), + ]: + redis = Redis( + host=CONFIG.get("redis.host"), + port=6379, + db=db, + password=CONFIG.get("redis.password"), + ) + redis.flushall() diff --git a/lifecycle/system_migrations/to_0_14_events..py b/lifecycle/system_migrations/to_0_14_events..py index 4745b8853..b1a0cc727 100644 --- a/lifecycle/system_migrations/to_0_14_events..py +++ b/lifecycle/system_migrations/to_0_14_events..py @@ -1,12 +1,9 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; +SQL_STATEMENT = """ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; UPDATE django_migrations SET app = replace(app, 'authentik_audit', 'authentik_events'); -UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events'); - -END TRANSACTION;""" +UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events');""" class Migration(BaseMigration): @@ -17,5 +14,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) diff --git a/lifecycle/system_migrations/to_2021_3_authenticator.py b/lifecycle/system_migrations/to_2021_3_authenticator.py index 3dd895bdb..3b633fef1 100644 --- a/lifecycle/system_migrations/to_2021_3_authenticator.py +++ b/lifecycle/system_migrations/to_2021_3_authenticator.py @@ -1,7 +1,7 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; +SQL_STATEMENT = """ ALTER TABLE authentik_stages_otp_static_otpstaticstage RENAME TO authentik_stages_authenticator_static_otpstaticstage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); @@ -13,8 +13,7 @@ UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_ ALTER TABLE authentik_stages_otp_validate_otpvalidatestage RENAME TO authentik_stages_authenticator_validate_otpvalidatestage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); - -END TRANSACTION;""" +""" class Migration(BaseMigration): @@ -26,5 +25,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) diff --git a/lifecycle/system_migrations/to_2023_1_hibp_remove.py b/lifecycle/system_migrations/to_2023_1_hibp_remove.py index 4c8b9e292..c43f6bb85 100644 --- a/lifecycle/system_migrations/to_2023_1_hibp_remove.py +++ b/lifecycle/system_migrations/to_2023_1_hibp_remove.py @@ -1,10 +1,8 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; -DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp'; -END TRANSACTION;""" +SQL_STATEMENT = """DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; +DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp';""" class Migration(BaseMigration): @@ -16,5 +14,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) From 090d2d836264372a5a7bcd509cc44b1ca1a8347f Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 6 Oct 2023 15:46:45 +0200 Subject: [PATCH 18/41] Revert "lifecycle: improve reliability of system migrations" This reverts commit 3b8b307c4ddc86cd8d16ac53d2d7f798baf73691. --- lifecycle/migrate.py | 21 +++------ lifecycle/system_migrations/install_id.py | 33 +++++++------- lifecycle/system_migrations/otp_merge.py | 44 ++++++++++--------- lifecycle/system_migrations/to_0_10.py | 28 +++++++----- .../system_migrations/to_0_13_authentik.py | 35 ++++++++------- .../system_migrations/to_0_14_events..py | 11 +++-- .../to_2021_3_authenticator.py | 9 ++-- .../to_2023_1_hibp_remove.py | 10 +++-- 8 files changed, 98 insertions(+), 93 deletions(-) diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 978455cf7..8eee74adb 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -1,12 +1,12 @@ #!/usr/bin/env python """System Migration handler""" +import os from importlib.util import module_from_spec, spec_from_file_location from inspect import getmembers, isclass -from os import environ, system from pathlib import Path from typing import Any -from psycopg import Connection, Cursor, connect +from psycopg import connect from structlog.stdlib import get_logger from authentik.lib.config import CONFIG @@ -19,24 +19,13 @@ LOCKED = False class BaseMigration: """Base System Migration""" - cur: Cursor - con: Connection + cur: Any + con: Any def __init__(self, cur: Any, con: Any): self.cur = cur self.con = con - def system_crit(self, command: str): - """Run system command""" - LOGGER.debug("Running system_crit command", command=command) - retval = system(command) # nosec - if retval != 0: - raise Exception("Migration error") - - def fake_migration(self, *app_migration: tuple[str, str]): - for app, migration in app_migration: - self.system_crit(f"./manage.py migrate {app} {migration} --fake") - def needs_migration(self) -> bool: """Return true if Migration needs to be run""" return False @@ -93,7 +82,7 @@ if __name__ == "__main__": LOGGER.info("Migration finished applying", migration=sub) release_lock() LOGGER.info("applying django migrations") - environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") wait_for_lock() try: from django.core.management import execute_from_command_line diff --git a/lifecycle/system_migrations/install_id.py b/lifecycle/system_migrations/install_id.py index 3a4f8e8c2..28867d8fa 100644 --- a/lifecycle/system_migrations/install_id.py +++ b/lifecycle/system_migrations/install_id.py @@ -4,9 +4,11 @@ from uuid import uuid4 from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """CREATE TABLE IF NOT EXISTS authentik_install_id ( +SQL_STATEMENT = """BEGIN TRANSACTION; +CREATE TABLE IF NOT EXISTS authentik_install_id ( id TEXT NOT NULL -);""" +); +COMMIT;""" class Migration(BaseMigration): @@ -17,20 +19,19 @@ class Migration(BaseMigration): return not bool(self.cur.rowcount) def upgrade(self, migrate=False): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - if migrate: - # If we already have migrations in the database, assume we're upgrading an existing install - # and set the install id to the secret key - self.cur.execute( - "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) - ) - else: - # Otherwise assume a new install, generate an install ID based on a UUID - install_id = str(uuid4()) - self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) - self.con.commit() + self.cur.execute(SQL_STATEMENT) + self.con.commit() + if migrate: + # If we already have migrations in the database, assume we're upgrading an existing install + # and set the install id to the secret key + self.cur.execute( + "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) + ) + else: + # Otherwise assume a new install, generate an install ID based on a UUID + install_id = str(uuid4()) + self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) + self.con.commit() def run(self): self.cur.execute( diff --git a/lifecycle/system_migrations/otp_merge.py b/lifecycle/system_migrations/otp_merge.py index 7561f0df7..c3908bffa 100644 --- a/lifecycle/system_migrations/otp_merge.py +++ b/lifecycle/system_migrations/otp_merge.py @@ -1,7 +1,10 @@ # flake8: noqa +from os import system + from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ +BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'otp_static'; DELETE FROM django_migrations WHERE app = 'otp_totp'; -- Rename tables (static) @@ -12,7 +15,7 @@ ALTER SEQUENCE otp_static_staticdevice_id_seq RENAME TO authentik_stages_authent -- Rename tables (totp) ALTER TABLE otp_totp_totpdevice RENAME TO authentik_stages_authenticator_totp_totpdevice; ALTER SEQUENCE otp_totp_totpdevice_id_seq RENAME TO authentik_stages_authenticator_totp_totpdevice_id_seq; -""" +COMMIT;""" class Migration(BaseMigration): @@ -22,24 +25,23 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) + def system_crit(self, command): + retval = system(command) # nosec + if retval != 0: + raise Exception("Migration error") + def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) - self.fake_migration( - ( - "authentik_stages_authenticator_static", - "0008_initial", - ), - ( - "authentik_stages_authenticator_static", - "0009_throttling", - ), - ( - "authentik_stages_authenticator_totp", - "0008_initial", - ), - ( - "authentik_stages_authenticator_totp", - "0009_auto_20190420_0723", - ), - ) + self.cur.execute(SQL_STATEMENT) + self.con.commit() + self.system_crit( + "./manage.py migrate authentik_stages_authenticator_static 0008_initial --fake" + ) + self.system_crit( + "./manage.py migrate authentik_stages_authenticator_static 0009_throttling --fake" + ) + self.system_crit( + "./manage.py migrate authentik_stages_authenticator_totp 0008_initial --fake" + ) + self.system_crit( + "./manage.py migrate authentik_stages_authenticator_totp 0009_auto_20190420_0723 --fake" + ) diff --git a/lifecycle/system_migrations/to_0_10.py b/lifecycle/system_migrations/to_0_10.py index 84ab45b39..77ff3f69c 100644 --- a/lifecycle/system_migrations/to_0_10.py +++ b/lifecycle/system_migrations/to_0_10.py @@ -1,7 +1,10 @@ # flake8: noqa +from os import system + from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ +BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'passbook_stages_prompt'; DROP TABLE passbook_stages_prompt_prompt cascade; DROP TABLE passbook_stages_prompt_promptstage cascade; @@ -22,7 +25,7 @@ DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0008_defa DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0009_source_flows'; DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0010_provider_flows'; DELETE FROM django_migrations WHERE app = 'passbook_stages_password' AND name = '0002_passwordstage_change_flow'; -""" +COMMIT;""" class Migration(BaseMigration): @@ -32,14 +35,17 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) + def system_crit(self, command): + retval = system(command) # nosec + if retval != 0: + raise Exception("Migration error") + def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) - self.system_crit("./manage.py migrate passbook_stages_prompt") - self.fake_migration( - ("passbook_flows", "0008_default_flows"), - ("passbook_flows", "0009_source_flows"), - ("passbook_flows", "0010_provider_flows"), - ) - self.system_crit("./manage.py migrate passbook_flows") - self.fake_migration(("passbook_stages_password", "")) + self.cur.execute(SQL_STATEMENT) + self.con.commit() + self.system_crit("./manage.py migrate passbook_stages_prompt") + self.system_crit("./manage.py migrate passbook_flows 0008_default_flows --fake") + self.system_crit("./manage.py migrate passbook_flows 0009_source_flows --fake") + self.system_crit("./manage.py migrate passbook_flows 0010_provider_flows --fake") + self.system_crit("./manage.py migrate passbook_flows") + self.system_crit("./manage.py migrate passbook_stages_password --fake") diff --git a/lifecycle/system_migrations/to_0_13_authentik.py b/lifecycle/system_migrations/to_0_13_authentik.py index 8ba702132..ff2088349 100644 --- a/lifecycle/system_migrations/to_0_13_authentik.py +++ b/lifecycle/system_migrations/to_0_13_authentik.py @@ -4,7 +4,7 @@ from redis import Redis from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """ +SQL_STATEMENT = """BEGIN TRANSACTION; ALTER TABLE passbook_audit_event RENAME TO authentik_audit_event; ALTER TABLE passbook_core_application RENAME TO authentik_core_application; ALTER TABLE passbook_core_group RENAME TO authentik_core_group; @@ -92,7 +92,8 @@ ALTER SEQUENCE passbook_stages_prompt_promptstage_validation_policies_id_seq REN UPDATE django_migrations SET app = replace(app, 'passbook', 'authentik'); UPDATE django_content_type SET app_label = replace(app_label, 'passbook', 'authentik'); -""" + +END TRANSACTION;""" class Migration(BaseMigration): @@ -103,18 +104,18 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) - # We also need to clean the cache to make sure no pickeled objects still exist - for db in [ - CONFIG.get("redis.message_queue_db"), - CONFIG.get("redis.cache_db"), - CONFIG.get("redis.ws_db"), - ]: - redis = Redis( - host=CONFIG.get("redis.host"), - port=6379, - db=db, - password=CONFIG.get("redis.password"), - ) - redis.flushall() + self.cur.execute(SQL_STATEMENT) + self.con.commit() + # We also need to clean the cache to make sure no pickeled objects still exist + for db in [ + CONFIG.get("redis.message_queue_db"), + CONFIG.get("redis.cache_db"), + CONFIG.get("redis.ws_db"), + ]: + redis = Redis( + host=CONFIG.get("redis.host"), + port=6379, + db=db, + password=CONFIG.get("redis.password"), + ) + redis.flushall() diff --git a/lifecycle/system_migrations/to_0_14_events..py b/lifecycle/system_migrations/to_0_14_events..py index b1a0cc727..4745b8853 100644 --- a/lifecycle/system_migrations/to_0_14_events..py +++ b/lifecycle/system_migrations/to_0_14_events..py @@ -1,9 +1,12 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; +SQL_STATEMENT = """BEGIN TRANSACTION; +ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; UPDATE django_migrations SET app = replace(app, 'authentik_audit', 'authentik_events'); -UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events');""" +UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events'); + +END TRANSACTION;""" class Migration(BaseMigration): @@ -14,5 +17,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) + self.cur.execute(SQL_STATEMENT) + self.con.commit() diff --git a/lifecycle/system_migrations/to_2021_3_authenticator.py b/lifecycle/system_migrations/to_2021_3_authenticator.py index 3b633fef1..3dd895bdb 100644 --- a/lifecycle/system_migrations/to_2021_3_authenticator.py +++ b/lifecycle/system_migrations/to_2021_3_authenticator.py @@ -1,7 +1,7 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """ +SQL_STATEMENT = """BEGIN TRANSACTION; ALTER TABLE authentik_stages_otp_static_otpstaticstage RENAME TO authentik_stages_authenticator_static_otpstaticstage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); @@ -13,7 +13,8 @@ UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_ ALTER TABLE authentik_stages_otp_validate_otpvalidatestage RENAME TO authentik_stages_authenticator_validate_otpvalidatestage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); -""" + +END TRANSACTION;""" class Migration(BaseMigration): @@ -25,5 +26,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) + self.cur.execute(SQL_STATEMENT) + self.con.commit() diff --git a/lifecycle/system_migrations/to_2023_1_hibp_remove.py b/lifecycle/system_migrations/to_2023_1_hibp_remove.py index c43f6bb85..4c8b9e292 100644 --- a/lifecycle/system_migrations/to_2023_1_hibp_remove.py +++ b/lifecycle/system_migrations/to_2023_1_hibp_remove.py @@ -1,8 +1,10 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; -DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp';""" +SQL_STATEMENT = """BEGIN TRANSACTION; +DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; +DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp'; +END TRANSACTION;""" class Migration(BaseMigration): @@ -14,5 +16,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) + self.cur.execute(SQL_STATEMENT) + self.con.commit() From 7ac25e221e4bc4792182d497249e917e6c21ed88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:08:39 +0200 Subject: [PATCH 19/41] web: bump rollup from 4.0.0 to 4.0.1 in /web (#7091) Bumps [rollup](https://github.com/rollup/rollup) from 4.0.0 to 4.0.1. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.0.0...v4.0.1) --- updated-dependencies: - dependency-name: rollup 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> --- web/package-lock.json | 110 ++++++++++++++++++++++++------------------ web/package.json | 2 +- 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index b3a355a3c..cb821139e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -87,7 +87,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.0.0", + "rollup": "^4.0.1", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", @@ -4512,9 +4512,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.0.tgz", - "integrity": "sha512-rN3qt1JzOx0v7JWyK68zkb3yf1k1f1OhhHR0i7vLlGlediTtM3FKsOkestQN6HwJ9nEaP3KxPHxH5Xv7yr6f4w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.1.tgz", + "integrity": "sha512-u6xSfKQXP6NlQYr1+3b+rYEG2YsczVC46ZQjdkBtP+IKqRNT6w6ivTv4ywoxN/rMpBirrru73nvPF7F/gyTkJw==", "cpu": [ "arm" ], @@ -4525,9 +4525,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.0.tgz", - "integrity": "sha512-dcdg6Zp2bqIS/+2FHhdSS+lbcySufP2fYYoXkDa4W6uHE22L15psftdQZtFhxvvqRWPD1HsK0xIj5f07zuujkg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.1.tgz", + "integrity": "sha512-cV7bMb68ipnlgxNjV2fvJRLeIHaEnJr6MrYo6+Re4rp5+B3iJMeOvd/ICjneWcutKzEiFtiyK55FSyu4A1juMg==", "cpu": [ "arm64" ], @@ -4538,9 +4538,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.0.tgz", - "integrity": "sha512-mOz75DpOOHGk4+xYbh1E23vmSOrOqskTwq9s/e2Z46eYbTZ0+s/UVoS42cLG8dUe6enF2Xh3hTtiIEzLhO9kmA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.1.tgz", + "integrity": "sha512-I+AvpO2lt+ZpXcTIG1JU99fD1kNUqk7ppKBMcBRHRXlE+e+QV1Ewpq7yjD346dNg/O8Tq5qzM9hoUAziM3jVMw==", "cpu": [ "arm64" ], @@ -4551,9 +4551,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.0.tgz", - "integrity": "sha512-rEBuHQ2ejl9gb0//19F88gR7Z9HY2kcCX8jT5LhCHqGqAvlloETXO1FD7DKEdqGz98UtJy6pVAxxeVBN4tlWag==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.1.tgz", + "integrity": "sha512-qe4+FV6OhtOrn3gOCfzXN3BpxwJsrQg8SgnbdrtAFQyG9jZm1kTYREc1TvKSpFLGZyC0dtBS21JTS4e1+RXiCg==", "cpu": [ "x64" ], @@ -4564,9 +4564,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.0.tgz", - "integrity": "sha512-W4Elp0SGWqWOkdgoYniOp6ERrhHYRfMPikUZmnU/kAdLXQ9p0M0meF648Z6Y7ClHJr8pIQpcCdmr7E2h8Kn7Fw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.1.tgz", + "integrity": "sha512-UIvgXnd1Y5r9JiYzd1O8+rmyX+xfzNI04wHU7xhkJOKPTopia2NPV/vmyLokgjVffwY9kjfB8a9ZC+1ApGR9GA==", "cpu": [ "arm" ], @@ -4577,9 +4577,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.0.tgz", - "integrity": "sha512-/BTevM/UKprMJgFse0nm+YXQ83iDqArru+k3kZtQlvaNMWdkLcyscOP8SwWPpR0CJuLlXr8Gtpps+EgH3TUqLA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.1.tgz", + "integrity": "sha512-1AKiocQGspfLBrn71FDMpDOIjLJjQhvepwHV3/o9lO5XVSoN/hXH1OeRj6dSkcwozltUTRipQZJ6ku7mX0ZIkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.0.1.tgz", + "integrity": "sha512-/2oPDPDCby4mY2P5xaw6d34Q52sb4X/IgUsoYTkDttapxtnMdQTdD55GhCJhydbozXkn4EC8jbnlQieCB+eE+g==", "cpu": [ "arm64" ], @@ -4590,9 +4603,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.0.tgz", - "integrity": "sha512-Pz2FD/4FUZM98+rcpuGAJgatW5/dW/pXXrbanjtir38EYqqmdVc0odHwqlQ+KFY2C5P+B6PJO5vom8PmJQLdug==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.1.tgz", + "integrity": "sha512-8ow9ljQUBOdLKIKWFBVfdR9O80+TjkbrIo65YhC24Zxnpld342vZdgF3BRKgRECfKIq5nZY4A75JIhr9KaJiEA==", "cpu": [ "x64" ], @@ -4603,9 +4616,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.0.tgz", - "integrity": "sha512-Xs2tOshU5MD7nK5WnaSBUwiFdBlMtyKdXOOnBno4IRbDIyrjLtx9lnSIO47FNP0LtpGfyOcsK/lE/ZsLlnXyIg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.1.tgz", + "integrity": "sha512-EBbduwEBd4x3JprMc1CBZUeagX5EwwCMUx2mN7BNkoWbHrN3e0RDss1T7X9m2gmXsEl5fdPxTTgUo9t3h2V7IQ==", "cpu": [ "x64" ], @@ -4616,9 +4629,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.0.tgz", - "integrity": "sha512-h2r04SsqVMbmaIRSMN3HKQLYpKewJ7rWQx1SwEZQMeXRkecWFBBNOfoB3iMlvvUfc3VUOonR/3Dm/Op6yOD2Lg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.1.tgz", + "integrity": "sha512-AJ0NKL2X/eMq2ED7APz1zDrf70sqIJPdtD1zqgGnqKN0ipn8iDQCiNF9xRolx7ImH6CF+jA1n3/VzgD4a8eVNA==", "cpu": [ "arm64" ], @@ -4629,9 +4642,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.0.tgz", - "integrity": "sha512-1pl05L51RbVLnqZTEpbgG2RxeS7VLysF7vhU8v1EOAMqbLzko64r8+S2SxsNDKODsgusFqHO8rc3w+G9VUjodw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.1.tgz", + "integrity": "sha512-WLHoLsYM5MFbChbLZFyCg0PwqncENl/UKECSYmlSW8X/LZ1KWhBBVrPcI491+mW9BrxdlR0yi/cGGSrC9dr/ig==", "cpu": [ "ia32" ], @@ -4642,9 +4655,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.0.tgz", - "integrity": "sha512-GDi4TkL95/J0ven1wt+q2cfdg1k9UEIQiF58lSC36KUdA0xtlqgLPEDlNAhu6NTXJ491eiZ71lQbLu1D7hlz9w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.1.tgz", + "integrity": "sha512-ysfyyP59n4VUdn3GTfDHg8szzf4Gg01OY6n5DT3hC8jVyyq2pesj8Mq+3yiIGsnnA9uKO6kyWdOGGAy1m6ttAg==", "cpu": [ "x64" ], @@ -20392,9 +20405,9 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.0.tgz", - "integrity": "sha512-dtlkoIdp/g2glVlQb6FzhMAMzhMYVIJ3KLGjhWKkwz/ambEuHeVZ7Eg6GALhHZOsDRD+ZWSjnUikZXPyb22puQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.1.tgz", + "integrity": "sha512-D/1zxbxgSHPPwZS10ybZElOF9ohQc2yop6wG4vlAy8jQaKvjrPu3gjlGVe0+dI7I9NKkm9CtZAzomnaPie/05A==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -20404,17 +20417,18 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.0.0", - "@rollup/rollup-android-arm64": "4.0.0", - "@rollup/rollup-darwin-arm64": "4.0.0", - "@rollup/rollup-darwin-x64": "4.0.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.0.0", - "@rollup/rollup-linux-arm64-gnu": "4.0.0", - "@rollup/rollup-linux-x64-gnu": "4.0.0", - "@rollup/rollup-linux-x64-musl": "4.0.0", - "@rollup/rollup-win32-arm64-msvc": "4.0.0", - "@rollup/rollup-win32-ia32-msvc": "4.0.0", - "@rollup/rollup-win32-x64-msvc": "4.0.0", + "@rollup/rollup-android-arm-eabi": "4.0.1", + "@rollup/rollup-android-arm64": "4.0.1", + "@rollup/rollup-darwin-arm64": "4.0.1", + "@rollup/rollup-darwin-x64": "4.0.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.0.1", + "@rollup/rollup-linux-arm64-gnu": "4.0.1", + "@rollup/rollup-linux-arm64-musl": "4.0.1", + "@rollup/rollup-linux-x64-gnu": "4.0.1", + "@rollup/rollup-linux-x64-musl": "4.0.1", + "@rollup/rollup-win32-arm64-msvc": "4.0.1", + "@rollup/rollup-win32-ia32-msvc": "4.0.1", + "@rollup/rollup-win32-x64-msvc": "4.0.1", "fsevents": "~2.3.2" } }, diff --git a/web/package.json b/web/package.json index e9b59fd6a..c783892de 100644 --- a/web/package.json +++ b/web/package.json @@ -105,7 +105,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.0.0", + "rollup": "^4.0.1", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", From 9d63456ed955c77541c225d1d0bc72e100f752fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 17:42:08 +0200 Subject: [PATCH 20/41] web: bump rollup from 4.0.1 to 4.0.2 in /web (#7095) Bumps [rollup](https://github.com/rollup/rollup) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.0.1...v4.0.2) --- updated-dependencies: - dependency-name: rollup 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> --- web/package-lock.json | 104 +++++++++++++++++++++--------------------- web/package.json | 2 +- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index cb821139e..2c7b379f7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -87,7 +87,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.0.1", + "rollup": "^4.0.2", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", @@ -4512,9 +4512,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.1.tgz", - "integrity": "sha512-u6xSfKQXP6NlQYr1+3b+rYEG2YsczVC46ZQjdkBtP+IKqRNT6w6ivTv4ywoxN/rMpBirrru73nvPF7F/gyTkJw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.0.2.tgz", + "integrity": "sha512-xDvk1pT4vaPU2BOLy0MqHMdYZyntqpaBf8RhBiezlqG9OjY8F50TyctHo8znigYKd+QCFhCmlmXHOL/LoaOl3w==", "cpu": [ "arm" ], @@ -4525,9 +4525,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.1.tgz", - "integrity": "sha512-cV7bMb68ipnlgxNjV2fvJRLeIHaEnJr6MrYo6+Re4rp5+B3iJMeOvd/ICjneWcutKzEiFtiyK55FSyu4A1juMg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.0.2.tgz", + "integrity": "sha512-lqCglytY3E6raze27DD9VQJWohbwCxzqs9aSHcj5X/8hJpzZfNdbsr4Ja9Hqp6iPyF53+5PtPx0pKRlkSvlHZg==", "cpu": [ "arm64" ], @@ -4538,9 +4538,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.1.tgz", - "integrity": "sha512-I+AvpO2lt+ZpXcTIG1JU99fD1kNUqk7ppKBMcBRHRXlE+e+QV1Ewpq7yjD346dNg/O8Tq5qzM9hoUAziM3jVMw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.0.2.tgz", + "integrity": "sha512-nkBKItS6E6CCzvRwgiKad+j+1ibmL7SIInj7oqMWmdkCjiSX6VeVZw2mLlRKIUL+JjsBgpATTfo7BiAXc1v0jA==", "cpu": [ "arm64" ], @@ -4551,9 +4551,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.1.tgz", - "integrity": "sha512-qe4+FV6OhtOrn3gOCfzXN3BpxwJsrQg8SgnbdrtAFQyG9jZm1kTYREc1TvKSpFLGZyC0dtBS21JTS4e1+RXiCg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.0.2.tgz", + "integrity": "sha512-vX2C8xvWPIbpEgQht95+dY6BReKAvtDgPDGi0XN0kWJKkm4WdNmq5dnwscv/zxvi+n6jUTBhs6GtpkkWT4q8Gg==", "cpu": [ "x64" ], @@ -4564,9 +4564,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.1.tgz", - "integrity": "sha512-UIvgXnd1Y5r9JiYzd1O8+rmyX+xfzNI04wHU7xhkJOKPTopia2NPV/vmyLokgjVffwY9kjfB8a9ZC+1ApGR9GA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.0.2.tgz", + "integrity": "sha512-DVFIfcHOjgmeHOAqji4xNz2wczt1Bmzy9MwBZKBa83SjBVO/i38VHDR+9ixo8QpBOiEagmNw12DucG+v55tCrg==", "cpu": [ "arm" ], @@ -4577,9 +4577,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.1.tgz", - "integrity": "sha512-1AKiocQGspfLBrn71FDMpDOIjLJjQhvepwHV3/o9lO5XVSoN/hXH1OeRj6dSkcwozltUTRipQZJ6ku7mX0ZIkQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.0.2.tgz", + "integrity": "sha512-GCK/a9ItUxPI0V5hQEJjH4JtOJO90GF2Hja7TO+EZ8rmkGvEi8/ZDMhXmcuDpQT7/PWrTT9RvnG8snMd5SrhBQ==", "cpu": [ "arm64" ], @@ -4590,9 +4590,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.0.1.tgz", - "integrity": "sha512-/2oPDPDCby4mY2P5xaw6d34Q52sb4X/IgUsoYTkDttapxtnMdQTdD55GhCJhydbozXkn4EC8jbnlQieCB+eE+g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.0.2.tgz", + "integrity": "sha512-cLuBp7rOjIB1R2j/VazjCmHC7liWUur2e9mFflLJBAWCkrZ+X0+QwHLvOQakIwDymungzAKv6W9kHZnTp/Mqrg==", "cpu": [ "arm64" ], @@ -4603,9 +4603,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.1.tgz", - "integrity": "sha512-8ow9ljQUBOdLKIKWFBVfdR9O80+TjkbrIo65YhC24Zxnpld342vZdgF3BRKgRECfKIq5nZY4A75JIhr9KaJiEA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.0.2.tgz", + "integrity": "sha512-Zqw4iVnJr2naoyQus0yLy7sLtisCQcpdMKUCeXPBjkJtpiflRime/TMojbnl8O3oxUAj92mxr+t7im/RbgA20w==", "cpu": [ "x64" ], @@ -4616,9 +4616,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.1.tgz", - "integrity": "sha512-EBbduwEBd4x3JprMc1CBZUeagX5EwwCMUx2mN7BNkoWbHrN3e0RDss1T7X9m2gmXsEl5fdPxTTgUo9t3h2V7IQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.0.2.tgz", + "integrity": "sha512-jJRU9TyUD/iMqjf8aLAp7XiN3pIj5v6Qcu+cdzBfVTKDD0Fvua4oUoK8eVJ9ZuKBEQKt3WdlcwJXFkpmMLk6kg==", "cpu": [ "x64" ], @@ -4629,9 +4629,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.1.tgz", - "integrity": "sha512-AJ0NKL2X/eMq2ED7APz1zDrf70sqIJPdtD1zqgGnqKN0ipn8iDQCiNF9xRolx7ImH6CF+jA1n3/VzgD4a8eVNA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.0.2.tgz", + "integrity": "sha512-ZkS2NixCxHKC4zbOnw64ztEGGDVIYP6nKkGBfOAxEPW71Sji9v8z3yaHNuae/JHPwXA+14oDefnOuVfxl59SmQ==", "cpu": [ "arm64" ], @@ -4642,9 +4642,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.1.tgz", - "integrity": "sha512-WLHoLsYM5MFbChbLZFyCg0PwqncENl/UKECSYmlSW8X/LZ1KWhBBVrPcI491+mW9BrxdlR0yi/cGGSrC9dr/ig==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.0.2.tgz", + "integrity": "sha512-3SKjj+tvnZ0oZq2BKB+fI+DqYI83VrRzk7eed8tJkxeZ4zxJZcLSE8YDQLYGq1tZAnAX+H076RHHB4gTZXsQzw==", "cpu": [ "ia32" ], @@ -4655,9 +4655,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.1.tgz", - "integrity": "sha512-ysfyyP59n4VUdn3GTfDHg8szzf4Gg01OY6n5DT3hC8jVyyq2pesj8Mq+3yiIGsnnA9uKO6kyWdOGGAy1m6ttAg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.0.2.tgz", + "integrity": "sha512-MBdJIOxRauKkry7t2q+rTHa3aWjVez2eioWg+etRVS3dE4tChhmt5oqZYr48R6bPmcwEhxQr96gVRfeQrLbqng==", "cpu": [ "x64" ], @@ -20405,9 +20405,9 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.1.tgz", - "integrity": "sha512-D/1zxbxgSHPPwZS10ybZElOF9ohQc2yop6wG4vlAy8jQaKvjrPu3gjlGVe0+dI7I9NKkm9CtZAzomnaPie/05A==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.0.2.tgz", + "integrity": "sha512-MCScu4usMPCeVFaiLcgMDaBQeYi1z6vpWxz0r0hq0Hv77Y2YuOTZldkuNJ54BdYBH3e+nkrk6j0Rre/NLDBYzg==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -20417,18 +20417,18 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.0.1", - "@rollup/rollup-android-arm64": "4.0.1", - "@rollup/rollup-darwin-arm64": "4.0.1", - "@rollup/rollup-darwin-x64": "4.0.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.0.1", - "@rollup/rollup-linux-arm64-gnu": "4.0.1", - "@rollup/rollup-linux-arm64-musl": "4.0.1", - "@rollup/rollup-linux-x64-gnu": "4.0.1", - "@rollup/rollup-linux-x64-musl": "4.0.1", - "@rollup/rollup-win32-arm64-msvc": "4.0.1", - "@rollup/rollup-win32-ia32-msvc": "4.0.1", - "@rollup/rollup-win32-x64-msvc": "4.0.1", + "@rollup/rollup-android-arm-eabi": "4.0.2", + "@rollup/rollup-android-arm64": "4.0.2", + "@rollup/rollup-darwin-arm64": "4.0.2", + "@rollup/rollup-darwin-x64": "4.0.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.0.2", + "@rollup/rollup-linux-arm64-gnu": "4.0.2", + "@rollup/rollup-linux-arm64-musl": "4.0.2", + "@rollup/rollup-linux-x64-gnu": "4.0.2", + "@rollup/rollup-linux-x64-musl": "4.0.2", + "@rollup/rollup-win32-arm64-msvc": "4.0.2", + "@rollup/rollup-win32-ia32-msvc": "4.0.2", + "@rollup/rollup-win32-x64-msvc": "4.0.2", "fsevents": "~2.3.2" } }, diff --git a/web/package.json b/web/package.json index c783892de..e899eafc3 100644 --- a/web/package.json +++ b/web/package.json @@ -105,7 +105,7 @@ "pyright": "^1.1.330", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.0.1", + "rollup": "^4.0.2", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-postcss-lit": "^2.1.0", From 9860ac983c31b5090c5fe023a0f3bd573c5364be Mon Sep 17 00:00:00 2001 From: jon r Date: Fri, 6 Oct 2023 17:43:03 +0200 Subject: [PATCH 21/41] website/docs: fix typo in providers/scim (#7076) chore(docs): typo in providers/scim Signed-off-by: jon r --- website/docs/providers/scim/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/providers/scim/index.md b/website/docs/providers/scim/index.md index 1b47f919f..ee8f4c020 100644 --- a/website/docs/providers/scim/index.md +++ b/website/docs/providers/scim/index.md @@ -51,7 +51,7 @@ Applications can either match users on a unique ID sent by authentik called `ext #### OAuth/OIDC -The default provider configuration for the _Subject mode_ option of _Based on the User's hashed ID_ matches the `externalId` that's generated by default. If any other _Subjet mode_ is selected, the `externalId` attribute can be customized via SCIM mappings. +The default provider configuration for the _Subject mode_ option of _Based on the User's hashed ID_ matches the `externalId` that's generated by default. If any other _Subject mode_ is selected, the `externalId` attribute can be customized via SCIM mappings. #### SAML From ccb3875e865e484a7d6cc9828034643f3e2fd7c7 Mon Sep 17 00:00:00 2001 From: Philipp Kolberg <39984529+PKizzle@users.noreply.github.com> Date: Fri, 6 Oct 2023 17:50:46 +0200 Subject: [PATCH 22/41] root: Ignore the vendor folder (#7094) Ignore the vendor folder When creating a local development environment a vendor folder will automatically be created for storing Go dependencies. This data shall not be uploaded to GitHub. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 17f1a196d..713258ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -206,3 +206,6 @@ data/ .netlify .ruff_cache source_docs/ + +### Golang ### +/vendor/ From 25ee6f81166595aab71ad35cfd997e687d39c8ed Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 6 Oct 2023 18:01:09 +0200 Subject: [PATCH 23/41] sources/ldap: fix attribute path resolution (#7090) * lib: make set_path_in_dict reusable Signed-off-by: Jens Langhammer * sources/ldap: use set_path_in_dict to set attributes Signed-off-by: Jens Langhammer * stages/user_write: also use set_path_in_dict Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/lib/config.py | 30 ++++++++++++++++++---------- authentik/sources/ldap/sync/base.py | 4 ++-- authentik/stages/user_write/stage.py | 8 ++------ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/authentik/lib/config.py b/authentik/lib/config.py index 043f77460..63aa3493a 100644 --- a/authentik/lib/config.py +++ b/authentik/lib/config.py @@ -24,7 +24,7 @@ ENVIRONMENT = os.getenv(f"{ENV_PREFIX}_ENV", "local") def get_path_from_dict(root: dict, path: str, sep=".", default=None) -> Any: - """Recursively walk through `root`, checking each part of `path` split by `sep`. + """Recursively walk through `root`, checking each part of `path` separated by `sep`. If at any point a dict does not exist, return default""" for comp in path.split(sep): if root and comp in root: @@ -34,7 +34,19 @@ def get_path_from_dict(root: dict, path: str, sep=".", default=None) -> Any: return root -@dataclass +def set_path_in_dict(root: dict, path: str, value: Any, sep="."): + """Recursively walk through `root`, checking each part of `path` separated by `sep` + and setting the last value to `value`""" + # Walk each component of the path + path_parts = path.split(sep) + for comp in path_parts[:-1]: + if comp not in root: + root[comp] = {} + root = root.get(comp, {}) + root[path_parts[-1]] = value + + +@dataclass(slots=True) class Attr: """Single configuration attribute""" @@ -55,6 +67,10 @@ class Attr: # to the config file containing this change or the file containing this value source: Optional[str] = field(default=None) + def __post_init__(self): + if isinstance(self.value, Attr): + raise RuntimeError(f"config Attr with nested Attr for source {self.source}") + class AttrEncoder(JSONEncoder): """JSON encoder that can deal with `Attr` classes""" @@ -227,15 +243,7 @@ class ConfigLoader: def set(self, path: str, value: Any, sep="."): """Set value using same syntax as get()""" - # Walk sub_dicts before parsing path - root = self.raw - # Walk each component of the path - path_parts = path.split(sep) - for comp in path_parts[:-1]: - if comp not in root: - root[comp] = {} - root = root.get(comp, {}) - root[path_parts[-1]] = Attr(value) + set_path_in_dict(self.raw, path, Attr(value), sep=sep) CONFIG = ConfigLoader() diff --git a/authentik/sources/ldap/sync/base.py b/authentik/sources/ldap/sync/base.py index a131d935c..7490449ec 100644 --- a/authentik/sources/ldap/sync/base.py +++ b/authentik/sources/ldap/sync/base.py @@ -9,7 +9,7 @@ from structlog.stdlib import BoundLogger, get_logger from authentik.core.exceptions import PropertyMappingExpressionException from authentik.events.models import Event, EventAction -from authentik.lib.config import CONFIG +from authentik.lib.config import CONFIG, set_path_in_dict from authentik.lib.merge import MERGE_LIST_UNIQUE from authentik.sources.ldap.auth import LDAP_DISTINGUISHED_NAME from authentik.sources.ldap.models import LDAPPropertyMapping, LDAPSource @@ -164,7 +164,7 @@ class BaseLDAPSynchronizer: if object_field.startswith("attributes."): # Because returning a list might desired, we can't # rely on self._flatten here. Instead, just save the result as-is - properties["attributes"][object_field.replace("attributes.", "")] = value + set_path_in_dict(properties, object_field, value) else: properties[object_field] = self._flatten(value) except PropertyMappingExpressionException as exc: diff --git a/authentik/stages/user_write/stage.py b/authentik/stages/user_write/stage.py index 98494fae1..5a4c80974 100644 --- a/authentik/stages/user_write/stage.py +++ b/authentik/stages/user_write/stage.py @@ -14,6 +14,7 @@ from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import StageView from authentik.flows.views.executor import FlowExecutorView +from authentik.lib.config import set_path_in_dict from authentik.stages.password import BACKEND_INBUILT from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT @@ -44,12 +45,7 @@ class UserWriteStageView(StageView): # this is just a sanity check to ensure that is removed if parts[0] == "attributes": parts = parts[1:] - attrs = user.attributes - for comp in parts[:-1]: - if comp not in attrs: - attrs[comp] = {} - attrs = attrs.get(comp) - attrs[parts[-1]] = value + set_path_in_dict(user.attributes, ".".join(parts), value) def ensure_user(self) -> tuple[Optional[User], bool]: """Ensure a user exists""" From b90ed6bab314b5c008561de1c39d9e9ae5f64eab Mon Sep 17 00:00:00 2001 From: Jens L Date: Fri, 6 Oct 2023 18:56:10 +0200 Subject: [PATCH 24/41] lifecycle: improve reliability of system migrations (#7089) * lifecycle: improve reliability of system migrations better transaction handling which allows for re-trying migrations without needing manual intervention Signed-off-by: Jens Langhammer * fix lint Signed-off-by: Jens Langhammer * remove explicit commit --------- Signed-off-by: Jens Langhammer --- lifecycle/migrate.py | 27 +++++++++--- lifecycle/system_migrations/install_id.py | 31 ++++++------- lifecycle/system_migrations/otp_merge.py | 44 +++++++++---------- lifecycle/system_migrations/to_0_10.py | 28 +++++------- .../system_migrations/to_0_13_authentik.py | 35 +++++++-------- .../system_migrations/to_0_14_events..py | 11 ++--- .../to_2021_3_authenticator.py | 9 ++-- .../to_2023_1_hibp_remove.py | 10 ++--- 8 files changed, 97 insertions(+), 98 deletions(-) diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 8eee74adb..68d45dbc3 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -1,12 +1,12 @@ #!/usr/bin/env python """System Migration handler""" -import os from importlib.util import module_from_spec, spec_from_file_location from inspect import getmembers, isclass +from os import environ, system from pathlib import Path from typing import Any -from psycopg import connect +from psycopg import Connection, Cursor, connect from structlog.stdlib import get_logger from authentik.lib.config import CONFIG @@ -16,16 +16,33 @@ ADV_LOCK_UID = 1000 LOCKED = False +class CommandError(Exception): + """Error raised when a system_crit command fails""" + + class BaseMigration: """Base System Migration""" - cur: Any - con: Any + cur: Cursor + con: Connection def __init__(self, cur: Any, con: Any): self.cur = cur self.con = con + def system_crit(self, command: str): + """Run system command""" + LOGGER.debug("Running system_crit command", command=command) + retval = system(command) # nosec + if retval != 0: + raise CommandError("Migration error") + + def fake_migration(self, *app_migration: tuple[str, str]): + """Fake apply a list of migrations, arguments are + expected to be tuples of (app_label, migration_name)""" + for app, _migration in app_migration: + self.system_crit(f"./manage.py migrate {app} {_migration} --fake") + def needs_migration(self) -> bool: """Return true if Migration needs to be run""" return False @@ -82,7 +99,7 @@ if __name__ == "__main__": LOGGER.info("Migration finished applying", migration=sub) release_lock() LOGGER.info("applying django migrations") - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") + environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") wait_for_lock() try: from django.core.management import execute_from_command_line diff --git a/lifecycle/system_migrations/install_id.py b/lifecycle/system_migrations/install_id.py index 28867d8fa..2545bd910 100644 --- a/lifecycle/system_migrations/install_id.py +++ b/lifecycle/system_migrations/install_id.py @@ -4,11 +4,9 @@ from uuid import uuid4 from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -CREATE TABLE IF NOT EXISTS authentik_install_id ( +SQL_STATEMENT = """CREATE TABLE IF NOT EXISTS authentik_install_id ( id TEXT NOT NULL -); -COMMIT;""" +);""" class Migration(BaseMigration): @@ -19,19 +17,18 @@ class Migration(BaseMigration): return not bool(self.cur.rowcount) def upgrade(self, migrate=False): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - if migrate: - # If we already have migrations in the database, assume we're upgrading an existing install - # and set the install id to the secret key - self.cur.execute( - "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) - ) - else: - # Otherwise assume a new install, generate an install ID based on a UUID - install_id = str(uuid4()) - self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + if migrate: + # If we already have migrations in the database, assume we're upgrading an existing install + # and set the install id to the secret key + self.cur.execute( + "INSERT INTO authentik_install_id (id) VALUES (%s)", (CONFIG.get("secret_key"),) + ) + else: + # Otherwise assume a new install, generate an install ID based on a UUID + install_id = str(uuid4()) + self.cur.execute("INSERT INTO authentik_install_id (id) VALUES (%s)", (install_id,)) def run(self): self.cur.execute( diff --git a/lifecycle/system_migrations/otp_merge.py b/lifecycle/system_migrations/otp_merge.py index c3908bffa..7561f0df7 100644 --- a/lifecycle/system_migrations/otp_merge.py +++ b/lifecycle/system_migrations/otp_merge.py @@ -1,10 +1,7 @@ # flake8: noqa -from os import system - from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ -BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'otp_static'; DELETE FROM django_migrations WHERE app = 'otp_totp'; -- Rename tables (static) @@ -15,7 +12,7 @@ ALTER SEQUENCE otp_static_staticdevice_id_seq RENAME TO authentik_stages_authent -- Rename tables (totp) ALTER TABLE otp_totp_totpdevice RENAME TO authentik_stages_authenticator_totp_totpdevice; ALTER SEQUENCE otp_totp_totpdevice_id_seq RENAME TO authentik_stages_authenticator_totp_totpdevice_id_seq; -COMMIT;""" +""" class Migration(BaseMigration): @@ -25,23 +22,24 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) - def system_crit(self, command): - retval = system(command) # nosec - if retval != 0: - raise Exception("Migration error") - def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_static 0008_initial --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_static 0009_throttling --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_totp 0008_initial --fake" - ) - self.system_crit( - "./manage.py migrate authentik_stages_authenticator_totp 0009_auto_20190420_0723 --fake" - ) + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + self.fake_migration( + ( + "authentik_stages_authenticator_static", + "0008_initial", + ), + ( + "authentik_stages_authenticator_static", + "0009_throttling", + ), + ( + "authentik_stages_authenticator_totp", + "0008_initial", + ), + ( + "authentik_stages_authenticator_totp", + "0009_auto_20190420_0723", + ), + ) diff --git a/lifecycle/system_migrations/to_0_10.py b/lifecycle/system_migrations/to_0_10.py index 77ff3f69c..84ab45b39 100644 --- a/lifecycle/system_migrations/to_0_10.py +++ b/lifecycle/system_migrations/to_0_10.py @@ -1,10 +1,7 @@ # flake8: noqa -from os import system - from lifecycle.migrate import BaseMigration SQL_STATEMENT = """ -BEGIN TRANSACTION; DELETE FROM django_migrations WHERE app = 'passbook_stages_prompt'; DROP TABLE passbook_stages_prompt_prompt cascade; DROP TABLE passbook_stages_prompt_promptstage cascade; @@ -25,7 +22,7 @@ DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0008_defa DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0009_source_flows'; DELETE FROM django_migrations WHERE app = 'passbook_flows' AND name = '0010_provider_flows'; DELETE FROM django_migrations WHERE app = 'passbook_stages_password' AND name = '0002_passwordstage_change_flow'; -COMMIT;""" +""" class Migration(BaseMigration): @@ -35,17 +32,14 @@ class Migration(BaseMigration): ) return bool(self.cur.rowcount) - def system_crit(self, command): - retval = system(command) # nosec - if retval != 0: - raise Exception("Migration error") - def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - self.system_crit("./manage.py migrate passbook_stages_prompt") - self.system_crit("./manage.py migrate passbook_flows 0008_default_flows --fake") - self.system_crit("./manage.py migrate passbook_flows 0009_source_flows --fake") - self.system_crit("./manage.py migrate passbook_flows 0010_provider_flows --fake") - self.system_crit("./manage.py migrate passbook_flows") - self.system_crit("./manage.py migrate passbook_stages_password --fake") + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + self.system_crit("./manage.py migrate passbook_stages_prompt") + self.fake_migration( + ("passbook_flows", "0008_default_flows"), + ("passbook_flows", "0009_source_flows"), + ("passbook_flows", "0010_provider_flows"), + ) + self.system_crit("./manage.py migrate passbook_flows") + self.fake_migration(("passbook_stages_password", "")) diff --git a/lifecycle/system_migrations/to_0_13_authentik.py b/lifecycle/system_migrations/to_0_13_authentik.py index ff2088349..8ba702132 100644 --- a/lifecycle/system_migrations/to_0_13_authentik.py +++ b/lifecycle/system_migrations/to_0_13_authentik.py @@ -4,7 +4,7 @@ from redis import Redis from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; +SQL_STATEMENT = """ ALTER TABLE passbook_audit_event RENAME TO authentik_audit_event; ALTER TABLE passbook_core_application RENAME TO authentik_core_application; ALTER TABLE passbook_core_group RENAME TO authentik_core_group; @@ -92,8 +92,7 @@ ALTER SEQUENCE passbook_stages_prompt_promptstage_validation_policies_id_seq REN UPDATE django_migrations SET app = replace(app, 'passbook', 'authentik'); UPDATE django_content_type SET app_label = replace(app_label, 'passbook', 'authentik'); - -END TRANSACTION;""" +""" class Migration(BaseMigration): @@ -104,18 +103,18 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() - # We also need to clean the cache to make sure no pickeled objects still exist - for db in [ - CONFIG.get("redis.message_queue_db"), - CONFIG.get("redis.cache_db"), - CONFIG.get("redis.ws_db"), - ]: - redis = Redis( - host=CONFIG.get("redis.host"), - port=6379, - db=db, - password=CONFIG.get("redis.password"), - ) - redis.flushall() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) + # We also need to clean the cache to make sure no pickeled objects still exist + for db in [ + CONFIG.get("redis.message_queue_db"), + CONFIG.get("redis.cache_db"), + CONFIG.get("redis.ws_db"), + ]: + redis = Redis( + host=CONFIG.get("redis.host"), + port=6379, + db=db, + password=CONFIG.get("redis.password"), + ) + redis.flushall() diff --git a/lifecycle/system_migrations/to_0_14_events..py b/lifecycle/system_migrations/to_0_14_events..py index 4745b8853..b1a0cc727 100644 --- a/lifecycle/system_migrations/to_0_14_events..py +++ b/lifecycle/system_migrations/to_0_14_events..py @@ -1,12 +1,9 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; +SQL_STATEMENT = """ALTER TABLE authentik_audit_event RENAME TO authentik_events_event; UPDATE django_migrations SET app = replace(app, 'authentik_audit', 'authentik_events'); -UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events'); - -END TRANSACTION;""" +UPDATE django_content_type SET app_label = replace(app_label, 'authentik_audit', 'authentik_events');""" class Migration(BaseMigration): @@ -17,5 +14,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) diff --git a/lifecycle/system_migrations/to_2021_3_authenticator.py b/lifecycle/system_migrations/to_2021_3_authenticator.py index 3dd895bdb..3b633fef1 100644 --- a/lifecycle/system_migrations/to_2021_3_authenticator.py +++ b/lifecycle/system_migrations/to_2021_3_authenticator.py @@ -1,7 +1,7 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; +SQL_STATEMENT = """ ALTER TABLE authentik_stages_otp_static_otpstaticstage RENAME TO authentik_stages_authenticator_static_otpstaticstage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_static', 'authentik_stages_authenticator_static'); @@ -13,8 +13,7 @@ UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_ ALTER TABLE authentik_stages_otp_validate_otpvalidatestage RENAME TO authentik_stages_authenticator_validate_otpvalidatestage; UPDATE django_migrations SET app = replace(app, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); UPDATE django_content_type SET app_label = replace(app_label, 'authentik_stages_otp_validate', 'authentik_stages_authenticator_validate'); - -END TRANSACTION;""" +""" class Migration(BaseMigration): @@ -26,5 +25,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) diff --git a/lifecycle/system_migrations/to_2023_1_hibp_remove.py b/lifecycle/system_migrations/to_2023_1_hibp_remove.py index 4c8b9e292..c43f6bb85 100644 --- a/lifecycle/system_migrations/to_2023_1_hibp_remove.py +++ b/lifecycle/system_migrations/to_2023_1_hibp_remove.py @@ -1,10 +1,8 @@ # flake8: noqa from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """BEGIN TRANSACTION; -DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; -DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp'; -END TRANSACTION;""" +SQL_STATEMENT = """DROP TABLE "authentik_policies_hibp_haveibeenpwendpolicy"; +DELETE FROM django_migrations WHERE app = 'authentik_policies_hibp';""" class Migration(BaseMigration): @@ -16,5 +14,5 @@ class Migration(BaseMigration): return bool(self.cur.rowcount) def run(self): - self.cur.execute(SQL_STATEMENT) - self.con.commit() + with self.con.transaction(): + self.cur.execute(SQL_STATEMENT) From 6f3fc22c9b96e34b2ff0b5969709b91b9a4c42e4 Mon Sep 17 00:00:00 2001 From: Jens L Date: Mon, 9 Oct 2023 00:08:16 +0200 Subject: [PATCH 25/41] providers/saml: add default RelayState value for IDP-initiated requests (#7100) Signed-off-by: Jens Langhammer --- authentik/providers/saml/api/providers.py | 1 + .../0013_samlprovider_default_relay_state.py | 21 +++ authentik/providers/saml/models.py | 4 + .../saml/processors/authn_request_parser.py | 5 +- .../saml/tests/test_auth_n_request.py | 8 + blueprints/schema.json | 155 +++--------------- schema.yml | 13 ++ .../admin/providers/saml/SAMLProviderForm.ts | 18 ++ web/xliff/de.xlf | 13 +- web/xliff/en.xlf | 13 +- web/xliff/es.xlf | 13 +- web/xliff/fr.xlf | 14 +- web/xliff/pl.xlf | 13 +- web/xliff/pseudo-LOCALE.xlf | 13 +- web/xliff/tr.xlf | 13 +- web/xliff/zh-Hans.xlf | 14 +- web/xliff/zh-Hant.xlf | 13 +- web/xliff/zh_TW.xlf | 13 +- 18 files changed, 182 insertions(+), 175 deletions(-) create mode 100644 authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py diff --git a/authentik/providers/saml/api/providers.py b/authentik/providers/saml/api/providers.py index 891289a08..226ec7e58 100644 --- a/authentik/providers/saml/api/providers.py +++ b/authentik/providers/saml/api/providers.py @@ -146,6 +146,7 @@ class SAMLProviderSerializer(ProviderSerializer): "signing_kp", "verification_kp", "sp_binding", + "default_relay_state", "url_download_metadata", "url_sso_post", "url_sso_redirect", diff --git a/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py b/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py new file mode 100644 index 000000000..5ece7f52d --- /dev/null +++ b/authentik/providers/saml/migrations/0013_samlprovider_default_relay_state.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.6 on 2023-10-08 20:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_providers_saml", "0012_managed"), + ] + + operations = [ + migrations.AddField( + model_name="samlprovider", + name="default_relay_state", + field=models.TextField( + blank=True, + default="", + help_text="Default relay_state value for IDP-initiated logins", + ), + ), + ] diff --git a/authentik/providers/saml/models.py b/authentik/providers/saml/models.py index e92f62943..1a706df8e 100644 --- a/authentik/providers/saml/models.py +++ b/authentik/providers/saml/models.py @@ -138,6 +138,10 @@ class SAMLProvider(Provider): verbose_name=_("Signing Keypair"), ) + default_relay_state = models.TextField( + default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins") + ) + @property def launch_url(self) -> Optional[str]: """Use IDP-Initiated SAML flow as launch URL""" diff --git a/authentik/providers/saml/processors/authn_request_parser.py b/authentik/providers/saml/processors/authn_request_parser.py index 30eddf0d3..5587cb695 100644 --- a/authentik/providers/saml/processors/authn_request_parser.py +++ b/authentik/providers/saml/processors/authn_request_parser.py @@ -175,4 +175,7 @@ class AuthNRequestParser: def idp_initiated(self) -> AuthNRequest: """Create IdP Initiated AuthNRequest""" - return AuthNRequest() + relay_state = None + if self.provider.default_relay_state != "": + relay_state = self.provider.default_relay_state + return AuthNRequest(relay_state=relay_state) diff --git a/authentik/providers/saml/tests/test_auth_n_request.py b/authentik/providers/saml/tests/test_auth_n_request.py index 69326bd5f..df19eb736 100644 --- a/authentik/providers/saml/tests/test_auth_n_request.py +++ b/authentik/providers/saml/tests/test_auth_n_request.py @@ -8,6 +8,7 @@ from authentik.blueprints.tests import apply_blueprint from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow from authentik.crypto.models import CertificateKeyPair from authentik.events.models import Event, EventAction +from authentik.lib.generators import generate_id from authentik.lib.tests.utils import get_request from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider from authentik.providers.saml.processors.assertion import AssertionProcessor @@ -264,3 +265,10 @@ class TestAuthNRequest(TestCase): events.first().context["message"], "Failed to evaluate property-mapping: 'test'", ) + + def test_idp_initiated(self): + """Test IDP-initiated login""" + self.provider.default_relay_state = generate_id() + request = AuthNRequestParser(self.provider).idp_initiated() + self.assertEqual(request.id, None) + self.assertEqual(request.relay_state, self.provider.default_relay_state) diff --git a/blueprints/schema.json b/blueprints/schema.json index 7f7757a28..9dc77b796 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -4826,6 +4826,11 @@ ], "title": "Service Provider Binding", "description": "This determines how authentik sends the response back to the Service Provider." + }, + "default_relay_state": { + "type": "string", + "title": "Default relay state", + "description": "Default relay_state value for IDP-initiated logins" } }, "required": [] @@ -7427,146 +7432,32 @@ "model_authentik_stages_invitation.invitation": { "type": "object", "properties": { + "name": { + "type": "string", + "maxLength": 50, + "minLength": 1, + "pattern": "^[-a-zA-Z0-9_]+$", + "title": "Name" + }, "expires": { "type": "string", "format": "date-time", "title": "Expires" }, - "user": { + "fixed_data": { "type": "object", - "properties": { - "username": { - "type": "string", - "maxLength": 150, - "minLength": 1, - "title": "Username" - }, - "name": { - "type": "string", - "title": "Name", - "description": "User's display name." - }, - "is_active": { - "type": "boolean", - "title": "Active", - "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts." - }, - "last_login": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "title": "Last login" - }, - "groups": { - "type": "array", - "items": { - "type": "integer" - }, - "title": "Groups" - }, - "email": { - "type": "string", - "format": "email", - "maxLength": 254, - "title": "Email address" - }, - "attributes": { - "type": "object", - "additionalProperties": true, - "title": "Attributes" - }, - "path": { - "type": "string", - "minLength": 1, - "title": "Path" - }, - "type": { - "type": "string", - "enum": [ - "internal", - "external", - "service_account", - "internal_service_account" - ], - "title": "Type" - } - }, - "required": [ - "username", - "name" - ], - "title": "User" + "additionalProperties": true, + "title": "Fixed data" }, - "application": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "title": "Name", - "description": "Application's display Name." - }, - "slug": { - "type": "string", - "maxLength": 50, - "minLength": 1, - "pattern": "^[-a-zA-Z0-9_]+$", - "title": "Slug", - "description": "Internal application name, used in URLs." - }, - "provider": { - "type": "integer", - "title": "Provider" - }, - "backchannel_providers": { - "type": "array", - "items": { - "type": "integer" - }, - "title": "Backchannel providers" - }, - "open_in_new_tab": { - "type": "boolean", - "title": "Open in new tab", - "description": "Open launch URL in a new browser tab or window." - }, - "meta_launch_url": { - "type": "string", - "title": "Meta launch url" - }, - "meta_description": { - "type": "string", - "title": "Meta description" - }, - "meta_publisher": { - "type": "string", - "title": "Meta publisher" - }, - "policy_engine_mode": { - "type": "string", - "enum": [ - "all", - "any" - ], - "title": "Policy engine mode" - }, - "group": { - "type": "string", - "title": "Group" - } - }, - "required": [ - "name", - "slug" - ], - "title": "Application" + "single_use": { + "type": "boolean", + "title": "Single use", + "description": "When enabled, the invitation will be deleted after usage." }, - "permissions": { - "type": "string", - "minLength": 1, - "title": "Permissions" + "flow": { + "type": "integer", + "title": "Flow", + "description": "When set, only the configured flow can use this invitation." } }, "required": [] diff --git a/schema.yml b/schema.yml index 5b682a7ff..1d36b4530 100644 --- a/schema.yml +++ b/schema.yml @@ -16292,6 +16292,10 @@ paths: schema: type: string format: uuid + - in: query + name: default_relay_state + schema: + type: string - in: query name: digest_algorithm schema: @@ -36303,6 +36307,9 @@ components: * `redirect` - Redirect * `post` - Post + default_relay_state: + type: string + description: Default relay_state value for IDP-initiated logins PatchedSAMLSourceRequest: type: object description: SAMLSource Serializer @@ -38480,6 +38487,9 @@ components: * `redirect` - Redirect * `post` - Post + default_relay_state: + type: string + description: Default relay_state value for IDP-initiated logins url_download_metadata: type: string description: Get metadata download URL @@ -38624,6 +38634,9 @@ components: * `redirect` - Redirect * `post` - Post + default_relay_state: + type: string + description: Default relay_state value for IDP-initiated logins required: - acs_url - authorization_flow diff --git a/web/src/admin/providers/saml/SAMLProviderForm.ts b/web/src/admin/providers/saml/SAMLProviderForm.ts index e74fa76b3..012abdcae 100644 --- a/web/src/admin/providers/saml/SAMLProviderForm.ts +++ b/web/src/admin/providers/saml/SAMLProviderForm.ts @@ -318,6 +318,24 @@ export class SAMLProviderFormPage extends ModelForm {

+ + +

+ ${msg( + "When using IDP-initiated logins, the relay state will be set to this value.", + )} +

+ +
Validate SSL Certificates of upstream servers. SSL-Zertifikate der Upstream-Server prüfen. - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Verwenden Sie diesen Provider mit auth_request von Nginx oder forwardAuth von Traefik. Jede Anwendung/Domäne benötigt ihren eigenen Provider. Zusätzlich muss auf jeder Domain /outpost.goauthentik.io an den Außenposten weitergeleitet werden (wenn Sie einen gemanagten Außenposten verwenden, wird dies für Sie erledigt). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. Verwenden Sie diesen Anbieter mit auth_request von nginx oder forwardAuth von traefik. Pro Root-Domain wird nur ein einziger Anbieter benötigt. Sie können keine Autorisierung pro Anwendung vornehmen, aber Sie müssen nicht für jede Anwendung einen Anbieter erstellen. @@ -5925,6 +5921,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index 658eba084..66b8f5427 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -1041,10 +1041,6 @@ Validate SSL Certificates of upstream servers. Validate SSL Certificates of upstream servers. - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. @@ -6239,6 +6235,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index cc46a33f8..f0995aeb7 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -976,10 +976,6 @@ Validate SSL Certificates of upstream servers. Validar los certificados SSL de los servidores ascendentes. - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Use este proveedor con auth_request de nginx o ForwardAuth de traefik. Cada aplicación/dominio necesita su propio proveedor. Además, en cada dominio, /outpost.goauthentik.io debe enrutarse al puesto avanzado (cuando se usa un puesto avanzado administrado, esto se hace por usted). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. Use este proveedor con auth_request de nginx o ForwardAuth de traefik. Solo se requiere un único proveedor por dominio raíz. No puede realizar la autorización por solicitud, pero no tiene que crear un proveedor para cada solicitud. @@ -5833,6 +5829,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index 00909b58a..332d2ca4d 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -1295,11 +1295,6 @@ Il y a jour(s) Validate SSL Certificates of upstream servers. Valider les certificats SSL des serveurs amonts. - - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. @@ -7816,6 +7811,15 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti WebAuthn not supported by browser. WebAuthn n'est pas supporté pas ce navigateur. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index 99d097f04..b1456ad59 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -1002,10 +1002,6 @@ Validate SSL Certificates of upstream servers. Sprawdź poprawność certyfikatów SSL serwerów nadrzędnych. - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Użyj tego dostawcy z auth_request nginx lub forwardAuth traefik. Każda aplikacja/domena potrzebuje własnego dostawcy. Dodatkowo w każdej domenie /outpost.goauthentik.io musi być przekierowany do placówki (w przypadku korzystania z zarządzanej placówki jest to zrobione za Ciebie). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. Użyj tego dostawcy z auth_request nginx lub forwardAuth traefik. Tylko jeden dostawca jest wymagany na domenę główną. Nie możesz wykonać autoryzacji dla aplikacji, ale nie musisz tworzyć dostawcy dla każdej aplikacji. @@ -6072,6 +6068,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index dd53b9b84..a14093264 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -1025,10 +1025,6 @@ Validate SSL Certificates of upstream servers. - - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. @@ -6174,6 +6170,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 34c746642..f304d5ae3 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -975,10 +975,6 @@ Validate SSL Certificates of upstream servers. Yayın yukarı akış sunucularının SSL Sertifikalarını doğrulayın. - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - Bu sağlayıcıyı nginx'in auth_request veya traefik's forwardAuth ile kullanın. Her uygulama/etki alanının kendi sağlayıcısına ihtiyacı vardır. Ayrıca, her etki alanında /outpost.goauthentik.io üsse yönlendirilmelidir (manged bir üs kullanırken, bu sizin için yapılır). - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. Bu sağlayıcıyı nginx'in auth_request veya traefik'in forwardAuth ile kullanın. Kök etki alanı başına yalnızca tek bir sağlayıcı gereklidir. Uygulama başına yetkilendirme yapamazsınız, ancak her uygulama için bir sağlayıcı oluşturmanız gerekmez. @@ -5826,6 +5822,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index a760ca993..8e262f221 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1295,11 +1295,6 @@ Validate SSL Certificates of upstream servers. 验证上游服务器的 SSL 证书。 - - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - 与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。 - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. @@ -7818,6 +7813,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. 浏览器不支持 WebAuthn。 + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 2919040eb..3389edfd1 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -983,10 +983,6 @@ Validate SSL Certificates of upstream servers. 验证上游服务器的 SSL 证书。 - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - 将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个应用程序/域都需要自己的提供商。此外,在每个域上,/outpost.goauthentik.io必须路由到 Outpost(使用托管的 Outpost 时,这是为您完成的)。 - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. 将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个根域只需要一个提供程序。您无法执行每个应用程序的授权,但不必为每个应用程序创建提供程序。 @@ -5878,6 +5874,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index a4c2ec374..8392c2a81 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -983,10 +983,6 @@ Validate SSL Certificates of upstream servers. 验证上游服务器的 SSL 证书。 - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - 将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个应用程序/域都需要自己的提供商。此外,在每个域上,/outpost.goauthentik.io必须路由到 Outpost(使用托管的 Outpost 时,这是为您完成的)。 - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. 将此提供程序与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用。每个根域只需要一个提供程序。您无法执行每个应用程序的授权,但不必为每个应用程序创建提供程序。 @@ -5877,6 +5873,15 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + + + Default relay state + + + When using IDP-initiated logins, the relay state will be set to this value. From 962f9aad111789e82506f91301af20d20177d221 Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Sun, 8 Oct 2023 22:41:19 +0000 Subject: [PATCH 26/41] web: bump API Client version (#7101) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 2c7b379f7..15266839d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.2", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.8.3-1696335052", + "@goauthentik/api": "^2023.8.3-1696802918", "@lit-labs/context": "^0.4.1", "@lit-labs/task": "^3.0.2", "@lit/localize": "^0.11.4", @@ -2882,9 +2882,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.8.3-1696335052", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696335052.tgz", - "integrity": "sha512-MFgMdkk8NVvJfgU9RfZlP8ypUjH5xhBtnannnFWDJLuvsYxyyaD6Rbj2cLE2KSaIGHEpbsmzeW3eUy7ZRjpKOw==" + "version": "2023.8.3-1696802918", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696802918.tgz", + "integrity": "sha512-OEmk3PQrY0r01wvGCBPn3uVevi7odZSD99LpgT5RyFC8+8ZkyXi2x8EfhsSHYiCbFvwWIg2cgTLWi5TILOoQzw==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index e899eafc3..283202de0 100644 --- a/web/package.json +++ b/web/package.json @@ -35,7 +35,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.2", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.8.3-1696335052", + "@goauthentik/api": "^2023.8.3-1696802918", "@lit-labs/context": "^0.4.1", "@lit-labs/task": "^3.0.2", "@lit/localize": "^0.11.4", From 30da53f3d702c4270c441914586ca474fc1ed4ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:06:16 +0200 Subject: [PATCH 27/41] web: bump the storybook group in /web with 1 update (#7102) Bumps the storybook group in /web with 1 update: [eslint-plugin-storybook](https://github.com/storybookjs/eslint-plugin-storybook). - [Release notes](https://github.com/storybookjs/eslint-plugin-storybook/releases) - [Changelog](https://github.com/storybookjs/eslint-plugin-storybook/blob/main/CHANGELOG.md) - [Commits](https://github.com/storybookjs/eslint-plugin-storybook/compare/v0.6.14...v0.6.15) --- updated-dependencies: - dependency-name: eslint-plugin-storybook dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 15266839d..429514591 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -80,7 +80,7 @@ "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-lit": "^1.9.1", "eslint-plugin-sonarjs": "^0.21.0", - "eslint-plugin-storybook": "^0.6.14", + "eslint-plugin-storybook": "^0.6.15", "lit-analyzer": "^1.2.1", "npm-run-all": "^4.1.5", "prettier": "^3.0.3", @@ -13882,9 +13882,9 @@ } }, "node_modules/eslint-plugin-storybook": { - "version": "0.6.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.14.tgz", - "integrity": "sha512-IeYigPur/MvESNDo43Z+Z5UvlcEVnt0dDZmnw1odi9X2Th1R3bpGyOZsHXb9bp1pFecOpRUuoMG5xdID2TwwOg==", + "version": "0.6.15", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.15.tgz", + "integrity": "sha512-lAGqVAJGob47Griu29KXYowI4G7KwMoJDOkEip8ujikuDLxU+oWJ1l0WL6F2oDO4QiyUFXvtDkEkISMOPzo+7w==", "dev": true, "dependencies": { "@storybook/csf": "^0.0.1", diff --git a/web/package.json b/web/package.json index 283202de0..8060dc776 100644 --- a/web/package.json +++ b/web/package.json @@ -98,7 +98,7 @@ "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-lit": "^1.9.1", "eslint-plugin-sonarjs": "^0.21.0", - "eslint-plugin-storybook": "^0.6.14", + "eslint-plugin-storybook": "^0.6.15", "lit-analyzer": "^1.2.1", "npm-run-all": "^4.1.5", "prettier": "^3.0.3", From f192c665d9c7c4001efc9bb9248fb77b9513d1f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:06:23 +0200 Subject: [PATCH 28/41] web: bump the eslint group in /web with 1 update (#7103) Bumps the eslint group in /web with 1 update: [eslint](https://github.com/eslint/eslint). - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.50.0...v8.51.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 16 ++++++++-------- web/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 429514591..dbf922dad 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -75,7 +75,7 @@ "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", - "eslint": "^8.50.0", + "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-lit": "^1.9.1", @@ -2796,9 +2796,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -13778,15 +13778,15 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", diff --git a/web/package.json b/web/package.json index 8060dc776..f331ed97a 100644 --- a/web/package.json +++ b/web/package.json @@ -93,7 +93,7 @@ "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", - "eslint": "^8.50.0", + "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-custom-elements": "0.0.8", "eslint-plugin-lit": "^1.9.1", From f60b65c25f68b0885c20cbcf613783ecc1ad3cc8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:06:32 +0200 Subject: [PATCH 29/41] web: bump @rollup/plugin-node-resolve from 15.2.2 to 15.2.3 in /web (#7104) Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 15.2.2 to 15.2.3. - [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/node-resolve-v15.2.3/packages/node-resolve) --- updated-dependencies: - dependency-name: "@rollup/plugin-node-resolve" 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> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index dbf922dad..a1e6642de 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -57,7 +57,7 @@ "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.5", - "@rollup/plugin-node-resolve": "^15.2.2", + "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", @@ -4396,9 +4396,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.2.tgz", - "integrity": "sha512-f64bU4OKqV0yihtxFemmuf0oj37pToCFMISCA+sJbbIAl5wcpbRO9XgWNWb1tDiWQJUcPxo6V0l59hcuZOQ3kw==", + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", diff --git a/web/package.json b/web/package.json index f331ed97a..3fec6d8a9 100644 --- a/web/package.json +++ b/web/package.json @@ -75,7 +75,7 @@ "@lit/localize-tools": "^0.6.10", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.5", - "@rollup/plugin-node-resolve": "^15.2.2", + "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^5.0.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", From 4db365c94717e5f34fbed37b3bb3dd92a6248c96 Mon Sep 17 00:00:00 2001 From: Jens L Date: Mon, 9 Oct 2023 01:06:52 +0200 Subject: [PATCH 30/41] providers/proxy: improve SLO by backchannel logging out sessions (#7099) * outposts: add support for provider-specific websocket messages Signed-off-by: Jens Langhammer * providers/proxy: add custom signal on logout to logout in provider Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/outposts/channels.py | 14 ++++++ authentik/outposts/tasks.py | 4 +- authentik/providers/proxy/apps.py | 4 ++ authentik/providers/proxy/signals.py | 20 ++++++++ authentik/providers/proxy/tasks.py | 20 ++++++++ blueprints/system/providers-proxy.yaml | 1 + internal/outpost/ak/api.go | 8 +++ internal/outpost/ak/api_ws.go | 5 ++ internal/outpost/ak/api_ws_msg.go | 2 + .../proxyv2/application/application.go | 4 +- .../outpost/proxyv2/application/claims.go | 3 +- .../outpost/proxyv2/application/session.go | 6 +-- internal/outpost/proxyv2/proxyv2.go | 1 + internal/outpost/proxyv2/ws.go | 49 +++++++++++++++++++ 14 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 authentik/providers/proxy/signals.py create mode 100644 internal/outpost/proxyv2/ws.go diff --git a/authentik/outposts/channels.py b/authentik/outposts/channels.py index 8b3f978ac..f0b656a47 100644 --- a/authentik/outposts/channels.py +++ b/authentik/outposts/channels.py @@ -27,6 +27,9 @@ class WebsocketMessageInstruction(IntEnum): # Message sent by us to trigger an Update TRIGGER_UPDATE = 2 + # Provider specific message + PROVIDER_SPECIFIC = 3 + @dataclass(slots=True) class WebsocketMessage: @@ -131,3 +134,14 @@ class OutpostConsumer(AuthJsonConsumer): self.send_json( asdict(WebsocketMessage(instruction=WebsocketMessageInstruction.TRIGGER_UPDATE)) ) + + def event_provider_specific(self, event): + """Event handler which can be called by provider-specific + implementations to send specific messages to the outpost""" + self.send_json( + asdict( + WebsocketMessage( + instruction=WebsocketMessageInstruction.PROVIDER_SPECIFIC, args=event + ) + ) + ) diff --git a/authentik/outposts/tasks.py b/authentik/outposts/tasks.py index 227127352..ddb0d5352 100644 --- a/authentik/outposts/tasks.py +++ b/authentik/outposts/tasks.py @@ -5,7 +5,6 @@ from socket import gethostname from typing import Any, Optional from urllib.parse import urlparse -import yaml from asgiref.sync import async_to_sync from channels.layers import get_channel_layer from django.core.cache import cache @@ -16,6 +15,7 @@ from docker.constants import DEFAULT_UNIX_SOCKET from kubernetes.config.incluster_config import SERVICE_TOKEN_FILENAME from kubernetes.config.kube_config import KUBE_CONFIG_DEFAULT_LOCATION from structlog.stdlib import get_logger +from yaml import safe_load from authentik.events.monitored_tasks import ( MonitoredTask, @@ -279,7 +279,7 @@ def outpost_connection_discovery(self: MonitoredTask): with kubeconfig_path.open("r", encoding="utf8") as _kubeconfig: KubernetesServiceConnection.objects.create( name=kubeconfig_local_name, - kubeconfig=yaml.safe_load(_kubeconfig), + kubeconfig=safe_load(_kubeconfig), ) unix_socket_path = urlparse(DEFAULT_UNIX_SOCKET).path socket = Path(unix_socket_path) diff --git a/authentik/providers/proxy/apps.py b/authentik/providers/proxy/apps.py index 5e49fe181..4e1a9a883 100644 --- a/authentik/providers/proxy/apps.py +++ b/authentik/providers/proxy/apps.py @@ -9,3 +9,7 @@ class AuthentikProviderProxyConfig(ManagedAppConfig): label = "authentik_providers_proxy" verbose_name = "authentik Providers.Proxy" default = True + + def reconcile_load_providers_proxy_signals(self): + """Load proxy signals""" + self.import_module("authentik.providers.proxy.signals") diff --git a/authentik/providers/proxy/signals.py b/authentik/providers/proxy/signals.py new file mode 100644 index 000000000..3e199d3c3 --- /dev/null +++ b/authentik/providers/proxy/signals.py @@ -0,0 +1,20 @@ +"""Proxy provider signals""" +from django.contrib.auth.signals import user_logged_out +from django.db.models.signals import pre_delete +from django.dispatch import receiver +from django.http import HttpRequest + +from authentik.core.models import AuthenticatedSession, User +from authentik.providers.proxy.tasks import proxy_on_logout + + +@receiver(user_logged_out) +def logout_proxy_revoke_direct(sender: type[User], request: HttpRequest, **_): + """Catch logout by direct logout and forward to proxy providers""" + proxy_on_logout.delay(request.session.session_key) + + +@receiver(pre_delete, sender=AuthenticatedSession) +def logout_proxy_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_): + """Catch logout by expiring sessions being deleted""" + proxy_on_logout.delay(instance.session_key) diff --git a/authentik/providers/proxy/tasks.py b/authentik/providers/proxy/tasks.py index a5a4dc45f..630b0d186 100644 --- a/authentik/providers/proxy/tasks.py +++ b/authentik/providers/proxy/tasks.py @@ -1,6 +1,9 @@ """proxy provider tasks""" +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer from django.db import DatabaseError, InternalError, ProgrammingError +from authentik.outposts.models import Outpost, OutpostState, OutpostType from authentik.providers.proxy.models import ProxyProvider from authentik.root.celery import CELERY_APP @@ -13,3 +16,20 @@ def proxy_set_defaults(): for provider in ProxyProvider.objects.all(): provider.set_oauth_defaults() provider.save() + + +@CELERY_APP.task() +def proxy_on_logout(session_id: str): + """Update outpost instances connected to a single outpost""" + layer = get_channel_layer() + for outpost in Outpost.objects.filter(type=OutpostType.PROXY): + for state in OutpostState.for_outpost(outpost): + for channel in state.channel_ids: + async_to_sync(layer.send)( + channel, + { + "type": "event.provider.specific", + "sub_type": "logout", + "session_id": session_id, + }, + ) diff --git a/blueprints/system/providers-proxy.yaml b/blueprints/system/providers-proxy.yaml index 1214d157d..0086645a8 100644 --- a/blueprints/system/providers-proxy.yaml +++ b/blueprints/system/providers-proxy.yaml @@ -15,6 +15,7 @@ entries: # This mapping is used by the authentik proxy. It passes extra user attributes, # which are used for example for the HTTP-Basic Authentication mapping. return { + "sid": request.http_request.session.session_key, "ak_proxy": { "user_attributes": request.user.group_attributes(request), "is_superuser": request.user.is_superuser, diff --git a/internal/outpost/ak/api.go b/internal/outpost/ak/api.go index cfdb41dd0..f6003c02f 100644 --- a/internal/outpost/ak/api.go +++ b/internal/outpost/ak/api.go @@ -22,6 +22,8 @@ import ( log "github.com/sirupsen/logrus" ) +type WSHandler func(ctx context.Context, args map[string]interface{}) + const ConfigLogLevel = "log_level" // APIController main controller which connects to the authentik api via http and ws @@ -42,6 +44,7 @@ type APIController struct { lastWsReconnect time.Time wsIsReconnecting bool wsBackoffMultiplier int + wsHandlers []WSHandler refreshHandlers []func() instanceUUID uuid.UUID @@ -106,6 +109,7 @@ func NewAPIController(akURL url.URL, token string) *APIController { reloadOffset: time.Duration(rand.Intn(10)) * time.Second, instanceUUID: uuid.New(), Outpost: outpost, + wsHandlers: []WSHandler{}, wsBackoffMultiplier: 1, refreshHandlers: make([]func(), 0), } @@ -156,6 +160,10 @@ func (a *APIController) AddRefreshHandler(handler func()) { a.refreshHandlers = append(a.refreshHandlers, handler) } +func (a *APIController) AddWSHandler(handler WSHandler) { + a.wsHandlers = append(a.wsHandlers, handler) +} + func (a *APIController) OnRefresh() error { // Because we don't know the outpost UUID, we simply do a list and pick the first // The service account this token belongs to should only have access to a single outpost diff --git a/internal/outpost/ak/api_ws.go b/internal/outpost/ak/api_ws.go index 681b26fa4..24c5099f4 100644 --- a/internal/outpost/ak/api_ws.go +++ b/internal/outpost/ak/api_ws.go @@ -1,6 +1,7 @@ package ak import ( + "context" "crypto/tls" "fmt" "net/http" @@ -145,6 +146,10 @@ func (ac *APIController) startWSHandler() { "build": constants.BUILD("tagged"), }).SetToCurrentTime() } + } else if wsMsg.Instruction == WebsocketInstructionProviderSpecific { + for _, h := range ac.wsHandlers { + h(context.Background(), wsMsg.Args) + } } } } diff --git a/internal/outpost/ak/api_ws_msg.go b/internal/outpost/ak/api_ws_msg.go index f1f2e3aa8..cedecb93d 100644 --- a/internal/outpost/ak/api_ws_msg.go +++ b/internal/outpost/ak/api_ws_msg.go @@ -9,6 +9,8 @@ const ( WebsocketInstructionHello websocketInstruction = 1 // WebsocketInstructionTriggerUpdate Code received to trigger a config update WebsocketInstructionTriggerUpdate websocketInstruction = 2 + // WebsocketInstructionProviderSpecific Code received to trigger some provider specific function + WebsocketInstructionProviderSpecific websocketInstruction = 3 ) type websocketMessage struct { diff --git a/internal/outpost/proxyv2/application/application.go b/internal/outpost/proxyv2/application/application.go index 657bcbec7..eae4c6774 100644 --- a/internal/outpost/proxyv2/application/application.go +++ b/internal/outpost/proxyv2/application/application.go @@ -280,7 +280,9 @@ func (a *Application) handleSignOut(rw http.ResponseWriter, r *http.Request) { "id_token_hint": []string{cc.RawToken}, } redirect += "?" + uv.Encode() - err = a.Logout(r.Context(), cc.Sub) + err = a.Logout(r.Context(), func(c Claims) bool { + return c.Sub == cc.Sub + }) if err != nil { a.log.WithError(err).Warning("failed to logout of other sessions") } diff --git a/internal/outpost/proxyv2/application/claims.go b/internal/outpost/proxyv2/application/claims.go index bd34e1309..32f4d26eb 100644 --- a/internal/outpost/proxyv2/application/claims.go +++ b/internal/outpost/proxyv2/application/claims.go @@ -11,10 +11,11 @@ type Claims struct { Exp int `json:"exp"` Email string `json:"email"` Verified bool `json:"email_verified"` - Proxy *ProxyClaims `json:"ak_proxy"` Name string `json:"name"` PreferredUsername string `json:"preferred_username"` Groups []string `json:"groups"` + Sid string `json:"sid"` + Proxy *ProxyClaims `json:"ak_proxy"` RawToken string } diff --git a/internal/outpost/proxyv2/application/session.go b/internal/outpost/proxyv2/application/session.go index 739b23e84..55d2bbb46 100644 --- a/internal/outpost/proxyv2/application/session.go +++ b/internal/outpost/proxyv2/application/session.go @@ -88,7 +88,7 @@ func (a *Application) getAllCodecs() []securecookie.Codec { return cs } -func (a *Application) Logout(ctx context.Context, sub string) error { +func (a *Application) Logout(ctx context.Context, filter func(c Claims) bool) error { if _, ok := a.sessions.(*sessions.FilesystemStore); ok { files, err := os.ReadDir(os.TempDir()) if err != nil { @@ -118,7 +118,7 @@ func (a *Application) Logout(ctx context.Context, sub string) error { continue } claims := s.Values[constants.SessionClaims].(Claims) - if claims.Sub == sub { + if filter(claims) { a.log.WithField("path", fullPath).Trace("deleting session") err := os.Remove(fullPath) if err != nil { @@ -153,7 +153,7 @@ func (a *Application) Logout(ctx context.Context, sub string) error { continue } claims := c.(Claims) - if claims.Sub == sub { + if filter(claims) { a.log.WithField("key", key).Trace("deleting session") _, err := client.Del(ctx, key).Result() if err != nil { diff --git a/internal/outpost/proxyv2/proxyv2.go b/internal/outpost/proxyv2/proxyv2.go index 154f79e34..70364957f 100644 --- a/internal/outpost/proxyv2/proxyv2.go +++ b/internal/outpost/proxyv2/proxyv2.go @@ -65,6 +65,7 @@ func NewProxyServer(ac *ak.APIController) *ProxyServer { globalMux.PathPrefix("/outpost.goauthentik.io/static").HandlerFunc(s.HandleStatic) globalMux.Path("/outpost.goauthentik.io/ping").HandlerFunc(sentryutils.SentryNoSample(s.HandlePing)) rootMux.PathPrefix("/").HandlerFunc(s.Handle) + ac.AddWSHandler(s.handleWSMessage) return s } diff --git a/internal/outpost/proxyv2/ws.go b/internal/outpost/proxyv2/ws.go new file mode 100644 index 000000000..b75ba50fd --- /dev/null +++ b/internal/outpost/proxyv2/ws.go @@ -0,0 +1,49 @@ +package proxyv2 + +import ( + "context" + + "github.com/mitchellh/mapstructure" + "goauthentik.io/internal/outpost/proxyv2/application" +) + +type WSProviderSubType string + +const ( + WSProviderSubTypeLogout WSProviderSubType = "logout" +) + +type WSProviderMsg struct { + SubType WSProviderSubType `mapstructure:"sub_type"` + SessionID string `mapstructure:"session_id"` +} + +func ParseWSProvider(args map[string]interface{}) (*WSProviderMsg, error) { + msg := &WSProviderMsg{} + err := mapstructure.Decode(args, &msg) + if err != nil { + return nil, err + } + return msg, nil +} + +func (ps *ProxyServer) handleWSMessage(ctx context.Context, args map[string]interface{}) { + msg, err := ParseWSProvider(args) + if err != nil { + ps.log.WithError(err).Warning("invalid provider-specific ws message") + return + } + switch msg.SubType { + case WSProviderSubTypeLogout: + for _, p := range ps.apps { + err := p.Logout(ctx, func(c application.Claims) bool { + return c.Sid == msg.SessionID + }) + if err != nil { + ps.log.WithField("provider", p.Host).WithError(err).Warning("failed to logout") + } + } + default: + ps.log.WithField("sub_type", msg.SubType).Warning("invalid sub_type") + } +} From d1bef0ce48197f0648d5076dfe548cc9214a5737 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:51:04 +0200 Subject: [PATCH 31/41] web: bump the eslint group in /tests/wdio with 1 update (#7107) Bumps the eslint group in /tests/wdio with 1 update: [eslint](https://github.com/eslint/eslint). - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.50.0...v8.51.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 16 ++++++++-------- tests/wdio/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 22492829e..c63e0b12e 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -13,7 +13,7 @@ "@wdio/local-runner": "^8.16.20", "@wdio/mocha-framework": "^8.16.17", "@wdio/spec-reporter": "^8.16.17", - "eslint": "^8.49.0", + "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.21.0", "npm-run-all": "^4.1.5", @@ -340,9 +340,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2945,15 +2945,15 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 84f70256a..3b2337fd2 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -10,7 +10,7 @@ "@wdio/local-runner": "^8.16.20", "@wdio/mocha-framework": "^8.16.17", "@wdio/spec-reporter": "^8.16.17", - "eslint": "^8.49.0", + "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.21.0", "npm-run-all": "^4.1.5", From 1b0024518b1ad135e12b727f4a9b6d41f4821a39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:51:21 +0200 Subject: [PATCH 32/41] core: bump golang.org/x/oauth2 from 0.12.0 to 0.13.0 (#7106) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.12.0 to 0.13.0. - [Commits](https://github.com/golang/oauth2/compare/v0.12.0...v0.13.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index cc8e33016..6a36e2a64 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/gorilla/sessions v1.2.1 github.com/gorilla/websocket v1.5.0 github.com/jellydator/ttlcache/v3 v3.1.0 + github.com/mitchellh/mapstructure v1.5.0 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/pires/go-proxyproto v0.7.0 github.com/prometheus/client_golang v1.17.0 @@ -28,7 +29,7 @@ require ( github.com/stretchr/testify v1.8.4 goauthentik.io/api/v3 v3.2023083.4 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab - golang.org/x/oauth2 v0.12.0 + golang.org/x/oauth2 v0.13.0 golang.org/x/sync v0.4.0 gopkg.in/yaml.v2 v2.4.0 layeh.com/radius v0.0.0-20210819152912-ad72663a72ab @@ -60,7 +61,6 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -72,9 +72,9 @@ require ( go.mongodb.org/mongo-driver v1.11.3 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.16.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 0d025a2c4..f41cdf62e 100644 --- a/go.sum +++ b/go.sum @@ -359,8 +359,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -427,16 +428,16 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -490,8 +491,9 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= From 026dfadb59002174977b678d8e171839e4358a5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:52:05 +0200 Subject: [PATCH 33/41] core: bump goauthentik.io/api/v3 from 3.2023083.4 to 3.2023083.5 (#7105) Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2023083.4 to 3.2023083.5. - [Release notes](https://github.com/goauthentik/client-go/releases) - [Commits](https://github.com/goauthentik/client-go/compare/v3.2023083.4...v3.2023083.5) --- updated-dependencies: - dependency-name: goauthentik.io/api/v3 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> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6a36e2a64..a1943cc8d 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - goauthentik.io/api/v3 v3.2023083.4 + goauthentik.io/api/v3 v3.2023083.5 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.13.0 golang.org/x/sync v0.4.0 diff --git a/go.sum b/go.sum index f41cdf62e..7d02c5bc8 100644 --- a/go.sum +++ b/go.sum @@ -346,8 +346,8 @@ go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvx go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -goauthentik.io/api/v3 v3.2023083.4 h1:WIi2+LFfBTvhxcbH/WqvhY/4EsX8bAN6mrPODq02B/w= -goauthentik.io/api/v3 v3.2023083.4/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023083.5 h1:U9/+QWIVpsfZCZivMAsG6E6dq3/4wT5qt/k7uUC9rZc= +goauthentik.io/api/v3 v3.2023083.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= From ab1b3b09d6e303219dbd033585b720f22655a676 Mon Sep 17 00:00:00 2001 From: horego <40524748+horego@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:34:38 +0200 Subject: [PATCH 34/41] core/api: add uuid field to core api user http response (#7110) * feat: Add uuid field to core api user response * update schema Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Co-authored-by: hor Co-authored-by: Jens Langhammer --- authentik/core/api/users.py | 1 + schema.yml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/authentik/core/api/users.py b/authentik/core/api/users.py index 09a5dc553..be59dc1c1 100644 --- a/authentik/core/api/users.py +++ b/authentik/core/api/users.py @@ -190,6 +190,7 @@ class UserSerializer(ModelSerializer): "uid", "path", "type", + "uuid", ] extra_kwargs = { "name": {"allow_blank": True}, diff --git a/schema.yml b/schema.yml index 1d36b4530..03eed6d01 100644 --- a/schema.yml +++ b/schema.yml @@ -40155,6 +40155,10 @@ components: type: string type: $ref: '#/components/schemas/UserTypeEnum' + uuid: + type: string + format: uuid + readOnly: true required: - avatar - groups_obj @@ -40163,6 +40167,7 @@ components: - pk - uid - username + - uuid UserAccountRequest: type: object description: Account adding/removing operations From 8ad7339cf106d49e292b9a0243d8e6c52bd614f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:34:46 +0200 Subject: [PATCH 35/41] web: bump the wdio group in /tests/wdio with 4 updates (#7108) Bumps the wdio group in /tests/wdio with 4 updates: [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli), [@wdio/local-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-local-runner), [@wdio/mocha-framework](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-mocha-framework) and [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter). Updates `@wdio/cli` from 8.16.20 to 8.16.22 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.22/packages/wdio-cli) Updates `@wdio/local-runner` from 8.16.20 to 8.16.22 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.22/packages/wdio-local-runner) Updates `@wdio/mocha-framework` from 8.16.17 to 8.16.22 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.22/packages/wdio-mocha-framework) Updates `@wdio/spec-reporter` from 8.16.17 to 8.16.22 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.16.22/packages/wdio-spec-reporter) --- updated-dependencies: - dependency-name: "@wdio/cli" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio - dependency-name: "@wdio/local-runner" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio - dependency-name: "@wdio/mocha-framework" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio - dependency-name: "@wdio/spec-reporter" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 138 +++++++++++++++++------------------ tests/wdio/package.json | 8 +- 2 files changed, 73 insertions(+), 73 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index c63e0b12e..db3b5e383 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -9,10 +9,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", - "@wdio/cli": "^8.16.20", - "@wdio/local-runner": "^8.16.20", - "@wdio/mocha-framework": "^8.16.17", - "@wdio/spec-reporter": "^8.16.17", + "@wdio/cli": "^8.16.22", + "@wdio/local-runner": "^8.16.22", + "@wdio/mocha-framework": "^8.16.22", + "@wdio/spec-reporter": "^8.16.22", "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.21.0", @@ -1067,18 +1067,18 @@ } }, "node_modules/@wdio/cli": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.20.tgz", - "integrity": "sha512-FYd5b2PhlCccC/Sn9D3ZG4/8NGGCLGijbNS1DJLkvYp/XJFqcf1kz0gdum2ct9IVEuFhgRdjqOlRPD3fUa7fDA==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.16.22.tgz", + "integrity": "sha512-/cv/fQ3qZoTJEnjmxWwPC2ohPfg5GrtBxi1MXNMJK85l1RHVYLkuNwUq18gSNcLol2vJ7GGoFowadlBjoCj56Q==", "dev": true, "dependencies": { "@types/node": "^20.1.1", - "@wdio/config": "8.16.20", - "@wdio/globals": "8.16.20", + "@wdio/config": "8.16.22", + "@wdio/globals": "8.16.22", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "async-exit-hook": "^2.0.1", "chalk": "^5.2.0", "chokidar": "^3.5.3", @@ -1093,7 +1093,7 @@ "lodash.union": "^4.6.0", "read-pkg-up": "10.1.0", "recursive-readdir": "^2.2.3", - "webdriverio": "8.16.20", + "webdriverio": "8.16.22", "yargs": "^17.7.2", "yarn-install": "^1.0.0" }, @@ -1117,14 +1117,14 @@ } }, "node_modules/@wdio/config": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.20.tgz", - "integrity": "sha512-JFD7aYs3nGF2kNhc0eV03mWFQMJku42NCBl+aedb1jzP3z6tBWV3n1a0ETS4MTLps8lFXBDZWvWEnl+ZvVrHZw==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.16.22.tgz", + "integrity": "sha512-sxqiVUEq++GFDKeR+HfzlgNhEbYuJZlrkU09p2rZzCRpPM3ty4azzdHB+XEdHHJJlV4UguvqUkp7n2126d9SAQ==", "dev": true, "dependencies": { "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "decamelize": "^6.0.0", "deepmerge-ts": "^5.0.0", "glob": "^10.2.2", @@ -1136,29 +1136,29 @@ } }, "node_modules/@wdio/globals": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.20.tgz", - "integrity": "sha512-4MG2E7t1z6IGq6ycGnumLj853n4KVRaS4njlRT74jtamFij0OluyV/e0CHf8Tc0r+ePwD7+UqACFxgwb5KIz6Q==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.16.22.tgz", + "integrity": "sha512-YGmGboSDTnFk+Bp/FJX2oPf548YILOr6M2T+wLnZtfgEPV5X8LbhT+XMqOYOiIdnI5MfgWGn8+XIgdjtNumHwQ==", "dev": true, "engines": { "node": "^16.13 || >=18" }, "optionalDependencies": { "expect-webdriverio": "^4.2.5", - "webdriverio": "8.16.20" + "webdriverio": "8.16.22" } }, "node_modules/@wdio/local-runner": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.20.tgz", - "integrity": "sha512-jPhm4fdPpae3RlM1OEPOZQa+fPLXhkDHBsGOHY2FWerNPF/kkHutjBE1OTRS4I7Tn8Ou0644kggB56GcGVWRcw==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.16.22.tgz", + "integrity": "sha512-ZhP8lDgjYzBuopIROALMcAmjvo7KGYjk6W+eJAR2p1EgdQy8IFMIuYuK1lWhAGCN3GRMRC1CTVtEVxc79/EJMg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.16.17", "@wdio/repl": "8.10.1", - "@wdio/runner": "8.16.20", - "@wdio/types": "8.16.12", + "@wdio/runner": "8.16.22", + "@wdio/types": "8.16.22", "async-exit-hook": "^2.0.1", "split2": "^4.1.0", "stream-buffers": "^3.0.2" @@ -1195,16 +1195,16 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.16.17.tgz", - "integrity": "sha512-aJ3CMzSBPOCb1i7hPyAsGYwccxPkD96qqdme/YUGL4U4SB+kEgDgNvouTJbyqvAB4VEuCcs+KqNWIMtM+rPi0Q==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.16.22.tgz", + "integrity": "sha512-/TgHCr4QoNRChGAXfBNZZHGEs+hMO2A8aU6mNEyrokAcHBoCL3NhnAP2SiQV0uT5wzoAOfv4RXqXOJ3bJa30Rw==", "dev": true, "dependencies": { "@types/mocha": "^10.0.0", "@types/node": "^20.1.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "mocha": "^10.0.0" }, "engines": { @@ -1230,14 +1230,14 @@ } }, "node_modules/@wdio/reporter": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.16.17.tgz", - "integrity": "sha512-c7B4dnOhCM9qCn/0vlV0IjCTL/Dv++MNOMtZFTQlEEo5qXSX+LNkpsZi0STnkPqnv6ZP7liwz4bA01MFksGaww==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.16.22.tgz", + "integrity": "sha512-5f4H2bAaq+mxl51j+4pyDuhgvE5MIJOhF3G75AGCjEnXgDEHYJ+yzpvRwmLxPB98BkxZ/ldxrQth/I/l3+j1fQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.12", + "@wdio/types": "8.16.22", "diff": "^5.0.0", "object-inspect": "^1.12.0" }, @@ -1246,35 +1246,35 @@ } }, "node_modules/@wdio/runner": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.20.tgz", - "integrity": "sha512-egNa/pR7NpU/Ocy+txBnezxE8zE8ghNM6z5WTYBZ2uA1jmwcqR6GFUyZWQmhfkqdVltOnWVa9eRvMb25wqhGtw==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.16.22.tgz", + "integrity": "sha512-SgWW1GPlZ7kS/7VZuuCYmCKIF6/WlOccGS2kHAg2rM45MjUId3KegNQ+INi2S3CkgU19M0rH2nNEUozp68dddw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.20", - "@wdio/globals": "8.16.20", + "@wdio/config": "8.16.22", + "@wdio/globals": "8.16.22", "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "deepmerge-ts": "^5.0.0", "expect-webdriverio": "^4.2.5", "gaze": "^1.1.2", - "webdriver": "8.16.20", - "webdriverio": "8.16.20" + "webdriver": "8.16.22", + "webdriverio": "8.16.22" }, "engines": { "node": "^16.13 || >=18" } }, "node_modules/@wdio/spec-reporter": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.16.17.tgz", - "integrity": "sha512-CBpZhTJASDWpxJBUK5TLBZKBWbZxsVctpqXjpjG9fl9+IXBG00P5oFecDa90aUa00Dq+eIE1UUsVJa7evd36Tg==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.16.22.tgz", + "integrity": "sha512-bOELqVNDGRf4hxAtnYKjQiejMSKr/KNKgIwvyk6Ww2WHavzbZ/3oPRKNiyu5qgQR1lU+IN46V848EQV/RwtG+Q==", "dev": true, "dependencies": { - "@wdio/reporter": "8.16.17", - "@wdio/types": "8.16.12", + "@wdio/reporter": "8.16.22", + "@wdio/types": "8.16.22", "chalk": "^5.1.2", "easy-table": "^1.2.0", "pretty-ms": "^7.0.0" @@ -1296,9 +1296,9 @@ } }, "node_modules/@wdio/types": { - "version": "8.16.12", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.12.tgz", - "integrity": "sha512-TjCZJ3P9ual21G0dRv0lC9QgHGd3Igv+guEINevBKf/oD4/N84PvQ2eZG1nSbZ3xh8X/dvi+O64A6VEv43gx2w==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.16.22.tgz", + "integrity": "sha512-bg30seCgYu5JXukJ7M0qWKZLNATpKROvnl5/lRSOu4oopjm28UUan/+gHfHfyJ3MJ2uFNhaIVotPAvUziVJAdg==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -1308,14 +1308,14 @@ } }, "node_modules/@wdio/utils": { - "version": "8.16.17", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.17.tgz", - "integrity": "sha512-jDyOrxbQRDJO0OPt9UBgnwpUIKqtRn4+R0gR5VSDrIG/in5ZZg28yer8urrIVY4yY9ut5r/22VaMHZI9LEXF5w==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.16.22.tgz", + "integrity": "sha512-1hQjm7Jweiz+ABakS33TyWXYoxEg7LxL12RqbEYqtGB6ZTJhik+Cwyj/jcJbETSjiYJflmHxDvhFwuOkLR8ljg==", "dev": true, "dependencies": { "@puppeteer/browsers": "^1.6.0", "@wdio/logger": "8.16.17", - "@wdio/types": "8.16.12", + "@wdio/types": "8.16.22", "decamelize": "^6.0.0", "deepmerge-ts": "^5.1.0", "edgedriver": "^5.3.5", @@ -8693,18 +8693,18 @@ } }, "node_modules/webdriver": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.20.tgz", - "integrity": "sha512-3Dynj9pfTqmbDadqmMmD/sQgGFwho92zQPGgpAqLUMebE/qEkraoIfRWdbi2tw1ityiThOJVPTXfwsY/bpvknw==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.16.22.tgz", + "integrity": "sha512-7W3LwQ5Np/qQG/EHD02aujv4QBuiE3/PbDd576s4QRDVa5RHLTvuAg3sZpj5kJ4wZEK2MbPsj1Nb8xqSyCUUqw==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "8.16.20", + "@wdio/config": "8.16.22", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "deepmerge-ts": "^5.1.0", "got": "^ 12.6.1", "ky": "^0.33.0", @@ -8752,18 +8752,18 @@ } }, "node_modules/webdriverio": { - "version": "8.16.20", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.20.tgz", - "integrity": "sha512-2xSJDrMxwPF1kucB/r7Wc8yF689GGi7iSKrog7vkkoIiRY25vd3U129iN2mTYgNDyM6SM0kw+GP5W1s73khpYw==", + "version": "8.16.22", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.16.22.tgz", + "integrity": "sha512-fzZtONvimqYc+C7DnnntkOz883+VP50uIvofLkDdH5yXU6duyclclChwWNZWllEHZvkLfpmLgrpgbS7R1wNGQg==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/config": "8.16.20", + "@wdio/config": "8.16.22", "@wdio/logger": "8.16.17", "@wdio/protocols": "8.16.5", "@wdio/repl": "8.10.1", - "@wdio/types": "8.16.12", - "@wdio/utils": "8.16.17", + "@wdio/types": "8.16.22", + "@wdio/utils": "8.16.22", "archiver": "^6.0.0", "aria-query": "^5.0.0", "css-shorthand-properties": "^1.1.1", @@ -8780,7 +8780,7 @@ "resq": "^1.9.1", "rgb2hex": "0.2.5", "serialize-error": "^11.0.1", - "webdriver": "8.16.20" + "webdriver": "8.16.22" }, "engines": { "node": "^16.13 || >=18" diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 3b2337fd2..043f17643 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -6,10 +6,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.2.0", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", - "@wdio/cli": "^8.16.20", - "@wdio/local-runner": "^8.16.20", - "@wdio/mocha-framework": "^8.16.17", - "@wdio/spec-reporter": "^8.16.17", + "@wdio/cli": "^8.16.22", + "@wdio/local-runner": "^8.16.22", + "@wdio/mocha-framework": "^8.16.22", + "@wdio/spec-reporter": "^8.16.22", "eslint": "^8.51.0", "eslint-config-google": "^0.14.0", "eslint-plugin-sonarjs": "^0.21.0", From 73930d7e8b57e1297e526e79bea21628e265d149 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:36:12 +0200 Subject: [PATCH 36/41] translate: Updates for file web/xliff/en.xlf in zh_CN on branch main (#7111) Translate web/xliff/en.xlf in zh_CN 100% translated source file: 'web/xliff/en.xlf' on 'zh_CN'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh_CN.xlf | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index acee9dc6b..411ef8e82 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -1295,11 +1295,6 @@ Validate SSL Certificates of upstream servers. 验证上游服务器的 SSL 证书。 - - - Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you). - 与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。 - Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application. @@ -7818,6 +7813,18 @@ Bindings to groups/users are checked against the user of the event. WebAuthn not supported by browser. 浏览器不支持 WebAuthn。 + + + Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + 与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。 + + + Default relay state + 默认中继状态 + + + When using IDP-initiated logins, the relay state will be set to this value. + 当使用 IDP 发起的登录时,中继状态会被设置为此值。 From 15559974a869f097e6dde01377c4822a48872983 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:36:27 +0200 Subject: [PATCH 37/41] translate: Updates for file web/xliff/en.xlf in zh-Hans on branch main (#7112) Translate web/xliff/en.xlf in zh-Hans 100% translated source file: 'web/xliff/en.xlf' on 'zh-Hans'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh-Hans.xlf | 49 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 8e262f221..6fdf19dd8 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1067,8 +1067,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,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1809,8 +1809,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"。 @@ -3233,8 +3233,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,...' @@ -4026,8 +4026,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"。 @@ -4036,8 +4036,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -4233,10 +4233,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 ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5337,7 +5337,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 这样的“漫游”身份验证器 @@ -5672,10 +5672,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5724,7 +5724,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,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7816,13 +7816,16 @@ Bindings to groups/users are checked against the user of the event. Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). + 与 nginx 的 auth_request 或 traefik 的 ForwardAuth 一起使用此提供程序。每个应用程序/域名都需要自己的提供程序。此外,在每个域名上,/outpost.goauthentik.io 必须路由到前哨(在使用托管的 Outpost 时,这已经为您处理好了)。 Default relay state + 默认中继状态 When using IDP-initiated logins, the relay state will be set to this value. + 当使用 IDP 发起的登录时,中继状态会被设置为此值。 - + \ No newline at end of file From a9011a641fec91de99b61a8f19eb66dce20c7a6b Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:50:20 +0000 Subject: [PATCH 38/41] web: bump API Client version (#7113) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index a1e6642de..5a54dcfec 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.2", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.8.3-1696802918", + "@goauthentik/api": "^2023.8.3-1696847703", "@lit-labs/context": "^0.4.1", "@lit-labs/task": "^3.0.2", "@lit/localize": "^0.11.4", @@ -2882,9 +2882,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.8.3-1696802918", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696802918.tgz", - "integrity": "sha512-OEmk3PQrY0r01wvGCBPn3uVevi7odZSD99LpgT5RyFC8+8ZkyXi2x8EfhsSHYiCbFvwWIg2cgTLWi5TILOoQzw==" + "version": "2023.8.3-1696847703", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.3-1696847703.tgz", + "integrity": "sha512-RsOANX4L6RHaGXvMhJNq9g+E0ZLW3cwgl/t5CyQxLYvWgmVvZU4t78hxlOF7vFREoO5nhZUZnOOlD2+n5gOqLg==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index 3fec6d8a9..08ede48ca 100644 --- a/web/package.json +++ b/web/package.json @@ -35,7 +35,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.2", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.8.3-1696802918", + "@goauthentik/api": "^2023.8.3-1696847703", "@lit-labs/context": "^0.4.1", "@lit-labs/task": "^3.0.2", "@lit/localize": "^0.11.4", From f11bb8bfd4a57d58b032637449687fc77011be66 Mon Sep 17 00:00:00 2001 From: vherrlein Date: Mon, 9 Oct 2023 13:17:46 +0200 Subject: [PATCH 39/41] providers/ldap: add windows adsi support (#7098) * fix(outpost/ldap): missing user object classes * add "person" object class * update user object classes * update boolean strings to upper for being compliant tags: WIP-LDAP-Outpost-Windows-ADSI-Support * feat(outpost/ldap): add subschema attributes * add supported capability OIDs for Windows * add relevant supported ldap control OIDs tags: WIP-LDAP-Outpost-Windows-ADSI-Support * feat(outpost/ldap): update schema for windows Compatibility * add relevant dITContentRules for authentik * add all existing attribute types for Windows/Unix/Linux * add missing object classes definitions * update classes definitions for being compliant with LDAP schema * update attributes orders tags: WIP-LDAP-Outpost-Windows-ADSI-Support * feat(outpost/ldap): refine LDAP attribute types * remove unsused attribute types * order attribute types tags: WIP-LDAP-Outpost-Windows-ADSI-Support --- internal/outpost/ldap/constants/constants.go | 3 + internal/outpost/ldap/entries.go | 10 +- internal/outpost/ldap/search/direct/base.go | 23 +++++ internal/outpost/ldap/search/direct/schema.go | 94 +++++++++++-------- 4 files changed, 88 insertions(+), 42 deletions(-) diff --git a/internal/outpost/ldap/constants/constants.go b/internal/outpost/ldap/constants/constants.go index cfa85711e..a60db0e9f 100644 --- a/internal/outpost/ldap/constants/constants.go +++ b/internal/outpost/ldap/constants/constants.go @@ -25,6 +25,7 @@ const ( ) const ( + OCPerson = "person" OCUser = "user" OCOrgPerson = "organizationalPerson" OCInetOrgPerson = "inetOrgPerson" @@ -54,6 +55,8 @@ func GetContainerOCs() map[string]bool { func GetUserOCs() map[string]bool { return map[string]bool{ + OCTop: true, + OCPerson: true, OCUser: true, OCOrgPerson: true, OCInetOrgPerson: true, diff --git a/internal/outpost/ldap/entries.go b/internal/outpost/ldap/entries.go index 23bab252d..2236a9964 100644 --- a/internal/outpost/ldap/entries.go +++ b/internal/outpost/ldap/entries.go @@ -31,8 +31,8 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry { u.Email = api.PtrString("") } attrs = utils.EnsureAttributes(attrs, map[string][]string{ - "ak-active": {strconv.FormatBool(*u.IsActive)}, - "ak-superuser": {strconv.FormatBool(u.IsSuperuser)}, + "ak-active": {strings.ToUpper(strconv.FormatBool(*u.IsActive))}, + "ak-superuser": {strings.ToUpper(strconv.FormatBool(u.IsSuperuser))}, "memberOf": pi.GroupsForUser(u), "cn": {u.Username}, "sAMAccountName": {u.Username}, @@ -41,11 +41,13 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry { "displayName": {u.Name}, "mail": {*u.Email}, "objectClass": { - constants.OCUser, + constants.OCTop, + constants.OCPerson, constants.OCOrgPerson, constants.OCInetOrgPerson, - constants.OCAKUser, + constants.OCUser, constants.OCPosixAccount, + constants.OCAKUser, }, "uidNumber": {pi.GetUidNumber(u)}, "gidNumber": {pi.GetUidNumber(u)}, diff --git a/internal/outpost/ldap/search/direct/base.go b/internal/outpost/ldap/search/direct/base.go index 87eadd715..0f87b7bf3 100644 --- a/internal/outpost/ldap/search/direct/base.go +++ b/internal/outpost/ldap/search/direct/base.go @@ -33,6 +33,29 @@ func (ds *DirectSearcher) SearchBase(req *search.Request) (ldap.ServerSearchResu Name: "supportedLDAPVersion", Values: []string{"3"}, }, + { + Name: "supportedCapabilities", + Values: []string{ + "1.2.840.113556.1.4.800", //LDAP_CAP_ACTIVE_DIRECTORY_OID + "1.2.840.113556.1.4.1791", //LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID + "1.2.840.113556.1.4.1670", //LDAP_CAP_ACTIVE_DIRECTORY_V51_OID + "1.2.840.113556.1.4.1880", //LDAP_CAP_ACTIVE_DIRECTORY_ADAM_DIGEST_OID + "1.2.840.113556.1.4.1851", //LDAP_CAP_ACTIVE_DIRECTORY_ADAM_OID + "1.2.840.113556.1.4.1920", //LDAP_CAP_ACTIVE_DIRECTORY_PARTIAL_SECRETS_OID + "1.2.840.113556.1.4.1935", //LDAP_CAP_ACTIVE_DIRECTORY_V60_OID + "1.2.840.113556.1.4.2080", //LDAP_CAP_ACTIVE_DIRECTORY_V61_R2_OID + "1.2.840.113556.1.4.2237", //LDAP_CAP_ACTIVE_DIRECTORY_W8_OID + }, + }, + { + Name: "supportedControl", + Values: []string{ + "2.16.840.1.113730.3.4.9", //VLV Request LDAPv3 Control + "2.16.840.1.113730.3.4.10", //VLV Response LDAPv3 Control + "1.2.840.113556.1.4.474", //Sort result + "1.2.840.113556.1.4.319", //Paged Result Control + }, + }, { Name: "subschemaSubentry", Values: []string{"cn=subschema"}, diff --git a/internal/outpost/ldap/search/direct/schema.go b/internal/outpost/ldap/search/direct/schema.go index 81e601846..669bb6a3b 100644 --- a/internal/outpost/ldap/search/direct/schema.go +++ b/internal/outpost/ldap/search/direct/schema.go @@ -29,62 +29,80 @@ func (ds *DirectSearcher) SearchSubschema(req *search.Request) (ldap.ServerSearc }, }, { - Name: "objectClasses", + Name: "dITContentRules", Values: []string{ - "( 2.5.6.0 NAME 'top' ABSTRACT MUST ( objectClass ) MAY (cn $ description $ displayName $ memberOf $ name ) )", - "( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( cn ) MAY (sn $ telephoneNumber ) )", - "( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL MAY (c $ l $ o $ ou $ title $ givenName $ co $ department $ company $ division $ mail $ mobile $ telephoneNumber ) )", - "( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST (cn $ member ) MAY (o $ ou ) )", - "( 1.2.840.113556.1.5.9 NAME 'user' SUP organizationalPerson STRUCTURAL MAY ( name $ displayName $ uid $ mail ) )", - "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY MAY (cn $ description $ homeDirectory $ uid $ uidNumber $ gidNumber ) )", - "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' AUX ( posixAccount ) MUST ( sAMAccountName ) MAY ( uidNumber $ gidNumber ))", - // Custom attributes - // Temporarily use 1.3.6.1.4.1.26027.1.1 as a base - // https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid - "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' SUP organizationalPerson STRUCTURAL MAY ( ak-active $ sAMAccountName $ goauthentikio-user-sources $ goauthentik.io/user/sources $ goauthentik.io/ldap/active $ goauthentik.io/ldap/superuser ) )", + "( 2.5.6.0 NAME 'top' )", + "( 2.5.6.6 NAME 'person' )", + "( 2.5.6.7 NAME 'organizationalPerson' )", + "( 2.5.6.9 NAME 'groupOfNames' )", + "( 1.2.840.113556.1.5.9 NAME 'user' )", + "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' )", + "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' )", + "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' )", }, }, { Name: "attributeTypes", Values: []string{ - "( 2.5.4.0 NAME 'objectClass' DESC 'RFC4512: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", - "( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts' DESC 'RFC4512: naming contexts' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )", - "( 2.5.18.10 NAME 'subschemaSubentry' DESC 'RFC4512: name of controlling subschema entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", - "( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion' DESC 'RFC4512: supported LDAP versions' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )", - "( 1.3.6.1.1.20 NAME 'entryDN' DESC 'DN of the entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", - "( 1.3.6.1.1.4 NAME 'vendorName' DESC 'RFC3045: name of implementation vendor' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", - "( 1.3.6.1.1.5 NAME 'vendorVersion' DESC 'RFC3045: version of implementation' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", - "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 0.9.2342.19200300.100.1.3 NAME 'mail' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 0.9.2342.19200300.100.1.41 NAME 'mobile' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.2.102 NAME 'memberOf' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' NO-USER-MODIFICATION )", - "( 1.2.840.113556.1.2.13 NAME 'displayName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.4.1 NAME 'name' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE NO-USER-MODIFICATION )", - "( 1.2.840.113556.1.2.131 NAME 'co' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.2.141 NAME 'department' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.2.146 NAME 'company' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.4.44 NAME 'homeDirectory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.4.221 NAME 'sAMAccountName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.2.840.113556.1.4.261 NAME 'division' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 1.3.6.1.1.1.1.0 NAME 'uidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )", - "( 1.3.6.1.1.1.1.1 NAME 'gidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )", + "( 2.5.4.0 NAME 'objectClass' SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' NO-USER-MODIFICATION )", + "( 2.5.4.4 NAME 'sn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 2.5.4.3 NAME 'cn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.6 NAME 'c' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.7 NAME 'l' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.10 NAME 'o' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )", "( 2.5.4.11 NAME 'ou' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )", - "( 2.5.4.20 NAME 'telephoneNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 2.5.4.42 NAME 'givenName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 2.5.4.0 NAME 'objectClass' SYNTAX '1.3.6.1.4.1.1466.115.121.1.38' NO-USER-MODIFICATION )", - "( 2.5.4.3 NAME 'cn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", - "( 2.5.4.4 NAME 'sn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.12 NAME 'title' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.13 NAME 'description' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )", + "( 2.5.4.20 NAME 'telephoneNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 2.5.4.31 NAME 'member' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' )", + "( 2.5.4.42 NAME 'givenName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 2.5.21.2 NAME 'dITContentRules' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", + "( 2.5.21.5 NAME 'attributeTypes' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", + "( 2.5.21.6 NAME 'objectClasses' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", + "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )", + "( 0.9.2342.19200300.100.1.3 NAME 'mail' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 0.9.2342.19200300.100.1.41 NAME 'mobile' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.2.13 NAME 'displayName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.2.146 NAME 'company' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.2.102 NAME 'memberOf' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' NO-USER-MODIFICATION )", + "( 1.2.840.113556.1.2.131 NAME 'co' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.2.141 NAME 'department' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.4.1 NAME 'name' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE NO-USER-MODIFICATION )", + "( 1.2.840.113556.1.4.44 NAME 'homeDirectory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.4.221 NAME 'sAMAccountName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.4.261 NAME 'division' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + "( 1.2.840.113556.1.4.750 NAME 'groupType' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )", + "( 1.2.840.113556.1.4.782 NAME 'objectCategory' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' SINGLE-VALUE )", + "( 1.3.6.1.1.1.1.0 NAME 'uidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )", + "( 1.3.6.1.1.1.1.1 NAME 'gidNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )", + "( 1.3.6.1.1.1.1.12 NAME 'memberUid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.26' )", + // Custom attributes // Temporarily use 1.3.6.1.4.1.26027.1.1 as a base // https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid "( 1.3.6.1.4.1.26027.1.1.2 NAME ( 'goauthentik.io/ldap/superuser' 'ak-superuser' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.7' SINGLE-VALUE )", "( 1.3.6.1.4.1.26027.1.1.3 NAME ( 'goauthentik.io/ldap/active' 'ak-active' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.7' SINGLE-VALUE )", + "( 1.3.6.1.4.1.26027.1.1.4 NAME ( 'goauthentik.io/ldap/sources' 'goauthentikio-user-sources' ) SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", + }, + }, + { + Name: "objectClasses", + Values: []string{ + "( 2.5.6.0 NAME 'top' ABSTRACT MUST ( objectClass ) MAY ( objectCategory $ cn $ description $ displayName $ memberOf $ name ) )", + "( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( cn ) MAY ( sn $ telephoneNumber ) )", + "( 2.5.6.7 NAME 'organizationalPerson' SUP person STRUCTURAL MAY ( c $ l $ o $ ou $ title $ givenName $ co $ department $ company $ division $ mail $ mobile $ telephoneNumber ) )", + "( 2.5.6.9 NAME 'groupOfNames' SUP top STRUCTURAL MUST ( cn $ member ) MAY ( o $ ou ) )", + "( 1.2.840.113556.1.5.9 NAME 'user' SUP organizationalPerson STRUCTURAL MAY ( name $ displayName $ uid $ mail ) )", + "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY MAY ( cn $ description $ homeDirectory $ uid $ uidNumber $ gidNumber ) )", + "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' SUP user STRUCTURAL MAY ( uidNumber $ gidNumber $ displayName $ homeDirectory ) )", + "( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL MUST ( ou ) MAY ( c $ l ) )", + "( 1.2.840.113556.1.5.8 NAME 'group' SUP top AUXILIARY MAY ( cn $ groupType $ member ) )", + "( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top AUXILIARY MAY ( cn $ description $ gidNumber $ memberUid ) )", + "( 2.5.20.1 NAME 'subSchema' SUP top STRUCTURAL MAY ( dITContentRules $ attributeTypes $ objectClasses ) )", + // Custom attributes + // Temporarily use 1.3.6.1.4.1.26027.1.1 as a base + // https://docs.oracle.com/cd/E19450-01/820-6169/working-with-object-identifiers.html#obtaining-a-base-oid + "( 1.3.6.1.4.1.26027.1.1.1 NAME 'goauthentik.io/ldap/user' SUP organizationalPerson STRUCTURAL MAY ( ak-superuser $ ak-active $ sAMAccountName $ goauthentikio-user-sources $ goauthentik.io/user/sources $ goauthentik.io/ldap/active $ goauthentik.io/ldap/superuser ) )", }, }, }, From 94fd22b448b49fe4a1d33a0abccfebbb62c95598 Mon Sep 17 00:00:00 2001 From: Philipp Kolberg <39984529+PKizzle@users.noreply.github.com> Date: Mon, 9 Oct 2023 19:20:02 +0200 Subject: [PATCH 40/41] core: bump Go from 1.20 to 1.21 (#7117) Initial commit. --- .github/workflows/ci-outpost.yml | 2 +- go.mod | 2 +- go.sum | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-outpost.yml b/.github/workflows/ci-outpost.yml index fe8ebf3b8..517407003 100644 --- a/.github/workflows/ci-outpost.yml +++ b/.github/workflows/ci-outpost.yml @@ -29,7 +29,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.52.2 + version: v1.54.2 args: --timeout 5000s --verbose skip-cache: true test-unittest: diff --git a/go.mod b/go.mod index a1943cc8d..a0bd758e2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module goauthentik.io -go 1.20 +go 1.21 require ( beryju.io/ldap v0.1.0 diff --git a/go.sum b/go.sum index 7d02c5bc8..36bc70908 100644 --- a/go.sum +++ b/go.sum @@ -49,7 +49,9 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -78,6 +80,7 @@ github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -196,6 +199,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -242,6 +246,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -269,6 +274,7 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -294,6 +300,7 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -343,9 +350,11 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= goauthentik.io/api/v3 v3.2023083.5 h1:U9/+QWIVpsfZCZivMAsG6E6dq3/4wT5qt/k7uUC9rZc= goauthentik.io/api/v3 v3.2023083.5/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -647,6 +656,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= From a22bc5a261a38feb939d68317c2e8ea9f2662b35 Mon Sep 17 00:00:00 2001 From: Jens L Date: Mon, 9 Oct 2023 19:52:06 +0200 Subject: [PATCH 41/41] lifecycle: fix install_id migration not running (#7116) * lifecycle: fix install_id migration not running Signed-off-by: Jens Langhammer * fix ldap test? Signed-off-by: Jens Langhammer * idk if this works Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- internal/outpost/ldap/search/direct/schema.go | 2 +- lifecycle/system_migrations/install_id.py | 8 +++++--- tests/e2e/test_provider_ldap.py | 19 +++++++++++++------ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/outpost/ldap/search/direct/schema.go b/internal/outpost/ldap/search/direct/schema.go index 669bb6a3b..6fe88ead7 100644 --- a/internal/outpost/ldap/search/direct/schema.go +++ b/internal/outpost/ldap/search/direct/schema.go @@ -59,7 +59,7 @@ func (ds *DirectSearcher) SearchSubschema(req *search.Request) (ldap.ServerSearc "( 2.5.21.2 NAME 'dITContentRules' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", "( 2.5.21.5 NAME 'attributeTypes' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", "( 2.5.21.6 NAME 'objectClasses' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' NO-USER-MODIFICATION )", - "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )", + "( 0.9.2342.19200300.100.1.1 NAME 'uid' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 0.9.2342.19200300.100.1.3 NAME 'mail' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 0.9.2342.19200300.100.1.41 NAME 'mobile' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", "( 1.2.840.113556.1.2.13 NAME 'displayName' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )", diff --git a/lifecycle/system_migrations/install_id.py b/lifecycle/system_migrations/install_id.py index 2545bd910..2f66dcafc 100644 --- a/lifecycle/system_migrations/install_id.py +++ b/lifecycle/system_migrations/install_id.py @@ -4,9 +4,11 @@ from uuid import uuid4 from authentik.lib.config import CONFIG from lifecycle.migrate import BaseMigration -SQL_STATEMENT = """CREATE TABLE IF NOT EXISTS authentik_install_id ( +SQL_STATEMENT = """BEGIN TRANSACTION; +CREATE TABLE IF NOT EXISTS authentik_install_id ( id TEXT NOT NULL -);""" +); +COMMIT;""" class Migration(BaseMigration): @@ -17,8 +19,8 @@ class Migration(BaseMigration): return not bool(self.cur.rowcount) def upgrade(self, migrate=False): + self.cur.execute(SQL_STATEMENT) with self.con.transaction(): - self.cur.execute(SQL_STATEMENT) if migrate: # If we already have migrations in the database, assume we're upgrading an existing install # and set the install id to the secret key diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py index 02564e4bd..aa12587ab 100644 --- a/tests/e2e/test_provider_ldap.py +++ b/tests/e2e/test_provider_ldap.py @@ -231,6 +231,7 @@ class TestProviderLDAP(SeleniumTestCase): for obj in response: del obj["raw_attributes"] del obj["raw_dn"] + obj["attributes"] = dict(obj["attributes"]) o_user = outpost.user expected = [ { @@ -244,11 +245,13 @@ class TestProviderLDAP(SeleniumTestCase): "sn": o_user.name, "mail": "", "objectClass": [ - "user", + "top", + "person", "organizationalPerson", "inetOrgPerson", - "goauthentik.io/ldap/user", + "user", "posixAccount", + "goauthentik.io/ldap/user", ], "uidNumber": 2000 + o_user.pk, "gidNumber": 2000 + o_user.pk, @@ -270,11 +273,13 @@ class TestProviderLDAP(SeleniumTestCase): "sn": embedded_account.name, "mail": "", "objectClass": [ - "user", + "top", + "person", "organizationalPerson", "inetOrgPerson", - "goauthentik.io/ldap/user", + "user", "posixAccount", + "goauthentik.io/ldap/user", ], "uidNumber": 2000 + embedded_account.pk, "gidNumber": 2000 + embedded_account.pk, @@ -296,11 +301,13 @@ class TestProviderLDAP(SeleniumTestCase): "sn": self.user.name, "mail": self.user.email, "objectClass": [ - "user", + "top", + "person", "organizationalPerson", "inetOrgPerson", - "goauthentik.io/ldap/user", + "user", "posixAccount", + "goauthentik.io/ldap/user", ], "uidNumber": 2000 + self.user.pk, "gidNumber": 2000 + self.user.pk,