diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index 2d7ae2385..41002dd20 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -6,7 +6,7 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDoesNotExist, PermissionDenied from django.db import transaction -from django.db.models import ManyToManyField, ProtectedError +from django.db.models import ManyToManyField, ProtectedError, Q from django.urls import reverse from rest_framework.exceptions import APIException from rest_framework.permissions import BasePermission @@ -339,12 +339,13 @@ class ModelViewSet(_ModelViewSet): } permission_required = TokenPermissions.perms_map[request.method][0] % kwargs - # Enforce object-level permissions - attrs = ObjectPermission.objects.get_attr_constraints(request.user, permission_required) - if attrs: - # Update the view's QuerySet to filter only the permitted objects - self.queryset = self.queryset.filter(attrs) - return True + # Update the view's QuerySet to filter only the permitted objects + obj_perm_attrs = request.user._object_perm_cache[permission_required] + attrs = Q() + for perm_attrs in obj_perm_attrs: + if perm_attrs: + attrs |= Q(**perm_attrs) + self.queryset = self.queryset.filter(attrs) def dispatch(self, request, *args, **kwargs): logger = logging.getLogger('netbox.api.views.ModelViewSet') diff --git a/netbox/utilities/auth_backends.py b/netbox/utilities/auth_backends.py index 41d7033af..6d34678be 100644 --- a/netbox/utilities/auth_backends.py +++ b/netbox/utilities/auth_backends.py @@ -80,7 +80,12 @@ class ObjectPermissionBackend(ModelBackend): obj_perm_attrs = self.get_object_permissions(user_obj)[perm] attrs = Q() for perm_attrs in obj_perm_attrs: - attrs |= Q(**perm_attrs) + if perm_attrs: + attrs |= Q(**perm_attrs) + else: + # Found ObjectPermission with null attrs; allow model-level access + attrs = Q() + break # Permission to perform the requested action on the object depends on whether the specified object matches # the specified attributes. Note that this check is made against the *database* record representing the object,