0

I'm having troubles putting two permissions together using an OR operator. The documentation says: Doc

Provided they inherit from rest_framework.permissions.BasePermission, permissions can be composed using standard Python bitwise operators. For example, IsAuthenticatedOrReadOnly could be written: ... permission_classes = [IsAuthenticated|ReadOnly]

So I have created the permissions: permissions.py

class IsFullUserOrReadOnly(permissions.BasePermission):
    """
    This class defines the permission to only allow the request to certain users with a
    certain role."""
    def has_permission(self, request, view):
        """
        This function overrides the default has_permission method to allow the writing methods
        only to full users or admin users
        """

        if request.method in permissions.SAFE_METHODS:
            return True

        is_full_user = False


        queryset = User.objects.get(email=request.user)
        if queryset:
            user = UserSerializer(queryset)
            if 'roles' in user.data:
                for role in user.data['roles']:
                    if role == ADMIN or role == FULL_USER:
                        is_full_user = True

        print('IsFullUserOrReadOnly')
        print(is_full_user)
        print(request.method)
        print(request.method =='POST')
        return is_full_user or request.method =='POST'

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    This class defines the permission to only allow the POST and PUT methods to the creator of
    the item."""
    def has_object_permission(self, request, view, obj):
        """
        This function overrides the default has_object_permission method to allow the writing
        methods to the owner of the object
        """
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `created_by`.
        print('IsOwnerOrReadOnly')
        print(obj.created_by == request.user)

        return obj.created_by == request.user

And then I add them in my view: view.py


class ItemViewset(viewsets.ModelViewSet): # pylint: disable=too-many-ancestors
    """API Endpoint to return the list of items"""
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    # permission_classes = (IsAuthenticated, IsFullUserOrReadOnly,)
    permission_classes = [IsAuthenticated, IsFullUserOrReadOnly|IsOwnerOrReadOnly,]
    # permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]

The two commented lines work as expected for permission_classes but when I try to use them together, that means, that is accepted being a full user OR an owner for the non safe methods it always allows everything. It looks as there where no conditions anymore.

I don't know if I am missing something, but from what I understand this should work. Am I missing something?

nck
  • 1,673
  • 16
  • 40

1 Answers1

0

After some research I found in this link a bug reported. As a workaround I added the following method to IsFullUserOrReadOnly:

    def has_object_permission(self, request, view, obj):
        """ 
        This function overrides the default has_object_permission to prevent the bug documented in:
        https://github.com/encode/django-rest-framework/issues/7117
        """

        return self.has_permission(request, view)

And then i switched the order to:

    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly|IsFullUserOrReadOnly,)

And does seem to do the trick

nck
  • 1,673
  • 16
  • 40