Coverage for src/model_permissions/backends.py: 100.00%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2django-model-permissions - simple object permissions for django.
4Copyright (C) 2018 Mathias Stelzer
6This program is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18"""
19from django.conf import settings
20from django.contrib.auth.backends import (
21 ModelBackend as DjangoModelBackend,
22 AllowAllUsersModelBackend as DjangoAllowAllUsersModelBackend,
23 RemoteUserBackend as DjangoRemoteUserBackend,
24 AllowAllUsersRemoteUserBackend as DjangoAllowAllUsersRemoteUserBackend,
25)
26from django.utils.module_loading import import_string
29# mixins
31class BaseObjectBackendMixin(object):
32 """Base class for object permission backends."""
34 def get_permission_function(self, obj):
35 """
36 Get the function to list the given objects permissions.
38 This checks the given object for a ``get_permissions`` method and,
39 if it doesn't exist, the ``MODEL_PERMISSIONS`` setting to find the
40 objects :ref:`manual-permission-function`.
42 :param obj: The model instance to get the function for.
43 :type obj: :class:`django.db.models.Model`
44 :return: The function to list the objects permissions.
45 :rtype: :class:`callable`
46 """
47 get_permissions = getattr(obj, 'get_permissions', None)
48 if get_permissions is not None:
49 return self.model_permission_wrapper
51 model_permissions = getattr(settings, 'MODEL_PERMISSIONS', {})
52 f = model_permissions.get(obj._meta.label, None)
53 if f is None:
54 return
56 if callable(f):
57 return f
59 # assume string
60 return import_string(f)
62 def model_permission_wrapper(self, user_obj, obj):
63 """Object permission wrapper for the `get_permissions` model method."""
64 return obj.get_permissions(user_obj)
66 def get_object_permissions(self, user_obj, obj=None):
67 """
68 Get object permissions for the given user and object.
70 Exit early and return an empty set if:
72 * no object is given
73 * the user is
75 * inactive
76 * anonymous
77 * a superuser
79 * no permission function can be found
81 :param user_obj: User instance.
82 :type user_obj: :class:`django.contrib.auth.models.AbstractUser`
83 :param obj: Model instance.
84 :type obj: :class:`django.db.models.Model`
85 :return: Set of permissions.
86 :rtype: :class:`set`
87 """
88 if obj is None:
89 return set()
91 get_permissions = self.get_permission_function(obj)
92 if get_permissions is None:
93 return set()
95 perm_cache_name = '_{}_{}_perm_cache'.format(obj._meta.label, obj.pk)
96 if not hasattr(user_obj, perm_cache_name):
97 perms = get_permissions(user_obj, obj)
98 if perms is None:
99 perms = set()
100 setattr(user_obj, perm_cache_name, perms)
101 return getattr(user_obj, perm_cache_name)
104class ObjectModelBackendMixin(BaseObjectBackendMixin):
105 """Mixin for dual permission authentication backends."""
107 def get_all_permissions(self, user_obj, obj=None):
108 """Get all permissions for the given user and object."""
109 perms = super().get_all_permissions(user_obj)
110 perms.update(self.get_object_permissions(user_obj, obj=obj))
111 return perms
114class ObjectBackendMixin(BaseObjectBackendMixin):
115 """Mixin for object-only permission authentication backends."""
117 def get_all_permissions(self, user_obj, obj=None):
118 """Get all permissions for the given user and object."""
119 return self.get_object_permissions(user_obj, obj=obj)
122# backends
124class ObjectBackend(ObjectBackendMixin, DjangoModelBackend):
125 """An authentication backend with object permissions only."""
127 pass
130class ObjectModelBackend(ObjectModelBackendMixin, DjangoModelBackend):
131 """An authentication backend with default and object permissions."""
133 pass
136class AllowAllUsersObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersModelBackend):
137 """Django's `AllowAllUsersModelBackend` with object permissions only."""
139 pass
142class AllowAllUsersObjectModelBackend(ObjectModelBackendMixin, DjangoAllowAllUsersModelBackend):
143 """Django's `AllowAllUsersModelBackend` with dual permissions."""
145 pass
148class RemoteUserObjectBackend(ObjectBackendMixin, DjangoRemoteUserBackend):
149 """Django's `RemoteUserBackend` with object permissions only."""
151 pass
154class RemoteUserBackend(ObjectModelBackendMixin, DjangoRemoteUserBackend):
155 """Django's `RemoteUserBackend` with dual permissions."""
157 pass
160class AllowAllUsersRemoteUserObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersRemoteUserBackend):
161 """Django's `AllowAllUsersRemoteUserBackend` with object permissions only."""
163 pass
166class AllowAllUsersRemoteUserBackend(ObjectModelBackendMixin, DjangoAllowAllUsersRemoteUserBackend):
167 """Django's `AllowAllUsersRemoteUserBackend` with dual permissions."""
169 pass