Raise conditional permission error in get_queryset DRF

I want to get all users of an organization by uuid. I am following REST standards so I want my url to look like 'organizations/uuid/users/'. If super admin hits this API, it should be allowed but If an admin user tries using this API, then it should only allow if the admin belongs to the same organization for which users are requested. I used ListAPIView generic view class and I was able to get list of all users in an organization from admin of different organization but it still returns info when it should return 403 error.

urls.py

    path('organizations/<uuid:pk>/users/', OrganizationUsersView.as_view()),

views.py

    class OrganizationUsersView(ListAPIView):
        serializer_class = UserSerializer
        permission_classes = (IsAuthenticated, IsSuperAdmin|IsAdmin,)

        def get_queryset(self):
            uuid = self.kwargs['pk']
            if self.request.user.role == 'admin':
                if self.request.user.org.id != uuid:
                    return IsOrganizationAdmin()
            org = Organization.objects.get(id=uuid)
            return User.objects.filter(org=org)

models.py

    class Organization(models.Model):
        name = models.CharField(max_length=255, null=False)

    class User(AbstractBaseUser):
        ....
        other fields
        ....
        org = models.ForeignKey(Organization, on_delete=models.CASCADE, null=False, related_name='users')

It looks like you're on the right track, but there are a few issues with the code you've provided. First, in the get_queryset method, you're returning the IsOrganizationAdmin permission class when the user is an admin and does not belong to the organization. Instead, you should raise a permission denied exception, like so:

    class OrganizationUsersView(ListAPIView):
        serializer_class = UserSerializer
        permission_classes = (IsAuthenticated, IsSuperAdmin|IsAdmin,)

        def get_queryset(self):
            uuid = self.kwargs['pk']
            if self.request.user.role == 'admin':
                if self.request.user.org.id != uuid:
                    raise PermissionDenied()
            org = Organization.objects.get(id=uuid)
            return User.objects.filter(org=org)

Second, it is not guaranteed that the user will have an org field, as it is not a requirement for the user model. You should check if the user has an org field before accessing it.

    class OrganizationUsersView(ListAPIView):
        serializer_class = UserSerializer
        permission_classes = (IsAuthenticated, IsSuperAdmin|IsAdmin,)

        def get_queryset(self):
            uuid = self.kwargs['pk']
            if self.request.user.role == 'admin':
                if not hasattr(self.request.user, "org") or self.request.user.org.id != uuid:
                    raise PermissionDenied()
            org = Organization.objects.get(id=uuid)
            return User.objects.filter(org=org)

Finally, you may want to consider using the IsOrganizationAdmin custom permission class instead of IsSuperAdmin|IsAdmin. This would ensure that only users with the admin role and belonging to the specified organization can access the API.

Back to Top