summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorBerker Peksag <berker.peksag@gmail.com>2016-08-25 19:26:18 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-08-29 19:32:12 +0200
commit400ec5125ec32e3b18d267bbb4f3aab09d741ce4 (patch)
tree96ef0b85d3dc5b7ea132307ab7fc1f6683201905 /django
parentfa7ffc6cb3b143fb8566cbf6a387d0f032377dc7 (diff)
Fixed #18763 -- Added ModelBackend/UserManager.with_perm() methods.
Co-authored-by: Nick Pope <nick.pope@flightdataservices.com>
Diffstat (limited to 'django')
-rw-r--r--django/contrib/auth/backends.py37
-rw-r--r--django/contrib/auth/models.py26
2 files changed, 63 insertions, 0 deletions
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
index a3765ae0f1..559d06fe33 100644
--- a/django/contrib/auth/backends.py
+++ b/django/contrib/auth/backends.py
@@ -3,6 +3,7 @@ import warnings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
+from django.db.models import Exists, OuterRef, Q
from django.utils.deprecation import RemovedInDjango31Warning
UserModel = get_user_model()
@@ -119,6 +120,42 @@ class ModelBackend(BaseBackend):
for perm in self.get_all_permissions(user_obj)
)
+ def with_perm(self, perm, is_active=True, include_superusers=True, obj=None):
+ """
+ Return users that have permission "perm". By default, filter out
+ inactive users and include superusers.
+ """
+ if isinstance(perm, str):
+ try:
+ app_label, codename = perm.split('.')
+ except ValueError:
+ raise ValueError(
+ 'Permission name should be in the form '
+ 'app_label.permission_codename.'
+ )
+ elif not isinstance(perm, Permission):
+ raise TypeError(
+ 'The `perm` argument must be a string or a permission instance.'
+ )
+
+ UserModel = get_user_model()
+ if obj is not None:
+ return UserModel._default_manager.none()
+
+ permission_q = Q(group__user=OuterRef('pk')) | Q(user=OuterRef('pk'))
+ if isinstance(perm, Permission):
+ permission_q &= Q(pk=perm.pk)
+ else:
+ permission_q &= Q(codename=codename, content_type__app_label=app_label)
+
+ user_q = Exists(Permission.objects.filter(permission_q))
+ if include_superusers:
+ user_q |= Q(is_superuser=True)
+ if is_active is not None:
+ user_q &= Q(is_active=is_active)
+
+ return UserModel._default_manager.filter(user_q)
+
def get_user(self, user_id):
try:
user = UserModel._default_manager.get(pk=user_id)
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 971621d9c7..27278af4d2 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -157,6 +157,32 @@ class UserManager(BaseUserManager):
return self._create_user(username, email, password, **extra_fields)
+ def with_perm(self, perm, is_active=True, include_superusers=True, backend=None, obj=None):
+ if backend is None:
+ backends = auth._get_backends(return_tuples=True)
+ if len(backends) == 1:
+ backend, _ = backends[0]
+ else:
+ raise ValueError(
+ 'You have multiple authentication backends configured and '
+ 'therefore must provide the `backend` argument.'
+ )
+ elif not isinstance(backend, str):
+ raise TypeError(
+ 'backend must be a dotted import path string (got %r).'
+ % backend
+ )
+ else:
+ backend = auth.load_backend(backend)
+ if hasattr(backend, 'with_perm'):
+ return backend.with_perm(
+ perm,
+ is_active=is_active,
+ include_superusers=include_superusers,
+ obj=obj,
+ )
+ return self.none()
+
# A few helper functions for common logic between User and AnonymousUser.
def _user_get_permissions(user, obj, from_name):