From c3e8cad7aa75268d2d48ac4b7398e75eea575707 Mon Sep 17 00:00:00 2001 From: hashlash Date: Sun, 26 Feb 2023 04:42:54 +0000 Subject: [PATCH 1/2] Use APIView.permission_denied to handle 401 and 403 http errors --- rules/contrib/rest_framework.py | 2 +- tests/testsuite/contrib/test_rest_framework.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/rules/contrib/rest_framework.py b/rules/contrib/rest_framework.py index 8ecaa96..d419c5d 100644 --- a/rules/contrib/rest_framework.py +++ b/rules/contrib/rest_framework.py @@ -72,4 +72,4 @@ def initial(self, *args, **kwargs): # Finally, check permission perm = self.get_queryset().model.get_perm(perm_type) if not self.request.user.has_perm(perm, obj): - raise PermissionDenied + self.permission_denied(self.request) diff --git a/tests/testsuite/contrib/test_rest_framework.py b/tests/testsuite/contrib/test_rest_framework.py index 33f7082..72ea153 100644 --- a/tests/testsuite/contrib/test_rest_framework.py +++ b/tests/testsuite/contrib/test_rest_framework.py @@ -1,13 +1,14 @@ from __future__ import absolute_import -from django.contrib.auth.models import AnonymousUser +from django.contrib.auth.models import AnonymousUser, User from django.core.exceptions import ImproperlyConfigured from django.test import TestCase +from rest_framework.authentication import BasicAuthentication from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.serializers import ModelSerializer -from rest_framework.test import APIRequestFactory +from rest_framework.test import APIRequestFactory, force_authenticate from rest_framework.viewsets import ModelViewSet import rules # noqa @@ -26,6 +27,7 @@ class Meta: class TestViewSet(AutoPermissionViewSetMixin, ModelViewSet): queryset = TestModel.objects.all() serializer_class = TestModelSerializer + authentication_classes = [BasicAuthentication] permission_type_map = AutoPermissionViewSetMixin.permission_type_map.copy() permission_type_map["custom_detail"] = "add" permission_type_map["custom_nodetail"] = "add" @@ -58,7 +60,14 @@ def test_predefined_action(self): self.assertEqual( self.vs.as_view({"get": "retrieve"})(self.req, pk=1).status_code, 200 ) - # Destroy should be forbidden due to missing delete permission + # Unauthenticated destroy should be return 401 due to missing credentials + self.assertEqual( + self.vs.as_view({"get": "destroy"})(self.req, pk=1).status_code, 401 + ) + # Authenticated with unauthorized destroy should be forbidden due to missing + # delete permission + user = User.objects.create_user(username='user', password='pass') + force_authenticate(self.req, user=user) self.assertEqual( self.vs.as_view({"get": "destroy"})(self.req, pk=1).status_code, 403 ) From 5edf57c7a8cf39e3c92a52f8d7883a57cc61ca40 Mon Sep 17 00:00:00 2001 From: hashlash <23237214+hashlash@users.noreply.github.com> Date: Sun, 26 Feb 2023 11:53:06 +0700 Subject: [PATCH 2/2] Fix lint --- rules/contrib/rest_framework.py | 2 +- tests/testsuite/contrib/test_rest_framework.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/contrib/rest_framework.py b/rules/contrib/rest_framework.py index d419c5d..68d67e1 100644 --- a/rules/contrib/rest_framework.py +++ b/rules/contrib/rest_framework.py @@ -1,4 +1,4 @@ -from django.core.exceptions import ImproperlyConfigured, PermissionDenied +from django.core.exceptions import ImproperlyConfigured class AutoPermissionViewSetMixin: diff --git a/tests/testsuite/contrib/test_rest_framework.py b/tests/testsuite/contrib/test_rest_framework.py index 72ea153..83ed78f 100644 --- a/tests/testsuite/contrib/test_rest_framework.py +++ b/tests/testsuite/contrib/test_rest_framework.py @@ -66,7 +66,7 @@ def test_predefined_action(self): ) # Authenticated with unauthorized destroy should be forbidden due to missing # delete permission - user = User.objects.create_user(username='user', password='pass') + user = User.objects.create_user(username="user", password="pass") force_authenticate(self.req, user=user) self.assertEqual( self.vs.as_view({"get": "destroy"})(self.req, pk=1).status_code, 403