diff --git a/src/documents/permissions.py b/src/documents/permissions.py index 65609618a..a97df8ec4 100644 --- a/src/documents/permissions.py +++ b/src/documents/permissions.py @@ -188,6 +188,12 @@ def permitted_document_ids( if getattr(user, "is_superuser", False): return base_docs.values_list("id", flat=True) + # Guardian's UserObjectPermission/GroupObjectPermission always store a bare + # codename, but has_perm()-style callers commonly pass the qualified + # "app_label.codename" form. content_type already disambiguates the + # codename, so just drop any prefix rather than silently under-permitting. + perm = perm.rsplit(".", 1)[-1] + document_ct = ContentType.objects.get_for_model(Document) perm_filter = { "permission__codename": perm, diff --git a/src/documents/tests/test_permission_filtering_security.py b/src/documents/tests/test_permission_filtering_security.py index bf6ab26ca..4ec6cf13c 100644 --- a/src/documents/tests/test_permission_filtering_security.py +++ b/src/documents/tests/test_permission_filtering_security.py @@ -241,6 +241,18 @@ class TestPermittedDocumentIdsArbitraryPermission: expected_hidden=[doc.pk], ) + def test_qualified_permission_string_is_normalized_to_codename(self): + owner = User.objects.create_user(username="owner") + editor = User.objects.create_user(username="editor") + doc = DocumentFactory(owner=owner) + assign_perm("change_document", editor, doc) + + assert_visible_document_ids( + permitted_document_ids(editor, perm="documents.change_document"), + expected_visible=[doc.pk], + expected_hidden=[], + ) + def test_delete_permission_with_include_deleted_for_trash_restore(self): owner = User.objects.create_user(username="owner") stranger = User.objects.create_user(username="mallory")