Просмотр исходного кода

Reimplement the ViewExemptModelBackend to explicitly cache all exempted view permissions on the User instance

Jeremy Stretch 5 лет назад
Родитель
Сommit
a275a30dca
1 измененных файлов с 20 добавлено и 23 удалено
  1. 20 23
      netbox/utilities/auth_backends.py

+ 20 - 23
netbox/utilities/auth_backends.py

@@ -3,7 +3,6 @@ import logging
 from django.conf import settings
 from django.conf import settings
 from django.contrib.auth.backends import ModelBackend, RemoteUserBackend as RemoteUserBackend_
 from django.contrib.auth.backends import ModelBackend, RemoteUserBackend as RemoteUserBackend_
 from django.contrib.auth.models import Group, Permission
 from django.contrib.auth.models import Group, Permission
-from django.contrib.contenttypes.models import ContentType
 from django.db.models import Q
 from django.db.models import Q
 
 
 from users.models import ObjectPermission
 from users.models import ObjectPermission
@@ -14,28 +13,26 @@ class ViewExemptModelBackend(ModelBackend):
     Custom implementation of Django's stock ModelBackend which allows for the exemption of arbitrary models from view
     Custom implementation of Django's stock ModelBackend which allows for the exemption of arbitrary models from view
     permission enforcement.
     permission enforcement.
     """
     """
-    def has_perm(self, user_obj, perm, obj=None):
-
-        # If this is a view permission, check whether the model has been exempted from enforcement
-        try:
-            app, codename = perm.split('.')
-            action, model = codename.split('_')
-            if action == 'view':
-                if (
-                    # All models are exempt from view permission enforcement
-                    '*' in settings.EXEMPT_VIEW_PERMISSIONS
-                ) or (
-                    # This specific model is exempt from view permission enforcement
-                    '.'.join((app, model)) in settings.EXEMPT_VIEW_PERMISSIONS
-                ):
-                    return True
-        except ValueError:
-            pass
-
-        # Fall back to ModelBackend's default behavior, with one exception: Set obj to None. Model-level permissions
-        # override object-level permissions, so if a user has the model-level permission we can ignore any specified
-        # object. (By default, ModelBackend will return False if an object is specified.)
-        return super().has_perm(user_obj, perm, None)
+    def _get_user_permissions(self, user_obj):
+
+        if not settings.EXEMPT_VIEW_PERMISSIONS:
+            # No view permissions have been exempted from enforcement, so fall back to the built-in logic.
+            return super()._get_user_permissions(user_obj)
+
+        if '*' in settings.EXEMPT_VIEW_PERMISSIONS:
+            # All view permissions have been exempted from enforcement, so include all view permissions when fetching
+            # User permissions.
+            return Permission.objects.filter(
+                Q(user=user_obj) | Q(codename__startswith='view_')
+            )
+
+        # Return all Permissions that are either assigned to the user or that are view permissions listed in
+        # EXEMPT_VIEW_PERMISSIONS.
+        qs_filter = Q(user=user_obj)
+        for model in settings.EXEMPT_VIEW_PERMISSIONS:
+            app, name = model.split('.')
+            qs_filter |= Q(content_type__app_label=app, codename=f'view_{name}')
+        return Permission.objects.filter(qs_filter)
 
 
 
 
 class ObjectPermissionBackend(ModelBackend):
 class ObjectPermissionBackend(ModelBackend):