Browse Source

Add additional_permissions to ObjectPermissionRequiredMixin

Jeremy Stretch 5 years ago
parent
commit
3ef4287d57
3 changed files with 16 additions and 16 deletions
  1. 5 7
      netbox/dcim/views.py
  2. 1 3
      netbox/ipam/views.py
  3. 10 6
      netbox/utilities/views.py

+ 5 - 7
netbox/dcim/views.py

@@ -1082,7 +1082,7 @@ class DeviceInventoryView(ObjectView):
 
 
 
 
 class DeviceStatusView(ObjectView):
 class DeviceStatusView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
     queryset = Device.objects.all()
 
 
     def get(self, request, pk):
     def get(self, request, pk):
@@ -1096,7 +1096,7 @@ class DeviceStatusView(ObjectView):
 
 
 
 
 class DeviceLLDPNeighborsView(ObjectView):
 class DeviceLLDPNeighborsView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
     queryset = Device.objects.all()
 
 
     def get(self, request, pk):
     def get(self, request, pk):
@@ -1114,7 +1114,7 @@ class DeviceLLDPNeighborsView(ObjectView):
 
 
 
 
 class DeviceConfigView(ObjectView):
 class DeviceConfigView(ObjectView):
-    permission_required = ('dcim.view_device', 'dcim.napalm_read')
+    additional_permissions = ['dcim.napalm_read']
     queryset = Device.objects.all()
     queryset = Device.objects.all()
 
 
     def get(self, request, pk):
     def get(self, request, pk):
@@ -1857,11 +1857,11 @@ class CableView(ObjectView):
         })
         })
 
 
 
 
-class CableTraceView(ObjectPermissionRequiredMixin, View):
+class CableTraceView(ObjectView):
     """
     """
     Trace a cable path beginning from the given termination.
     Trace a cable path beginning from the given termination.
     """
     """
-    permission_required = 'dcim.view_cable'
+    additional_permissions = ['dcim.view_cable']
 
 
     def dispatch(self, request, *args, **kwargs):
     def dispatch(self, request, *args, **kwargs):
         model = kwargs.pop('model')
         model = kwargs.pop('model')
@@ -2006,7 +2006,6 @@ class CableBulkDeleteView(BulkDeleteView):
 #
 #
 
 
 class ConsoleConnectionsListView(ObjectListView):
 class ConsoleConnectionsListView(ObjectListView):
-    permission_required = ('dcim.view_consoleport', 'dcim.view_consoleserverport')
     queryset = ConsolePort.objects.prefetch_related(
     queryset = ConsolePort.objects.prefetch_related(
         'device', 'connected_endpoint__device'
         'device', 'connected_endpoint__device'
     ).filter(
     ).filter(
@@ -2038,7 +2037,6 @@ class ConsoleConnectionsListView(ObjectListView):
 
 
 
 
 class PowerConnectionsListView(ObjectListView):
 class PowerConnectionsListView(ObjectListView):
-    permission_required = ('dcim.view_powerport', 'dcim.view_poweroutlet')
     queryset = PowerPort.objects.prefetch_related(
     queryset = PowerPort.objects.prefetch_related(
         'device', '_connected_poweroutlet__device'
         'device', '_connected_poweroutlet__device'
     ).filter(
     ).filter(

+ 1 - 3
netbox/ipam/views.py

@@ -671,7 +671,7 @@ class IPAddressEditView(ObjectEditView):
         return obj
         return obj
 
 
 
 
-class IPAddressAssignView(ObjectPermissionRequiredMixin, View):
+class IPAddressAssignView(ObjectView):
     """
     """
     Search for IPAddresses to be assigned to an Interface.
     Search for IPAddresses to be assigned to an Interface.
     """
     """
@@ -719,7 +719,6 @@ class IPAddressDeleteView(ObjectDeleteView):
 
 
 
 
 class IPAddressBulkCreateView(BulkCreateView):
 class IPAddressBulkCreateView(BulkCreateView):
-    permission_required = 'ipam.add_ipaddress'
     form = forms.IPAddressBulkCreateForm
     form = forms.IPAddressBulkCreateForm
     model_form = forms.IPAddressBulkAddForm
     model_form = forms.IPAddressBulkAddForm
     pattern_target = 'address'
     pattern_target = 'address'
@@ -761,7 +760,6 @@ class VLANGroupListView(ObjectListView):
 
 
 
 
 class VLANGroupEditView(ObjectEditView):
 class VLANGroupEditView(ObjectEditView):
-    permission_required = 'ipam.add_vlangroup'
     queryset = VLANGroup.objects.all()
     queryset = VLANGroup.objects.all()
     model_form = forms.VLANGroupForm
     model_form = forms.VLANGroupForm
     default_return_url = 'ipam:vlangroup_list'
     default_return_url = 'ipam:vlangroup_list'

+ 10 - 6
netbox/utilities/views.py

@@ -43,18 +43,24 @@ class ObjectPermissionRequiredMixin(AccessMixin):
     Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level
     Similar to Django's built-in PermissionRequiredMixin, but extended to check for both model-level and object-level
     permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered
     permission assignments. If the user has only object-level permissions assigned, the view's queryset is filtered
     to return only those objects on which the user is permitted to perform the specified action.
     to return only those objects on which the user is permitted to perform the specified action.
+
+    additional_permissions: An optional iterable of statically declared permissions to evaluate in addition to those
+                            derived from the object type
     """
     """
-    permission_required = None
+    additional_permissions = list()
 
 
     def get_required_permission(self):
     def get_required_permission(self):
-        return self.permission_required
+        """
+        Return the specific permission necessary to perform the requested action on an object.
+        """
+        raise NotImplementedError(f"{self.__class__.__name__} must implement get_required_permission()")
 
 
     def has_permission(self):
     def has_permission(self):
         user = self.request.user
         user = self.request.user
         permission_required = self.get_required_permission()
         permission_required = self.get_required_permission()
 
 
-        # First, check that the user is granted the required permission at either the model or object level.
-        if not user.has_perm(permission_required):
+        # First, check that the user is granted the required permission(s) at either the model or object level.
+        if not user.has_perms((permission_required, *self.additional_permissions)):
             return False
             return False
 
 
         # Superusers implicitly have all permissions
         # Superusers implicitly have all permissions
@@ -148,8 +154,6 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
     action_buttons = ('add', 'import', 'export')
     action_buttons = ('add', 'import', 'export')
 
 
     def get_required_permission(self):
     def get_required_permission(self):
-        if getattr(self, 'permission_required') is not None:
-            return self.permission_required
         return get_permission_for_model(self.queryset.model, 'view')
         return get_permission_for_model(self.queryset.model, 'view')
 
 
     def queryset_to_yaml(self):
     def queryset_to_yaml(self):