From b7265830849296640cfd5f7bbd4e6fde7bab8351 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 27 Feb 2019 12:35:48 +0100 Subject: [PATCH] Keep GET parameters throughout entire login process --- passbook/core/auth/view.py | 21 ++++++++++++++------- passbook/core/views/authentication.py | 4 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/passbook/core/auth/view.py b/passbook/core/auth/view.py index 7a300e3d8..6696f808f 100644 --- a/passbook/core/auth/view.py +++ b/passbook/core/auth/view.py @@ -4,6 +4,7 @@ from logging import getLogger from django.contrib.auth import login from django.contrib.auth.mixins import UserPassesTestMixin from django.shortcuts import get_object_or_404, redirect, reverse +from django.utils.http import urlencode from django.views.generic import View from passbook.core.models import Factor, User @@ -13,6 +14,12 @@ from passbook.lib.utils.urls import is_url_absolute LOGGER = getLogger(__name__) +def _redirect_with_qs(view, get_query_set=None): + """Wrapper to redirect whilst keeping GET Parameters""" + target = reverse(view) + if get_query_set: + target += '?' + urlencode({key: value for key, value in get_query_set.items()}) + return redirect(target) class AuthenticationView(UserPassesTestMixin, View): """Wizard-like Multi-factor authenticator""" @@ -37,7 +44,7 @@ class AuthenticationView(UserPassesTestMixin, View): # Function from UserPassesTestMixin if 'next' in self.request.GET: return redirect(self.request.GET.get('next')) - return redirect(reverse('passbook_core:overview')) + return _redirect_with_qs('passbook_core:overview', self.request.GET) def dispatch(self, request, *args, **kwargs): # Extract pending user from session (only remember uid) @@ -46,7 +53,7 @@ class AuthenticationView(UserPassesTestMixin, View): User, id=self.request.session[AuthenticationView.SESSION_PENDING_USER]) else: # No Pending user, redirect to login screen - return redirect(reverse('passbook_core:auth-login')) + return _redirect_with_qs('passbook_core:auth-login', request.GET) # Write pending factors to session if AuthenticationView.SESSION_PENDING_FACTORS in request.session: self.pending_factors = request.session[AuthenticationView.SESSION_PENDING_FACTORS] @@ -101,8 +108,8 @@ class AuthenticationView(UserPassesTestMixin, View): self.pending_factors self.request.session[AuthenticationView.SESSION_FACTOR] = next_factor LOGGER.debug("Rendering Factor is %s", next_factor) - # return redirect(reverse('passbook_core:auth-process', kwargs={'factor': next_factor})) - return redirect(reverse('passbook_core:auth-process')) + # return _redirect_with_qs('passbook_core:auth-process', kwargs={'factor': next_factor}) + return _redirect_with_qs('passbook_core:auth-process', self.request.GET) # User passed all factors LOGGER.debug("User passed all factors, logging in") return self._user_passed() @@ -112,7 +119,7 @@ class AuthenticationView(UserPassesTestMixin, View): This should only be shown if user authenticated successfully, but is disabled/locked/etc""" LOGGER.debug("User invalid") self.cleanup() - return redirect(reverse('passbook_core:auth-denied')) + return _redirect_with_qs('passbook_core:auth-denied', self.request.GET) def _user_passed(self): """User Successfully passed all factors""" @@ -123,9 +130,9 @@ class AuthenticationView(UserPassesTestMixin, View): # Cleanup self.cleanup() next_param = self.request.GET.get('next', None) - if next_param and is_url_absolute(next_param): + if next_param and not is_url_absolute(next_param): return redirect(next_param) - return redirect(reverse('passbook_core:overview')) + return _redirect_with_qs('passbook_core:overview') def cleanup(self): """Remove temporary data from session""" diff --git a/passbook/core/views/authentication.py b/passbook/core/views/authentication.py index 50912b6c3..3d24dc5d7 100644 --- a/passbook/core/views/authentication.py +++ b/passbook/core/views/authentication.py @@ -12,7 +12,7 @@ from django.utils.translation import ugettext as _ from django.views import View from django.views.generic import FormView -from passbook.core.auth.view import AuthenticationView +from passbook.core.auth.view import AuthenticationView, _redirect_with_qs from passbook.core.exceptions import PasswordPolicyInvalid from passbook.core.forms.authentication import LoginForm, SignUpForm from passbook.core.models import Invitation, Nonce, Source, User @@ -73,7 +73,7 @@ class LoginView(UserPassesTestMixin, FormView): return self.invalid_login(self.request) self.request.session.flush() self.request.session[AuthenticationView.SESSION_PENDING_USER] = pre_user.pk - return redirect(reverse('passbook_core:auth-process')) + return _redirect_with_qs('passbook_core:auth-process', self.request.GET) def invalid_login(self, request: HttpRequest, disabled_user: User = None) -> HttpResponse: """Handle login for disabled users/invalid login attempts"""