]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Change: restrict superuser modifications to superusers only
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 24 Oct 2025 23:25:59 +0000 (16:25 -0700)
committershamoon <4887959+shamoon@users.noreply.github.com>
Fri, 24 Oct 2025 23:25:59 +0000 (16:25 -0700)
src/documents/tests/test_admin.py
src/paperless/views.py

index 278014f7cded27b7c453499a2169dd55e1d4f53e..61a579dc748c91125be46310eca4339f64dc4d07 100644 (file)
@@ -2,9 +2,11 @@ import types
 from unittest.mock import patch
 
 from django.contrib.admin.sites import AdminSite
+from django.contrib.auth.models import Permission
 from django.contrib.auth.models import User
 from django.test import TestCase
 from django.utils import timezone
+from rest_framework import status
 
 from documents import index
 from documents.admin import DocumentAdmin
@@ -125,3 +127,36 @@ class TestPaperlessAdmin(DirectoriesMixin, TestCase):
         form.request = types.SimpleNamespace(user=superuser)
         self.assertTrue(form.is_valid())
         self.assertEqual({}, form.errors)
+
+    def test_superuser_can_only_be_modified_by_superuser(self):
+        superuser = User.objects.create_superuser(username="superuser", password="test")
+        user = User.objects.create(
+            username="test",
+            is_superuser=False,
+            is_staff=True,
+        )
+        change_user_perm = Permission.objects.get(codename="change_user")
+        user.user_permissions.add(change_user_perm)
+
+        self.client.force_login(user)
+        response = self.client.patch(
+            f"/api/users/{superuser.pk}/",
+            {"first_name": "Updated"},
+            content_type="application/json",
+        )
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+        self.assertEqual(
+            response.content.decode(),
+            "Superusers can only be modified by other superusers",
+        )
+
+        self.client.logout()
+        self.client.force_login(superuser)
+        response = self.client.patch(
+            f"/api/users/{superuser.pk}/",
+            {"first_name": "Updated"},
+            content_type="application/json",
+        )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        superuser.refresh_from_db()
+        self.assertEqual(superuser.first_name, "Updated")
index fc5bb54634a966008bb301398a373c0313a8d579..69375e1bc23772ca9bb4e0c9c4fbd641706e5ec5 100644 (file)
@@ -125,6 +125,10 @@ class UserViewSet(ModelViewSet):
 
     def update(self, request, *args, **kwargs):
         user_to_update: User = self.get_object()
+        if not request.user.is_superuser and user_to_update.is_superuser:
+            return HttpResponseForbidden(
+                "Superusers can only be modified by other superusers",
+            )
         if (
             not request.user.is_superuser
             and request.data.get("is_superuser") is not None