From bf2e6802bf5f5488a4179c160ed7ce84048f6f14 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 14 Jun 2021 11:15:57 +0100 Subject: [PATCH] Extract login utils out of two_factor view This better reflects how the code is reused in other views and is not specific to two factor actions. We have a pattern of testing utility functionality for each view (as opposed to testing the util + the view calls the util), so I'm leaving the tests as-is. --- app/main/views/new_password.py | 2 +- app/main/views/two_factor.py | 41 ++++---------------------- app/main/views/webauthn_credentials.py | 3 +- app/utils/login.py | 39 +++++++++++++++++++++++- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/app/main/views/new_password.py b/app/main/views/new_password.py index 5167d7ae2..210496447 100644 --- a/app/main/views/new_password.py +++ b/app/main/views/new_password.py @@ -14,8 +14,8 @@ from notifications_utils.url_safe_token import check_token from app.main import main from app.main.forms import NewPasswordForm -from app.main.views.two_factor import log_in_user from app.models.user import User +from app.utils.login import log_in_user @main.route('/new-password/', methods=['GET', 'POST']) diff --git a/app/main/views/two_factor.py b/app/main/views/two_factor.py index 8a2e2036e..75cdd0d78 100644 --- a/app/main/views/two_factor.py +++ b/app/main/views/two_factor.py @@ -17,7 +17,11 @@ from app.main import main from app.main.forms import TwoFactorForm from app.models.user import User from app.utils import is_less_than_days_ago -from app.utils.login import redirect_to_sign_in +from app.utils.login import ( + log_in_user, + redirect_to_sign_in, + redirect_when_logged_in, +) @main.route('/two-factor-email-sent', methods=['GET']) @@ -97,38 +101,3 @@ def revalidate_email_sent(): title = 'Email resent' if request.args.get('email_resent') else 'Check your email' redirect_url = request.args.get('next') return render_template('views/re-validate-email-sent.html', title=title, redirect_url=redirect_url) - - -# see http://flask.pocoo.org/snippets/62/ -def _is_safe_redirect_url(target): - from urllib.parse import urljoin, urlparse - host_url = urlparse(request.host_url) - redirect_url = urlparse(urljoin(request.host_url, target)) - return redirect_url.scheme in ('http', 'https') and \ - host_url.netloc == redirect_url.netloc - - -def log_in_user(user_id): - try: - user = User.from_id(user_id) - # the user will have a new current_session_id set by the API - store it in the cookie for future requests - session['current_session_id'] = user.current_session_id - # Check if coming from new password page - if 'password' in session.get('user_details', {}): - user.update_password(session['user_details']['password'], validated_email_access=True) - user.activate() - user.login() - finally: - # get rid of anything in the session that we don't expect to have been set during register/sign in flow - session.pop("user_details", None) - session.pop("file_uploads", None) - - return redirect_when_logged_in(platform_admin=user.platform_admin) - - -def redirect_when_logged_in(platform_admin): - next_url = request.args.get('next') - if next_url and _is_safe_redirect_url(next_url): - return redirect(next_url) - - return redirect(url_for('main.show_accounts_or_dashboard')) diff --git a/app/main/views/webauthn_credentials.py b/app/main/views/webauthn_credentials.py index 953242147..008e24ada 100644 --- a/app/main/views/webauthn_credentials.py +++ b/app/main/views/webauthn_credentials.py @@ -6,12 +6,11 @@ from flask_login import current_user from werkzeug.exceptions import Forbidden from app.main import main -from app.main.views.two_factor import log_in_user from app.models.user import User from app.models.webauthn_credential import RegistrationError, WebAuthnCredential from app.notify_client.user_api_client import user_api_client from app.utils import is_less_than_days_ago -from app.utils.login import redirect_to_sign_in +from app.utils.login import log_in_user, redirect_to_sign_in from app.utils.user import user_is_platform_admin diff --git a/app/utils/login.py b/app/utils/login.py index c96fba71f..0c7be1f48 100644 --- a/app/utils/login.py +++ b/app/utils/login.py @@ -1,6 +1,8 @@ from functools import wraps -from flask import redirect, session, url_for +from flask import redirect, request, session, url_for + +from app.models.user import User def redirect_to_sign_in(f): @@ -11,3 +13,38 @@ def redirect_to_sign_in(f): else: return f(*args, **kwargs) return wrapped + + +def log_in_user(user_id): + try: + user = User.from_id(user_id) + # the user will have a new current_session_id set by the API - store it in the cookie for future requests + session['current_session_id'] = user.current_session_id + # Check if coming from new password page + if 'password' in session.get('user_details', {}): + user.update_password(session['user_details']['password'], validated_email_access=True) + user.activate() + user.login() + finally: + # get rid of anything in the session that we don't expect to have been set during register/sign in flow + session.pop("user_details", None) + session.pop("file_uploads", None) + + return redirect_when_logged_in(platform_admin=user.platform_admin) + + +def redirect_when_logged_in(platform_admin): + next_url = request.args.get('next') + if next_url and _is_safe_redirect_url(next_url): + return redirect(next_url) + + return redirect(url_for('main.show_accounts_or_dashboard')) + + +# see http://flask.pocoo.org/snippets/62/ +def _is_safe_redirect_url(target): + from urllib.parse import urljoin, urlparse + host_url = urlparse(request.host_url) + redirect_url = urlparse(urljoin(request.host_url, target)) + return redirect_url.scheme in ('http', 'https') and \ + host_url.netloc == redirect_url.netloc