diff --git a/kallithea/controllers/login.py b/kallithea/controllers/login.py
--- a/kallithea/controllers/login.py
+++ b/kallithea/controllers/login.py
@@ -42,6 +42,7 @@ from kallithea.lib.auth import AuthUser,
from kallithea.lib.auth_modules import importplugin
from kallithea.lib.base import BaseController, render
from kallithea.lib.exceptions import UserCreationError
+from kallithea.lib.utils2 import safe_str
from kallithea.model.db import User, Setting
from kallithea.model.forms import LoginForm, RegisterForm, PasswordResetForm
from kallithea.model.user import UserModel
@@ -102,9 +103,14 @@ class LoginController(BaseController):
came_from = url('home')
return came_from
+ def _redirect_to_origin(self, origin, headers=None):
+ '''redirect to the original page, preserving any get arguments given'''
+ request.GET.pop('came_from', None)
+ raise HTTPFound(location=url(origin, **request.GET), headers=headers)
+
def index(self):
_default_came_from = url('home')
- came_from = self._validate_came_from(request.GET.get('came_from'))
+ came_from = self._validate_came_from(safe_str(request.GET.get('came_from', '')))
c.came_from = came_from or _default_came_from
not_default = self.authuser.username != User.DEFAULT_USER
@@ -112,7 +118,7 @@ class LoginController(BaseController):
# redirect if already logged in
if self.authuser.is_authenticated and not_default and ip_allowed:
- raise HTTPFound(location=c.came_from)
+ return self._redirect_to_origin(c.came_from)
if request.POST:
# import Login Form validator class
@@ -124,7 +130,8 @@ class LoginController(BaseController):
headers = self._store_user_in_session(
username=c.form_result['username'],
remember=c.form_result['remember'])
- raise HTTPFound(location=c.came_from, headers=headers)
+ return self._redirect_to_origin(c.came_from, headers)
+
except formencode.Invalid, errors:
defaults = errors.value
# remove password from filling in form again
@@ -157,7 +164,8 @@ class LoginController(BaseController):
if auth_info:
headers = self._store_user_in_session(auth_info.get('username'))
- raise HTTPFound(location=c.came_from, headers=headers)
+ return self._redirect_to_origin(c.came_from, headers)
+
return render('/login.html')
@HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py
--- a/kallithea/lib/auth.py
+++ b/kallithea/lib/auth.py
@@ -711,7 +711,7 @@ def redirect_to_login(message=None):
if message:
h.flash(h.literal(message), category='warning')
log.debug('Redirecting to login page, origin: %s' % p)
- return redirect(url('login_home', came_from=p))
+ return redirect(url('login_home', came_from=p, **request.GET))
class LoginRequired(object):
"""
diff --git a/kallithea/templates/login.html b/kallithea/templates/login.html
--- a/kallithea/templates/login.html
+++ b/kallithea/templates/login.html
@@ -16,7 +16,7 @@
%endif
- ${h.form(h.url.current(came_from=c.came_from))}
+ ${h.form(h.url.current(**request.GET))}
diff --git a/kallithea/tests/functional/test_login.py b/kallithea/tests/functional/test_login.py
--- a/kallithea/tests/functional/test_login.py
+++ b/kallithea/tests/functional/test_login.py
@@ -66,7 +66,7 @@ class TestLoginController(TestController
('mailto:test@example.com',),
('file:///etc/passwd',),
('ftp://some.ftp.server',),
- ('http://other.domain',),
+ ('http://other.domain/bl%C3%A5b%C3%A6rgr%C3%B8d',),
])
def test_login_bad_came_froms(self, url_came_from):
response = self.app.post(url(controller='login', action='index',
@@ -96,6 +96,66 @@ class TestLoginController(TestController
response.mustcontain('invalid user name')
response.mustcontain('invalid password')
+ # verify that get arguments are correctly passed along login redirection
+
+ @parameterized.expand([
+ ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
+ ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
+ ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
+ ])
+ def test_redirection_to_login_form_preserves_get_args(self, args, args_encoded):
+ with fixture.anon_access(False):
+ response = self.app.get(url(controller='summary', action='index',
+ repo_name=HG_REPO,
+ **args))
+ self.assertEqual(response.status, '302 Found')
+ for encoded in args_encoded:
+ self.assertIn(encoded, response.location)
+
+ @parameterized.expand([
+ ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
+ ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
+ ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
+ ])
+ def test_login_form_preserves_get_args(self, args, args_encoded):
+ response = self.app.get(url(controller='login', action='index',
+ came_from = '/_admin/users',
+ **args))
+ for encoded in args_encoded:
+ self.assertIn(encoded, response.form.action)
+
+ @parameterized.expand([
+ ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
+ ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
+ ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
+ ])
+ def test_redirection_after_successful_login_preserves_get_args(self, args, args_encoded):
+ response = self.app.post(url(controller='login', action='index',
+ came_from = '/_admin/users',
+ **args),
+ {'username': 'test_admin',
+ 'password': 'test12'})
+ self.assertEqual(response.status, '302 Found')
+ for encoded in args_encoded:
+ self.assertIn(encoded, response.location)
+
+ @parameterized.expand([
+ ({'foo':'one', 'bar':'two'}, ('foo=one', 'bar=two')),
+ ({'blue': u'blå'.encode('utf-8'), 'green':u'grøn'},
+ ('blue=bl%C3%A5', 'green=gr%C3%B8n')),
+ ])
+ def test_login_form_after_incorrect_login_preserves_get_args(self, args, args_encoded):
+ response = self.app.post(url(controller='login', action='index',
+ came_from = '/_admin/users',
+ **args),
+ {'username': 'error',
+ 'password': 'test12'})
+
+ response.mustcontain('invalid user name')
+ response.mustcontain('invalid password')
+ for encoded in args_encoded:
+ self.assertIn(encoded, response.form.action)
+
#==========================================================================
# REGISTRATIONS
#==========================================================================