1 |
1 |
import copy
|
2 |
2 |
import functools
|
3 |
3 |
|
|
4 |
from django.apps import apps
|
4 |
5 |
from django.conf import settings
|
5 |
6 |
from django.contrib.contenttypes.models import ContentType
|
6 |
7 |
from django.core.exceptions import FieldDoesNotExist
|
|
8 |
from django.db import models
|
7 |
9 |
from django.db.models.query import Q
|
8 |
10 |
|
9 |
11 |
from django_rbac import utils
|
... | ... | |
20 |
22 |
return field.related_model
|
21 |
23 |
|
22 |
24 |
|
|
25 |
_MODEL_CHILDREN = None
|
|
26 |
_MODEL_PARENTS = None
|
|
27 |
|
|
28 |
|
|
29 |
def get_model_inheritance():
|
|
30 |
global _MODEL_CHILDREN # pylint: disable=global-statement
|
|
31 |
global _MODEL_PARENTS # pylint: disable=global-statement
|
|
32 |
|
|
33 |
if _MODEL_CHILDREN is None or _MODEL_PARENTS is None:
|
|
34 |
_MODEL_CHILDREN = {}
|
|
35 |
_MODEL_PARENTS = {}
|
|
36 |
for app in apps.get_app_configs():
|
|
37 |
for child in app.get_models():
|
|
38 |
for parent in child.__bases__:
|
|
39 |
if (
|
|
40 |
issubclass(parent, models.Model)
|
|
41 |
and hasattr(parent, '_meta')
|
|
42 |
and not parent._meta.abstract
|
|
43 |
):
|
|
44 |
_MODEL_CHILDREN.setdefault(parent, set()).add(child)
|
|
45 |
_MODEL_PARENTS.setdefault(child, set()).add(parent)
|
|
46 |
return _MODEL_CHILDREN, _MODEL_PARENTS
|
|
47 |
|
|
48 |
|
|
49 |
def get_model_child_classes(model):
|
|
50 |
return get_model_inheritance()[0].get(model) or ()
|
|
51 |
|
|
52 |
|
|
53 |
def get_model_parent_classes(model):
|
|
54 |
return get_model_inheritance()[1].get(model) or ()
|
|
55 |
|
|
56 |
|
23 |
57 |
class DjangoRBACBackend:
|
24 |
58 |
_DEFAULT_DJANGO_RBAC_PERMISSIONS_HIERARCHY = {
|
25 |
59 |
'view': ['search'],
|
... | ... | |
59 |
93 |
target = ContentType.objects.get_for_id(permission.target_id)
|
60 |
94 |
app_label = target.app_label
|
61 |
95 |
model = target.model
|
|
96 |
model_child_classes = get_model_child_classes(target.model_class())
|
62 |
97 |
if permission.ou_id:
|
63 |
98 |
key = 'ou.%s' % permission.ou_id
|
64 |
99 |
else:
|
... | ... | |
66 |
101 |
else:
|
67 |
102 |
app_label = target_ct.app_label
|
68 |
103 |
model = target_ct.model
|
|
104 |
model_child_classes = get_model_child_classes(target_ct.model_class)
|
69 |
105 |
key = '%s.%s' % (permission.target_ct_id, permission.target_id)
|
70 |
106 |
slug = permission.operation.slug
|
71 |
|
perms = [str('%s.%s_%s' % (app_label, slug, model))]
|
|
107 |
perms = ['%s.%s_%s' % (app_label, slug, model)]
|
|
108 |
for model_child_class in model_child_classes:
|
|
109 |
perms.append(
|
|
110 |
f'{model_child_class._meta.app_label}.{slug}_{model_child_class._meta.model_name}'
|
|
111 |
)
|
72 |
112 |
perm_hierarchy = getattr(
|
73 |
113 |
settings,
|
74 |
114 |
'DJANGO_RBAC_PERMISSIONS_HIERARCHY',
|
... | ... | |
77 |
117 |
if slug in perm_hierarchy:
|
78 |
118 |
for other_perm in perm_hierarchy[slug]:
|
79 |
119 |
perms.append(str('%s.%s_%s' % (app_label, other_perm, model)))
|
|
120 |
for model_child_class in model_child_classes:
|
|
121 |
for other_perm in perm_hierarchy[slug]:
|
|
122 |
perms.append(
|
|
123 |
f'{model_child_class._meta.app_label}.{other_perm}_{model_child_class._meta.model_name}'
|
|
124 |
)
|
80 |
125 |
permissions = perms_cache.setdefault(key, set())
|
81 |
126 |
permissions.update(perms)
|
82 |
127 |
# optimization for has_module_perms
|
... | ... | |
93 |
138 |
ct = ContentType.objects.get_for_model(obj)
|
94 |
139 |
key = '%s.%s' % (ct.id, obj.pk)
|
95 |
140 |
if key in perms_cache:
|
|
141 |
object_permissions = perms_cache[key]
|
96 |
142 |
permissions.update(perms_cache[key])
|
|
143 |
# add equivalent permissions with parent app_label.model_name
|
|
144 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
145 |
for permission in object_permissions:
|
|
146 |
_, rest = permission.split('.')
|
|
147 |
operation, _ = rest.rsplit('_', 1)
|
|
148 |
permissions.add(f'{parent._meta.app_label}.{operation}_{parent._meta.model_name}')
|
97 |
149 |
for permission in perms_cache.get('__all__', set()):
|
98 |
150 |
if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model):
|
99 |
151 |
permissions.add(permission)
|
|
152 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
153 |
if permission.startswith(parent._meta.app_label) and permission.endswith(
|
|
154 |
f'_{parent._meta.model_name}'
|
|
155 |
):
|
|
156 |
permissions.add(permission)
|
100 |
157 |
if hasattr(obj, 'ou_id') and obj.ou_id:
|
101 |
158 |
key = 'ou.%s' % obj.ou_id
|
102 |
159 |
for permission in perms_cache.get(key, ()):
|
103 |
160 |
if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model):
|
104 |
161 |
permissions.add(permission)
|
|
162 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
163 |
if permission.startswith(parent._meta.app_label) and permission.endswith(
|
|
164 |
f'_{parent._meta.model_name}'
|
|
165 |
):
|
|
166 |
permissions.add(permission)
|
105 |
167 |
return permissions
|
106 |
168 |
else:
|
107 |
169 |
return perms_cache.get('__all__', [])
|