Source code for model_permissions.backends

"""
django-model-permissions - simple object permissions for django.

Copyright (C) 2018 Mathias Stelzer

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
from django.conf import settings
from django.contrib.auth.backends import (
    ModelBackend as DjangoModelBackend,
    AllowAllUsersModelBackend as DjangoAllowAllUsersModelBackend,
    RemoteUserBackend as DjangoRemoteUserBackend,
    AllowAllUsersRemoteUserBackend as DjangoAllowAllUsersRemoteUserBackend,
)
from django.utils.module_loading import import_string


# mixins

[docs]class BaseObjectBackendMixin(object): """Base class for object permission backends."""
[docs] def get_permission_function(self, obj): """ Get the function to list the given objects permissions. This checks the given object for a ``get_permissions`` method and, if it doesn't exist, the ``MODEL_PERMISSIONS`` setting to find the objects :ref:`manual-permission-function`. :param obj: The model instance to get the function for. :type obj: :class:`django.db.models.Model` :return: The function to list the objects permissions. :rtype: :class:`callable` """ get_permissions = getattr(obj, 'get_permissions', None) if get_permissions is not None: return self.model_permission_wrapper model_permissions = getattr(settings, 'MODEL_PERMISSIONS', {}) f = model_permissions.get(obj._meta.label, None) if f is None: return if callable(f): return f # assume string return import_string(f)
[docs] def model_permission_wrapper(self, user_obj, obj): """Object permission wrapper for the `get_permissions` model method.""" return obj.get_permissions(user_obj)
[docs] def get_object_permissions(self, user_obj, obj=None): """ Get object permissions for the given user and object. Exit early and return an empty set if: * no object is given * the user is * inactive * anonymous * a superuser * no permission function can be found :param user_obj: User instance. :type user_obj: :class:`django.contrib.auth.models.AbstractUser` :param obj: Model instance. :type obj: :class:`django.db.models.Model` :return: Set of permissions. :rtype: :class:`set` """ if obj is None: return set() get_permissions = self.get_permission_function(obj) if get_permissions is None: return set() perm_cache_name = '_{}_{}_perm_cache'.format(obj._meta.label, obj.pk) if not hasattr(user_obj, perm_cache_name): perms = get_permissions(user_obj, obj) if perms is None: perms = set() setattr(user_obj, perm_cache_name, perms) return getattr(user_obj, perm_cache_name)
[docs]class ObjectModelBackendMixin(BaseObjectBackendMixin): """Mixin for dual permission authentication backends."""
[docs] def get_all_permissions(self, user_obj, obj=None): """Get all permissions for the given user and object.""" perms = super().get_all_permissions(user_obj) perms.update(self.get_object_permissions(user_obj, obj=obj)) return perms
[docs]class ObjectBackendMixin(BaseObjectBackendMixin): """Mixin for object-only permission authentication backends."""
[docs] def get_all_permissions(self, user_obj, obj=None): """Get all permissions for the given user and object.""" return self.get_object_permissions(user_obj, obj=obj)
# backends
[docs]class ObjectBackend(ObjectBackendMixin, DjangoModelBackend): """An authentication backend with object permissions only.""" pass
[docs]class ObjectModelBackend(ObjectModelBackendMixin, DjangoModelBackend): """An authentication backend with default and object permissions.""" pass
[docs]class AllowAllUsersObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersModelBackend): """Django's `AllowAllUsersModelBackend` with object permissions only.""" pass
[docs]class AllowAllUsersObjectModelBackend(ObjectModelBackendMixin, DjangoAllowAllUsersModelBackend): """Django's `AllowAllUsersModelBackend` with dual permissions.""" pass
[docs]class RemoteUserObjectBackend(ObjectBackendMixin, DjangoRemoteUserBackend): """Django's `RemoteUserBackend` with object permissions only.""" pass
[docs]class RemoteUserBackend(ObjectModelBackendMixin, DjangoRemoteUserBackend): """Django's `RemoteUserBackend` with dual permissions.""" pass
[docs]class AllowAllUsersRemoteUserObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersRemoteUserBackend): """Django's `AllowAllUsersRemoteUserBackend` with object permissions only.""" pass
[docs]class AllowAllUsersRemoteUserBackend(ObjectModelBackendMixin, DjangoAllowAllUsersRemoteUserBackend): """Django's `AllowAllUsersRemoteUserBackend` with dual permissions.""" pass