Przeglądaj źródła

Introduced ObjectPermissionRequiredMixin

Jeremy Stretch 5 lat temu
rodzic
commit
4b5d64939d
2 zmienionych plików z 42 dodań i 1 usunięć
  1. 2 1
      netbox/dcim/views.py
  2. 40 0
      netbox/netbox/authentication.py

+ 2 - 1
netbox/dcim/views.py

@@ -21,6 +21,7 @@ from extras.models import Graph
 from extras.views import ObjectConfigContextView
 from extras.views import ObjectConfigContextView
 from ipam.models import Prefix, VLAN
 from ipam.models import Prefix, VLAN
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
 from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
+from netbox.authentication import ObjectPermissionRequiredMixin
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator
 from utilities.paginator import EnhancedPaginator
 from utilities.utils import csv_format
 from utilities.utils import csv_format
@@ -185,7 +186,7 @@ class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 # Sites
 # Sites
 #
 #
 
 
-class SiteListView(PermissionRequiredMixin, ObjectListView):
+class SiteListView(ObjectPermissionRequiredMixin, ObjectListView):
     permission_required = 'dcim.view_site'
     permission_required = 'dcim.view_site'
     queryset = Site.objects.prefetch_related('region', 'tenant')
     queryset = Site.objects.prefetch_related('region', 'tenant')
     filterset = filters.SiteFilterSet
     filterset = filters.SiteFilterSet

+ 40 - 0
netbox/netbox/authentication.py

@@ -0,0 +1,40 @@
+from django.contrib.auth.mixins import AccessMixin
+from django.contrib.contenttypes.models import ContentType
+from django.db.models import Q
+
+from users.models import ObjectPermission
+
+
+class ObjectPermissionRequiredMixin(AccessMixin):
+    permission_required = None
+
+    def has_permission(self):
+
+        # First, check whether the user has a model-level permission assigned
+        if self.request.user.has_perm(self.permission_required):
+            return True
+
+        # If not, check for an object-level permission
+        app, codename = self.permission_required.split('.')
+        action, model_name = codename.split('_')
+        model = self.queryset.model
+        obj_permissions = ObjectPermission.objects.filter(
+            Q(users=self.request.user) | Q(groups__user=self.request.user),
+            model=ContentType.objects.get_for_model(model),
+            **{f'can_{action}': True}
+        )
+        if obj_permissions:
+
+            # Update the view's QuerySet to filter only the permitted objects
+            # TODO: Do this more efficiently
+            for perm in obj_permissions:
+                self.queryset = self.queryset.filter(**perm.attrs)
+
+            return True
+
+        return False
+
+    def dispatch(self, request, *args, **kwargs):
+        if not self.has_permission():
+            return self.handle_no_permission()
+        return super().dispatch(request, *args, **kwargs)