Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using DjangoObjectPermissionsFilter to filter objects of user using django-guardian

I was able to setup django-guardian and my django-rest-framework project as the example in drf docs, but I'm failing to achieve the behavior that I want. Could someone please point out if I'm doing something wrong or if what I want can't be done with guardian?

Setup

settings.py

INSTALLED_APPS = (
    ...
    'guardian',
    'simple',
)

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'guardian.backends.ObjectPermissionBackend',
)

'DEFAULT_PERMISSION_CLASSES': (
    'infrastructure.permissions.DjangoObjectPermissions',
)

infrastructure.permissions.py

from rest_framework import permissions


class DjangoObjectPermissions(permissions.DjangoObjectPermissions):
    """
    Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
    """
    perms_map = {
        'GET': ['%(app_label)s.view_%(model_name)s'],
        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
        'HEAD': ['%(app_label)s.view_%(model_name)s'],
        'POST': ['%(app_label)s.add_%(model_name)s'],
        'PUT': ['%(app_label)s.change_%(model_name)s'],
        'PATCH': ['%(app_label)s.change_%(model_name)s'],
        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
    }

models.py

class Event(models.Model):
    name = models.CharField(max_length=255)
    min_age = models.IntegerField()

    def __str__(self):
        return self.name

    class Meta:
        permissions = (('view_event', 'Can view event'),)

views.py

class EventViewSet(viewsets.ModelViewSet):
    queryset = models.Event.objects.all()
    serializer_class = serializers.EventSerializer
    filter_backends = (filters.DjangoObjectPermissionsFilter,)

Expected behavior

  • The list of Events returned by EventViewSet.list contains only objects that the request user can view (request user has django.auth view_event permission OR ('view_event', event_object).
  • EventViewSet.details returns the Event instance only if the request user has the view_event permission OR the ('view_event', event_object) permission.

Actual behavior

  • If the user has the django auth permission view_event and the guardian permission ('view_event', event_obj), it can access the routes list (getting all entries) and details associated with the event_obj.
  • If the user DOESN'T have the auth permission view_event, but has the guardian permission ('view_event', event_obj), they receive a 403 in all routes (including the details route associated with the event_obj that they have permission over).
  • If the user has view_event but doesn't have ('view_event', event_obj), they can access the route list (seeing all entries), but they receive a 404 in details route, regardless the entry being accessed.

Thank you!

like image 539
ldavid Avatar asked Jul 30 '15 00:07

ldavid


1 Answers

Ok, turns out that all views with permission class DjangoObjectPermissions will only allow users to see a given resource if they have model-level and object-level permissions. The fact that my users are being able to list all objects, but not retrieving any of them, is because of a known bug that was already corrected but isn't on the current release just yet.

like image 160
ldavid Avatar answered Sep 30 '22 17:09

ldavid