Keep GET parameters throughout entire login process

This commit is contained in:
Jens Langhammer 2019-02-27 12:35:48 +01:00
parent 48055d1cfd
commit b726583084
2 changed files with 16 additions and 9 deletions

View File

@ -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"""

View File

@ -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"""