Merge branch 'main' into application-wizard-2-with-api-and-tests

* main:
  web: cleanup (#6664)
  *: fix api errors raised in general validate() to specify a field (#6663)
  web: bump the storybook group in /web with 5 updates (#6662)
  web: bump @typescript-eslint/parser from 6.4.1 to 6.5.0 in /web (#6660)
  web: bump @codemirror/lang-javascript from 6.2.0 to 6.2.1 in /web (#6658)
  core: bump twisted from 22.10.0 to 23.8.0 (#6655)
  web: bump the sentry group in /web with 2 updates (#6656)
  web: bump @codemirror/lang-html from 6.4.5 to 6.4.6 in /web (#6661)
  web: bump the eslint group in /web with 1 update (#6657)
  web: bump yaml from 2.3.1 to 2.3.2 in /web (#6659)
This commit is contained in:
Ken Sternberg 2023-08-29 09:27:57 -07:00
commit f641f63b11
46 changed files with 1534 additions and 1212 deletions

View file

@ -9,6 +9,7 @@ from drf_spectacular.plumbing import (
)
from drf_spectacular.settings import spectacular_settings
from drf_spectacular.types import OpenApiTypes
from rest_framework.settings import api_settings
from authentik.api.pagination import PAGINATION_COMPONENT_NAME, PAGINATION_SCHEMA
@ -31,7 +32,7 @@ GENERIC_ERROR = build_object_type(
VALIDATION_ERROR = build_object_type(
description=_("Validation Error"),
properties={
"non_field_errors": build_array_type(build_standard_type(OpenApiTypes.STR)),
api_settings.NON_FIELD_ERRORS_KEY: build_array_type(build_standard_type(OpenApiTypes.STR)),
"code": build_standard_type(OpenApiTypes.STR),
},
required=[],

View file

@ -31,7 +31,7 @@ class ApplyBlueprintMetaSerializer(PassiveSerializer):
required = attrs["required"]
instance = BlueprintInstance.objects.filter(**identifiers).first()
if not instance and required:
raise ValidationError("Required blueprint does not exist")
raise ValidationError({"identifiers": "Required blueprint does not exist"})
self.blueprint_instance = instance
return super().validate(attrs)

View file

@ -47,7 +47,7 @@ class TokenSerializer(ManagedSerializer, ModelSerializer):
attrs.setdefault("user", request.user)
attrs.setdefault("intent", TokenIntents.INTENT_API)
if attrs.get("intent") not in [TokenIntents.INTENT_API, TokenIntents.INTENT_APP_PASSWORD]:
raise ValidationError(f"Invalid intent {attrs.get('intent')}")
raise ValidationError({"intent": f"Invalid intent {attrs.get('intent')}"})
return attrs
class Meta:

View file

@ -78,7 +78,6 @@
</main>
{% endblock %}
<footer class="pf-c-login__footer">
<p></p>
<ul class="pf-c-list pf-m-inline">
{% for link in footer_links %}
<li>

View file

@ -39,7 +39,7 @@ class NotificationTransportSerializer(ModelSerializer):
mode = attrs.get("mode")
if mode in [TransportMode.WEBHOOK, TransportMode.WEBHOOK_SLACK]:
if "webhook_url" not in attrs or attrs.get("webhook_url", "") == "":
raise ValidationError("Webhook URL may not be empty.")
raise ValidationError({"webhook_url": "Webhook URL may not be empty."})
return attrs
class Meta:

View file

@ -59,7 +59,9 @@ class ProxyProviderSerializer(ProviderSerializer):
attrs.get("mode", ProxyMode.PROXY) == ProxyMode.PROXY
and attrs.get("internal_host", "") == ""
):
raise ValidationError(_("Internal host cannot be empty when forward auth is disabled."))
raise ValidationError(
{"internal_host": _("Internal host cannot be empty when forward auth is disabled.")}
)
return attrs
def create(self, validated_data: dict):

View file

@ -69,7 +69,7 @@ class ProxyProviderTests(APITestCase):
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
response.content.decode(),
{"non_field_errors": ["Internal host cannot be empty when forward auth is disabled."]},
{"internal_host": ["Internal host cannot be empty when forward auth is disabled."]},
)
def test_create_defaults(self):

View file

@ -44,8 +44,12 @@ class LDAPSourceSerializer(SourceSerializer):
sources = sources.exclude(pk=self.instance.pk)
if sources.exists():
raise ValidationError(
{
"sync_users_password": (
"Only a single LDAP Source with password synchronization is allowed"
)
}
)
return super().validate(attrs)
class Meta:

View file

@ -63,7 +63,7 @@ class OAuthSourceSerializer(SourceSerializer):
well_known_config.raise_for_status()
except RequestException as exc:
text = exc.response.text if exc.response else str(exc)
raise ValidationError(text)
raise ValidationError({"oidc_well_known_url": text})
config = well_known_config.json()
try:
attrs["authorization_url"] = config["authorization_endpoint"]
@ -71,7 +71,9 @@ class OAuthSourceSerializer(SourceSerializer):
attrs["profile_url"] = config["userinfo_endpoint"]
attrs["oidc_jwks_url"] = config["jwks_uri"]
except (IndexError, KeyError) as exc:
raise ValidationError(f"Invalid well-known configuration: {exc}")
raise ValidationError(
{"oidc_well_known_url": f"Invalid well-known configuration: {exc}"}
)
jwks_url = attrs.get("oidc_jwks_url")
if jwks_url and jwks_url != "":
@ -80,7 +82,7 @@ class OAuthSourceSerializer(SourceSerializer):
jwks_config.raise_for_status()
except RequestException as exc:
text = exc.response.text if exc.response else str(exc)
raise ValidationError(text)
raise ValidationError({"jwks_url": text})
config = jwks_config.json()
attrs["oidc_jwks"] = config

View file

@ -99,6 +99,7 @@ class TestUserLoginStage(FlowTestCase):
session[SESSION_KEY_PLAN] = plan
session.save()
before_request = now()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
)
@ -108,7 +109,7 @@ class TestUserLoginStage(FlowTestCase):
session_key = self.client.session.session_key
session = AuthenticatedSession.objects.filter(session_key=session_key).first()
self.assertAlmostEqual(
session.expires.timestamp() - now().timestamp(),
session.expires.timestamp() - before_request.timestamp(),
timedelta_from_string(self.stage.session_duration).total_seconds(),
delta=1,
)

View file

@ -36,7 +36,7 @@ class TenantSerializer(ModelSerializer):
if self.instance:
tenants = tenants.exclude(pk=self.instance.pk)
if tenants.exists():
raise ValidationError("Only a single Tenant can be set as default.")
raise ValidationError({"default": "Only a single Tenant can be set as default."})
return super().validate(attrs)
class Meta:

View file

@ -59,7 +59,6 @@
</div>
</main>
<footer class="pf-c-login__footer">
<p></p>
<ul class="pf-c-list pf-m-inline">
<li>
<a href="https://goauthentik.io?utm_source=authentik_outpost&utm_campaign=proxy_error">

47
poetry.lock generated
View file

@ -3137,6 +3137,7 @@ files = [
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
@ -3144,8 +3145,15 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
@ -3162,6 +3170,7 @@ files = [
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
@ -3169,6 +3178,7 @@ files = [
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
@ -3721,44 +3731,43 @@ requests = ">=2.0.0"
[[package]]
name = "twisted"
version = "22.10.0"
version = "23.8.0"
description = "An asynchronous networking framework written in Python"
optional = false
python-versions = ">=3.7.1"
files = [
{file = "Twisted-22.10.0-py3-none-any.whl", hash = "sha256:86c55f712cc5ab6f6d64e02503352464f0400f66d4f079096d744080afcccbd0"},
{file = "Twisted-22.10.0.tar.gz", hash = "sha256:32acbd40a94f5f46e7b42c109bfae2b302250945561783a8b7a059048f2d4d31"},
{file = "twisted-23.8.0-py3-none-any.whl", hash = "sha256:b8bdba145de120ffb36c20e6e071cce984e89fba798611ed0704216fb7f884cd"},
{file = "twisted-23.8.0.tar.gz", hash = "sha256:3c73360add17336a622c0d811c2a2ce29866b6e59b1125fd6509b17252098a24"},
]
[package.dependencies]
attrs = ">=19.2.0"
Automat = ">=0.8.0"
attrs = ">=21.3.0"
automat = ">=0.8.0"
constantly = ">=15.1"
hyperlink = ">=17.1.1"
idna = {version = ">=2.4", optional = true, markers = "extra == \"tls\""}
incremental = ">=21.3.0"
incremental = ">=22.10.0"
pyopenssl = {version = ">=21.0.0", optional = true, markers = "extra == \"tls\""}
service-identity = {version = ">=18.1.0", optional = true, markers = "extra == \"tls\""}
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
typing-extensions = ">=3.6.5"
"zope.interface" = ">=4.4.2"
typing-extensions = ">=3.10.0"
zope-interface = ">=5"
[package.extras]
all-non-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"]
conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "cryptography (>=2.6)", "pyasn1"]
conch-nacl = ["PyNaCl", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "cryptography (>=2.6)", "pyasn1"]
all-non-platform = ["twisted[conch,contextvars,http2,serial,test,tls]", "twisted[conch,contextvars,http2,serial,test,tls]"]
conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"]
contextvars = ["contextvars (>=2.4,<3)"]
dev = ["coverage (>=6b1,<7)", "pydoctor (>=22.9.0,<22.10.0)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)", "twistedchecker (>=0.7,<1.0)"]
dev-release = ["pydoctor (>=22.9.0,<22.10.0)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)"]
gtk-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pygobject", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"]
dev = ["coverage (>=6b1,<7)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "twisted[dev-release]", "twistedchecker (>=0.7,<1.0)"]
dev-release = ["pydoctor (>=23.4.0,<23.5.0)", "pydoctor (>=23.4.0,<23.5.0)", "readthedocs-sphinx-ext (>=2.2,<3.0)", "readthedocs-sphinx-ext (>=2.2,<3.0)", "sphinx (>=5,<7)", "sphinx (>=5,<7)", "sphinx-rtd-theme (>=1.2,<2.0)", "sphinx-rtd-theme (>=1.2,<2.0)", "towncrier (>=22.12,<23.0)", "towncrier (>=22.12,<23.0)", "urllib3 (<2)", "urllib3 (<2)"]
gtk-platform = ["pygobject", "pygobject", "twisted[all-non-platform]", "twisted[all-non-platform]"]
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
macos-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyobjc-core", "pyobjc-framework-CFNetwork", "pyobjc-framework-Cocoa", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"]
mypy = ["PyHamcrest (>=1.9.0)", "PyNaCl", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "coverage (>=6b1,<7)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "mypy (==0.930)", "mypy-zope (==0.3.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pydoctor (>=22.9.0,<22.10.0)", "pyflakes (>=2.2,<3.0)", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "python-subunit (>=1.4,<2.0)", "pywin32 (!=226)", "readthedocs-sphinx-ext (>=2.1,<3.0)", "service-identity (>=18.1.0)", "sphinx (>=5.0,<6)", "sphinx-rtd-theme (>=1.0,<2.0)", "towncrier (>=22.8,<23.0)", "twistedchecker (>=0.7,<1.0)", "types-pyOpenSSL", "types-setuptools"]
osx-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyobjc-core", "pyobjc-framework-CFNetwork", "pyobjc-framework-Cocoa", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "service-identity (>=18.1.0)"]
macos-platform = ["pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "twisted[all-non-platform]", "twisted[all-non-platform]"]
mypy = ["mypy (==0.981)", "mypy-extensions (==0.4.3)", "mypy-zope (==0.3.11)", "twisted[all-non-platform,dev]", "types-pyopenssl", "types-setuptools"]
osx-platform = ["twisted[macos-platform]", "twisted[macos-platform]"]
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
test = ["PyHamcrest (>=1.9.0)", "cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.0,<7.0)"]
test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"]
tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"]
windows-platform = ["PyHamcrest (>=1.9.0)", "appdirs (>=1.4.0)", "bcrypt (>=3.0.0)", "contextvars (>=2.4,<3)", "cryptography (>=2.6)", "cython-test-exception-raiser (>=1.0.2,<2)", "h2 (>=3.0,<5.0)", "hypothesis (>=6.0,<7.0)", "idna (>=2.4)", "priority (>=1.1.0,<2.0)", "pyasn1", "pyopenssl (>=21.0.0)", "pyserial (>=3.0)", "pywin32 (!=226)", "pywin32 (!=226)", "service-identity (>=18.1.0)"]
windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platform]", "twisted[all-non-platform]"]
[[package]]
name = "twisted-iocpsupport"

2514
web/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -26,8 +26,8 @@
"storybook:build": "node --max-old-space-size=4096 ./node_modules/.bin/storybook build"
},
"dependencies": {
"@codemirror/lang-html": "^6.4.5",
"@codemirror/lang-javascript": "^6.2.0",
"@codemirror/lang-html": "^6.4.6",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/lang-python": "^6.1.3",
"@codemirror/lang-xml": "^6.0.2",
"@codemirror/legacy-modes": "^6.3.3",
@ -40,8 +40,8 @@
"@lit/localize": "^0.11.4",
"@patternfly/elements": "^2.4.0",
"@patternfly/patternfly": "^4.224.2",
"@sentry/browser": "^7.64.0",
"@sentry/tracing": "^7.64.0",
"@sentry/browser": "^7.65.0",
"@sentry/tracing": "^7.65.0",
"@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1",
"chart.js": "^4.4.0",
@ -56,7 +56,7 @@
"rapidoc": "^9.3.4",
"style-mod": "^4.1.0",
"webcomponent-qr-code": "^1.2.0",
"yaml": "^2.3.1"
"yaml": "^2.3.2"
},
"devDependencies": {
"@babel/core": "^7.22.11",
@ -77,17 +77,17 @@
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-typescript": "^11.1.3",
"@rollup/plugin-terser": "^0.4.3",
"@storybook/addon-essentials": "^7.3.2",
"@storybook/addon-links": "^7.3.2",
"@storybook/addon-essentials": "^7.4.0",
"@storybook/addon-links": "^7.4.0",
"@storybook/blocks": "^7.1.1",
"@storybook/web-components": "^7.3.2",
"@storybook/web-components-vite": "^7.3.2",
"@storybook/web-components": "^7.4.0",
"@storybook/web-components-vite": "^7.4.0",
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@types/chart.js": "^2.9.37",
"@types/codemirror": "5.60.9",
"@types/grecaptcha": "^3.0.4",
"@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths": "^1.0.3",
"eslint": "^8.48.0",
@ -105,7 +105,7 @@
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-cssimport": "^1.0.3",
"rollup-plugin-postcss-lit": "^2.1.0",
"storybook": "^7.3.2",
"storybook": "^7.4.0",
"storybook-addon-mock": "^4.2.1",
"ts-lit-plugin": "^1.2.1",
"tslib": "^2.6.2",

View file

@ -42,11 +42,11 @@ export class DummyPolicyForm extends ModelForm<DummyPolicy, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"A policy used for testing. Always returns the same result as specified below after waiting a random duration.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -54,11 +54,11 @@ export class EventMatcherPolicyForm extends ModelForm<EventMatcherPolicy, string
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Matches an event against a set of criteria. If any of the configured values match, the policy passes.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -42,11 +42,11 @@ export class PasswordExpiryPolicyForm extends ModelForm<PasswordExpiryPolicy, st
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Checks if the request's user's password has been changed in the last x days, and denys based on settings.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -44,11 +44,11 @@ export class ExpressionPolicyForm extends ModelForm<ExpressionPolicy, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Executes the python snippet to determine whether to allow or deny a request.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -230,11 +230,11 @@ export class PasswordPolicyForm extends ModelForm<PasswordPolicy, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Checks the value from the policy request against several rules, mostly used to ensure password strength.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -42,21 +42,21 @@ export class ReputationPolicyForm extends ModelForm<ReputationPolicy, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg("Allows/denys requests based on the users and/or the IPs reputation.")}
</div>
<div class="form-help-text">
</span>
<span>
${msg(
`Invalid login attempts will decrease the score for the client's IP, and the
username they are attempting to login as, by one.`,
)}
</div>
<div class="form-help-text">
</span>
<span>
${msg(
`The policy passes when the reputation score is below the threshold, and
doesn't pass when either or both of the selected options are equal or above the threshold.`,
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -217,7 +217,6 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("TLS Server name")}
?required=${true}
name="tlsServerName"
>
<input

View file

@ -51,11 +51,11 @@ export class AuthenticatorDuoStageForm extends ModelForm<AuthenticatorDuoStage,
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Stage used to configure a duo-based authenticator. This stage should be used for configuration flows.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -208,9 +208,7 @@ export class AuthenticatorSMSStageForm extends ModelForm<AuthenticatorSMSStage,
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
${msg("Stage used to configure an SMS-based TOTP authenticator.")}
</div>
<span> ${msg("Stage used to configure an SMS-based TOTP authenticator.")} </span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -49,11 +49,11 @@ export class AuthenticatorStaticStageForm extends ModelForm<AuthenticatorStaticS
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -51,11 +51,11 @@ export class AuthenticatorTOTPStageForm extends ModelForm<AuthenticatorTOTPStage
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Stage used to configure a TOTP authenticator (i.e. Authy/Google Authenticator).",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -72,11 +72,11 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Stage used to validate any authenticator. This stage should be used during authentication or authorization flows.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -56,11 +56,11 @@ export class AuthenticateWebAuthnStageForm extends ModelForm<AuthenticateWebAuth
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Stage used to configure a WebAutnn authenticator (i.e. Yubikey, FaceID/Windows Hello).",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -41,11 +41,11 @@ export class CaptchaStageForm extends ModelForm<CaptchaStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"This stage checks the user's current session against the Google reCaptcha (or compatible) service.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -50,11 +50,11 @@ export class ConsentStageForm extends ModelForm<ConsentStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Prompt for the user's consent. The consent can either be permanent or expire in a defined amount of time.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -40,11 +40,11 @@ export class DenyStageForm extends ModelForm<DenyStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Statically deny the flow. To use this stage effectively, disable *Evaluate on plan* on the respective binding.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -41,11 +41,11 @@ export class DummyStageForm extends ModelForm<DummyStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Dummy stage used for testing. Shows a simple continue button and always passes.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -148,11 +148,11 @@ export class EmailStageForm extends ModelForm<EmailStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -69,9 +69,9 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg("Let the user identify themselves with their username or Email address.")}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -41,9 +41,9 @@ export class InvitationStageForm extends ModelForm<InvitationStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg("This stage can be included in enrollment flows to accept invitations.")}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -63,9 +63,7 @@ export class PasswordStageForm extends ModelForm<PasswordStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
${msg("Validate the user's password against the selected backend(s).")}
</div>
<span> ${msg("Validate the user's password against the selected backend(s).")} </span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -61,11 +61,11 @@ export class PromptStageForm extends ModelForm<PromptStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -40,11 +40,11 @@ export class UserDeleteStageForm extends ModelForm<UserDeleteStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
"Delete the currently pending user. CAUTION, this stage does not ask for confirmation. Use a consent stage to ensure the user is aware of their actions.",
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -43,7 +43,7 @@ export class UserLoginStageForm extends ModelForm<UserLoginStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">${msg("Log the currently pending user in.")}</div>
<span>${msg("Log the currently pending user in.")}</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -40,7 +40,7 @@ export class UserLogoutStageForm extends ModelForm<UserLogoutStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">${msg("Remove the user from the current session.")}</div>
<span>${msg("Remove the user from the current session.")}</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -45,12 +45,12 @@ export class UserWriteStageForm extends ModelForm<UserWriteStage, string> {
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<div class="form-help-text">
<span>
${msg(
`Write any data from the flow's context's 'prompt_data' to the currently pending user. If no user
is pending, a new user is created, and data is written to them.`,
)}
</div>
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"

View file

@ -78,9 +78,13 @@ html > form > input {
}
.pf-c-login__footer {
flex-grow: 2;
display: flex;
justify-content: start;
flex-direction: column;
}
.pf-c-login__footer ul.pf-c-list.pf-m-inline {
justify-content: center;
padding: 2rem 0;
}
/*****************************
* End Login adjustments
@ -113,15 +117,7 @@ html > form > input {
color: var(--pf-global--danger-color--100);
}
.form-help-text {
color: var(--pf-global--Color--100);
}
.pf-c-description-list__description .pf-c-button {
margin-right: 6px;
margin-bottom: 6px;
}
.pf-c-data-list__item {
background-color: transparent;
}

View file

@ -208,9 +208,6 @@ select[multiple] option:checked {
.pf-c-check__label {
color: var(--ak-dark-foreground);
}
.form-help-text {
color: var(--ak-dark-foreground);
}
.pf-c-dropdown__toggle::before {
border-color: transparent;
}

View file

@ -509,7 +509,6 @@ export class FlowExecutor extends Interface implements StageHost {
${this.renderChallengeWrapper()}
</div>
<footer class="pf-c-login__footer">
<p></p>
<ul class="pf-c-list pf-m-inline">
${this.tenant?.uiFooterLinks?.map((link) => {
return html`<li>

View file

@ -42,6 +42,9 @@ export class UserSourceSettingsPage extends AKElement {
:host([theme="dark"]) .pf-c-data-list__cell img {
filter: invert(1);
}
.pf-c-data-list__item {
background-color: transparent;
}
`,
];
}

View file

@ -14,7 +14,6 @@ module.exports = async function () {
projectName: "authentik",
themeConfig: {
navbar: {
title: "authentik",
logo: {
alt: "authentik logo",
src: "img/icon_left_brand.svg",