Merge pull request #18319 from edx/adeel/learner_3810_ratelimit_form_validation_calls
Rate limiting registration form validation end point.
This commit is contained in:
@@ -2333,6 +2333,7 @@ REST_FRAMEWORK = {
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'user': '60/minute',
|
||||
'service_user': '120/minute',
|
||||
'registration_validation': '30/minute',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -574,6 +574,11 @@ ACTIVATION_EMAIL_FROM_ADDRESS = 'test_activate@edx.org'
|
||||
|
||||
TEMPLATES[0]['OPTIONS']['debug'] = True
|
||||
|
||||
########################### DRF default throttle rates ############################
|
||||
# Increasing rates to enable test cases hitting registration view succesfully.
|
||||
# Lower rate is causing view to get blocked, causing test case failure.
|
||||
REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['registration_validation'] = '100/minute'
|
||||
|
||||
########################## VIDEO TRANSCRIPTS STORAGE ############################
|
||||
VIDEO_TRANSCRIPTS_SETTINGS = dict(
|
||||
VIDEO_TRANSCRIPTS_MAX_BYTES=3 * 1024 * 1024, # 3 MB
|
||||
|
||||
@@ -9,11 +9,13 @@ import ddt
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from six import text_type
|
||||
|
||||
from openedx.core.djangoapps.user_api import accounts
|
||||
from openedx.core.djangoapps.user_api.accounts.tests import testutils
|
||||
from openedx.core.lib.api import test_utils
|
||||
from openedx.core.djangoapps.user_api.validation.views import RegistrationValidationThrottle
|
||||
from util.password_policy_validators import password_max_length, password_min_length
|
||||
|
||||
|
||||
@@ -199,3 +201,24 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
|
||||
{"username": "somephrase", "password": "somephrase"},
|
||||
{"username": "", "password": u"Password cannot be the same as the username."}
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
CACHES={
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
'LOCATION': 'registration_proxy',
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_rate_limiting_registration_view(self):
|
||||
"""
|
||||
Confirm rate limits work as expected for registration
|
||||
end point /api/user/v1/validation/registration/. Note
|
||||
that drf's rate limiting makes use of the default cache
|
||||
to enforce limits; that's why this test needs a "real"
|
||||
default cache (as opposed to the usual-for-tests DummyCache)
|
||||
"""
|
||||
for _ in range(RegistrationValidationThrottle().num_requests):
|
||||
self.request_without_auth('post', self.path)
|
||||
response = self.request_without_auth('post', self.path)
|
||||
self.assertEqual(response.status_code, 429)
|
||||
|
||||
@@ -5,6 +5,7 @@ An API for client-side validation of (potential) user data.
|
||||
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.throttling import AnonRateThrottle
|
||||
|
||||
from openedx.core.djangoapps.user_api.accounts.api import (
|
||||
get_email_validation_error,
|
||||
@@ -16,6 +17,20 @@ from openedx.core.djangoapps.user_api.accounts.api import (
|
||||
get_username_validation_error,
|
||||
get_username_existence_validation_error
|
||||
)
|
||||
from ipware.ip import get_ip
|
||||
|
||||
|
||||
class RegistrationValidationThrottle(AnonRateThrottle):
|
||||
"""
|
||||
Custom throttle rate for /api/user/v1/validation/registration
|
||||
endpoint's use case.
|
||||
"""
|
||||
|
||||
scope = 'registration_validation'
|
||||
|
||||
def get_ident(self, request):
|
||||
client_ip = get_ip(request)
|
||||
return client_ip
|
||||
|
||||
|
||||
class RegistrationValidationView(APIView):
|
||||
@@ -106,6 +121,7 @@ class RegistrationValidationView(APIView):
|
||||
|
||||
# This end-point is available to anonymous users, so no authentication is needed.
|
||||
authentication_classes = []
|
||||
throttle_classes = (RegistrationValidationThrottle,)
|
||||
|
||||
def name_handler(self, request):
|
||||
name = request.data.get('name')
|
||||
|
||||
Reference in New Issue
Block a user