From 71d3aa13d79b6e721cfbce6e6175aaf65388fc5d Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Wed, 14 Jul 2021 23:10:49 +0100 Subject: [PATCH] follow sign_in redirect even if you're already signed in --- app/main/views/sign_in.py | 5 ++++- app/utils/login.py | 6 +++--- tests/app/main/views/test_sign_in.py | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index 047fd6c48..3f3b58758 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -15,17 +15,20 @@ from app.main import main from app.main.forms import LoginForm from app.models.user import InvitedUser, User from app.utils import hide_from_search_engines +from app.utils.login import is_safe_redirect_url @main.route('/sign-in', methods=(['GET', 'POST'])) @hide_from_search_engines def sign_in(): + redirect_url = request.args.get('next') if current_user and current_user.is_authenticated: + if redirect_url and is_safe_redirect_url(redirect_url): + return redirect(redirect_url) return redirect(url_for('main.show_accounts_or_dashboard')) form = LoginForm() password_reset_url = url_for('.forgot_password', next=request.args.get('next')) - redirect_url = request.args.get('next') if form.validate_on_submit(): diff --git a/app/utils/login.py b/app/utils/login.py index 99627c6eb..807cf0259 100644 --- a/app/utils/login.py +++ b/app/utils/login.py @@ -36,7 +36,7 @@ def log_in_user(user_id): def redirect_when_logged_in(platform_admin): next_url = request.args.get('next') - if next_url and _is_safe_redirect_url(next_url): + if next_url and is_safe_redirect_url(next_url): return redirect(next_url) return redirect(url_for('main.show_accounts_or_dashboard')) @@ -46,8 +46,8 @@ def email_needs_revalidating(user): return not is_less_than_days_ago(user.email_access_validated_at, 90) -# see http://flask.pocoo.org/snippets/62/ -def _is_safe_redirect_url(target): +# see https://stackoverflow.com/questions/60532973/how-do-i-get-a-is-safe-url-function-to-use-with-flask-and-how-does-it-work # noqa +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)) diff --git a/tests/app/main/views/test_sign_in.py b/tests/app/main/views/test_sign_in.py index d6d37c42b..6a62b62af 100644 --- a/tests/app/main/views/test_sign_in.py +++ b/tests/app/main/views/test_sign_in.py @@ -105,6 +105,28 @@ def test_logged_in_user_redirects_to_account( ) +def test_logged_in_user_redirects_to_next_url( + client_request +): + client_request.get( + 'main.sign_in', + next='/user-profile', + _expected_status=302, + _expected_redirect=url_for('main.user_profile', _external=True), + ) + + +def test_logged_in_user_doesnt_do_evil_redirect( + client_request +): + client_request.get( + 'main.sign_in', + next='http://www.evil.com', + _expected_status=302, + _expected_redirect=url_for('main.show_accounts_or_dashboard', _external=True), + ) + + @pytest.mark.parametrize('redirect_url', [ None, f'/services/{SERVICE_ONE_ID}/templates',