From c6252f4803a86b40e807c8eac79d69a8c58791aa Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Tue, 7 Dec 2021 14:54:52 +0100
Subject: [PATCH 3/3] a2_rbac: test rbac backend with new operation model
 (#58829)

---
 tests/test_a2_rbac.py | 90 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/tests/test_a2_rbac.py b/tests/test_a2_rbac.py
index 3009888c..92b2d497 100644
--- a/tests/test_a2_rbac.py
+++ b/tests/test_a2_rbac.py
@@ -18,6 +18,8 @@ import pytest
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.core.management import call_command
+from django.db import connection
+from django.test.utils import CaptureQueriesContext
 
 from authentic2.a2_rbac.models import Operation
 from authentic2.a2_rbac.models import OrganizationalUnit as OU
@@ -26,6 +28,7 @@ from authentic2.a2_rbac.utils import get_default_ou
 from authentic2.custom_user.models import User
 from authentic2.models import Service
 from authentic2.utils.misc import get_hex_uuid
+from django_rbac import backends
 
 from .utils import login, request_select2
 
@@ -518,3 +521,90 @@ def test_update_content_types_roles(transactional_db, simple_user):
     update_user_permissions()
     assert simple_user.has_perm('custom_user.manage_authorizations_user')
     assert [x for x in simple_user.get_all_permissions() if x == 'custom_user.manage_authorizations_user']
+
+
+def test_rbac_backend_with_a2_operation_model(db):
+    ou1 = OU.objects.create(name='ou1', slug='ou1')
+    ou2 = OU.objects.create(name='ou2', slug='ou2')
+    user1 = User.objects.create(username='john.doe')
+    ct_ct = ContentType.objects.get_for_model(ContentType)
+    role_ct = ContentType.objects.get_for_model(Role)
+    change_op = Operation.objects.get(slug='change')
+    view_op = Operation.objects.get(slug='view')
+    delete_op = Operation.objects.get(slug='delete')
+    add_op = Operation.objects.get(slug='add')
+    admin_op = Operation.objects.get(slug='admin')
+    perm1 = Permission.objects.create(operation=change_op, target_ct=ct_ct, target_id=role_ct.pk)
+    perm2 = Permission.objects.create(operation=view_op, target_ct=ct_ct, target_id=role_ct.pk)
+    role1 = Role.objects.create(name='role1')
+    role2 = Role.objects.create(name='role2', ou=ou1)
+    role1.permissions.add(perm1)
+    role2.permissions.add(perm2)
+    role1.add_child(role2)
+    role2.members.add(user1)
+    perm3 = Permission.objects.create(operation=delete_op, target_ct=role_ct, target_id=role1.pk)
+    perm4 = Permission.objects.create(operation=add_op, ou=ou1, target_ct=ct_ct, target_id=role_ct.pk)
+    role1.permissions.add(perm3)
+    role1.permissions.add(perm4)
+
+    rbac_backend = backends.DjangoRBACBackend()
+    ctx = CaptureQueriesContext(connection)
+    with ctx:
+        assert rbac_backend.get_all_permissions(user1) == {
+            'a2_rbac.change_role',
+            'a2_rbac.search_role',
+            'a2_rbac.view_role',
+            'a2_rbac.manage_members_role',
+        }
+        assert rbac_backend.get_all_permissions(user1, obj=role1) == {
+            'a2_rbac.delete_role',
+            'a2_rbac.change_role',
+            'a2_rbac.search_role',
+            'a2_rbac.view_role',
+            'a2_rbac.manage_members_role',
+        }
+        assert rbac_backend.get_all_permissions(user1, obj=role2) == {
+            'a2_rbac.change_role',
+            'a2_rbac.view_role',
+            'a2_rbac.search_role',
+            'a2_rbac.add_role',
+            'a2_rbac.manage_members_role',
+        }
+        assert not rbac_backend.has_perm(user1, 'a2_rbac.delete_role', obj=role2)
+        assert rbac_backend.has_perm(user1, 'a2_rbac.delete_role', obj=role1)
+        assert rbac_backend.has_perms(
+            user1, ['a2_rbac.delete_role', 'a2_rbac.change_role', 'a2_rbac.view_role'], obj=role1
+        )
+        assert rbac_backend.has_module_perms(user1, 'a2_rbac')
+        assert not rbac_backend.has_module_perms(user1, 'contenttypes')
+    assert len(ctx.captured_queries) == 1
+
+    # Test admin op as a generalization of other ops
+    user2 = User.objects.create(username='donald.knuth')
+    role3 = Role.objects.create(name='role3')
+    role3.members.add(user2)
+
+    # four objects returned by filter? xxx unicity issues
+    perms5 = Permission.objects.filter(operation=admin_op, target_ct=ct_ct, target_id=role_ct.pk)
+    # iteration needed here?? xxx
+    for perm in perms5:
+        role3.permissions.add(perm)
+    assert rbac_backend.get_all_permissions(user2) == {
+        'a2_rbac.add_role',
+        'a2_rbac.change_role',
+        'a2_rbac.search_role',
+        'a2_rbac.admin_role',
+        'a2_rbac.view_role',
+        'a2_rbac.delete_role',
+        'a2_rbac.manage_members_role',
+        'a2_rbac.reset_password_role',
+        'a2_rbac.manage_authorizations_role',
+        'a2_rbac.activate_role',
+        'a2_rbac.change_password_role',
+        'a2_rbac.change_email_role',
+    }
+
+    # test ous_with_perm
+    assert set(rbac_backend.ous_with_perm(user1, 'a2_rbac.add_role')) == {ou1}
+    assert set(rbac_backend.ous_with_perm(user1, 'a2_rbac.view_role')) == {ou1, ou2, get_default_ou()}
+    assert set(rbac_backend.ous_with_perm(user1, 'a2_rbac.delete_role')) == set()
-- 
2.34.1

