-
Notifications
You must be signed in to change notification settings - Fork 567
/
backends.py
109 lines (87 loc) · 3.79 KB
/
backends.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.db import models
from guardian.conf import settings
from guardian.core import ObjectPermissionChecker
from guardian.ctypes import get_content_type
from guardian.exceptions import WrongAppError
def check_object_support(obj):
"""
Returns ``True`` if given ``obj`` is supported
"""
# Backend checks only object permissions (isinstance implies that obj
# is not None)
# Backend checks only permissions for Django models
return isinstance(obj, models.Model)
def check_user_support(user_obj):
"""
Returns a tuple of checkresult and ``user_obj`` which should be used for
permission checks
Checks if the given user is supported. Anonymous users need explicit
activation via ANONYMOUS_USER_NAME
"""
# This is how we support anonymous users - simply try to retrieve User
# instance and perform checks for that predefined user
if not user_obj.is_authenticated:
# If anonymous user permission is disabled then they are always
# unauthorized
if settings.ANONYMOUS_USER_NAME is None:
return False, user_obj
User = get_user_model()
lookup = {User.USERNAME_FIELD: settings.ANONYMOUS_USER_NAME}
user_obj = User.objects.get(**lookup)
return True, user_obj
def check_support(user_obj, obj):
"""
Combination of ``check_object_support`` and ``check_user_support``
"""
obj_support = check_object_support(obj)
user_support, user_obj = check_user_support(user_obj)
return obj_support and user_support, user_obj
class ObjectPermissionBackend(object):
supports_object_permissions = True
supports_anonymous_user = True
supports_inactive_user = True
def authenticate(self, username, password):
return None
def has_perm(self, user_obj, perm, obj=None):
"""
Returns ``True`` if given ``user_obj`` has ``perm`` for ``obj``. If no
``obj`` is given, ``False`` is returned.
.. note::
Remember, that if user is not *active*, all checks would return
``False``.
Main difference between Django's ``ModelBackend`` is that we can pass
``obj`` instance here and ``perm`` doesn't have to contain
``app_label`` as it can be retrieved from given ``obj``.
**Inactive user support**
If user is authenticated but inactive at the same time, all checks
always returns ``False``.
"""
# check if user_obj and object are supported
support, user_obj = check_support(user_obj, obj)
if not support:
return False
if '.' in perm:
app_label, _ = perm.split('.', maxsplit=1)
if app_label != obj._meta.app_label:
# Check the content_type app_label when permission
# and obj app labels don't match.
ctype = get_content_type(obj)
if app_label != ctype.app_label:
raise WrongAppError("Passed perm has app label of '%s' while "
"given obj has app label '%s' and given obj"
"content_type has app label '%s'" %
(app_label, obj._meta.app_label, ctype.app_label))
check = ObjectPermissionChecker(user_obj)
return check.has_perm(perm, obj)
def get_all_permissions(self, user_obj, obj=None):
"""
Returns a set of permission strings that the given ``user_obj`` has for ``obj``
"""
# check if user_obj and object are supported
support, user_obj = check_support(user_obj, obj)
if not support:
return set()
check = ObjectPermissionChecker(user_obj)
return check.get_perms(obj)