202 lines
7.5 KiB
Python
202 lines
7.5 KiB
Python
# authentic2 - versatile identity manager
|
|
# Copyright (C) 2010-2020 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from django.test.utils import override_settings
|
|
from django.urls import reverse
|
|
|
|
from . import utils
|
|
|
|
|
|
def test_send_password_reset_email(app, simple_user, mailoutbox):
|
|
from authentic2.utils import send_password_reset_mail
|
|
|
|
assert len(mailoutbox) == 0
|
|
with utils.run_on_commit_hooks():
|
|
send_password_reset_mail(
|
|
simple_user,
|
|
legacy_subject_templates=['registration/password_reset_subject.txt'],
|
|
legacy_body_templates=['registration/password_reset_email.html'],
|
|
)
|
|
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().follow()
|
|
assert str(app.session['_auth_user_id']) == str(simple_user.pk)
|
|
utils.assert_event('user.password.reset', user=simple_user, session=app.session)
|
|
|
|
|
|
def test_reset_by_email(app, simple_user, mailoutbox, settings):
|
|
url = reverse('password_reset')
|
|
resp = app.get(url, status=200)
|
|
resp.form.set('email', simple_user.email)
|
|
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
|
|
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_can_reset_by_username(app, db, simple_user, settings, mailoutbox):
|
|
resp = app.get('/accounts/password/reset/')
|
|
assert 'email_or_username' not in resp.form.fields
|
|
settings.A2_USER_CAN_RESET_PASSWORD_BY_USERNAME = True
|
|
resp = app.get('/accounts/password/reset/')
|
|
assert 'email_or_username' in resp.form.fields
|
|
|
|
resp.form.set('email_or_username', simple_user.username)
|
|
resp = resp.form.submit().follow()
|
|
|
|
assert 'an email has been sent to %s' % simple_user.username in resp
|
|
assert len(mailoutbox) == 1
|
|
assert mailoutbox[0].to == [simple_user.email]
|
|
|
|
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)
|
|
|
|
|
|
def test_can_reset_by_username_with_email(app, db, simple_user, settings, mailoutbox):
|
|
settings.A2_USER_CAN_RESET_PASSWORD_BY_USERNAME = True
|
|
resp = app.get('/accounts/password/reset/')
|
|
resp.form.set('email_or_username', simple_user.email)
|
|
resp = resp.form.submit().follow()
|
|
assert 'an email has been sent to %s' % simple_user.username in resp
|
|
assert len(mailoutbox) == 1
|
|
|
|
|
|
def test_reset_by_email_no_account(app, db, mailoutbox):
|
|
resp = app.get('/accounts/password/reset/')
|
|
resp.form.set('email', 'john.doe@example.com')
|
|
resp = resp.form.submit().follow()
|
|
|
|
assert 'an email has been sent to john.doe@example.com' in resp
|
|
assert len(mailoutbox) == 1
|
|
assert 'no account was found' in mailoutbox[0].body
|
|
|
|
|
|
def test_can_reset_by_username_no_account(app, db, settings, mailoutbox):
|
|
settings.A2_USER_CAN_RESET_PASSWORD_BY_USERNAME = True
|
|
|
|
resp = app.get('/accounts/password/reset/')
|
|
resp.form.set('email_or_username', 'john.doe')
|
|
resp = resp.form.submit().follow()
|
|
assert 'an email has been sent to john.doe' in resp
|
|
assert len(mailoutbox) == 0
|
|
|
|
|
|
def test_can_reset_by_username_no_account_email(app, db, settings, mailoutbox):
|
|
settings.A2_USER_CAN_RESET_PASSWORD_BY_USERNAME = True
|
|
|
|
resp = app.get('/accounts/password/reset/')
|
|
resp.form.set('email_or_username', 'john.doe@example.com')
|
|
resp = resp.form.submit().follow()
|
|
assert 'an email has been sent to john.doe' in resp
|
|
assert len(mailoutbox) == 1
|
|
|
|
|
|
def test_user_exclude(app, simple_user, mailoutbox, settings):
|
|
settings.A2_USER_EXCLUDE = {'username': simple_user.username} # will not match simple_user
|
|
|
|
url = reverse('password_reset')
|
|
resp = app.get(url, status=200)
|
|
resp.form.set('email', simple_user.email)
|
|
assert len(mailoutbox) == 0
|
|
resp = resp.form.submit()
|
|
assert 'no account was found associated with this address' in mailoutbox[0].body
|
|
|
|
|
|
def test_old_url_redirect(app):
|
|
response = app.get('/accounts/password/reset/whatever')
|
|
assert response.location == '/accounts/password/reset/'
|
|
response = response.follow()
|
|
assert 'please reset your password again' in response
|
|
|
|
|
|
def test_send_password_reset_email_no_account(app, db, mailoutbox):
|
|
url = reverse('password_reset')
|
|
resp = app.get(url, status=200)
|
|
resp.form.set('email', 'test@entrouvert.com')
|
|
resp = resp.form.submit()
|
|
|
|
mail = mailoutbox[0]
|
|
assert mail.subject == 'Password reset on testserver'
|
|
for body in (mail.body, mail.alternatives[0][0]):
|
|
assert 'no account was found associated with this address' in body
|
|
assert 'http://testserver/accounts/register/' in body
|
|
|
|
|
|
def test_send_password_reset_email_disabled_account(app, simple_user, mailoutbox):
|
|
simple_user.is_active = False
|
|
simple_user.save()
|
|
|
|
url = reverse('password_reset')
|
|
resp = app.get(url, status=200)
|
|
resp.form.set('email', simple_user.email)
|
|
resp = resp.form.submit()
|
|
|
|
mail = mailoutbox[0]
|
|
assert mail.subject == 'Your account on testserver is disabled'
|
|
assert 'your account has been disabled on this server' in mail.body
|
|
|
|
|
|
def test_email_validation(app, db):
|
|
resp = app.get('/accounts/password/reset/')
|
|
resp.form.set('email', 'coin@')
|
|
resp = resp.form.submit()
|
|
assert 'Enter a valid email address.' in resp
|
|
|
|
|
|
def test_honeypot(app, db, settings, mailoutbox):
|
|
settings.DEFAULT_FROM_EMAIL = 'show only addr <noreply@example.net>'
|
|
|
|
url = reverse('password_reset')
|
|
response = app.get(url, status=200)
|
|
response = app.post(
|
|
url,
|
|
params={
|
|
'email': 'testbot@entrouvert.com',
|
|
'csrfmiddlewaretoken': response.context['csrf_token'],
|
|
'robotcheck': 'a',
|
|
},
|
|
)
|
|
response = response.follow()
|
|
assert len(mailoutbox) == 0
|
|
assert 'Your password reset request has been refused' in response
|