diff --git a/src/backend/InvenTree/users/serializers.py b/src/backend/InvenTree/users/serializers.py index 528b1beeee..393b858cf2 100644 --- a/src/backend/InvenTree/users/serializers.py +++ b/src/backend/InvenTree/users/serializers.py @@ -544,6 +544,19 @@ class UserCreateSerializer(ExtendedUserSerializer): _('You do not have permission to create users') ) + # Email-based flows (password reset, login link) look users up by email, + # and fail silently if more than one user has the same address + if email := attrs.get('email'): + from allauth.account.models import EmailAddress + + if ( + User.objects.filter(email__iexact=email).exists() + or EmailAddress.objects.filter(email__iexact=email).exists() + ): + raise serializers.ValidationError({ + 'email': _('A user with this email address already exists') + }) + # Generate a random password password = make_random_password(length=14) attrs.update({'password': password}) diff --git a/src/backend/InvenTree/users/test_api.py b/src/backend/InvenTree/users/test_api.py index 4644ef23f8..c332e2d81d 100644 --- a/src/backend/InvenTree/users/test_api.py +++ b/src/backend/InvenTree/users/test_api.py @@ -131,11 +131,24 @@ class UserAPITests(InvenTreeAPITestCase): ).exists() ) + # A second user with the same email address (any case) is rejected + response = self.post( + url, + data={**data, 'username': 'test2', 'email': 'AA@example.org'}, + expected_code=400, + ) + self.assertIn('email', response.data) + # Try to adjust the 'is_superuser' field # Only a "superuser" can set this field response = self.post( url, - data={**data, 'username': 'Superuser', 'is_superuser': True}, + data={ + **data, + 'username': 'Superuser', + 'email': 'su@example.org', + 'is_superuser': True, + }, expected_code=403, ) @@ -147,7 +160,12 @@ class UserAPITests(InvenTreeAPITestCase): response = self.post( url, - data={**data, 'username': 'Superuser', 'is_superuser': True}, + data={ + **data, + 'username': 'Superuser', + 'email': 'su@example.org', + 'is_superuser': True, + }, expected_code=201, ) @@ -186,7 +204,12 @@ class UserAPITests(InvenTreeAPITestCase): # Creating a user without specifying groups must still work response = self.post( url, - data={**data, 'username': 'ungrouped', 'group_ids': []}, + data={ + **data, + 'username': 'ungrouped', + 'email': 'ungrouped@example.org', + 'group_ids': [], + }, expected_code=201, ) self.assertEqual(response.data['groups'], [])