diff --git a/src/backend/InvenTree/InvenTree/permissions.py b/src/backend/InvenTree/InvenTree/permissions.py index 3fc25b744e..bd77fab42b 100644 --- a/src/backend/InvenTree/InvenTree/permissions.py +++ b/src/backend/InvenTree/InvenTree/permissions.py @@ -363,6 +363,9 @@ class UserSettingsPermissionsOrScope(OASTokenMixin, permissions.BasePermission): except AttributeError: # pragma: no cover return False + if not user.is_authenticated: + return False + return user == obj.user def has_permission(self, request, view): diff --git a/src/backend/InvenTree/common/api.py b/src/backend/InvenTree/common/api.py index 14bae578aa..f8863a5f7e 100644 --- a/src/backend/InvenTree/common/api.py +++ b/src/backend/InvenTree/common/api.py @@ -275,6 +275,9 @@ class UserSettingsList(SettingsList): queryset = super().filter_queryset(queryset) + if not user.is_authenticated: # pragma: no cover + raise PermissionDenied('User must be authenticated to access user settings') + queryset = queryset.filter(user=user) return queryset @@ -351,6 +354,10 @@ class NotificationList(NotificationMessageMixin, BulkDeleteMixin, ListAPI): return common.models.NotificationMessage.objects.none() queryset = super().filter_queryset(queryset) + + if not user.is_authenticated: # pragma: no cover + raise PermissionDenied('User must be authenticated to access notifications') + queryset = queryset.filter(user=user) return queryset diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py index 3d4ac83d72..95917822ea 100644 --- a/src/backend/InvenTree/common/tests.py +++ b/src/backend/InvenTree/common/tests.py @@ -661,6 +661,21 @@ class GlobalSettingsApiTest(InvenTreeAPITestCase): class UserSettingsApiTest(InvenTreeAPITestCase): """Tests for the user settings API.""" + def test_unauthenticated_user(self): + """Test access with unauthenticated user.""" + self.client.logout() + + # Check list API endpoint + url = reverse('api-user-setting-list') + response = self.get(url, expected_code=401).data + self.assertIn( + 'Authentication credentials were not provided', str(response['detail']) + ) + + # Check the detail API endpoint + url = reverse('api-user-setting-detail', kwargs={'key': 'LABEL_INLINE'}) + self.get(url, expected_code=401) + def test_user_settings_api_list(self): """Test list URL for user settings.""" url = reverse('api-user-setting-list')