From ced45513b8cbad2304b01a75637f3572d7d6742c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Mar 2021 09:26:18 +0100 Subject: [PATCH 01/65] build(deps-dev): bump typescript from 4.2.2 to 4.2.3 in /web (#615) Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.2.2 to 4.2.3. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 6 +++--- web/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index f0a718d0a..8185f2edf 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -3383,9 +3383,9 @@ "dev": true }, "typescript": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", - "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "uglify-js": { diff --git a/web/package.json b/web/package.json index 29d2f8db8..56ad750de 100644 --- a/web/package.json +++ b/web/package.json @@ -44,6 +44,6 @@ "rollup-plugin-sourcemaps": "^0.6.3", "rollup-plugin-terser": "^7.0.2", "ts-lit-plugin": "^1.2.1", - "typescript": "^4.2.2" + "typescript": "^4.2.3" } } From 705836662314ceccbb7eeb089761f5d7254f2eb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Mar 2021 09:26:42 +0100 Subject: [PATCH 02/65] build(deps): bump defusedxml from 0.6.0 to 0.7.0 (#614) Bumps [defusedxml](https://github.com/tiran/defusedxml) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/tiran/defusedxml/releases) - [Changelog](https://github.com/tiran/defusedxml/blob/master/CHANGES.txt) - [Commits](https://github.com/tiran/defusedxml/compare/v0.6.0...v0.7.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 2431413bf..5aab8afb8 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -124,10 +124,10 @@ }, "botocore": { "hashes": [ - "sha256:80c32a81fb1ee8bdfa074a79bfb885bb2006e8a9782f2353c0c9f6392704e13a", - "sha256:e9e724b59278ebf5caf032be1e32bde0990d79e8052e3bbbb97b6c1d32feba28" + "sha256:8c0ea010847cd2104e0798f03e6d921c96bce6ddbd7a6e175c8fecc2e9c7bc83", + "sha256:b604bbda4205b1a463c20d8434c7ddce1abbc3f6a4d5bf911e2b7774b2807f03" ], - "version": "==1.20.20" + "version": "==1.20.21" }, "cachetools": { "hashes": [ @@ -304,11 +304,11 @@ }, "defusedxml": { "hashes": [ - "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", - "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5" + "sha256:86b15d9e3c639de79f4cb38aeffea3281f62aff78dde7d798e1352c63bfa6ea0", + "sha256:a290cad10346ed366c8a0133d868eaf6585ec6afdd0c511286cdb11f5fc3d285" ], "index": "pypi", - "version": "==0.6.0" + "version": "==0.7.0" }, "django": { "hashes": [ @@ -445,10 +445,10 @@ }, "google-auth": { "hashes": [ - "sha256:d3640ea61ee025d5af00e3ffd82ba0a06dd99724adaf50bdd52f49daf29f3f65", - "sha256:da5218cbf33b8461d7661d6b4ad91c12c0107e2767904d5e3ae6408031d5463e" + "sha256:63a5636d7eacfe6ef5b7e36e112b3149fa1c5b5ad77dd6df54910459bcd6b89f", + "sha256:d8958af6968e4ecd599f82357ebcfeb126f826ed0656126ad68416f810f7531e" ], - "version": "==1.27.0" + "version": "==1.27.1" }, "gunicorn": { "hashes": [ From 49db283e717fe05b05995998c6b47458402e2114 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Mar 2021 09:27:03 +0100 Subject: [PATCH 03/65] build(deps): bump boto3 from 1.17.20 to 1.17.21 (#613) Bumps [boto3](https://github.com/boto/boto3) from 1.17.20 to 1.17.21. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.17.20...1.17.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Pipfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 5aab8afb8..96a5f095d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -116,11 +116,11 @@ }, "boto3": { "hashes": [ - "sha256:2219f1ebe88d266afa5516f993983eba8742b957fa4fd6854f3c73aa3030e931", - "sha256:c0d51f344b71656c2d395d2168600d91bea252a64fb5d503a955ea96426cde8b" + "sha256:8624a959c9122d3d5cd8c84231c1cd0cfe5cfbfc93a7b51eb380eb3f9ce0bac6", + "sha256:b52180720eb7a67bb8d2260aa3abaa30f6d7dd061663a83ad6e4dcd1263ab36a" ], "index": "pypi", - "version": "==1.17.20" + "version": "==1.17.21" }, "botocore": { "hashes": [ From 0fe009d37cec9d410ad32b6b93cc85ec63c60f72 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 4 Mar 2021 21:12:51 +0100 Subject: [PATCH 04/65] stages/authenticator_webauthn: add missing migration --- .../migrations/0004_auto_20210304_1850.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 authentik/stages/authenticator_webauthn/migrations/0004_auto_20210304_1850.py diff --git a/authentik/stages/authenticator_webauthn/migrations/0004_auto_20210304_1850.py b/authentik/stages/authenticator_webauthn/migrations/0004_auto_20210304_1850.py new file mode 100644 index 000000000..e223ff7d4 --- /dev/null +++ b/authentik/stages/authenticator_webauthn/migrations/0004_auto_20210304_1850.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.7 on 2021-03-04 18:50 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_stages_authenticator_webauthn", "0003_webauthndevice_confirmed"), + ] + + operations = [ + migrations.AlterModelOptions( + name="webauthndevice", + options={ + "verbose_name": "WebAuthn Device", + "verbose_name_plural": "WebAuthn Devices", + }, + ), + ] From 56f75aecc73c0bfaabbb9b2dc4013027ba5082df Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 5 Mar 2021 14:14:09 +0100 Subject: [PATCH 05/65] docs: bump version of outpost in docs --- .bumpversion.cfg | 2 ++ .../outposts/manual-deploy-docker-compose.md | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 2e6f3873f..8ff326d40 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -36,3 +36,5 @@ values = [bumpversion:file:outpost/pkg/version.go] [bumpversion:file:web/src/constants.ts] + +[bumpversion:file:website/docs/outpusts/manual-deploy-docker-compose.md] diff --git a/website/docs/outposts/manual-deploy-docker-compose.md b/website/docs/outposts/manual-deploy-docker-compose.md index 9cbedbd84..22cca7eb1 100644 --- a/website/docs/outposts/manual-deploy-docker-compose.md +++ b/website/docs/outposts/manual-deploy-docker-compose.md @@ -10,13 +10,13 @@ You can also run the outpost in a separate docker-compose project, you just have version: "3.5" services: - authentik_proxy: - image: beryju/authentik-proxy:0.10.0-stable - ports: - - 4180:4180 - - 4443:4443 - environment: - AUTHENTIK_HOST: https://your-authentik.tld - AUTHENTIK_INSECURE: "false" - AUTHENTIK_TOKEN: token-generated-by-authentik + authentik_proxy: + image: beryju/authentik-proxy:2021.3.2 + ports: + - 4180:4180 + - 4443:4443 + environment: + AUTHENTIK_HOST: https://your-authentik.tld + AUTHENTIK_INSECURE: "false" + AUTHENTIK_TOKEN: token-generated-by-authentik ``` From de4b3d6290644c6b80f1acd734540558bae7022f Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 5 Mar 2021 14:14:32 +0100 Subject: [PATCH 06/65] providers/oauth2: always set CORS headers on provider info view --- authentik/providers/oauth2/views/provider.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/authentik/providers/oauth2/views/provider.py b/authentik/providers/oauth2/views/provider.py index ab28e8db3..1bfc7cd93 100644 --- a/authentik/providers/oauth2/views/provider.py +++ b/authentik/providers/oauth2/views/provider.py @@ -103,9 +103,10 @@ class ProviderInfoView(View): provider: OAuth2Provider = get_object_or_404( OAuth2Provider, pk=application.provider_id ) - response = JsonResponse( - self.get_info(provider), json_dumps_params={"indent": 2} - ) - response["Access-Control-Allow-Origin"] = "*" + return JsonResponse(self.get_info(provider), json_dumps_params={"indent": 2}) + def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + # Since this view only supports get, we can statically set the CORS headers + response = super().dispatch(request, *args, **kwargs) + response["Access-Control-Allow-Origin"] = "*" return response From 0e9e378bdfb1fbab218acf3a9019d10272822423 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 5 Mar 2021 15:30:41 +0100 Subject: [PATCH 07/65] docs: update manual k8s outpost deployment --- .bumpversion.cfg | 2 + .../docs/outposts/manual-deploy-kubernetes.md | 171 ++++++++++-------- 2 files changed, 99 insertions(+), 74 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 8ff326d40..7d8d2069b 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -38,3 +38,5 @@ values = [bumpversion:file:web/src/constants.ts] [bumpversion:file:website/docs/outpusts/manual-deploy-docker-compose.md] + +[bumpversion:file:website/docs/outpusts/manual-deploy-kubernetes.md] diff --git a/website/docs/outposts/manual-deploy-kubernetes.md b/website/docs/outposts/manual-deploy-kubernetes.md index e3ee2b44b..8f164db61 100644 --- a/website/docs/outposts/manual-deploy-kubernetes.md +++ b/website/docs/outposts/manual-deploy-kubernetes.md @@ -10,92 +10,115 @@ Afterwards, configure the proxy provider to connect to `. Date: Fri, 5 Mar 2021 16:57:37 +0100 Subject: [PATCH 08/65] providers/oauth2: allow protected_resource_view when method is OPTIONS --- authentik/providers/oauth2/utils.py | 4 +++- authentik/providers/oauth2/views/provider.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/authentik/providers/oauth2/utils.py b/authentik/providers/oauth2/utils.py index 59334ce1d..2ab16c774 100644 --- a/authentik/providers/oauth2/utils.py +++ b/authentik/providers/oauth2/utils.py @@ -101,7 +101,9 @@ def protected_resource_view(scopes: list[str]): This decorator also injects the token into `kwargs`""" def wrapper(view): - def view_wrapper(request, *args, **kwargs): + def view_wrapper(request: HttpRequest, *args, **kwargs): + if request.method == "OPTIONS": + return view(request, *args, **kwargs) try: access_token = extract_access_token(request) if not access_token: diff --git a/authentik/providers/oauth2/views/provider.py b/authentik/providers/oauth2/views/provider.py index 1bfc7cd93..12bf1c118 100644 --- a/authentik/providers/oauth2/views/provider.py +++ b/authentik/providers/oauth2/views/provider.py @@ -19,6 +19,7 @@ from authentik.providers.oauth2.models import ( ResponseTypes, ScopeMapping, ) +from authentik.providers.oauth2.utils import cors_allow_any LOGGER = get_logger() @@ -108,5 +109,5 @@ class ProviderInfoView(View): def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: # Since this view only supports get, we can statically set the CORS headers response = super().dispatch(request, *args, **kwargs) - response["Access-Control-Allow-Origin"] = "*" + cors_allow_any(request, response) return response From 93b50e7d6e0348becc180f368199b898c7ee2dec Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 5 Mar 2021 17:18:50 +0100 Subject: [PATCH 09/65] tests/e2e: add tests for OIDC implicit flow --- .../e2e/test_provider_oauth2_oidc_implicit.py | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 tests/e2e/test_provider_oauth2_oidc_implicit.py diff --git a/tests/e2e/test_provider_oauth2_oidc_implicit.py b/tests/e2e/test_provider_oauth2_oidc_implicit.py new file mode 100644 index 000000000..52bc5664b --- /dev/null +++ b/tests/e2e/test_provider_oauth2_oidc_implicit.py @@ -0,0 +1,273 @@ +"""test OAuth2 OpenID Provider flow""" +from json import loads +from sys import platform +from time import sleep +from unittest.case import skipUnless + +from docker import DockerClient, from_env +from docker.models.containers import Container +from docker.types import Healthcheck +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as ec +from structlog.stdlib import get_logger + +from authentik.core.models import Application +from authentik.crypto.models import CertificateKeyPair +from authentik.flows.models import Flow +from authentik.policies.expression.models import ExpressionPolicy +from authentik.policies.models import PolicyBinding +from authentik.providers.oauth2.constants import ( + SCOPE_OPENID, + SCOPE_OPENID_EMAIL, + SCOPE_OPENID_PROFILE, +) +from authentik.providers.oauth2.generators import ( + generate_client_id, + generate_client_secret, +) +from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider, ScopeMapping +from tests.e2e.utils import ( + USER, + SeleniumTestCase, + apply_migration, + object_manager, + retry, +) + +LOGGER = get_logger() + + +@skipUnless(platform.startswith("linux"), "requires local docker") +class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): + """test OAuth with OpenID Provider flow""" + + def setUp(self): + self.client_id = generate_client_id() + self.client_secret = generate_client_secret() + self.application_slug = "test" + super().setUp() + + def setup_client(self) -> Container: + """Setup client saml-sp container which we test SAML against""" + sleep(1) + client: DockerClient = from_env() + container = client.containers.run( + image="beryju/oidc-test-client", + detach=True, + network_mode="host", + auto_remove=True, + healthcheck=Healthcheck( + test=["CMD", "wget", "--spider", "http://localhost:9009/health"], + interval=5 * 100 * 1000000, + start_period=1 * 100 * 1000000, + ), + environment={ + "OIDC_CLIENT_ID": self.client_id, + "OIDC_CLIENT_SECRET": self.client_secret, + "OIDC_PROVIDER": f"{self.live_server_url}/application/o/{self.application_slug}/", + }, + ) + while True: + container.reload() + status = container.attrs.get("State", {}).get("Health", {}).get("Status") + if status == "healthy": + return container + LOGGER.info("Container failed healthcheck") + sleep(1) + + @retry() + @apply_migration("authentik_core", "0003_default_user") + @apply_migration("authentik_flows", "0008_default_flows") + @apply_migration("authentik_flows", "0010_provider_flows") + @apply_migration("authentik_crypto", "0002_create_self_signed_kp") + def test_redirect_uri_error(self): + """test OpenID Provider flow (invalid redirect URI, check error message)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-implicit-consent" + ) + provider = OAuth2Provider.objects.create( + name=self.application_slug, + client_type=ClientTypes.CONFIDENTIAL, + client_id=self.client_id, + client_secret=self.client_secret, + rsa_key=CertificateKeyPair.objects.first(), + redirect_uris="http://localhost:9009/", + authorization_flow=authorization_flow, + ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + ) + ) + provider.save() + Application.objects.create( + name=self.application_slug, + slug=self.application_slug, + provider=provider, + ) + self.container = self.setup_client() + + self.driver.get("http://localhost:9009/implicit/") + sleep(2) + self.assertEqual( + self.driver.find_element(By.CLASS_NAME, "pf-c-title").text, + "Redirect URI Error", + ) + + @retry() + @apply_migration("authentik_core", "0003_default_user") + @apply_migration("authentik_flows", "0008_default_flows") + @apply_migration("authentik_flows", "0010_provider_flows") + @apply_migration("authentik_crypto", "0002_create_self_signed_kp") + @object_manager + def test_authorization_consent_implied(self): + """test OpenID Provider flow (default authorization flow with implied consent)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-implicit-consent" + ) + provider = OAuth2Provider.objects.create( + name=self.application_slug, + client_type=ClientTypes.CONFIDENTIAL, + client_id=self.client_id, + client_secret=self.client_secret, + rsa_key=CertificateKeyPair.objects.first(), + redirect_uris="http://localhost:9009/implicit/", + authorization_flow=authorization_flow, + ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + ) + ) + provider.save() + Application.objects.create( + name=self.application_slug, + slug=self.application_slug, + provider=provider, + ) + self.container = self.setup_client() + + self.driver.get("http://localhost:9009/implicit/") + self.login() + self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pre"))) + sleep(1) + body = loads(self.driver.find_element(By.CSS_SELECTOR, "pre").text) + print(body) + self.assertEqual(body["profile"]["nickname"], USER().username) + self.assertEqual(body["profile"]["name"], USER().name) + self.assertEqual(body["profile"]["email"], USER().email) + + @retry() + @apply_migration("authentik_core", "0003_default_user") + @apply_migration("authentik_flows", "0008_default_flows") + @apply_migration("authentik_flows", "0010_provider_flows") + @apply_migration("authentik_crypto", "0002_create_self_signed_kp") + @object_manager + def test_authorization_consent_explicit(self): + """test OpenID Provider flow (default authorization flow with explicit consent)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-explicit-consent" + ) + provider = OAuth2Provider.objects.create( + name=self.application_slug, + authorization_flow=authorization_flow, + client_type=ClientTypes.CONFIDENTIAL, + client_id=self.client_id, + client_secret=self.client_secret, + rsa_key=CertificateKeyPair.objects.first(), + redirect_uris="http://localhost:9009/implicit/", + ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + ) + ) + provider.save() + app = Application.objects.create( + name=self.application_slug, + slug=self.application_slug, + provider=provider, + ) + self.container = self.setup_client() + + self.driver.get("http://localhost:9009/implicit/") + self.login() + + self.wait.until( + ec.presence_of_element_located((By.CSS_SELECTOR, "ak-flow-executor")) + ) + + flow_executor = self.get_shadow_root("ak-flow-executor") + consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor) + + self.assertIn( + app.name, + consent_stage.find_element(By.CSS_SELECTOR, "#header-text").text, + ) + consent_stage.find_element( + By.CSS_SELECTOR, + ("[type=submit]"), + ).click() + + self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pre"))) + sleep(1) + body = loads(self.driver.find_element(By.CSS_SELECTOR, "pre").text) + + self.assertEqual(body["profile"]["nickname"], USER().username) + self.assertEqual(body["profile"]["name"], USER().name) + self.assertEqual(body["profile"]["email"], USER().email) + + @retry() + @apply_migration("authentik_core", "0003_default_user") + @apply_migration("authentik_flows", "0008_default_flows") + @apply_migration("authentik_flows", "0010_provider_flows") + @apply_migration("authentik_crypto", "0002_create_self_signed_kp") + def test_authorization_denied(self): + """test OpenID Provider flow (default authorization with access deny)""" + sleep(1) + # Bootstrap all needed objects + authorization_flow = Flow.objects.get( + slug="default-provider-authorization-explicit-consent" + ) + provider = OAuth2Provider.objects.create( + name=self.application_slug, + authorization_flow=authorization_flow, + client_type=ClientTypes.CONFIDENTIAL, + client_id=self.client_id, + client_secret=self.client_secret, + rsa_key=CertificateKeyPair.objects.first(), + redirect_uris="http://localhost:9009/implicit/", + ) + provider.property_mappings.set( + ScopeMapping.objects.filter( + scope_name__in=[SCOPE_OPENID, SCOPE_OPENID_EMAIL, SCOPE_OPENID_PROFILE] + ) + ) + provider.save() + app = Application.objects.create( + name=self.application_slug, + slug=self.application_slug, + provider=provider, + ) + + negative_policy = ExpressionPolicy.objects.create( + name="negative-static", expression="return False" + ) + PolicyBinding.objects.create(target=app, policy=negative_policy, order=0) + + self.container = self.setup_client() + self.driver.get("http://localhost:9009/implicit/") + self.login() + self.wait.until( + ec.presence_of_element_located((By.CSS_SELECTOR, "header > h1")) + ) + self.assertEqual( + self.driver.find_element(By.CSS_SELECTOR, "header > h1").text, + "Permission denied", + ) From 082628771bf80c1e3ee28d8dbd2a9f648a5b826d Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 5 Mar 2021 19:09:13 +0100 Subject: [PATCH 10/65] tests/integration: add more tests for docker outpost --- tests/integration/test_outpost_docker.py | 13 +++ ...bernetes.py => test_outpost_kubernetes.py} | 0 tests/integration/test_proxy_docker.py | 108 ++++++++++++++++++ tests/integration/test_proxy_kubernetes.py | 2 +- 4 files changed, 122 insertions(+), 1 deletion(-) rename tests/integration/{test_outposts_kubernetes.py => test_outpost_kubernetes.py} (100%) create mode 100644 tests/integration/test_proxy_docker.py diff --git a/tests/integration/test_outpost_docker.py b/tests/integration/test_outpost_docker.py index 9b491c5af..8a1c4dc69 100644 --- a/tests/integration/test_outpost_docker.py +++ b/tests/integration/test_outpost_docker.py @@ -3,11 +3,13 @@ from shutil import rmtree from tempfile import mkdtemp from time import sleep +import yaml from django.test import TestCase from docker import DockerClient, from_env from docker.models.containers import Container from docker.types.healthcheck import Healthcheck +from authentik import __version__ from authentik.crypto.models import CertificateKeyPair from authentik.flows.models import Flow from authentik.outposts.apps import AuthentikOutpostConfig @@ -93,3 +95,14 @@ class OutpostDockerTests(TestCase): controller = DockerController(self.outpost, self.service_connection) controller.up() controller.down() + + def test_docker_static(self): + """test that deployment requires update""" + controller = DockerController(self.outpost, self.service_connection) + manifest = controller.get_static_deployment() + compose = yaml.load(manifest, Loader=yaml.SafeLoader) + self.assertEqual(compose["version"], "3.5") + self.assertEqual( + compose["services"]["authentik_proxy"]["image"], + f"beryju/authentik-proxy:{__version__}", + ) diff --git a/tests/integration/test_outposts_kubernetes.py b/tests/integration/test_outpost_kubernetes.py similarity index 100% rename from tests/integration/test_outposts_kubernetes.py rename to tests/integration/test_outpost_kubernetes.py diff --git a/tests/integration/test_proxy_docker.py b/tests/integration/test_proxy_docker.py new file mode 100644 index 000000000..532810230 --- /dev/null +++ b/tests/integration/test_proxy_docker.py @@ -0,0 +1,108 @@ +"""outpost tests""" +from shutil import rmtree +from tempfile import mkdtemp +from time import sleep + +import yaml +from django.test import TestCase +from docker import DockerClient, from_env +from docker.models.containers import Container +from docker.types.healthcheck import Healthcheck + +from authentik import __version__ +from authentik.crypto.models import CertificateKeyPair +from authentik.flows.models import Flow +from authentik.outposts.apps import AuthentikOutpostConfig +from authentik.outposts.models import DockerServiceConnection, Outpost, OutpostType +from authentik.providers.proxy.controllers.docker import DockerController +from authentik.providers.proxy.models import ProxyProvider + + +class TestProxyDocker(TestCase): + """Test Docker Controllers""" + + def _start_container(self, ssl_folder: str) -> Container: + client: DockerClient = from_env() + container = client.containers.run( + image="library/docker:dind", + detach=True, + network_mode="host", + remove=True, + privileged=True, + healthcheck=Healthcheck( + test=["CMD", "docker", "info"], + interval=5 * 100 * 1000000, + start_period=5 * 100 * 1000000, + ), + environment={"DOCKER_TLS_CERTDIR": "/ssl"}, + volumes={ + f"{ssl_folder}/": { + "bind": "/ssl", + } + }, + ) + while True: + container.reload() + status = container.attrs.get("State", {}).get("Health", {}).get("Status") + if status == "healthy": + return container + sleep(1) + + def setUp(self): + super().setUp() + self.ssl_folder = mkdtemp() + self.container = self._start_container(self.ssl_folder) + # Ensure that local connection have been created + AuthentikOutpostConfig.init_local_connection() + self.provider: ProxyProvider = ProxyProvider.objects.create( + name="test", + internal_host="http://localhost", + external_host="http://localhost", + authorization_flow=Flow.objects.first(), + ) + authentication_kp = CertificateKeyPair.objects.create( + name="docker-authentication", + certificate_data=open(f"{self.ssl_folder}/client/cert.pem").read(), + key_data=open(f"{self.ssl_folder}/client/key.pem").read(), + ) + verification_kp = CertificateKeyPair.objects.create( + name="docker-verification", + certificate_data=open(f"{self.ssl_folder}/client/ca.pem").read(), + ) + self.service_connection = DockerServiceConnection.objects.create( + url="https://localhost:2376", + tls_verification=verification_kp, + tls_authentication=authentication_kp, + ) + self.outpost: Outpost = Outpost.objects.create( + name="test", + type=OutpostType.PROXY, + service_connection=self.service_connection, + ) + self.outpost.providers.add(self.provider) + self.outpost.save() + + def tearDown(self) -> None: + super().tearDown() + self.container.kill() + try: + rmtree(self.ssl_folder) + except PermissionError: + pass + + def test_docker_controller(self): + """test that deployment requires update""" + controller = DockerController(self.outpost, self.service_connection) + controller.up() + controller.down() + + def test_docker_static(self): + """test that deployment requires update""" + controller = DockerController(self.outpost, self.service_connection) + manifest = controller.get_static_deployment() + compose = yaml.load(manifest, Loader=yaml.SafeLoader) + self.assertEqual(compose["version"], "3.5") + self.assertEqual( + compose["services"]["authentik_proxy"]["image"], + f"beryju/authentik-proxy:{__version__}", + ) diff --git a/tests/integration/test_proxy_kubernetes.py b/tests/integration/test_proxy_kubernetes.py index 89f83f5d7..61b9a92aa 100644 --- a/tests/integration/test_proxy_kubernetes.py +++ b/tests/integration/test_proxy_kubernetes.py @@ -9,7 +9,7 @@ from authentik.providers.proxy.controllers.kubernetes import ProxyKubernetesCont from authentik.providers.proxy.models import ProxyProvider -class TestControllers(TestCase): +class TestProxyKubernetes(TestCase): """Test Controllers""" def setUp(self): From cbc86d674d9d6b44e6f72743ff766c5ef8794bc2 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 6 Mar 2021 23:00:29 +0100 Subject: [PATCH 11/65] web: fix Colours for user settings in dark mode --- authentik/core/templates/user/settings.html | 2 +- web/src/authentik.css | 4 ++++ web/src/elements/Tabs.ts | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/authentik/core/templates/user/settings.html b/authentik/core/templates/user/settings.html index ff803e4be..bf7424569 100644 --- a/authentik/core/templates/user/settings.html +++ b/authentik/core/templates/user/settings.html @@ -13,7 +13,7 @@

{% trans "Configure settings relevant to your user profile." %}

- +
diff --git a/web/src/authentik.css b/web/src/authentik.css index 273b340d1..a7bc1b696 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -155,6 +155,10 @@ ak-message { .pf-c-table__sort-indicator i { color: var(--ak-dark-foreground) !important; } + /* tabs, vertical */ + .pf-c-tabs__link { + background-color: var(--ak-dark-background-light); + } /* table, on mobile */ @media screen and (max-width: 1200px) { .pf-m-grid-xl.pf-c-table tbody:first-of-type { diff --git a/web/src/elements/Tabs.ts b/web/src/elements/Tabs.ts index 814106eb4..2d1006f5c 100644 --- a/web/src/elements/Tabs.ts +++ b/web/src/elements/Tabs.ts @@ -4,6 +4,8 @@ import { ifDefined } from "lit-html/directives/if-defined"; import TabsStyle from "@patternfly/patternfly/components/Tabs/tabs.css"; // @ts-ignore import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; +// @ts-ignore +import AKGlobal from "../authentik.css"; import { CURRENT_CLASS } from "../constants"; import { gettext } from "django"; @@ -16,7 +18,7 @@ export class Tabs extends LitElement { vertical = false; static get styles(): CSSResult[] { - return [GlobalsStyle, TabsStyle, css` + return [GlobalsStyle, TabsStyle, AKGlobal, css` ::slotted(*) { height: 100%; flex-grow: 2; @@ -24,6 +26,9 @@ export class Tabs extends LitElement { :host([vertical]) { display: flex; } + :host([vertical]) .pf-c-tabs__list { + height: 100%; + } `]; } From 0a24202f1ede1a19dc530fcfb66a4738e8f9f821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Mar 2021 07:45:40 +0100 Subject: [PATCH 12/65] build(deps): bump boto3 from 1.17.21 to 1.17.22 (#617) --- Pipfile.lock | 137 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 50 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 96a5f095d..b73c5670e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,45 +18,45 @@ "default": { "aiohttp": { "hashes": [ - "sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0", - "sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6", - "sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf", - "sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9", - "sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e", - "sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0", - "sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329", - "sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2", - "sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40", - "sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a", - "sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4", - "sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de", - "sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9", - "sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9", - "sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb", - "sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076", - "sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de", - "sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907", - "sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d", - "sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536", - "sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d", - "sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54", - "sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc", - "sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212", - "sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9", - "sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d", - "sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b", - "sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7", - "sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81", - "sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c", - "sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895", - "sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297", - "sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb", - "sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe", - "sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242", - "sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0", - "sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2" + "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe", + "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe", + "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5", + "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8", + "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd", + "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb", + "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c", + "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87", + "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0", + "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290", + "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5", + "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287", + "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde", + "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf", + "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8", + "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16", + "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf", + "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809", + "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213", + "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f", + "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013", + "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b", + "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9", + "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5", + "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb", + "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df", + "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4", + "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439", + "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f", + "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22", + "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f", + "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5", + "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970", + "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009", + "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc", + "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a", + "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95" ], - "version": "==3.7.4" + "version": "==3.7.4.post0" }, "aioredis": { "hashes": [ @@ -116,18 +116,18 @@ }, "boto3": { "hashes": [ - "sha256:8624a959c9122d3d5cd8c84231c1cd0cfe5cfbfc93a7b51eb380eb3f9ce0bac6", - "sha256:b52180720eb7a67bb8d2260aa3abaa30f6d7dd061663a83ad6e4dcd1263ab36a" + "sha256:4e177c9dd4ac45d9e41867cfb747f4c985d6b05ff14637ac5861a60daa95c7c1", + "sha256:ee03a05669c4e82021db8da61c1e7744f231b7481010917ed9066862c8d3cad9" ], "index": "pypi", - "version": "==1.17.21" + "version": "==1.17.22" }, "botocore": { "hashes": [ - "sha256:8c0ea010847cd2104e0798f03e6d921c96bce6ddbd7a6e175c8fecc2e9c7bc83", - "sha256:b604bbda4205b1a463c20d8434c7ddce1abbc3f6a4d5bf911e2b7774b2807f03" + "sha256:32e86f9d18555bd3b4dc694a2639a1c1fc8c8b42a49da543b95ac9d04c40770b", + "sha256:e92e22275ddc15b80015ee630b14ac3701bd9834bffc0814a65a894d490d2eaf" ], - "version": "==1.20.21" + "version": "==1.20.22" }, "cachetools": { "hashes": [ @@ -217,10 +217,10 @@ }, "chardet": { "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" ], - "version": "==3.0.4" + "version": "==4.0.0" }, "click": { "hashes": [ @@ -1069,10 +1069,47 @@ }, "ruamel.yaml": { "hashes": [ - "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5", - "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e" + "sha256:64b06e7873eb8e1125525ecef7345447d786368cadca92a7cd9b59eae62e95a3", + "sha256:bb48c514222702878759a05af96f4b7ecdba9b33cd4efcf25c86b882cef3a942" ], - "version": "==0.16.12" + "version": "==0.16.13" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b", + "sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f", + "sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c", + "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91", + "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc", + "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7", + "sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3", + "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7", + "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6", + "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6", + "sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd", + "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0", + "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62", + "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99", + "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5", + "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026", + "sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb", + "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2", + "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1", + "sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4", + "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b", + "sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923", + "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e", + "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c", + "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988", + "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f", + "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5", + "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a", + "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1", + "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", + "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" + ], + "markers": "platform_python_implementation == 'CPython' and python_version < '3.10'", + "version": "==0.2.2" }, "s3transfer": { "hashes": [ From a59d78a7c710afacc31b5d1475ef4a728b9370a0 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 8 Mar 2021 10:05:01 +0100 Subject: [PATCH 13/65] web: fix styling for static token list --- web/src/authentik.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/authentik.css b/web/src/authentik.css index a7bc1b696..f5edceb1c 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -55,6 +55,7 @@ select[multiple] { -webkit-columns: 2; -moz-columns: 2; margin-left: var(--pf-global--spacer--xs); + width: 100%; } .ak-otp-tokens li { font-size: var(--pf-global--FontSize--2xl); From 3f0e4bb6549a84e712af667127bb4b97d2311264 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 8 Mar 2021 10:19:18 +0100 Subject: [PATCH 14/65] stages/authenticator_static: fix error when disable static tokens --- authentik/stages/authenticator_static/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/authentik/stages/authenticator_static/views.py b/authentik/stages/authenticator_static/views.py index 2d4fb048b..13e5517bb 100644 --- a/authentik/stages/authenticator_static/views.py +++ b/authentik/stages/authenticator_static/views.py @@ -34,7 +34,8 @@ class UserSettingsView(LoginRequiredMixin, TemplateView): class DisableView(LoginRequiredMixin, View): """Disable Static Tokens for user""" - def get(self, request: HttpRequest) -> HttpResponse: + # pylint: disable=unused-argument + def get(self, request: HttpRequest, **kwargs) -> HttpResponse: """Delete all the devices for user""" devices = StaticDevice.objects.filter(user=request.user, confirmed=True) devices.delete() From 1c6d4986214f0f0d857667126032afe7ce8c08d4 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 8 Mar 2021 10:23:43 +0100 Subject: [PATCH 15/65] web: fix Flow executor not showing spinner when redirecting # Conflicts: # web/src/pages/generic/FlowExecutor.ts --- web/src/pages/generic/FlowExecutor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/pages/generic/FlowExecutor.ts b/web/src/pages/generic/FlowExecutor.ts index 552df1b32..c2de4caa4 100644 --- a/web/src/pages/generic/FlowExecutor.ts +++ b/web/src/pages/generic/FlowExecutor.ts @@ -136,13 +136,13 @@ export class FlowExecutor extends LitElement implements StageHost { renderChallenge(): TemplateResult { if (!this.challenge) { - return html``; + return this.renderLoading(); } switch (this.challenge.type) { case ChallengeTypes.redirect: console.debug(`authentik/flows: redirecting to ${(this.challenge as RedirectChallenge).to}`); window.location.assign((this.challenge as RedirectChallenge).to); - break; + return this.renderLoading(); case ChallengeTypes.shell: return html`${unsafeHTML((this.challenge as ShellChallenge).body)}`; case ChallengeTypes.native: From 2852fa3c5e10f08024c8e53a7621a3ccc2068223 Mon Sep 17 00:00:00 2001 From: Jens L Date: Mon, 8 Mar 2021 11:14:00 +0100 Subject: [PATCH 16/65] web: use generated API Client (#616) * api: fix types for config API * api: remove broken swagger UI * admin: re-fix system task enum * events: make event optional * events: fix Schema for notification transport test * flows: use APIView for Flow Executor * core: fix schema for Metrics APIs * web: rewrite to use generated API client * web: generate API Client in CI * admin: use x_cord and y_cord to prevent yaml issues * events: fix linting errors * web: don't lint generated code * core: fix fields not being required in TypeSerializer * flows: fix missing permission_classes * web: cleanup * web: fix rendering of graph on Overview page * web: cleanup imports * core: fix missing background image filter * flows: fix flows not advancing properly * stages/*: fix warnings during get_challenge * web: send Flow response as JSON instead of FormData * web: fix styles for horizontal tabs * web: add base chart class and custom chart for application view * root: generate ts client for e2e tests * web: don't attempt to connect to websocket in selenium tests * web: fix UserTokenList not being included in the build * web: fix styling for static token list * web: fix CSRF Token missing * stages/authenticator_static: fix error when disable static tokens * core: fix display issue when updating user info * web: fix Flow executor not showing spinner when redirecting --- .github/workflows/release.yml | 3 + Dockerfile | 1 + authentik/admin/api/metrics.py | 30 +++- authentik/admin/api/tasks.py | 4 +- authentik/api/v2/urls.py | 37 ++-- authentik/core/api/applications.py | 4 +- authentik/core/api/utils.py | 6 +- authentik/core/templates/login/base_full.html | 10 ++ authentik/core/views/user.py | 3 +- authentik/events/api/notification.py | 2 +- .../events/api/notification_transport.py | 27 ++- authentik/flows/challenge.py | 6 +- authentik/flows/stage.py | 5 +- authentik/flows/views.py | 27 ++- authentik/providers/saml/views/flows.py | 2 +- .../stages/authenticator_static/stage.py | 2 +- authentik/stages/authenticator_totp/stage.py | 2 +- .../stages/authenticator_validate/stage.py | 2 +- .../stages/authenticator_webauthn/stage.py | 2 +- authentik/stages/captcha/stage.py | 2 +- authentik/stages/consent/stage.py | 2 +- authentik/stages/dummy/stage.py | 2 +- authentik/stages/email/stage.py | 2 +- authentik/stages/identification/stage.py | 2 +- authentik/stages/password/stage.py | 2 +- authentik/stages/prompt/stage.py | 2 +- azure-pipelines.yml | 1 + outpost/azure-pipelines.yml | 8 +- swagger.yaml | 165 ++++++++++++++--- web/.eslintignore | 5 + web/azure-pipelines.yml | 65 +++++-- web/src/api/.gitignore | 4 + web/src/api/.openapi-generator-ignore | 23 +++ web/src/api/.openapi-generator/FILES | 167 ++++++++++++++++++ web/src/api/.openapi-generator/VERSION | 1 + web/src/api/Applications.ts | 32 ---- web/src/api/CertificateKeyPair.ts | 26 --- web/src/api/Client.ts | 94 +--------- web/src/api/Config.ts | 65 ++++--- web/src/api/EventNotification.ts | 30 ---- web/src/api/EventRules.ts | 26 --- web/src/api/EventTransports.ts | 25 --- web/src/api/Events.ts | 34 +--- web/src/api/Flows.ts | 115 +----------- web/src/api/Groups.ts | 28 --- web/src/api/Invitations.ts | 27 --- web/src/api/Outposts.ts | 79 --------- web/src/api/Policies.ts | 38 ---- web/src/api/PolicyBindings.ts | 31 ---- web/src/api/Prompts.ts | 30 ---- web/src/api/PropertyMapping.ts | 31 ---- web/src/api/Providers.ts | 40 ----- web/src/api/Sources.ts | 34 ---- web/src/api/SystemTask.ts | 33 ---- web/src/api/Tokens.ts | 47 ----- web/src/api/Users.ts | 48 +---- web/src/api/Versions.ts | 17 -- web/src/api/legacy.ts | 97 ++++++++++ web/src/api/providers/OAuth2.ts | 43 ----- web/src/api/providers/Proxy.ts | 30 ---- web/src/api/providers/SAML.ts | 33 ---- web/src/api/sources/LDAP.ts | 35 ---- web/src/api/sources/OAuth.ts | 22 --- web/src/api/sources/SAML.ts | 32 ---- web/src/authentik.css | 2 +- web/src/elements/AdminLoginsChart.ts | 119 ------------- web/src/elements/buttons/ActionButton.ts | 49 ++--- web/src/elements/buttons/TokenCopyButton.ts | 13 +- web/src/elements/charts/AdminLoginsChart.ts | 41 +++++ .../charts/ApplicationAuthorizeChart.ts | 32 ++++ web/src/elements/charts/Chart.ts | 103 +++++++++++ web/src/elements/messages/MessageContainer.ts | 1 + .../notifications/NotificationDrawer.ts | 19 +- .../elements/policies/BoundPoliciesList.ts | 20 +-- web/src/elements/sidebar/SidebarBrand.ts | 18 +- web/src/elements/sidebar/SidebarUser.ts | 7 +- web/src/elements/table/Table.ts | 2 +- web/src/elements/table/TablePagination.ts | 8 +- web/src/flow.ts | 2 +- .../{pages/generic => flows}/FlowExecutor.ts | 109 ++++++------ .../AuthenticatorStaticStage.ts | 1 + .../AuthenticatorTOTPStage.ts | 3 +- .../AuthenticatorValidateStage.ts | 4 +- .../AuthenticatorValidateStageCode.ts | 1 + .../AuthenticatorValidateStageWebAuthn.ts | 2 +- .../WebAuthnAuthenticatorRegisterStage.ts | 2 +- .../stages/authenticator_webauthn/utils.ts | 0 .../stages/autosubmit/AutosubmitStage.ts | 3 +- web/src/{elements => flows}/stages/base.ts | 8 +- .../stages/captcha/CaptchaStage.ts | 3 +- .../stages/consent/ConsentStage.ts | 1 + .../stages/email/EmailStage.ts | 5 +- web/src/{elements => flows}/stages/form.ts | 0 .../identification/IdentificationStage.ts | 3 +- .../stages/password/PasswordStage.ts | 1 + .../stages/prompt/PromptStage.ts | 3 +- web/src/interfaces/AdminInterface.ts | 14 +- web/src/main.ts | 27 +-- web/src/pages/LibraryPage.ts | 17 +- .../pages/admin-overview/AdminOverviewPage.ts | 4 +- .../admin-overview/TopApplicationsTable.ts | 17 +- .../admin-overview/cards/AdminStatusCard.ts | 16 +- .../cards/FlowCacheStatusCard.ts | 7 +- .../cards/PolicyCacheStatusCard.ts | 7 +- .../cards/PolicyUnboundStatusCard.ts | 13 +- .../cards/ProviderStatusCard.ts | 11 +- .../cards/UserCountStatusCard.ts | 9 +- .../admin-overview/cards/VersionStatusCard.ts | 9 +- .../admin-overview/cards/WorkerStatusCard.ts | 7 +- .../pages/applications/ApplicationListPage.ts | 22 +-- .../pages/applications/ApplicationViewPage.ts | 22 ++- .../crypto/CertificateKeyPairListPage.ts | 57 +++--- web/src/pages/events/EventInfo.ts | 31 ++-- web/src/pages/events/EventInfoPage.ts | 12 +- web/src/pages/events/EventListPage.ts | 19 +- web/src/pages/events/RuleListPage.ts | 22 +-- web/src/pages/events/TransportListPage.ts | 31 ++-- web/src/pages/flows/BoundStagesList.ts | 27 +-- web/src/pages/flows/FlowDiagram.ts | 9 +- web/src/pages/flows/FlowListPage.ts | 24 +-- web/src/pages/flows/FlowViewPage.ts | 14 +- web/src/pages/groups/GroupListPage.ts | 18 +- web/src/pages/outposts/OutpostHealth.ts | 14 +- web/src/pages/outposts/OutpostListPage.ts | 21 ++- .../OutpostServiceConnectionListPage.ts | 38 ++-- web/src/pages/policies/PolicyListPage.ts | 22 +-- .../PropertyMappingListPage.ts | 20 ++- .../pages/providers/OAuth2ProviderViewPage.ts | 32 ++-- web/src/pages/providers/ProviderListPage.ts | 20 ++- web/src/pages/providers/ProviderViewPage.ts | 18 +- .../pages/providers/ProxyProviderViewPage.ts | 17 +- .../providers/RelatedApplicationButton.ts | 12 +- .../pages/providers/SAMLProviderViewPage.ts | 19 +- web/src/pages/sources/LDAPSourceViewPage.ts | 65 ++++--- web/src/pages/sources/OAuthSourceViewPage.ts | 23 ++- web/src/pages/sources/SAMLSourceViewPage.ts | 24 ++- web/src/pages/sources/SourceViewPage.ts | 13 +- web/src/pages/sources/SourcesListPage.ts | 18 +- web/src/pages/stages/InvitationListPage.ts | 16 +- web/src/pages/stages/PromptListPage.ts | 18 +- web/src/pages/stages/StageListPage.ts | 18 +- .../pages/system-tasks/SystemTaskListPage.ts | 43 ++--- web/src/pages/tokens/TokenListPage.ts | 12 +- web/src/pages/tokens/UserTokenList.ts | 55 ++++-- web/src/pages/users/UserListPage.ts | 28 +-- web/src/utils.ts | 8 - 146 files changed, 1593 insertions(+), 1882 deletions(-) create mode 100644 web/src/api/.gitignore create mode 100644 web/src/api/.openapi-generator-ignore create mode 100644 web/src/api/.openapi-generator/FILES create mode 100644 web/src/api/.openapi-generator/VERSION delete mode 100644 web/src/api/Applications.ts delete mode 100644 web/src/api/CertificateKeyPair.ts delete mode 100644 web/src/api/EventNotification.ts delete mode 100644 web/src/api/EventRules.ts delete mode 100644 web/src/api/EventTransports.ts delete mode 100644 web/src/api/Groups.ts delete mode 100644 web/src/api/Invitations.ts delete mode 100644 web/src/api/Outposts.ts delete mode 100644 web/src/api/Policies.ts delete mode 100644 web/src/api/PolicyBindings.ts delete mode 100644 web/src/api/Prompts.ts delete mode 100644 web/src/api/PropertyMapping.ts delete mode 100644 web/src/api/Providers.ts delete mode 100644 web/src/api/Sources.ts delete mode 100644 web/src/api/SystemTask.ts delete mode 100644 web/src/api/Tokens.ts delete mode 100644 web/src/api/Versions.ts create mode 100644 web/src/api/legacy.ts delete mode 100644 web/src/api/providers/OAuth2.ts delete mode 100644 web/src/api/providers/Proxy.ts delete mode 100644 web/src/api/providers/SAML.ts delete mode 100644 web/src/api/sources/LDAP.ts delete mode 100644 web/src/api/sources/OAuth.ts delete mode 100644 web/src/api/sources/SAML.ts delete mode 100644 web/src/elements/AdminLoginsChart.ts create mode 100644 web/src/elements/charts/AdminLoginsChart.ts create mode 100644 web/src/elements/charts/ApplicationAuthorizeChart.ts create mode 100644 web/src/elements/charts/Chart.ts rename web/src/{pages/generic => flows}/FlowExecutor.ts (64%) rename web/src/{elements => flows}/stages/authenticator_static/AuthenticatorStaticStage.ts (98%) rename web/src/{elements => flows}/stages/authenticator_totp/AuthenticatorTOTPStage.ts (97%) rename web/src/{elements => flows}/stages/authenticator_validate/AuthenticatorValidateStage.ts (98%) rename web/src/{elements => flows}/stages/authenticator_validate/AuthenticatorValidateStageCode.ts (98%) rename web/src/{elements => flows}/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts (98%) rename web/src/{elements => flows}/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts (98%) rename web/src/{elements => flows}/stages/authenticator_webauthn/utils.ts (100%) rename web/src/{elements => flows}/stages/autosubmit/AutosubmitStage.ts (95%) rename web/src/{elements => flows}/stages/base.ts (58%) rename web/src/{elements => flows}/stages/captcha/CaptchaStage.ts (96%) rename web/src/{elements => flows}/stages/consent/ConsentStage.ts (98%) rename web/src/{elements => flows}/stages/email/EmailStage.ts (92%) rename web/src/{elements => flows}/stages/form.ts (100%) rename web/src/{elements => flows}/stages/identification/IdentificationStage.ts (98%) rename web/src/{elements => flows}/stages/password/PasswordStage.ts (98%) rename web/src/{elements => flows}/stages/prompt/PromptStage.ts (99%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2138920ae..a448a83fc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,6 +59,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 + - name: prepare ts api client + run: | + docker run --rm -v $(pwd):/local openapitools/openapi-generator-cli generate -i /local/swagger.yaml -g typescript-fetch -o /local/web/src/api --additional-properties=typescriptThreePlus=true - name: Docker Login Registry env: DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} diff --git a/Dockerfile b/Dockerfile index 5041486ca..a806fb659 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,4 +45,5 @@ COPY ./lifecycle/ /lifecycle USER authentik STOPSIGNAL SIGINT ENV TMPDIR /dev/shm/ +ENV PYTHONUBUFFERED 1 ENTRYPOINT [ "/lifecycle/bootstrap.sh" ] diff --git a/authentik/admin/api/metrics.py b/authentik/admin/api/metrics.py index d3e9f812e..ad3943e16 100644 --- a/authentik/admin/api/metrics.py +++ b/authentik/admin/api/metrics.py @@ -7,8 +7,8 @@ from django.db.models import Count, ExpressionWrapper, F, Model from django.db.models.fields import DurationField from django.db.models.functions import ExtractHour from django.utils.timezone import now -from drf_yasg2.utils import swagger_auto_schema -from rest_framework.fields import SerializerMethodField +from drf_yasg2.utils import swagger_auto_schema, swagger_serializer_method +from rest_framework.fields import IntegerField, SerializerMethodField from rest_framework.permissions import IsAdminUser from rest_framework.request import Request from rest_framework.response import Response @@ -37,23 +37,39 @@ def get_events_per_1h(**filter_kwargs) -> list[dict[str, int]]: for hour in range(0, -24, -1): results.append( { - "x": time.mktime((_now + timedelta(hours=hour)).timetuple()) * 1000, - "y": data[hour * -1], + "x_cord": time.mktime((_now + timedelta(hours=hour)).timetuple()) + * 1000, + "y_cord": data[hour * -1], } ) return results -class AdministrationMetricsSerializer(Serializer): +class CoordinateSerializer(Serializer): + """Coordinates for diagrams""" + + x_cord = IntegerField(read_only=True) + y_cord = IntegerField(read_only=True) + + def create(self, validated_data: dict) -> Model: + raise NotImplementedError + + def update(self, instance: Model, validated_data: dict) -> Model: + raise NotImplementedError + + +class LoginMetricsSerializer(Serializer): """Login Metrics per 1h""" logins_per_1h = SerializerMethodField() logins_failed_per_1h = SerializerMethodField() + @swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True)) def get_logins_per_1h(self, _): """Get successful logins per hour for the last 24 hours""" return get_events_per_1h(action=EventAction.LOGIN) + @swagger_serializer_method(serializer_or_field=CoordinateSerializer(many=True)) def get_logins_failed_per_1h(self, _): """Get failed logins per hour for the last 24 hours""" return get_events_per_1h(action=EventAction.LOGIN_FAILED) @@ -70,8 +86,8 @@ class AdministrationMetricsViewSet(ViewSet): permission_classes = [IsAdminUser] - @swagger_auto_schema(responses={200: AdministrationMetricsSerializer(many=True)}) + @swagger_auto_schema(responses={200: LoginMetricsSerializer(many=False)}) def list(self, request: Request) -> Response: """Login Metrics per 1h""" - serializer = AdministrationMetricsSerializer(True) + serializer = LoginMetricsSerializer(True) return Response(serializer.data) diff --git a/authentik/admin/api/tasks.py b/authentik/admin/api/tasks.py index 3dca24bc1..d3abd5dea 100644 --- a/authentik/admin/api/tasks.py +++ b/authentik/admin/api/tasks.py @@ -25,8 +25,8 @@ class TaskSerializer(Serializer): task_finish_timestamp = DateTimeField(source="finish_timestamp") status = ChoiceField( - source="result.status.value", - choices=[(x.value, x.name) for x in TaskResultStatus], + source="result.status.name", + choices=[(x.name, x.name) for x in TaskResultStatus], ) messages = ListField(source="result.messages") diff --git a/authentik/api/v2/urls.py b/authentik/api/v2/urls.py index 8ea2ec4ae..9f3fd39e7 100644 --- a/authentik/api/v2/urls.py +++ b/authentik/api/v2/urls.py @@ -1,4 +1,5 @@ """api v2 urls""" +from django.conf import settings from django.urls import path, re_path from drf_yasg2 import openapi from drf_yasg2.views import get_schema_view @@ -156,6 +157,14 @@ router.register("stages/user_write", UserWriteStageViewSet) router.register("stages/dummy", DummyStageViewSet) router.register("policies/dummy", DummyPolicyViewSet) +api_urls = router.urls + [ + path( + "flows/executor//", + FlowExecutorView.as_view(), + name="flow-executor", + ), +] + info = openapi.Info( title="authentik API", default_version="v2", @@ -165,26 +174,22 @@ info = openapi.Info( ), ) SchemaView = get_schema_view( - info, - public=True, - permission_classes=(AllowAny,), + info, public=True, permission_classes=(AllowAny,), patterns=api_urls ) -urlpatterns = [ +urlpatterns = api_urls + [ re_path( r"^swagger(?P\.json|\.yaml)$", SchemaView.without_ui(cache_timeout=0), name="schema-json", ), - path( - "swagger/", - SchemaView.with_ui("swagger", cache_timeout=0), - name="schema-swagger-ui", - ), - path("redoc/", SchemaView.with_ui("redoc", cache_timeout=0), name="schema-redoc"), - path( - "flows/executor//", - FlowExecutorView.as_view(), - name="flow-executor", - ), -] + router.urls +] + +if settings.DEBUG: + urlpatterns = urlpatterns + [ + path( + "swagger/", + SchemaView.with_ui("swagger", cache_timeout=0), + name="schema-swagger-ui", + ), + ] diff --git a/authentik/core/api/applications.py b/authentik/core/api/applications.py index 76cc432b9..eae9fc986 100644 --- a/authentik/core/api/applications.py +++ b/authentik/core/api/applications.py @@ -2,6 +2,7 @@ from django.core.cache import cache from django.db.models import QuerySet from django.http.response import Http404 +from drf_yasg2.utils import swagger_auto_schema from guardian.shortcuts import get_objects_for_user from rest_framework.decorators import action from rest_framework.fields import SerializerMethodField @@ -13,7 +14,7 @@ from rest_framework.viewsets import ModelViewSet from rest_framework_guardian.filters import ObjectPermissionsFilter from structlog.stdlib import get_logger -from authentik.admin.api.metrics import get_events_per_1h +from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h from authentik.core.api.providers import ProviderSerializer from authentik.core.models import Application from authentik.events.models import EventAction @@ -109,6 +110,7 @@ class ApplicationViewSet(ModelViewSet): serializer = self.get_serializer(allowed_applications, many=True) return self.get_paginated_response(serializer.data) + @swagger_auto_schema(responses={200: CoordinateSerializer(many=True)}) @action(detail=True) def metrics(self, request: Request, slug: str): """Metrics for application logins""" diff --git a/authentik/core/api/utils.py b/authentik/core/api/utils.py index b93f75155..438efa2df 100644 --- a/authentik/core/api/utils.py +++ b/authentik/core/api/utils.py @@ -28,9 +28,9 @@ class MetaNameSerializer(Serializer): class TypeCreateSerializer(Serializer): """Types of an object that can be created""" - name = CharField(read_only=True) - description = CharField(read_only=True) - link = CharField(read_only=True) + name = CharField(required=True) + description = CharField(required=True) + link = CharField(required=True) def create(self, validated_data: dict) -> Model: raise NotImplementedError diff --git a/authentik/core/templates/login/base_full.html b/authentik/core/templates/login/base_full.html index 6f58568d6..22c343ea9 100644 --- a/authentik/core/templates/login/base_full.html +++ b/authentik/core/templates/login/base_full.html @@ -16,6 +16,16 @@ {% block body %}
+ + + + + + + + + +

${item.body}

- ${created.toLocaleString()} + ${item.created?.toLocaleString()} `; } diff --git a/web/src/elements/policies/BoundPoliciesList.ts b/web/src/elements/policies/BoundPoliciesList.ts index 03d198cbe..c608b5149 100644 --- a/web/src/elements/policies/BoundPoliciesList.ts +++ b/web/src/elements/policies/BoundPoliciesList.ts @@ -2,16 +2,16 @@ import { gettext } from "django"; import { customElement, html, property, TemplateResult } from "lit-element"; import { AKResponse } from "../../api/Client"; import { Table, TableColumn } from "../../elements/table/Table"; -import { PolicyBinding } from "../../api/PolicyBindings"; +import { PoliciesApi, PolicyBinding } from "../../api"; import "../../elements/Tabs"; -import "../../elements/AdminLoginsChart"; import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; import "../../elements/buttons/Dropdown"; -import { Policy } from "../../api/Policies"; import { until } from "lit-html/directives/until"; import { PAGE_SIZE } from "../../constants"; +import { DEFAULT_CONFIG } from "../../api/Config"; +import { AdminURLManager } from "../../api/legacy"; @customElement("ak-bound-policies-list") export class BoundPoliciesList extends Table { @@ -19,11 +19,11 @@ export class BoundPoliciesList extends Table { target?: string; apiEndpoint(page: number): Promise> { - return PolicyBinding.list({ + return new PoliciesApi(DEFAULT_CONFIG).policiesBindingsList({ target: this.target || "", ordering: "order", page: page, - page_size: PAGE_SIZE, + pageSize: PAGE_SIZE, }); } @@ -56,13 +56,13 @@ export class BoundPoliciesList extends Table { html`${item.order}`, html`${item.timeout}`, html` - + ${gettext("Edit")}
- + ${gettext("Delete")} @@ -78,7 +78,7 @@ export class BoundPoliciesList extends Table { ${gettext("No policies are currently bound to this object.")}
- + ${gettext("Bind Policy")} @@ -96,7 +96,7 @@ export class BoundPoliciesList extends Table { - + ${gettext("Bind Policy")} diff --git a/web/src/elements/sidebar/SidebarBrand.ts b/web/src/elements/sidebar/SidebarBrand.ts index e55e17edd..1d9e5eef7 100644 --- a/web/src/elements/sidebar/SidebarBrand.ts +++ b/web/src/elements/sidebar/SidebarBrand.ts @@ -3,15 +3,17 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu import PageStyle from "@patternfly/patternfly/components/Page/page.css"; // @ts-ignore import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css"; -import { Config } from "../../api/Config"; +import { configureSentry } from "../../api/Config"; +import { Config } from "../../api"; +import { ifDefined } from "lit-html/directives/if-defined"; export const DefaultConfig: Config = { - branding_logo: " /static/dist/assets/icons/icon_left_brand.svg", - branding_title: "authentik", + brandingLogo: " /static/dist/assets/icons/icon_left_brand.svg", + brandingTitle: "authentik", - error_reporting_enabled: false, - error_reporting_environment: "", - error_reporting_send_pii: false, + errorReportingEnabled: false, + errorReportingEnvironment: "", + errorReportingSendPii: false, }; @customElement("ak-sidebar-brand") @@ -40,13 +42,13 @@ export class SidebarBrand extends LitElement { } firstUpdated(): void { - Config.get().then((c) => (this.config = c)); + configureSentry().then((c) => {this.config = c;}); } render(): TemplateResult { return html`
- authentik icon + authentik icon
`; } diff --git a/web/src/elements/sidebar/SidebarUser.ts b/web/src/elements/sidebar/SidebarUser.ts index 01a75d470..fc17cfbde 100644 --- a/web/src/elements/sidebar/SidebarUser.ts +++ b/web/src/elements/sidebar/SidebarUser.ts @@ -5,10 +5,11 @@ import NavStyle from "@patternfly/patternfly/components/Nav/nav.css"; import fa from "@fortawesome/fontawesome-free/css/all.css"; // @ts-ignore import AvatarStyle from "@patternfly/patternfly/components/Avatar/avatar.css"; -import { User } from "../../api/Users"; +import { me } from "../../api/Users"; import { until } from "lit-html/directives/until"; import "../notifications/NotificationTrigger"; +import { ifDefined } from "lit-html/directives/if-defined"; @customElement("ak-sidebar-user") export class SidebarUser extends LitElement { @@ -37,8 +38,8 @@ export class SidebarUser extends LitElement { render(): TemplateResult { return html` - ${until(User.me().then((u) => { - return html``; + ${until(me().then((u) => { + return html``; }), html``)} diff --git a/web/src/elements/table/Table.ts b/web/src/elements/table/Table.ts index f6c4a2b22..c40412425 100644 --- a/web/src/elements/table/Table.ts +++ b/web/src/elements/table/Table.ts @@ -5,7 +5,7 @@ import { COMMON_STYLES } from "../../common/styles"; import "./TablePagination"; import "../EmptyState"; - +import "../Spinner"; export class TableColumn { diff --git a/web/src/elements/table/TablePagination.ts b/web/src/elements/table/TablePagination.ts index fbcae2f27..0bfee7c84 100644 --- a/web/src/elements/table/TablePagination.ts +++ b/web/src/elements/table/TablePagination.ts @@ -1,12 +1,12 @@ import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; import { COMMON_STYLES } from "../../common/styles"; -import { PBPagination } from "../../api/Client"; +import { AKPagination } from "../../api/Client"; import { gettext } from "django"; @customElement("ak-table-pagination") export class TablePagination extends LitElement { @property({attribute: false}) - pages?: PBPagination; + pages?: AKPagination; @property({attribute: false}) // eslint-disable-next-line @@ -22,8 +22,8 @@ export class TablePagination extends LitElement {
- ${this.pages?.start_index} - - ${this.pages?.end_index} of + ${this.pages?.startIndex} - + ${this.pages?.endIndex} of ${this.pages?.count}
diff --git a/web/src/flow.ts b/web/src/flow.ts index 202eaae2f..0c7d9baac 100644 --- a/web/src/flow.ts +++ b/web/src/flow.ts @@ -1,3 +1,3 @@ import "construct-style-sheets-polyfill"; -import "./pages/generic/FlowExecutor"; +import "./flows/FlowExecutor"; diff --git a/web/src/pages/generic/FlowExecutor.ts b/web/src/flows/FlowExecutor.ts similarity index 64% rename from web/src/pages/generic/FlowExecutor.ts rename to web/src/flows/FlowExecutor.ts index c2de4caa4..fa8526ccc 100644 --- a/web/src/pages/generic/FlowExecutor.ts +++ b/web/src/flows/FlowExecutor.ts @@ -1,34 +1,34 @@ import { gettext } from "django"; import { LitElement, html, customElement, property, TemplateResult, CSSResult, css } from "lit-element"; import { unsafeHTML } from "lit-html/directives/unsafe-html"; -import { getCookie } from "../../utils"; -import "../../elements/stages/authenticator_static/AuthenticatorStaticStage"; -import "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage"; -import "../../elements/stages/authenticator_validate/AuthenticatorValidateStage"; -import "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; -import "../../elements/stages/autosubmit/AutosubmitStage"; -import "../../elements/stages/captcha/CaptchaStage"; -import "../../elements/stages/consent/ConsentStage"; -import "../../elements/stages/email/EmailStage"; -import "../../elements/stages/identification/IdentificationStage"; -import "../../elements/stages/password/PasswordStage"; -import "../../elements/stages/prompt/PromptStage"; -import { ShellChallenge, Challenge, ChallengeTypes, Flow, RedirectChallenge } from "../../api/Flows"; -import { DefaultClient } from "../../api/Client"; -import { IdentificationChallenge } from "../../elements/stages/identification/IdentificationStage"; -import { PasswordChallenge } from "../../elements/stages/password/PasswordStage"; -import { ConsentChallenge } from "../../elements/stages/consent/ConsentStage"; -import { EmailChallenge } from "../../elements/stages/email/EmailStage"; -import { AutosubmitChallenge } from "../../elements/stages/autosubmit/AutosubmitStage"; -import { PromptChallenge } from "../../elements/stages/prompt/PromptStage"; -import { AuthenticatorTOTPChallenge } from "../../elements/stages/authenticator_totp/AuthenticatorTOTPStage"; -import { AuthenticatorStaticChallenge } from "../../elements/stages/authenticator_static/AuthenticatorStaticStage"; -import { AuthenticatorValidateStageChallenge } from "../../elements/stages/authenticator_validate/AuthenticatorValidateStage"; -import { WebAuthnAuthenticatorRegisterChallenge } from "../../elements/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; -import { CaptchaChallenge } from "../../elements/stages/captcha/CaptchaStage"; -import { COMMON_STYLES } from "../../common/styles"; -import { SpinnerSize } from "../../elements/Spinner"; -import { StageHost } from "../../elements/stages/base"; +import "./stages/authenticator_static/AuthenticatorStaticStage"; +import "./stages/authenticator_totp/AuthenticatorTOTPStage"; +import "./stages/authenticator_validate/AuthenticatorValidateStage"; +import "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; +import "./stages/autosubmit/AutosubmitStage"; +import "./stages/captcha/CaptchaStage"; +import "./stages/consent/ConsentStage"; +import "./stages/email/EmailStage"; +import "./stages/identification/IdentificationStage"; +import "./stages/password/PasswordStage"; +import "./stages/prompt/PromptStage"; +import { ShellChallenge, RedirectChallenge } from "../api/Flows"; +import { IdentificationChallenge } from "./stages/identification/IdentificationStage"; +import { PasswordChallenge } from "./stages/password/PasswordStage"; +import { ConsentChallenge } from "./stages/consent/ConsentStage"; +import { EmailChallenge } from "./stages/email/EmailStage"; +import { AutosubmitChallenge } from "./stages/autosubmit/AutosubmitStage"; +import { PromptChallenge } from "./stages/prompt/PromptStage"; +import { AuthenticatorTOTPChallenge } from "./stages/authenticator_totp/AuthenticatorTOTPStage"; +import { AuthenticatorStaticChallenge } from "./stages/authenticator_static/AuthenticatorStaticStage"; +import { AuthenticatorValidateStageChallenge } from "./stages/authenticator_validate/AuthenticatorValidateStage"; +import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage"; +import { CaptchaChallenge } from "./stages/captcha/CaptchaStage"; +import { COMMON_STYLES } from "../common/styles"; +import { SpinnerSize } from "../elements/Spinner"; +import { StageHost } from "./stages/base"; +import { Challenge, ChallengeTypeEnum, FlowsApi } from "../api"; +import { DEFAULT_CONFIG } from "../api/Config"; @customElement("ak-flow-executor") export class FlowExecutor extends LitElement implements StageHost { @@ -68,37 +68,30 @@ export class FlowExecutor extends LitElement implements StageHost { }); } - submit(formData?: FormData): Promise { - const csrftoken = getCookie("authentik_csrf"); - const request = new Request(DefaultClient.makeUrl(["flows", "executor", this.flowSlug]), { - headers: { - "X-CSRFToken": csrftoken, - }, - }); + submit(formData?: T): Promise { this.loading = true; - return fetch(request, { - method: "POST", - mode: "same-origin", - body: formData, - }) - .then((response) => { - return response.json(); - }) - .then((data) => { - this.challenge = data; - }) - .catch((e) => { - this.errorMessage(e); - }) - .finally(() => { - this.loading = false; - }); + return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({ + flowSlug: this.flowSlug, + data: formData || {}, + }).then((challengeRaw) => { + return challengeRaw.raw.json(); + }).then((data) => { + this.challenge = data; + }).catch((e) => { + this.errorMessage(e); + }).finally(() => { + this.loading = false; + }); } firstUpdated(): void { this.loading = true; - Flow.executor(this.flowSlug).then((challenge) => { - this.challenge = challenge; + new FlowsApi(DEFAULT_CONFIG).flowsExecutorGetRaw({ + flowSlug: this.flowSlug + }).then((challengeRaw) => { + return challengeRaw.raw.json(); + }).then((challenge) => { + this.challenge = challenge as Challenge; }).catch((e) => { // Catch JSON or Update errors this.errorMessage(e); @@ -109,7 +102,7 @@ export class FlowExecutor extends LitElement implements StageHost { errorMessage(error: string): void { this.challenge = { - type: ChallengeTypes.shell, + type: ChallengeTypeEnum.Shell, body: `