mirror of
https://github.com/pretix/pretix.git
synced 2026-09-15 16:34:42 +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
|
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):
|
class NativeAuthBackend(BaseAuthBackend):
|
||||||
identifier = 'native'
|
identifier = 'native'
|
||||||
|
|||||||
@@ -39,18 +39,19 @@ def process_login(request, user, keep_logged_in):
|
|||||||
:return: This method returns a ``HttpResponse``.
|
:return: This method returns a ``HttpResponse``.
|
||||||
"""
|
"""
|
||||||
request.session['pretix_auth_long_session'] = settings.PRETIX_LONG_SESSIONS and keep_logged_in
|
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:
|
if user.require_2fa:
|
||||||
request.session['pretix_auth_2fa_user'] = user.pk
|
request.session['pretix_auth_2fa_user'] = user.pk
|
||||||
request.session['pretix_auth_2fa_time'] = str(int(time.time()))
|
request.session['pretix_auth_2fa_time'] = str(int(time.time()))
|
||||||
twofa_url = reverse('control:auth.login.2fa')
|
twofa_url = reverse('control:auth.login.2fa')
|
||||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||||
twofa_url += '?next=' + quote(request.GET.get('next'))
|
twofa_url += '?next=' + quote(next_url)
|
||||||
return redirect(twofa_url)
|
return redirect(twofa_url)
|
||||||
else:
|
else:
|
||||||
auth_login(request, user)
|
auth_login(request, user)
|
||||||
request.session['pretix_auth_login_time'] = int(time.time())
|
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):
|
if next_url and is_safe_url(next_url, allowed_hosts=None):
|
||||||
return redirect(request.GET.get("next"))
|
return redirect(next_url)
|
||||||
return redirect(reverse('control:index'))
|
return redirect(reverse('control:index'))
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +73,8 @@ def login(request):
|
|||||||
if not backend.visible:
|
if not backend.visible:
|
||||||
backend = [b for b in backends if b.visible][0]
|
backend = [b for b in backends if b.visible][0]
|
||||||
if request.user.is_authenticated:
|
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':
|
if request.method == 'POST':
|
||||||
form = LoginForm(backend=backend, data=request.POST)
|
form = LoginForm(backend=backend, data=request.POST)
|
||||||
if form.is_valid() and form.user_cache and form.user_cache.auth_backend == backend.identifier:
|
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())
|
t = int(time.time())
|
||||||
request.session['pretix_auth_login_time'] = t
|
request.session['pretix_auth_login_time'] = t
|
||||||
request.session['pretix_auth_last_used'] = t
|
request.session['pretix_auth_last_used'] = t
|
||||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
next_url = get_auth_backends()[request.user.auth_backend].get_next_url(request)
|
||||||
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'))
|
return redirect(reverse('control:index'))
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('The password you entered was invalid, please try again.'))
|
messages.error(request, _('The password you entered was invalid, please try again.'))
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get(self, 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 u and u == request.user:
|
||||||
if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
|
next_url = backend.get_next_url(request)
|
||||||
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'))
|
return redirect(reverse('control:index'))
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,11 @@ class LoginFormTest(TestCase):
|
|||||||
response = self.client.get('/control/')
|
response = self.client.get('/control/')
|
||||||
assert b'hallo@example.org' in response.content
|
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):
|
class RegistrationFormTest(TestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -36,3 +36,8 @@ class TestRequestAuthBackend(BaseAuthBackend):
|
|||||||
email=request.headers['X-Login-Email'],
|
email=request.headers['X-Login-Email'],
|
||||||
auth_backend='test_request'
|
auth_backend='test_request'
|
||||||
)[0]
|
)[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