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 issubclass(parent, models.Model) and hasattr(parent, '_meta'):
|
|
40 |
_MODEL_CHILDREN.setdefault(parent, set()).add(child)
|
|
41 |
_MODEL_PARENTS.setdefault(child, set()).add(parent)
|
|
42 |
return _MODEL_CHILDREN, _MODEL_PARENTS
|
|
43 |
|
|
44 |
|
|
45 |
def get_model_child_classes(model):
|
|
46 |
return get_model_inheritance()[0].get(model) or ()
|
|
47 |
|
|
48 |
|
|
49 |
def get_model_parent_classes(model):
|
|
50 |
return get_model_inheritance()[1].get(model) or ()
|
|
51 |
|
|
52 |
|
23 |
53 |
class DjangoRBACBackend:
|
24 |
54 |
_DEFAULT_DJANGO_RBAC_PERMISSIONS_HIERARCHY = {
|
25 |
55 |
'view': ['search'],
|
... | ... | |
59 |
89 |
target = ContentType.objects.get_for_id(permission.target_id)
|
60 |
90 |
app_label = target.app_label
|
61 |
91 |
model = target.model
|
|
92 |
model_child_classes = get_model_child_classes(target.model_class())
|
62 |
93 |
if permission.ou_id:
|
63 |
94 |
key = 'ou.%s' % permission.ou_id
|
64 |
95 |
else:
|
... | ... | |
66 |
97 |
else:
|
67 |
98 |
app_label = target_ct.app_label
|
68 |
99 |
model = target_ct.model
|
|
100 |
model_child_classes = get_model_child_classes(target_ct.model_class)
|
69 |
101 |
key = '%s.%s' % (permission.target_ct_id, permission.target_id)
|
70 |
102 |
slug = permission.operation.slug
|
71 |
|
perms = [str('%s.%s_%s' % (app_label, slug, model))]
|
|
103 |
perms = ['%s.%s_%s' % (app_label, slug, model)]
|
|
104 |
for model_child_class in model_child_classes:
|
|
105 |
perms.append(
|
|
106 |
f'{model_child_class._meta.app_label}.{slug}_{model_child_class._meta.model_name}'
|
|
107 |
)
|
72 |
108 |
perm_hierarchy = getattr(
|
73 |
109 |
settings,
|
74 |
110 |
'DJANGO_RBAC_PERMISSIONS_HIERARCHY',
|
... | ... | |
77 |
113 |
if slug in perm_hierarchy:
|
78 |
114 |
for other_perm in perm_hierarchy[slug]:
|
79 |
115 |
perms.append(str('%s.%s_%s' % (app_label, other_perm, model)))
|
|
116 |
for model_child_class in model_child_classes:
|
|
117 |
for other_perm in perm_hierarchy[slug]:
|
|
118 |
perms.append(
|
|
119 |
f'{model_child_class._meta.app_label}.{other_perm}_{model_child_class._meta.model_name}'
|
|
120 |
)
|
80 |
121 |
permissions = perms_cache.setdefault(key, set())
|
81 |
122 |
permissions.update(perms)
|
82 |
123 |
# optimization for has_module_perms
|
... | ... | |
93 |
134 |
ct = ContentType.objects.get_for_model(obj)
|
94 |
135 |
key = '%s.%s' % (ct.id, obj.pk)
|
95 |
136 |
if key in perms_cache:
|
|
137 |
object_permissions = perms_cache[key]
|
96 |
138 |
permissions.update(perms_cache[key])
|
|
139 |
# add equivalent permissions with parent app_label.model_name
|
|
140 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
141 |
for permission in object_permissions:
|
|
142 |
app_label, rest = permission.split('.')
|
|
143 |
operation, model_name = rest.rsplit('_', 1)
|
|
144 |
permissions.add(f'{parent._meta.app_label}.{operation}_{parent._meta.model_name}')
|
97 |
145 |
for permission in perms_cache.get('__all__', set()):
|
98 |
146 |
if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model):
|
99 |
147 |
permissions.add(permission)
|
|
148 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
149 |
if permission.startswith(parent._meta.app_label) and permission.endswith(
|
|
150 |
f'_{parent._meta.model_name}'
|
|
151 |
):
|
|
152 |
permissions.add(permission)
|
100 |
153 |
if hasattr(obj, 'ou_id') and obj.ou_id:
|
101 |
154 |
key = 'ou.%s' % obj.ou_id
|
102 |
155 |
for permission in perms_cache.get(key, ()):
|
103 |
156 |
if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model):
|
104 |
157 |
permissions.add(permission)
|
|
158 |
for parent in get_model_parent_classes(ct.model_class()):
|
|
159 |
if permission.startswith(parent._meta.app_label) and permission.endswith(
|
|
160 |
f'_{parent._meta.model_name}'
|
|
161 |
):
|
|
162 |
permissions.add(permission)
|
105 |
163 |
return permissions
|
106 |
164 |
else:
|
107 |
165 |
return perms_cache.get('__all__', [])
|