diff --git a/lms/djangoapps/save_for_later/api/v1/views.py b/lms/djangoapps/save_for_later/api/v1/views.py index 3d6c7bb0b6..598b7ee564 100644 --- a/lms/djangoapps/save_for_later/api/v1/views.py +++ b/lms/djangoapps/save_for_later/api/v1/views.py @@ -6,7 +6,7 @@ import logging from django.conf import settings from django.utils.decorators import method_decorator -from ratelimit.decorators import ratelimit +from django_ratelimit.decorators import ratelimit from rest_framework.response import Response from rest_framework.views import APIView from django.db import transaction @@ -33,8 +33,12 @@ class CourseSaveForLaterApiView(APIView): """ @transaction.atomic - @method_decorator(ratelimit(key=POST_EMAIL_KEY, rate=settings.SAVE_FOR_LATER_EMAIL_RATE_LIMIT, method='POST')) - @method_decorator(ratelimit(key=REAL_IP_KEY, rate=settings.SAVE_FOR_LATER_IP_RATE_LIMIT, method='POST')) + @method_decorator(ratelimit(key=POST_EMAIL_KEY, + rate=settings.SAVE_FOR_LATER_EMAIL_RATE_LIMIT, + method='POST', block=False)) + @method_decorator(ratelimit(key=REAL_IP_KEY, + rate=settings.SAVE_FOR_LATER_IP_RATE_LIMIT, + method='POST', block=False)) def post(self, request): """ **Use Case** @@ -124,8 +128,12 @@ class ProgramSaveForLaterApiView(APIView): """ @transaction.atomic - @method_decorator(ratelimit(key=POST_EMAIL_KEY, rate=settings.SAVE_FOR_LATER_EMAIL_RATE_LIMIT, method='POST')) - @method_decorator(ratelimit(key=REAL_IP_KEY, rate=settings.SAVE_FOR_LATER_IP_RATE_LIMIT, method='POST')) + @method_decorator(ratelimit(key=POST_EMAIL_KEY, + rate=settings.SAVE_FOR_LATER_EMAIL_RATE_LIMIT, + method='POST', block=False)) + @method_decorator(ratelimit(key=REAL_IP_KEY, + rate=settings.SAVE_FOR_LATER_IP_RATE_LIMIT, + method='POST', block=False)) def post(self, request): """ **Use Case** diff --git a/lms/djangoapps/static_template_view/views.py b/lms/djangoapps/static_template_view/views.py index f63cb58171..dc3a44bb79 100644 --- a/lms/djangoapps/static_template_view/views.py +++ b/lms/djangoapps/static_template_view/views.py @@ -15,8 +15,8 @@ from django.template import TemplateDoesNotExist from django.utils.safestring import mark_safe from django.views.decorators.csrf import ensure_csrf_cookie from django.views.defaults import permission_denied +from django_ratelimit.exceptions import Ratelimited from mako.exceptions import TopLevelLookupException -from ratelimit.exceptions import Ratelimited from common.djangoapps.edxmako.shortcuts import render_to_response, render_to_string from common.djangoapps.util.cache import cache_if_anonymous diff --git a/openedx/core/djangoapps/oauth_dispatch/views.py b/openedx/core/djangoapps/oauth_dispatch/views.py index 19b842f087..e430f9d48c 100644 --- a/openedx/core/djangoapps/oauth_dispatch/views.py +++ b/openedx/core/djangoapps/oauth_dispatch/views.py @@ -9,10 +9,10 @@ import json from django.conf import settings from django.utils.decorators import method_decorator from django.views.generic import View +from django_ratelimit import ALL +from django_ratelimit.decorators import ratelimit from edx_django_utils import monitoring as monitoring_utils from oauth2_provider import views as dot_views -from ratelimit import ALL -from ratelimit.decorators import ratelimit from openedx.core.djangoapps.auth_exchange import views as auth_exchange_views from openedx.core.djangoapps.oauth_dispatch import adapters diff --git a/openedx/core/djangoapps/user_authn/views/login.py b/openedx/core/djangoapps/user_authn/views/login.py index 1e0f045a33..893869b1af 100644 --- a/openedx/core/djangoapps/user_authn/views/login.py +++ b/openedx/core/djangoapps/user_authn/views/login.py @@ -22,13 +22,12 @@ from django.utils.translation import gettext as _ from django.views.decorators.csrf import csrf_exempt, csrf_protect, ensure_csrf_cookie from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.http import require_http_methods +from django_ratelimit.decorators import ratelimit from edx_django_utils.monitoring import set_custom_attribute -from ratelimit.decorators import ratelimit -from rest_framework.views import APIView - from openedx_events.learning.data import UserData, UserPersonalData from openedx_events.learning.signals import SESSION_LOGIN_COMPLETED from openedx_filters.learning.filters import StudentLoginRequested +from rest_framework.views import APIView from common.djangoapps import third_party_auth from common.djangoapps.edxmako.shortcuts import render_to_response @@ -46,6 +45,7 @@ from openedx.core.djangoapps.user_api import accounts from openedx.core.djangoapps.user_authn.config.waffle import ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY from openedx.core.djangoapps.user_authn.cookies import get_response_with_refreshed_jwt_cookies, set_logged_in_cookies from openedx.core.djangoapps.user_authn.exceptions import AuthFailedError, VulnerablePasswordError +from openedx.core.djangoapps.user_authn.tasks import check_pwned_password_and_send_track_event from openedx.core.djangoapps.user_authn.toggles import ( is_require_third_party_auth_enabled, should_redirect_to_authn_microfrontend @@ -53,7 +53,6 @@ from openedx.core.djangoapps.user_authn.toggles import ( from openedx.core.djangoapps.user_authn.views.login_form import get_login_session_form from openedx.core.djangoapps.user_authn.views.password_reset import send_password_reset_email_for_user from openedx.core.djangoapps.user_authn.views.utils import API_V1, ENTERPRISE_ENROLLMENT_URL_REGEX, UUID4_REGEX -from openedx.core.djangoapps.user_authn.tasks import check_pwned_password_and_send_track_event from openedx.core.djangoapps.util.user_messages import PageLevelMessages from openedx.core.djangolib.markup import HTML, Text from openedx.core.lib.api.view_utils import require_post_params # lint-amnesty, pylint: disable=unused-import @@ -492,11 +491,13 @@ def enterprise_selection_page(request, user, next_url): key='openedx.core.djangoapps.util.ratelimit.request_post_email_or_username', rate=settings.LOGISTRATION_PER_EMAIL_RATELIMIT_RATE, method='POST', + block=False, ) # lint-amnesty, pylint: disable=too-many-statements @ratelimit( key='openedx.core.djangoapps.util.ratelimit.real_ip', rate=settings.LOGISTRATION_RATELIMIT_RATE, method='POST', + block=False, ) # lint-amnesty, pylint: disable=too-many-statements def login_user(request, api_version='v1'): # pylint: disable=too-many-statements """ diff --git a/openedx/core/djangoapps/user_authn/views/login_form.py b/openedx/core/djangoapps/user_authn/views/login_form.py index cb152c1c4e..ee04123ddf 100644 --- a/openedx/core/djangoapps/user_authn/views/login_form.py +++ b/openedx/core/djangoapps/user_authn/views/login_form.py @@ -12,7 +12,7 @@ from django.urls import reverse from django.utils.translation import gettext as _ from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods -from ratelimit.decorators import ratelimit +from django_ratelimit.decorators import ratelimit from common.djangoapps import third_party_auth from common.djangoapps.edxmako.shortcuts import render_to_response diff --git a/openedx/core/djangoapps/user_authn/views/password_reset.py b/openedx/core/djangoapps/user_authn/views/password_reset.py index 17d44407ef..f8049d4d91 100644 --- a/openedx/core/djangoapps/user_authn/views/password_reset.py +++ b/openedx/core/djangoapps/user_authn/views/password_reset.py @@ -24,7 +24,7 @@ from django.views.decorators.http import require_POST from edx_ace import ace from edx_ace.recipient import Recipient from eventtracking import tracker -from ratelimit.decorators import ratelimit +from django_ratelimit.decorators import ratelimit from rest_framework.response import Response from rest_framework.throttling import AnonRateThrottle from rest_framework.views import APIView @@ -280,8 +280,8 @@ def request_password_change(email, is_secure): @csrf_exempt @require_POST -@ratelimit(key=POST_EMAIL_KEY, rate=settings.PASSWORD_RESET_EMAIL_RATE) -@ratelimit(key=REAL_IP_KEY, rate=settings.PASSWORD_RESET_IP_RATE) +@ratelimit(key=POST_EMAIL_KEY, rate=settings.PASSWORD_RESET_EMAIL_RATE, block=False) +@ratelimit(key=REAL_IP_KEY, rate=settings.PASSWORD_RESET_IP_RATE, block=False) def password_reset(request): """ Attempts to send a password reset e-mail. @@ -574,8 +574,8 @@ def _get_user_from_email(email): @require_POST -@ratelimit(key=POST_EMAIL_KEY, rate=settings.PASSWORD_RESET_EMAIL_RATE) -@ratelimit(key=REAL_IP_KEY, rate=settings.PASSWORD_RESET_IP_RATE) +@ratelimit(key=POST_EMAIL_KEY, rate=settings.PASSWORD_RESET_EMAIL_RATE, block=False) +@ratelimit(key=REAL_IP_KEY, rate=settings.PASSWORD_RESET_IP_RATE, block=False) def password_change_request_handler(request): """Handle password change requests originating from the account page. diff --git a/openedx/core/djangoapps/user_authn/views/register.py b/openedx/core/djangoapps/user_authn/views/register.py index 7c39a751b0..c494f8e015 100644 --- a/openedx/core/djangoapps/user_authn/views/register.py +++ b/openedx/core/djangoapps/user_authn/views/register.py @@ -28,7 +28,7 @@ from openedx_events.learning.data import UserData, UserPersonalData from openedx_events.learning.signals import STUDENT_REGISTRATION_COMPLETED from openedx_filters.learning.filters import StudentRegistrationRequested from pytz import UTC -from ratelimit.decorators import ratelimit +from django_ratelimit.decorators import ratelimit from requests import HTTPError from rest_framework.response import Response from rest_framework.views import APIView @@ -545,7 +545,7 @@ class RegistrationView(APIView): content_type="application/json") @method_decorator(csrf_exempt) - @method_decorator(ratelimit(key=REAL_IP_KEY, rate=settings.REGISTRATION_RATELIMIT, method='POST')) + @method_decorator(ratelimit(key=REAL_IP_KEY, rate=settings.REGISTRATION_RATELIMIT, method='POST', block=False)) def post(self, request): """Create the user's account. diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 77dd40708b..071af618d4 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -79,5 +79,4 @@ pytz==2022.2.1 # right now lots of packages have major upgrades and lots of tests failing. # so adding following constraints and will unpin one by one. -django-ratelimit<4.0.0 cryptography==38.0.4 # greater version has some issues. diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index d3e1785b37..1fcc0a15da 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -332,10 +332,8 @@ django-pipeline==2.0.8 # via -r requirements/edx/base.in django-pyfs==3.2.0 # via -r requirements/edx/base.in -django-ratelimit==3.0.1 - # via - # -c requirements/edx/../constraints.txt - # -r requirements/edx/base.in +django-ratelimit==4.0.0 + # via -r requirements/edx/base.in django-require @ git+https://github.com/openedx/django-require.git@0c54adb167142383b26ea6b3edecc3211822a776 # via -r requirements/edx/github.in django-sekizai==4.0.0 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4d881b999d..f0987c652a 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -442,10 +442,8 @@ django-pipeline==2.0.8 # via -r requirements/edx/testing.txt django-pyfs==3.2.0 # via -r requirements/edx/testing.txt -django-ratelimit==3.0.1 - # via - # -c requirements/edx/../constraints.txt - # -r requirements/edx/testing.txt +django-ratelimit==4.0.0 + # via -r requirements/edx/testing.txt django-require @ git+https://github.com/openedx/django-require.git@0c54adb167142383b26ea6b3edecc3211822a776 # via -r requirements/edx/testing.txt django-sekizai==4.0.0 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index c9b15e7cba..6eca8fb892 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -423,10 +423,8 @@ django-pipeline==2.0.8 # via -r requirements/edx/base.txt django-pyfs==3.2.0 # via -r requirements/edx/base.txt -django-ratelimit==3.0.1 - # via - # -c requirements/edx/../constraints.txt - # -r requirements/edx/base.txt +django-ratelimit==4.0.0 + # via -r requirements/edx/base.txt django-require @ git+https://github.com/openedx/django-require.git@0c54adb167142383b26ea6b3edecc3211822a776 # via -r requirements/edx/base.txt django-sekizai==4.0.0