From e35b35f6c2262c95df68858c92fec9d5f6a2f5ca Mon Sep 17 00:00:00 2001 From: Michael Frey Date: Tue, 15 Aug 2017 07:49:29 -0400 Subject: [PATCH] Increase rate-limit staff or superusers for enrollment API. --- .../djangoapps/enrollment/tests/test_views.py | 26 +++++++++++++++++++ common/djangoapps/enrollment/views.py | 12 ++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/common/djangoapps/enrollment/tests/test_views.py b/common/djangoapps/enrollment/tests/test_views.py index 6216144862..fdbb8ab9e1 100644 --- a/common/djangoapps/enrollment/tests/test_views.py +++ b/common/djangoapps/enrollment/tests/test_views.py @@ -547,6 +547,32 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente expected_status = status.HTTP_429_TOO_MANY_REQUESTS if attempt >= self.rate_limit else status.HTTP_200_OK self.assert_enrollment_status(expected_status=expected_status) + def test_enrollment_throttle_for_staff_user(self): + """ Make sure throttle rate is higher for staff users """ + self.rate_limit_config.enabled = True + self.rate_limit_config.save() + self.client.logout() + staff_user = UserFactory.create(password=self.PASSWORD, is_staff=True) + self.client.login(username=staff_user.username, password=self.PASSWORD) + + CourseModeFactory( + course_id=self.course.id, + mode_slug=CourseMode.DEFAULT_MODE_SLUG, + mode_display_name=CourseMode.DEFAULT_MODE_SLUG, + ) + + throttle = EnrollmentUserThrottle() + throttle.scope = 'staff' + rate_limit, __ = throttle.parse_rate(throttle.get_rate()) + + # Make enough requests to reach the rate limit + for attempt in xrange(rate_limit): + self.assert_enrollment_status(username=staff_user.username, expected_status=status.HTTP_200_OK) + + # Once the limit is reached, subsequent requests should fail + for attempt in xrange(rate_limit + 10): + self.assert_enrollment_status(username=staff_user.username, expected_status=status. HTTP_429_TOO_MANY_REQUESTS) + def test_enrollment_throttle_for_service(self): """Make sure a service can call the enrollment API as many times as needed. """ self.rate_limit_config.enabled = True diff --git a/common/djangoapps/enrollment/views.py b/common/djangoapps/enrollment/views.py index d9b8b81f96..12a22bcda3 100644 --- a/common/djangoapps/enrollment/views.py +++ b/common/djangoapps/enrollment/views.py @@ -68,9 +68,19 @@ class ApiKeyPermissionMixIn(object): class EnrollmentUserThrottle(UserRateThrottle, ApiKeyPermissionMixIn): """Limit the number of requests users can make to the enrollment API.""" - rate = '40/minute' + THROTTLE_RATES = { + 'user': '40/minute', + 'staff': '200/minute', + } def allow_request(self, request, view): + # Use a special scope for staff to allow for a separate throttle rate + user = request.user + if user.is_authenticated() and (user.is_staff or user.is_superuser): + self.scope = 'staff' + self.rate = self.get_rate() + self.num_requests, self.duration = self.parse_rate(self.rate) + return self.has_api_key_permissions(request) or super(EnrollmentUserThrottle, self).allow_request(request, view)