diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 898bd0e95..8b6e92215 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -51,6 +51,17 @@ class IsAuthenticated(BasePermission): return request.user and request.user.is_authenticated +class IsAuthenticatedOrOptionsOnly(BasePermission): + """ + Allows access only to authenticated users. + """ + + def has_permission(self, request, view): + if request.method == 'OPTIONS': + return True + return request.user and request.user.is_authenticated + + class IsAdminUser(BasePermission): """ Allows access only to admin users. diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 37540eb8e..96926ed70 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -522,3 +522,36 @@ class CustomPermissionsTests(TestCase): detail = response.data.get('detail') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(detail, self.custom_message) + + +class IsAuthenticatedOrOptionsOnlyAllowedView(generics.RetrieveUpdateDestroyAPIView): + queryset = BasicModel.objects.all() + serializer_class = BasicSerializer + authentication_classes = [authentication.BasicAuthentication] + permissions_classes = (permissions.IsAuthenticatedOrOptionsOnly,) + + +options_view = IsAuthenticatedOrOptionsOnlyAllowedView.as_view() + + +class IsAuthenticatedOrOptionsOnlyAllowedTests(TestCase): + def setUp(self): + BasicModel(text='foo').save() + User.objects.create_user('username', 'username@example.com', 'password') + + def test_options_allowed_if_not_authentificated(self): + self.request = factory.options('/1', format='json') + response = options_view(self.request, pk=1) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_options_get_not_allowed_if_not_authentificated(self): + credentials = basic_auth_header('username', 'wrongpassword') + self.request = factory.get('/1', format='json', HTTP_AUTHORIZATION=credentials) + response = options_view(self.request, pk=1) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_options_get_allowed_if_authentificated(self): + credentials = basic_auth_header('username', 'password') + self.request = factory.get('/1', format='json', HTTP_AUTHORIZATION=credentials) + response = options_view(self.request, pk=1) + self.assertEqual(response.status_code, status.HTTP_200_OK) \ No newline at end of file