Projet

Général

Profil

0001-Allow-users-to-provide-their-email-or-username-for-p.patch

Benjamin Renard, 17 décembre 2020 11:32

Télécharger (5,56 ko)

Voir les différences:

Subject: [PATCH 1/2] Allow users to provide their email or username for
 password reset process

 src/authentic2/forms/passwords.py |  5 +++--
 src/authentic2/utils/__init__.py  |  4 ++--
 src/authentic2/views.py           |  3 ++-
 tests/test_password_reset.py      | 30 ++++++++++++++++++++++++++++--
 4 files changed, 35 insertions(+), 7 deletions(-)
src/authentic2/forms/passwords.py
19 19

  
20 20
from django.contrib.auth import forms as auth_forms
21 21
from django.core.exceptions import ValidationError
22
from django.db.models import Q
22 23
from django.forms import Form
23 24
from django import forms
24 25
from django.utils.translation import ugettext_lazy as _
......
35 36
class PasswordResetForm(forms.Form):
36 37
    next_url = forms.CharField(widget=forms.HiddenInput, required=False)
37 38

  
38
    email = ValidatedEmailField(
39
    email = forms.CharField(
39 40
        label=_("Email"), max_length=254)
40 41

  
41 42
    def save(self):
......
45 46
        """
46 47
        email = self.cleaned_data["email"].strip()
47 48
        users = get_user_queryset()
48
        active_users = users.filter(email__iexact=email, is_active=True)
49
        active_users = users.filter(Q(email__iexact=email) | Q(username__iexact=email), is_active=True)
49 50
        for user in active_users:
50 51
            # we don't set the password to a random string, as some users should not have
51 52
            # a password
src/authentic2/utils/__init__.py
804 804
        user.save()
805 805
    lifetime = settings.PASSWORD_RESET_TIMEOUT_DAYS * 3600 * 24
806 806
    # invalidate any token associated with this user
807
    Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email).delete()
808
    token = Token.create('pw-reset', {'user': user.pk, 'email': user.email}, duration=lifetime)
807
    Token.objects.filter(kind='pw-reset', content__user=user.pk, content__email=user.email, content__username=user.username).delete()
808
    token = Token.create('pw-reset', {'user': user.pk, 'email': user.email, 'username': user.username}, duration=lifetime)
809 809
    reset_url = make_url(
810 810
        'password_reset_confirm',
811 811
        kwargs={'token': token.uuid_b64url},
src/authentic2/views.py
671 671

  
672 672
        # if an email has already been sent, warn once before allowing resend
673 673
        token = models.Token.objects.filter(
674
            kind='pw-reset', content__email=email, expires__gt=timezone.now()
674
            Q(content__email=email) | Q(content__username=email),
675
            kind='pw-reset', expires__gt=timezone.now()
675 676
        ).exists()
676 677
        resend_key = 'pw-reset-allow-resend'
677 678
        if app_settings.A2_TOKEN_EXISTS_WARNING and token and not self.request.session.get(resend_key):
tests/test_password_reset.py
43 43
    utils.assert_event('user.password.reset', user=simple_user, session=app.session)
44 44

  
45 45

  
46
def test_view(app, simple_user, mailoutbox, settings):
46
def test_view_with_email(app, simple_user, mailoutbox, settings):
47 47
    url = reverse('password_reset')
48 48
    resp = app.get(url, status=200)
49 49
    resp.form.set('email', simple_user.email)
......
53 53
    utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
54 54
    assert resp['Location'].endswith('/instructions/')
55 55
    resp = resp.follow()
56
    assert simple_user.email in resp.text
56
    assert '"noreply@example.net"' in resp.text
57
    assert 'show only addr' not in resp.text
58
    assert len(mailoutbox) == 1
59
    url = utils.get_link_from_mail(mailoutbox[0])
60
    relative_url = url.split('testserver')[1]
61
    resp = app.get(relative_url, status=200)
62
    resp.form.set('new_password1', '1234==aA')
63
    resp.form.set('new_password2', '1234==aA')
64
    resp = resp.form.submit()
65
    # verify user is logged
66
    assert str(app.session['_auth_user_id']) == str(simple_user.pk)
67

  
68
    with override_settings(A2_USER_CAN_RESET_PASSWORD=False):
69
        url = reverse('password_reset')
70
        app.get(url, status=404)
71

  
72

  
73
def test_view_with_username(app, simple_user, mailoutbox, settings):
74
    url = reverse('password_reset')
75
    resp = app.get(url, status=200)
76
    resp.form.set('email', simple_user.username)
77
    assert len(mailoutbox) == 0
78
    settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
79
    resp = resp.form.submit()
80
    utils.assert_event('user.password.reset.request', user=simple_user, email=simple_user.email)
81
    assert resp['Location'].endswith('/instructions/')
82
    resp = resp.follow()
57 83
    assert '"noreply@example.net"' in resp.text
58 84
    assert 'show only addr' not in resp.text
59 85
    assert len(mailoutbox) == 1
60
-