Merge pull request #15618 from open-craft/bdero/failed-password-reset-email
Add optional password reset failure emails
This commit is contained in:
@@ -283,6 +283,10 @@ FEATURES = {
|
||||
# Whether or not the dynamic EnrollmentTrackUserPartition should be registered.
|
||||
'ENABLE_ENROLLMENT_TRACK_USER_PARTITION': True,
|
||||
|
||||
# Whether to send an email for failed password reset attempts or not. This is mainly useful for notifying users
|
||||
# that they don't have an account associated with email addresses they believe they've registered with.
|
||||
'ENABLE_PASSWORD_RESET_FAILURE_EMAIL': False,
|
||||
|
||||
# Whether archived courses (courses with end dates in the past) should be
|
||||
# shown in Studio in a separate list.
|
||||
'ENABLE_SEPARATE_ARCHIVED_COURSES': True,
|
||||
|
||||
@@ -58,6 +58,9 @@ from openedx.core.djangoapps.user_api.errors import UserAPIInternalError
|
||||
LOGGER_NAME = 'audit'
|
||||
User = get_user_model() # pylint:disable=invalid-name
|
||||
|
||||
FEATURES_WITH_FAILED_PASSWORD_RESET_EMAIL = settings.FEATURES.copy()
|
||||
FEATURES_WITH_FAILED_PASSWORD_RESET_EMAIL['ENABLE_PASSWORD_RESET_FAILURE_EMAIL'] = True
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class StudentAccountUpdateTest(CacheIsolationTestCase, UrlResetMixin):
|
||||
@@ -147,6 +150,28 @@ class StudentAccountUpdateTest(CacheIsolationTestCase, UrlResetMixin):
|
||||
self._change_password()
|
||||
self.assertRaises(UserAPIInternalError)
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_FAILED_PASSWORD_RESET_EMAIL)
|
||||
def test_password_reset_failure_email(self):
|
||||
"""Test that a password reset failure email notification is sent, when enabled."""
|
||||
# Log the user out
|
||||
self.client.logout()
|
||||
|
||||
bad_email = 'doesnotexist@example.com'
|
||||
response = self._change_password(email=bad_email)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check that an email was sent
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
|
||||
# Verify that the body contains the failed password reset message
|
||||
email_body = mail.outbox[0].body
|
||||
self.assertIn(
|
||||
'However, there is currently no user account associated with your email address: {email}'.format(
|
||||
email=bad_email
|
||||
),
|
||||
email_body,
|
||||
)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_password_change_logged_out(self, send_email):
|
||||
# Log the user out
|
||||
|
||||
@@ -9,9 +9,11 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.core.mail import send_mail
|
||||
from django.core.urlresolvers import resolve, reverse
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.shortcuts import redirect
|
||||
from django.template import loader
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_http_methods
|
||||
@@ -217,6 +219,25 @@ def password_change_request_handler(request):
|
||||
AUDIT_LOG.info("Invalid password reset attempt")
|
||||
# Increment the rate limit counter
|
||||
limiter.tick_bad_request_counter(request)
|
||||
|
||||
# If enabled, send an email saying that a password reset was attempted, but that there is
|
||||
# no user associated with the email
|
||||
if configuration_helpers.get_value('ENABLE_PASSWORD_RESET_FAILURE_EMAIL',
|
||||
settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']):
|
||||
context = {
|
||||
'failed': True,
|
||||
'email_address': email,
|
||||
'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME),
|
||||
|
||||
}
|
||||
subject = loader.render_to_string('emails/password_reset_subject.txt', context)
|
||||
subject = ''.join(subject.splitlines())
|
||||
message = loader.render_to_string('registration/password_reset_email.html', context)
|
||||
from_email = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
|
||||
try:
|
||||
send_mail(subject, message, from_email, [email])
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.exception(u'Unable to send password reset failure email notification from "%s"', from_email)
|
||||
except UserAPIInternalError as err:
|
||||
log.exception('Error occured during password change for user {email}: {error}'
|
||||
.format(email=email, error=err))
|
||||
|
||||
@@ -421,6 +421,10 @@ FEATURES = {
|
||||
|
||||
# Whether HTML XBlocks/XModules return HTML content with the Course Blocks API student_view_data
|
||||
'ENABLE_HTML_XBLOCK_STUDENT_VIEW_DATA': False,
|
||||
|
||||
# Whether to send an email for failed password reset attempts or not. This is mainly useful for notifying users
|
||||
# that they don't have an account associated with email addresses they believe they've registered with.
|
||||
'ENABLE_PASSWORD_RESET_FAILURE_EMAIL': False,
|
||||
}
|
||||
|
||||
# Settings for the course reviews tool template and identification key, set either to None to disable course reviews
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{% load i18n %}{% autoescape off %}
|
||||
{% blocktrans %}You're receiving this e-mail because you requested a password reset for your user account at {{ platform_name }}.{% endblocktrans %}
|
||||
|
||||
{% if failed %}
|
||||
{% blocktrans %}However, there is currently no user account associated with your email address: {{ email_address }}.{% endblocktrans %}
|
||||
|
||||
{% trans "If you did not request this change, you can ignore this email." %}
|
||||
{% else %}
|
||||
{% trans "Please go to the following page and choose a new password:" %}
|
||||
{% block reset_link %}
|
||||
{{ protocol }}://{{ site_name }}{% url 'password_reset_confirm' uidb36=uid token=token %}
|
||||
@@ -9,6 +14,7 @@
|
||||
{% trans "If you didn't request this change, you can disregard this email - we have not yet reset your password." %}
|
||||
|
||||
{% trans "Thanks for using our site!" %}
|
||||
{% endif %}
|
||||
|
||||
{% blocktrans %}The {{ platform_name }} Team{% endblocktrans %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user