From ccfd45774e8c061369416fd8b23479f2c436cac7 Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 29 Aug 2023 14:41:48 +0200 Subject: [PATCH] *: fix api errors raised in general validate() to specify a field (#6663) * *: fix api errors raised in general validate() to specify a field Signed-off-by: Jens Langhammer * remove required flag for tls server name for ldap provider Signed-off-by: Jens Langhammer * attempt to make timing test less flaky Signed-off-by: Jens Langhammer * fix tests Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/api/schema.py | 3 ++- authentik/blueprints/v1/meta/apply_blueprint.py | 2 +- authentik/core/api/tokens.py | 2 +- authentik/events/api/notification_transports.py | 2 +- authentik/providers/proxy/api.py | 4 +++- authentik/providers/proxy/tests.py | 2 +- authentik/sources/ldap/api.py | 6 +++++- authentik/sources/oauth/api/source.py | 8 +++++--- authentik/stages/user_login/tests.py | 3 ++- authentik/tenants/api.py | 2 +- web/src/admin/providers/ldap/LDAPProviderForm.ts | 1 - 11 files changed, 22 insertions(+), 13 deletions(-) diff --git a/authentik/api/schema.py b/authentik/api/schema.py index 8e27c4037..e70caaf3e 100644 --- a/authentik/api/schema.py +++ b/authentik/api/schema.py @@ -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=[], diff --git a/authentik/blueprints/v1/meta/apply_blueprint.py b/authentik/blueprints/v1/meta/apply_blueprint.py index a825cb53f..5946342a3 100644 --- a/authentik/blueprints/v1/meta/apply_blueprint.py +++ b/authentik/blueprints/v1/meta/apply_blueprint.py @@ -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) diff --git a/authentik/core/api/tokens.py b/authentik/core/api/tokens.py index 7caabb9dd..e3c2d46bf 100644 --- a/authentik/core/api/tokens.py +++ b/authentik/core/api/tokens.py @@ -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: diff --git a/authentik/events/api/notification_transports.py b/authentik/events/api/notification_transports.py index edd7111e0..30cd88d17 100644 --- a/authentik/events/api/notification_transports.py +++ b/authentik/events/api/notification_transports.py @@ -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: diff --git a/authentik/providers/proxy/api.py b/authentik/providers/proxy/api.py index 215a6ed37..30f77d83d 100644 --- a/authentik/providers/proxy/api.py +++ b/authentik/providers/proxy/api.py @@ -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): diff --git a/authentik/providers/proxy/tests.py b/authentik/providers/proxy/tests.py index 76409df89..5c5b77a6e 100644 --- a/authentik/providers/proxy/tests.py +++ b/authentik/providers/proxy/tests.py @@ -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): diff --git a/authentik/sources/ldap/api.py b/authentik/sources/ldap/api.py index f81b4ad4e..1914c66da 100644 --- a/authentik/sources/ldap/api.py +++ b/authentik/sources/ldap/api.py @@ -44,7 +44,11 @@ class LDAPSourceSerializer(SourceSerializer): sources = sources.exclude(pk=self.instance.pk) if sources.exists(): raise ValidationError( - "Only a single LDAP Source with password synchronization is allowed" + { + "sync_users_password": ( + "Only a single LDAP Source with password synchronization is allowed" + ) + } ) return super().validate(attrs) diff --git a/authentik/sources/oauth/api/source.py b/authentik/sources/oauth/api/source.py index 4b1785a54..1a52a765f 100644 --- a/authentik/sources/oauth/api/source.py +++ b/authentik/sources/oauth/api/source.py @@ -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 diff --git a/authentik/stages/user_login/tests.py b/authentik/stages/user_login/tests.py index f63f8eb3e..fbf92b395 100644 --- a/authentik/stages/user_login/tests.py +++ b/authentik/stages/user_login/tests.py @@ -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, ) diff --git a/authentik/tenants/api.py b/authentik/tenants/api.py index a8c438907..f77763970 100644 --- a/authentik/tenants/api.py +++ b/authentik/tenants/api.py @@ -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: diff --git a/web/src/admin/providers/ldap/LDAPProviderForm.ts b/web/src/admin/providers/ldap/LDAPProviderForm.ts index d89902f6b..8e125312c 100644 --- a/web/src/admin/providers/ldap/LDAPProviderForm.ts +++ b/web/src/admin/providers/ldap/LDAPProviderForm.ts @@ -217,7 +217,6 @@ export class LDAPProviderFormPage extends ModelForm {