Allow users to provide their email or username for password reset process (#49131)
This commit is contained in:
parent
02f00a2046
commit
fd248ebb89
|
@ -19,6 +19,7 @@ from collections import OrderedDict
|
|||
|
||||
from django.contrib.auth import forms as auth_forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Q
|
||||
from django.forms import Form
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -35,7 +36,7 @@ logger = logging.getLogger(__name__)
|
|||
class PasswordResetForm(forms.Form):
|
||||
next_url = forms.CharField(widget=forms.HiddenInput, required=False)
|
||||
|
||||
email = ValidatedEmailField(
|
||||
email = forms.CharField(
|
||||
label=_("Email"), max_length=254)
|
||||
|
||||
def save(self):
|
||||
|
@ -45,7 +46,8 @@ class PasswordResetForm(forms.Form):
|
|||
"""
|
||||
email = self.cleaned_data["email"].strip()
|
||||
users = get_user_queryset()
|
||||
active_users = users.filter(email__iexact=email, deleted__isnull=True)
|
||||
active_users = users.filter(
|
||||
Q(email__iexact=email) | Q(username__iexact=email), deleted__isnull=True)
|
||||
for user in active_users:
|
||||
# we don't set the password to a random string, as some users should not have
|
||||
# a password
|
||||
|
|
|
@ -806,8 +806,8 @@ def build_reset_password_url(user, request=None, next_url=None, set_random_passw
|
|||
user.save()
|
||||
lifetime = settings.PASSWORD_RESET_TIMEOUT_DAYS * 3600 * 24
|
||||
# invalidate any token associated with this user
|
||||
Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email).delete()
|
||||
token = Token.create('pw-reset', {'user': user.pk, 'email': user.email}, duration=lifetime)
|
||||
Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email, content__username=user.username).delete()
|
||||
token = Token.create('pw-reset', {'user': user.pk, 'email': user.email, 'username': user.username}, duration=lifetime)
|
||||
reset_url = make_url(
|
||||
'password_reset_confirm',
|
||||
kwargs={'token': token.uuid_b64url},
|
||||
|
|
|
@ -673,7 +673,8 @@ class PasswordResetView(FormView):
|
|||
|
||||
# if an email has already been sent, warn once before allowing resend
|
||||
token = models.Token.objects.filter(
|
||||
kind='pw-reset', content__email=email, expires__gt=timezone.now()
|
||||
Q(content__email__iexact=email) | Q(content__username__iexact=email),
|
||||
kind='pw-reset', expires__gt=timezone.now()
|
||||
).exists()
|
||||
resend_key = 'pw-reset-allow-resend'
|
||||
if app_settings.A2_TOKEN_EXISTS_WARNING and token and not self.request.session.get(resend_key):
|
||||
|
|
|
@ -41,7 +41,7 @@ def test_send_password_reset_email(app, simple_user, mailoutbox):
|
|||
utils.assert_event('user.password.reset', user=simple_user, session=app.session)
|
||||
|
||||
|
||||
def test_view(app, simple_user, mailoutbox, settings):
|
||||
def test_view_with_email(app, simple_user, mailoutbox, settings):
|
||||
url = reverse('password_reset')
|
||||
resp = app.get(url, status=200)
|
||||
resp.form.set('email', simple_user.email)
|
||||
|
@ -51,7 +51,33 @@ def test_view(app, simple_user, mailoutbox, settings):
|
|||
utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
|
||||
assert resp['Location'].endswith('/instructions/')
|
||||
resp = resp.follow()
|
||||
assert simple_user.email in resp.text
|
||||
assert '"noreply@example.net"' in resp.text
|
||||
assert 'show only addr' not in resp.text
|
||||
assert len(mailoutbox) == 1
|
||||
url = utils.get_link_from_mail(mailoutbox[0])
|
||||
relative_url = url.split('testserver')[1]
|
||||
resp = app.get(relative_url, status=200)
|
||||
resp.form.set('new_password1', '1234==aA')
|
||||
resp.form.set('new_password2', '1234==aA')
|
||||
resp = resp.form.submit()
|
||||
# verify user is logged
|
||||
assert str(app.session['_auth_user_id']) == str(simple_user.pk)
|
||||
|
||||
with override_settings(A2_USER_CAN_RESET_PASSWORD=False):
|
||||
url = reverse('password_reset')
|
||||
app.get(url, status=404)
|
||||
|
||||
|
||||
def test_view_with_username(app, simple_user, mailoutbox, settings):
|
||||
url = reverse('password_reset')
|
||||
resp = app.get(url, status=200)
|
||||
resp.form.set('email', simple_user.username)
|
||||
assert len(mailoutbox) == 0
|
||||
settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
|
||||
resp = resp.form.submit()
|
||||
utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
|
||||
assert resp['Location'].endswith('/instructions/')
|
||||
resp = resp.follow()
|
||||
assert '"noreply@example.net"' in resp.text
|
||||
assert 'show only addr' not in resp.text
|
||||
assert len(mailoutbox) == 1
|
||||
|
|
Loading…
Reference in New Issue