mirror of
https://github.com/pretix/pretix.git
synced 2025-12-07 22:42:26 +00:00
Make next url authentication backend dependent (#1609)
* Make next url authentication backend dependent * Rename authentication next_url to get_next_url. * Add test for custom authentication backend get_next_url. * Fix typo in docstring of authentication backend get_next_url.
This commit is contained in:
@@ -85,6 +85,16 @@ class BaseAuthBackend:
|
||||
"""
|
||||
return
|
||||
|
||||
def get_next_url(self, request):
|
||||
"""
|
||||
This method will be called after a successful login to determine the next URL. Pretix in general uses the
|
||||
``'next'`` query parameter. However, external authentication methods could use custom attributes with hardcoded
|
||||
names for security purposes. For example, OAuth uses ``'state'`` for keeping track of application state.
|
||||
"""
|
||||
if "next" in request.GET:
|
||||
return request.GET.get("next")
|
||||
return None
|
||||
|
||||
|
||||
class NativeAuthBackend(BaseAuthBackend):
|
||||
identifier = 'native'
|
||||
|
||||
@@ -39,18 +39,19 @@ def process_login(request, user, keep_logged_in):
|
||||
:return: This method returns a ``HttpResponse``.
|
||||
"""
|
||||
request.session['pretix_auth_long_session'] = settings.PRETIX_LONG_SESSIONS and keep_logged_in
|
||||
next_url = get_auth_backends()[user.auth_backend].get_next_url(request)
|
||||
if user.require_2fa:
|
||||
request.session['pretix_auth_2fa_user'] = user.pk
|
||||
request.session['pretix_auth_2fa_time'] = str(int(time.time()))
|
||||
twofa_url = reverse('control:auth.login.2fa')
|
||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
||||
twofa_url += '?next=' + quote(request.GET.get('next'))
|
||||
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||
twofa_url += '?next=' + quote(next_url)
|
||||
return redirect(twofa_url)
|
||||
else:
|
||||
auth_login(request, user)
|
||||
request.session['pretix_auth_login_time'] = int(time.time())
|
||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
||||
return redirect(request.GET.get("next"))
|
||||
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||
return redirect(next_url)
|
||||
return redirect(reverse('control:index'))
|
||||
|
||||
|
||||
@@ -72,7 +73,8 @@ def login(request):
|
||||
if not backend.visible:
|
||||
backend = [b for b in backends if b.visible][0]
|
||||
if request.user.is_authenticated:
|
||||
return redirect(request.GET.get("next", 'control:index'))
|
||||
next_url = backend.get_next_url(request) or 'control:index'
|
||||
return redirect(next_url)
|
||||
if request.method == 'POST':
|
||||
form = LoginForm(backend=backend, data=request.POST)
|
||||
if form.is_valid() and form.user_cache and form.user_cache.auth_backend == backend.identifier:
|
||||
|
||||
@@ -101,18 +101,21 @@ class ReauthView(TemplateView):
|
||||
t = int(time.time())
|
||||
request.session['pretix_auth_login_time'] = t
|
||||
request.session['pretix_auth_last_used'] = t
|
||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
||||
return redirect(request.GET.get("next"))
|
||||
next_url = get_auth_backends()[request.user.auth_backend].get_next_url(request)
|
||||
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||
return redirect(next_url)
|
||||
return redirect(reverse('control:index'))
|
||||
else:
|
||||
messages.error(request, _('The password you entered was invalid, please try again.'))
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
u = get_auth_backends()[request.user.auth_backend].request_authenticate(request)
|
||||
backend = get_auth_backends()[request.user.auth_backend]
|
||||
u = backend.request_authenticate(request)
|
||||
if u and u == request.user:
|
||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
||||
return redirect(request.GET.get("next"))
|
||||
next_url = backend.get_next_url(request)
|
||||
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||
return redirect(next_url)
|
||||
return redirect(reverse('control:index'))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -148,6 +148,11 @@ class LoginFormTest(TestCase):
|
||||
response = self.client.get('/control/')
|
||||
assert b'hallo@example.org' in response.content
|
||||
|
||||
def test_custom_get_next_url(self):
|
||||
response = self.client.get('/control/login?state=/control/events/', HTTP_X_LOGIN_EMAIL='hallo@example.org')
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertIn('/control/events/', response['Location'])
|
||||
|
||||
|
||||
class RegistrationFormTest(TestCase):
|
||||
|
||||
|
||||
@@ -36,3 +36,8 @@ class TestRequestAuthBackend(BaseAuthBackend):
|
||||
email=request.headers['X-Login-Email'],
|
||||
auth_backend='test_request'
|
||||
)[0]
|
||||
|
||||
def get_next_url(self, request):
|
||||
if 'state' in request.GET:
|
||||
return request.GET.get('state')
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user