mirror of
https://github.com/wassname/flask-security.git
synced 2026-06-27 16:10:11 +08:00
c10c9050c7
The user may have been invited via a social network or an invitation system.
184 lines
5.9 KiB
Python
184 lines
5.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
test_recoverable
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
Recoverable functionality tests
|
|
"""
|
|
|
|
import time
|
|
|
|
import pytest
|
|
|
|
from flask import Flask
|
|
from flask_security.core import UserMixin
|
|
from flask_security.signals import reset_password_instructions_sent, password_reset
|
|
from flask_security.utils import capture_reset_password_requests, string_types
|
|
|
|
from utils import authenticate, logout
|
|
|
|
pytestmark = pytest.mark.recoverable()
|
|
|
|
|
|
def test_recoverable_flag(app, client, get_message):
|
|
recorded_resets = []
|
|
recorded_instructions_sent = []
|
|
|
|
@password_reset.connect_via(app)
|
|
def on_password_reset(app, user):
|
|
recorded_resets.append(user)
|
|
|
|
@reset_password_instructions_sent.connect_via(app)
|
|
def on_instructions_sent(app, user, token):
|
|
assert isinstance(app, Flask)
|
|
assert isinstance(user, UserMixin)
|
|
assert isinstance(token, string_types)
|
|
recorded_instructions_sent.append(user)
|
|
|
|
# Test the reset view
|
|
response = client.get('/reset')
|
|
assert b'<h1>Send password reset instructions</h1>' in response.data
|
|
|
|
# Test submitting email to reset password creates a token and sends email
|
|
with capture_reset_password_requests() as requests:
|
|
with app.mail.record_messages() as outbox:
|
|
response = client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True)
|
|
|
|
assert len(recorded_instructions_sent) == 1
|
|
assert len(outbox) == 1
|
|
assert response.status_code == 200
|
|
assert get_message('PASSWORD_RESET_REQUEST', email='joe@lp.com') in response.data
|
|
token = requests[0]['token']
|
|
|
|
# Test view for reset token
|
|
response = client.get('/reset/' + token)
|
|
assert b'<h1>Reset password</h1>' in response.data
|
|
|
|
# Test submitting a new password
|
|
response = client.post('/reset/' + token, data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
|
|
assert get_message('PASSWORD_RESET') in response.data
|
|
assert len(recorded_resets) == 1
|
|
|
|
logout(client)
|
|
|
|
# Test logging in with the new password
|
|
response = authenticate(client, 'joe@lp.com', 'newpassword', follow_redirects=True)
|
|
assert b'Hello joe@lp.com' in response.data
|
|
|
|
logout(client)
|
|
|
|
# Test submitting JSON
|
|
response = client.post('/reset', data='{"email": "joe@lp.com"}', headers={
|
|
'Content-Type': 'application/json'
|
|
})
|
|
assert response.headers['Content-Type'] == 'application/json'
|
|
assert 'user' not in response.jdata['response']
|
|
|
|
logout(client)
|
|
|
|
# Test invalid email
|
|
response = client.post('/reset', data=dict(email='bogus@lp.com'), follow_redirects=True)
|
|
assert get_message('USER_DOES_NOT_EXIST') in response.data
|
|
|
|
logout(client)
|
|
|
|
# Test invalid token
|
|
response = client.post('/reset/bogus', data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data
|
|
|
|
# Test mangled token
|
|
token = ("WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd.BZEw_Q.lQyo3npdPZtcJ"
|
|
"_sNHVHP103syjM&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d")
|
|
response = client.post('/reset/' + token, data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data
|
|
|
|
|
|
@pytest.mark.settings(reset_password_within='1 milliseconds')
|
|
def test_expired_reset_token(client, get_message):
|
|
with capture_reset_password_requests() as requests:
|
|
client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True)
|
|
|
|
user = requests[0]['user']
|
|
token = requests[0]['token']
|
|
|
|
time.sleep(1)
|
|
|
|
response = client.post('/reset/' + token, data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
|
|
msg = get_message('PASSWORD_RESET_EXPIRED', within='1 milliseconds', email=user.email)
|
|
assert msg in response.data
|
|
|
|
|
|
def test_used_reset_token(client, get_message):
|
|
with capture_reset_password_requests() as requests:
|
|
client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True)
|
|
|
|
token = requests[0]['token']
|
|
|
|
# use the token
|
|
response = client.post('/reset/' + token, data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
|
|
assert get_message('PASSWORD_RESET') in response.data
|
|
|
|
logout(client)
|
|
|
|
# attempt to use it a second time
|
|
response2 = client.post('/reset/' + token, data={
|
|
'password': 'otherpassword',
|
|
'password_confirm': 'otherpassword'
|
|
}, follow_redirects=True)
|
|
|
|
msg = get_message('INVALID_RESET_PASSWORD_TOKEN')
|
|
assert msg in response2.data
|
|
|
|
|
|
def test_reset_passwordless_user(client, get_message):
|
|
with capture_reset_password_requests() as requests:
|
|
client.post('/reset', data=dict(email='jess@lp.com'), follow_redirects=True)
|
|
|
|
token = requests[0]['token']
|
|
|
|
# use the token
|
|
response = client.post('/reset/' + token, data={
|
|
'password': 'newpassword',
|
|
'password_confirm': 'newpassword'
|
|
}, follow_redirects=True)
|
|
|
|
assert get_message('PASSWORD_RESET') in response.data
|
|
|
|
|
|
@pytest.mark.settings(reset_url='/custom_reset')
|
|
def test_custom_reset_url(client):
|
|
response = client.get('/custom_reset')
|
|
assert response.status_code == 200
|
|
|
|
|
|
@pytest.mark.settings(reset_password_template='custom_security/reset_password.html',
|
|
forgot_password_template='custom_security/forgot_password.html')
|
|
def test_custom_reset_templates(client):
|
|
response = client.get('/reset')
|
|
assert b'CUSTOM FORGOT PASSWORD' in response.data
|
|
|
|
with capture_reset_password_requests() as requests:
|
|
client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True)
|
|
token = requests[0]['token']
|
|
|
|
response = client.get('/reset/' + token)
|
|
assert b'CUSTOM RESET PASSWORD' in response.data
|