From 9c0cb341069604bb6126c1d276b9f6d2429b4ec1 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Wed, 8 Apr 2026 00:13:39 +0200 Subject: [PATCH] Merge commit from fork * fix behaviour * style fixes --------- Co-authored-by: Oliver Walters --- src/backend/InvenTree/users/serializers.py | 15 +++++++++++++- src/backend/InvenTree/users/test_api.py | 24 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/backend/InvenTree/users/serializers.py b/src/backend/InvenTree/users/serializers.py index 284b4611d3..5882121665 100644 --- a/src/backend/InvenTree/users/serializers.py +++ b/src/backend/InvenTree/users/serializers.py @@ -238,8 +238,21 @@ class ApiTokenSerializer(InvenTreeModelSerializer): def validate(self, data): """Validate the data for the serializer.""" + request_user = self.context['request'].user + if not request_user: + raise serializers.ValidationError( + _('User must be authenticated') + ) # pragma: no cover + if 'user' not in data: - data['user'] = self.context['request'].user + data['user'] = request_user + + # Only superusers can create tokens for other users + if data['user'] != request_user and not request_user.is_superuser: + raise serializers.ValidationError( + _('Only a superuser can create a token for another user') + ) + return super().validate(data) user_detail = UserSerializer(source='user', read_only=True) diff --git a/src/backend/InvenTree/users/test_api.py b/src/backend/InvenTree/users/test_api.py index 54c4ddfa3a..016070d5ef 100644 --- a/src/backend/InvenTree/users/test_api.py +++ b/src/backend/InvenTree/users/test_api.py @@ -259,6 +259,8 @@ class SuperuserAPITests(InvenTreeAPITestCase): class UserTokenTests(InvenTreeAPITestCase): """Tests for user token functionality.""" + fixtures = ['users'] + def test_token_generation(self): """Test user token generation.""" url = reverse('api-token') @@ -397,6 +399,28 @@ class UserTokenTests(InvenTreeAPITestCase): self.client.logout() self.get(reverse('api-token'), expected_code=401) + def test_token_security(self): + """Test that token generation is only available to users with the correct permissions.""" + url = reverse('api-token-list') + + # Try to generate a token for a different user (should fail) + response = self.post(url, data={'name': 'test', 'user': 1}, expected_code=400) + self.assertIn( + 'Only a superuser can create a token for another user', str(response.data) + ) + + # there should be no tokens created + self.assertEqual(ApiToken.objects.count(), 0) + + # now with superuser permissions + self.user.is_superuser = True + self.user.save() + + response = self.post(url, data={'name': 'test', 'user': 1}, expected_code=201) + self.assertIn('token', response.data) + + self.assertEqual(ApiToken.objects.count(), 1) + class GroupDetialTests(InvenTreeAPITestCase): """Tests for the GroupDetail API endpoint."""