From b1b5281f2b1180b4823523950ef081a1bdc0ae91 Mon Sep 17 00:00:00 2001 From: aliadnan Date: Thu, 3 Mar 2022 01:41:13 +0500 Subject: [PATCH] feat: remove check for password reset API if request is comming from support tools --- .../user_authn/views/password_reset.py | 5 +- .../views/tests/test_reset_password.py | 51 ++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/openedx/core/djangoapps/user_authn/views/password_reset.py b/openedx/core/djangoapps/user_authn/views/password_reset.py index 12ef579c57..7c472c9274 100644 --- a/openedx/core/djangoapps/user_authn/views/password_reset.py +++ b/openedx/core/djangoapps/user_authn/views/password_reset.py @@ -601,14 +601,15 @@ def password_change_request_handler(request): """ user = request.user - if (user.is_staff or user.is_superuser) and request.POST.get('email_from_support_tools'): + request_from_support_tools = (user.is_staff or user.is_superuser) and request.POST.get('email_from_support_tools') + if request_from_support_tools: email = request.POST.get('email_from_support_tools') else: # Prefer logged-in user's email email = user.email if user.is_authenticated else request.POST.get('email') AUDIT_LOG.info("Password reset initiated for email %s.", email) - if getattr(request, 'limited', False): + if getattr(request, 'limited', False) and not request_from_support_tools: AUDIT_LOG.warning("Password reset rate limit exceeded for email %s.", email) return HttpResponse( _("Your previous request is in progress, please try again in a few moments."), diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py index b3c7247ea0..ae8b6488d7 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_reset_password.py @@ -34,7 +34,7 @@ from openedx.core.djangoapps.user_api.tests.test_views import UserAPITestCase from openedx.core.djangoapps.user_api.accounts import EMAIL_MAX_LENGTH, EMAIL_MIN_LENGTH from openedx.core.djangoapps.user_authn.views.password_reset import ( SETTING_CHANGE_INITIATED, password_reset, LogistrationPasswordResetView, - PasswordResetConfirmWrapper) + PasswordResetConfirmWrapper, password_change_request_handler) from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory from common.djangoapps.student.tests.test_configuration_overrides import fake_get_value @@ -180,6 +180,55 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase): cache.clear() + @patch("openedx.core.djangoapps.user_authn.views.password_reset.request_password_change", Mock(return_value=None)) + def test_password_change_non_staff_user(self): + """ + Test that password reset endpoint does not allow more than 1 call for non staff users. + """ + cache.clear() + password_reset_req = self.request_factory.post( + '/account/password/', + {'email': self.user.email, 'email_from_support_tools': self.user.email}, + ) + + password_reset_req.user = self.user + password_reset_req.is_secure = Mock(return_value=True) + good_resp = password_change_request_handler(password_reset_req) + assert good_resp.status_code == 200 + + bad_resp = password_change_request_handler(password_reset_req) + assert bad_resp.status_code == 403 + assert bad_resp.content == b'Your previous request is in progress, please try again in a few moments.' + + cache.clear() + + @patch("openedx.core.djangoapps.user_authn.views.password_reset.request_password_change", Mock(return_value=None)) + def test_password_change_staff_user(self): + """ + Test that password reset endpoint allow multiple requests for staff users. + """ + cache.clear() + password_reset_req = self.request_factory.post( + '/account/password/', + {'email': self.user.email, 'email_from_support_tools': self.user.email}, + ) + self.user.is_staff = True + password_reset_req.user = self.user + password_reset_req.is_secure = Mock(return_value=True) + good_resp = password_change_request_handler(password_reset_req) + assert good_resp.status_code == 200 + + good_resp = password_change_request_handler(password_reset_req) + assert good_resp.status_code == 200 + + good_resp = password_change_request_handler(password_reset_req) + assert good_resp.status_code == 200 + + good_resp = password_change_request_handler(password_reset_req) + assert good_resp.status_code == 200 + + cache.clear() + def assert_email_sent_successfully(self, expected): """ Verify that the password confirm email has been sent to the user.