From f66f53666f9d1d768a2ed4cdb5aa54d0f601ee46 Mon Sep 17 00:00:00 2001 From: Ian Foote Date: Fri, 20 Jun 2014 15:04:35 +0100 Subject: [PATCH] Check throttles before permissions * This allows throttling requests with invalid authentication details --- rest_framework/tests/test_throttling.py | 32 +++++++++++++++++++++++-- rest_framework/views.py | 2 +- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/rest_framework/tests/test_throttling.py b/rest_framework/tests/test_throttling.py index 41bff6926..404586a33 100644 --- a/rest_framework/tests/test_throttling.py +++ b/rest_framework/tests/test_throttling.py @@ -5,6 +5,9 @@ from __future__ import unicode_literals from django.test import TestCase from django.contrib.auth.models import User from django.core.cache import cache +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.status import HTTP_429_TOO_MANY_REQUESTS from rest_framework.test import APIRequestFactory from rest_framework.views import APIView from rest_framework.throttling import BaseThrottle, UserRateThrottle, ScopedRateThrottle @@ -26,7 +29,12 @@ class NonTimeThrottle(BaseThrottle): if not hasattr(self.__class__, 'called'): self.__class__.called = True return True - return False + return False + + +class AlwaysThrottle(BaseThrottle): + def allow_request(self, request, view): + return False class MockView(APIView): @@ -50,6 +58,15 @@ class MockView_NonTimeThrottling(APIView): return Response('foo') +class MockView_PermissionThrotting(APIView): + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAuthenticated,) + throttle_classes = (AlwaysThrottle,) + + def get(self, request): + return Response('foo') + + class ThrottlingTests(TestCase): def setUp(self): """ @@ -169,7 +186,18 @@ class ThrottlingTests(TestCase): self.assertTrue(MockView_NonTimeThrottling.throttle_classes[0].called) response = MockView_NonTimeThrottling.as_view()(request) - self.assertFalse('X-Throttle-Wait-Seconds' in response) + self.assertFalse('X-Throttle-Wait-Seconds' in response) + + def test_throttle_failed_authentication(self): + authentication_header = { + 'Authorization': 'Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b', + } + request = self.factory.get('/') + request.META.update(authentication_header) + + view = MockView_PermissionThrotting.as_view() + response = view(request) + self.assertEqual(response.status_code, HTTP_429_TOO_MANY_REQUESTS) class ScopedRateThrottleTests(TestCase): diff --git a/rest_framework/views.py b/rest_framework/views.py index a2668f2c0..1e221578b 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -315,8 +315,8 @@ class APIView(View): # Ensure that the incoming request is permitted self.perform_authentication(request) - self.check_permissions(request) self.check_throttles(request) + self.check_permissions(request) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request)