diff --git a/api/custom_auth/serializers.py b/api/custom_auth/serializers.py index 03cab2cad5fa..f1128bd980c2 100644 --- a/api/custom_auth/serializers.py +++ b/api/custom_auth/serializers.py @@ -6,7 +6,6 @@ from rest_framework import serializers from rest_framework.authtoken.models import Token from rest_framework.exceptions import PermissionDenied -from rest_framework.validators import UniqueValidator from organisations.invites.models import Invite, InviteLink from users.auth_type import AuthType @@ -68,17 +67,21 @@ class Meta(UserCreateSerializer.Meta): # type: ignore[misc] write_only_fields = ("sign_up_type",) extra_kwargs = { "email": { - "validators": [ - UniqueValidator( - queryset=FFAdminUser.objects.all(), - lookup="iexact", - message="Email already exists. Please log in.", - ) - ] + "validators": list[object](), } } def validate(self, attrs): # type: ignore[no-untyped-def] + email = attrs.get("email", "") + self._validate_registration_invite( + email=email, sign_up_type=attrs.get("sign_up_type") + ) + + if FFAdminUser.objects.filter(email__iexact=email).exists(): + raise serializers.ValidationError( + {"email": "Email already exists. Please log in."} + ) + attrs = super().validate(attrs) email = attrs.get("email") if attrs.get("superuser"): @@ -101,10 +104,6 @@ def validate(self, attrs): # type: ignore[no-untyped-def] self.context.get("request"), email=email, raise_exception=True ) - self._validate_registration_invite( - email=email, sign_up_type=attrs.get("sign_up_type") - ) - attrs["email"] = email.lower() return attrs diff --git a/api/tests/integration/custom_auth/end_to_end/test_custom_auth_integration.py b/api/tests/integration/custom_auth/end_to_end/test_custom_auth_integration.py index 620025537176..ff36358c4b59 100644 --- a/api/tests/integration/custom_auth/end_to_end/test_custom_auth_integration.py +++ b/api/tests/integration/custom_auth/end_to_end/test_custom_auth_integration.py @@ -122,6 +122,29 @@ def test_register__without_invite_when_disabled__returns_forbidden( assert response.status_code == status.HTTP_403_FORBIDDEN +@override_settings(ALLOW_REGISTRATION_WITHOUT_INVITE=False) # type: ignore[misc] +def test_register__existing_email_without_invite_when_disabled__returns_forbidden( + db: None, + api_client: APIClient, + admin_user: FFAdminUser, +) -> None: + # Given + password = FFAdminUser.objects.make_random_password() + register_data = { + "email": admin_user.email, + "password": password, + "first_name": "test", + "last_name": "register", + } + + # When + url = reverse("api-v1:custom_auth:ffadminuser-list") + response = api_client.post(url, data=register_data) + + # Then + assert response.status_code == status.HTTP_403_FORBIDDEN + + @override_settings(ALLOW_REGISTRATION_WITHOUT_INVITE=False) # type: ignore[misc] def test_register__with_invite_when_registration_disabled__returns_created( db: None, diff --git a/api/tests/unit/custom_auth/test_unit_custom_auth_serializer.py b/api/tests/unit/custom_auth/test_unit_custom_auth_serializer.py index fc2f67c9d227..b4c202da442f 100644 --- a/api/tests/unit/custom_auth/test_unit_custom_auth_serializer.py +++ b/api/tests/unit/custom_auth/test_unit_custom_auth_serializer.py @@ -132,6 +132,24 @@ def test_invite_link_validation__hash_not_provided__raises_permission_denied( assert exc_info.value.detail == USER_REGISTRATION_WITHOUT_INVITE_ERROR_MESSAGE +def test_invite_link_validation__existing_email_without_invite__raises_permission_denied( + db: None, + settings: SettingsWrapper, +) -> None: + # Given + settings.ALLOW_REGISTRATION_WITHOUT_INVITE = False + FFAdminUser.objects.create(email="testuser@mail.com") + + serializer = CustomUserCreateSerializer(data=user_dict) + + # When + with pytest.raises(PermissionDenied) as exc_info: + serializer.is_valid(raise_exception=True) + + # Then + assert exc_info.value.detail == USER_REGISTRATION_WITHOUT_INVITE_ERROR_MESSAGE + + def test_invite_link_validation__invalid_hash__raises_permission_denied( invite_link: InviteLink, settings: SettingsWrapper,