mirror of
https://github.com/wassname/flask-security.git
synced 2026-06-27 16:10:11 +08:00
Merge pull request #389 from nickretallack/develop
Reset Password Fixes
This commit is contained in:
@@ -42,3 +42,5 @@ env/
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
.eggs/README.txt
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
from flask import current_app as app
|
||||
from werkzeug.local import LocalProxy
|
||||
from werkzeug.security import safe_str_cmp
|
||||
|
||||
from .signals import password_reset, reset_password_instructions_sent
|
||||
from .utils import send_mail, md5, encrypt_password, url_for_security, \
|
||||
@@ -53,7 +54,8 @@ def generate_reset_password_token(user):
|
||||
|
||||
:param user: The user to work with
|
||||
"""
|
||||
data = [str(user.id), md5(user.password)]
|
||||
password_hash = md5(user.password) if user.password else None
|
||||
data = [str(user.id), password_hash]
|
||||
return _security.reset_serializer.dumps(data)
|
||||
|
||||
|
||||
@@ -61,11 +63,19 @@ def reset_password_token_status(token):
|
||||
"""Returns the expired status, invalid status, and user of a password reset
|
||||
token. For example::
|
||||
|
||||
expired, invalid, user = reset_password_token_status('...')
|
||||
expired, invalid, user, data = reset_password_token_status('...')
|
||||
|
||||
:param token: The password reset token
|
||||
"""
|
||||
return get_token_status(token, 'reset', 'RESET_PASSWORD')
|
||||
expired, invalid, user, data = get_token_status(token, 'reset', 'RESET_PASSWORD',
|
||||
return_data=True)
|
||||
if not invalid:
|
||||
if user.password:
|
||||
password_hash = md5(user.password)
|
||||
if not safe_str_cmp(password_hash, data[1]):
|
||||
invalid = True
|
||||
|
||||
return expired, invalid, user
|
||||
|
||||
|
||||
def update_password(user, password):
|
||||
|
||||
@@ -341,7 +341,7 @@ def send_mail(subject, recipient, template, **context):
|
||||
mail.send(msg)
|
||||
|
||||
|
||||
def get_token_status(token, serializer, max_age=None):
|
||||
def get_token_status(token, serializer, max_age=None, return_data=False):
|
||||
"""Get the status of a token.
|
||||
|
||||
:param token: The token to check
|
||||
@@ -367,7 +367,11 @@ def get_token_status(token, serializer, max_age=None):
|
||||
user = _datastore.find_user(id=data[0])
|
||||
|
||||
expired = expired and (user is not None)
|
||||
return expired, invalid, user
|
||||
|
||||
if return_data:
|
||||
return expired, invalid, user, data
|
||||
else:
|
||||
return expired, invalid, user
|
||||
|
||||
|
||||
def get_identity_attributes(app=None):
|
||||
|
||||
@@ -122,6 +122,47 @@ def test_expired_reset_token(client, get_message):
|
||||
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')
|
||||
|
||||
Reference in New Issue
Block a user