From a0f7cd62863e0ee888eb6ac039acd9958eddfb7e Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Fri, 22 Dec 2017 14:42:19 +0100 Subject: [PATCH] send notification emails for unauthorized password reset requests (#20830) --- src/authentic2/profile_forms.py | 9 +++++++-- .../registration/password_reset_refused_body.html | 10 ++++++++++ .../templates/registration/password_reset_refused_body.txt | 2 ++ .../registration/password_reset_refused_subject.txt | 3 +++ tests/conftest.py | 7 +++++++ tests/test_password_reset.py | 14 ++++++++++++++ 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/authentic2/templates/registration/password_reset_refused_body.html create mode 100644 src/authentic2/templates/registration/password_reset_refused_body.txt create mode 100644 src/authentic2/templates/registration/password_reset_refused_subject.txt diff --git a/src/authentic2/profile_forms.py b/src/authentic2/profile_forms.py index 540591d5..1ca8f240 100644 --- a/src/authentic2/profile_forms.py +++ b/src/authentic2/profile_forms.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _ from django.contrib.auth import get_user_model from .backends import get_user_queryset -from .utils import send_password_reset_mail +from .utils import send_password_reset_mail, send_templated_mail from . import hooks, app_settings @@ -26,6 +26,7 @@ class PasswordResetForm(forms.Form): email = self.cleaned_data["email"].strip() users = get_user_queryset() active_users = users.filter(email__iexact=email, is_active=True) + inactive_users = users.filter(email__iexact=email, is_active=False) for user in active_users: # we don't set the password to a random string, as some users should not have # a password @@ -33,6 +34,10 @@ class PasswordResetForm(forms.Form): and app_settings.A2_SET_RANDOM_PASSWORD_ON_RESET) send_password_reset_mail(user, set_random_password=set_random_password, next_url=self.cleaned_data.get('next_url')) - if not active_users: + for user in inactive_users: + logger.info(u'password reset failed for user %r: account is disabled.', user) + send_templated_mail(user_or_email=user, template_names="registration/password_reset_refused") + + if not active_users and not inactive_users: logger.info(u'password reset requests for "%s", no user found') hooks.call_hooks('event', name='password-reset', email=email, users=active_users) diff --git a/src/authentic2/templates/registration/password_reset_refused_body.html b/src/authentic2/templates/registration/password_reset_refused_body.html new file mode 100644 index 00000000..6c1abf73 --- /dev/null +++ b/src/authentic2/templates/registration/password_reset_refused_body.html @@ -0,0 +1,10 @@ +{% load i18n %} + + +

+{% blocktrans with hostname=request.get_host %} +You requested reset of your password on {{ hostname }}. Unfortunately, your account has been disabled on this server, thus your request can't succeed. +{% endblocktrans %} +

+ + diff --git a/src/authentic2/templates/registration/password_reset_refused_body.txt b/src/authentic2/templates/registration/password_reset_refused_body.txt new file mode 100644 index 00000000..9665ce51 --- /dev/null +++ b/src/authentic2/templates/registration/password_reset_refused_body.txt @@ -0,0 +1,2 @@ +{% load i18n %} +{% blocktrans with hostname=request.get_host %}You requested reset of your password on {{ hostname }}. Unfortunately, your account has been disabled on this server, thus your request can't succeed.{% endblocktrans %} diff --git a/src/authentic2/templates/registration/password_reset_refused_subject.txt b/src/authentic2/templates/registration/password_reset_refused_subject.txt new file mode 100644 index 00000000..d0d1743c --- /dev/null +++ b/src/authentic2/templates/registration/password_reset_refused_subject.txt @@ -0,0 +1,3 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans with hostname=request.get_host %}Your account on {{ hostname }} is disabled{% endblocktrans %} +{% endautoescape %} diff --git a/tests/conftest.py b/tests/conftest.py index e968d341..2159bdb0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -63,6 +63,13 @@ def simple_user(db, ou1): @pytest.fixture +def inactive_user(db, ou1): + return create_user(username='user', first_name=u'Jôhn', last_name=u'Smïth', + email='yetanotheruser@example.net', ou=get_default_ou(), + is_active=False) + + +@pytest.fixture def superuser(db): return create_user(username='superuser', first_name='super', last_name='user', diff --git a/tests/test_password_reset.py b/tests/test_password_reset.py index 3feb5494..c088687f 100644 --- a/tests/test_password_reset.py +++ b/tests/test_password_reset.py @@ -23,6 +23,20 @@ def test_send_password_reset_email(app, simple_user, mailoutbox): assert str(app.session['_auth_user_id']) == str(simple_user.pk) +def test_send_password_reset_refused_email(app, inactive_user, mailoutbox): + from authentic2.profile_forms import PasswordResetForm + + inactive_user.is_active = False + form = PasswordResetForm() + form.cleaned_data = {'email': inactive_user.email} + + assert len(mailoutbox) == 0 + form.save() + assert len(mailoutbox) == 1 + assert 'disabled' in mailoutbox[0].subject + assert 'your account has been disabled' in mailoutbox[0].body + + def test_view(app, simple_user, mailoutbox): url = reverse('password_reset') + '?next=/moncul/' resp = app.get(url, status=200) -- 2.11.0