Files
notifications-admin/tests/app/main/views/test_new_password.py

181 lines
5.6 KiB
Python
Raw Normal View History

2016-03-07 18:18:52 +00:00
import json
from datetime import datetime
import pytest
2016-03-07 18:18:52 +00:00
from flask import url_for
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
from freezegun import freeze_time
from itsdangerous import SignatureExpired
from notifications_utils.url_safe_token import generate_token
from tests.conftest import SERVICE_ONE_ID, url_for_endpoint_with_token
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
@freeze_time("2021-01-01 11:11:11")
def test_should_render_new_password_template(
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
mocker,
notify_admin,
client_request,
mock_send_verify_code,
mock_get_user_by_email_request_password_reset,
):
client_request.logout()
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
user = mock_get_user_by_email_request_password_reset.return_value
user["password_changed_at"] = "2021-01-01 00:00:00"
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
mock_update_user_attribute = mocker.patch(
"app.user_api_client.update_user_attribute",
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
return_value=user,
)
data = json.dumps(
{"email": user["email_address"], "created_at": str(datetime.utcnow())}
)
token = generate_token(
data, notify_admin.config["SECRET_KEY"], notify_admin.config["DANGEROUS_SALT"]
)
page = client_request.get_url(
url_for_endpoint_with_token(".new_password", token=token)
)
assert "You can now create a new password for your account." in page.text
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
mock_update_user_attribute.assert_called_once_with(
user["id"], email_access_validated_at="2021-01-01T11:11:11"
Update `email_access_validated_at` on link click When someone uses a fresh password reset link they have proved that they have access to their inbox. At the moment, when revalidating a user’s email address we wait until after they’ve put in the 2FA code before updating the timestamp which records when they last validated their email address[1]. We can’t think of a good reason that we need the extra assurance of a valid 2FA code to assert that the user has access to their email – they’ve done that just by clicking the link. When the user clicks the link we already update their failed login count before they 2fa. Think it makes sense to handle `email_access_validated_at` then too. As a bonus, the functional tests never go as far as getting a 2FA code after a password reset[2], so the functional test user never gets its timestamp updated. This causes the functional tests start failing after 90 days. By moving the update to this point we ensure that the functional tests will keep passing indefinitely. 1. This code in the API (https://github.com/alphagov/notifications-api/blob/91542ad33eb995c9b3e617cde30a9714846dd37b/app/dao/users_dao.py#L131) which is called by this code in the admin app (https://github.com/alphagov/notifications-admin/blob/9ba37249a47f08b1396e63a34bc591c781739686/app/utils/login.py#L26) 2. https://github.com/alphagov/notifications-functional-tests/blob/5837eb01dc5c9b5bb255d2d1c54e64f778ff4f4e/tests/functional/preview_and_dev/test_email_auth.py#L43-L46
2021-08-17 16:14:47 +01:00
)
def test_should_return_404_when_email_address_does_not_exist(
notify_admin,
client_request,
mock_get_user_by_email_not_found,
):
client_request.logout()
data = json.dumps(
{"email": "no_user@d.gsa.gov", "created_at": str(datetime.utcnow())}
)
token = generate_token(
data, notify_admin.config["SECRET_KEY"], notify_admin.config["DANGEROUS_SALT"]
)
client_request.get_url(
url_for_endpoint_with_token(".new_password", token=token),
_expected_status=404,
)
@pytest.mark.parametrize(
"redirect_url",
[
None,
f"/services/{SERVICE_ONE_ID}/templates",
],
)
def test_should_redirect_to_two_factor_when_password_reset_is_successful(
notify_admin,
client_request,
mock_get_user_by_email_request_password_reset,
mock_login,
mock_send_verify_code,
mock_reset_failed_login_count,
redirect_url,
):
client_request.logout()
user = mock_get_user_by_email_request_password_reset.return_value
data = json.dumps(
{"email": user["email_address"], "created_at": str(datetime.utcnow())}
)
token = generate_token(
data, notify_admin.config["SECRET_KEY"], notify_admin.config["DANGEROUS_SALT"]
)
client_request.post_url(
url_for_endpoint_with_token(".new_password", token=token, next=redirect_url),
_data={"new_password": "a-new_password"},
_expected_redirect=url_for(".two_factor_sms", next=redirect_url),
)
mock_get_user_by_email_request_password_reset.assert_called_once_with(
user["email_address"]
)
def test_should_redirect_index_if_user_has_already_changed_password(
notify_admin,
client_request,
mock_get_user_by_email_user_changed_password,
mock_login,
mock_send_verify_code,
mock_reset_failed_login_count,
):
client_request.logout()
user = mock_get_user_by_email_user_changed_password.return_value
data = json.dumps(
{"email": user["email_address"], "created_at": str(datetime.utcnow())}
)
token = generate_token(
data, notify_admin.config["SECRET_KEY"], notify_admin.config["DANGEROUS_SALT"]
)
client_request.post_url(
url_for_endpoint_with_token(".new_password", token=token),
_data={"new_password": "a-new_password"},
_expected_redirect=url_for(".index"),
)
mock_get_user_by_email_user_changed_password.assert_called_once_with(
user["email_address"]
)
2016-03-07 18:18:52 +00:00
def test_should_redirect_to_forgot_password_with_flash_message_when_token_is_expired(
notify_admin, client_request, mock_login, mocker
):
client_request.logout()
mocker.patch(
"app.main.views.new_password.check_token",
side_effect=SignatureExpired("expired"),
)
token = generate_token(
"foo@bar.com",
notify_admin.config["SECRET_KEY"],
notify_admin.config["DANGEROUS_SALT"],
)
client_request.get_url(
url_for_endpoint_with_token(".new_password", token=token),
_expected_redirect=url_for(".forgot_password"),
)
def test_should_sign_in_when_password_reset_is_successful_for_email_auth(
mocker,
notify_admin,
client_request,
api_user_active,
mock_get_user_by_email_request_password_reset,
mock_login,
mock_send_verify_code,
mock_reset_failed_login_count,
mock_update_user_password,
):
client_request.logout()
user = mock_get_user_by_email_request_password_reset.return_value
mock_get_user = mocker.patch(
"app.user_api_client.get_user", return_value=api_user_active
)
user["auth_type"] = "email_auth"
data = json.dumps(
{"email": user["email_address"], "created_at": str(datetime.utcnow())}
)
token = generate_token(
data, notify_admin.config["SECRET_KEY"], notify_admin.config["DANGEROUS_SALT"]
)
client_request.post_url(
url_for_endpoint_with_token(".new_password", token=token),
_data={"new_password": "a-new_password"},
_expected_redirect=url_for(".show_accounts_or_dashboard"),
)
assert mock_get_user_by_email_request_password_reset.called
assert mock_reset_failed_login_count.called
# the log-in flow makes a couple of calls
mock_get_user.assert_called_once_with(user["id"])
mock_update_user_password.assert_called_once_with(user["id"], "a-new_password")
assert not mock_send_verify_code.called