0001-Allow-users-to-provide-their-email-or-username-for-p.patch
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 |
- |