mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
Add auditable superuser mode (#824)
* Remove is_superuser everywhere * Session handling * List of sessions, relative timeout * Absolute timeout * Optionally pseudo-force audit comments * Fix failing tests * Add tests * Add docs * Rebsae migration * Typos * Fix tests
This commit is contained in:
@@ -8,6 +8,7 @@ from django.contrib.auth.tokens import (
|
||||
)
|
||||
from django.core import mail as djmail
|
||||
from django.test import TestCase, override_settings
|
||||
from django.utils.timezone import now
|
||||
from django_otp.oath import TOTP
|
||||
from django_otp.plugins.otp_totp.models import TOTPDevice
|
||||
from u2flib_server.jsapi import JSONDict
|
||||
@@ -607,3 +608,105 @@ class SessionTimeOutTest(TestCase):
|
||||
self.client.defaults['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; Linux x86_64) Something else'
|
||||
response = self.client.get('/control/')
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user():
|
||||
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||
return user
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_impersonate(user, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
ss = user.staffsession_set.create(date_start=now(), session_key=client.session.session_key)
|
||||
t1 = int(time.time()) - 5
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = t1
|
||||
session['pretix_auth_last_used'] = t1
|
||||
session.save()
|
||||
user2 = User.objects.create_user('dummy2@dummy.dummy', 'dummy')
|
||||
response = client.post('/control/users/{user}/impersonate'.format(user=user2.pk), follow=True)
|
||||
assert b'dummy2@' in response.content
|
||||
response = client.get('/control/global/settings/')
|
||||
assert response.status_code == 403
|
||||
response = client.get('/control/')
|
||||
response = client.post('/control/users/impersonate/stop', follow=True)
|
||||
assert b'dummy@' in response.content
|
||||
assert b'dummy2@' not in response.content
|
||||
response = client.get('/control/global/settings/')
|
||||
assert response.status_code == 200 # staff session is preserved
|
||||
assert ss.logs.filter(url='/control/', impersonating=user2).exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_impersonate_require_recent_auth(user, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
user.staffsession_set.create(date_start=now(), session_key=client.session.session_key)
|
||||
t1 = int(time.time()) - 5 * 3600
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = t1
|
||||
session['pretix_auth_last_used'] = t1
|
||||
session.save()
|
||||
user2 = User.objects.create_user('dummy2@dummy.dummy', 'dummy')
|
||||
response = client.post('/control/users/{user}/impersonate'.format(user=user2.pk), follow=True)
|
||||
assert b'dummy2@' not in response.content
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_staff_session(user, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
t1 = int(time.time()) - 5
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = t1
|
||||
session['pretix_auth_last_used'] = t1
|
||||
session.save()
|
||||
response = client.get('/control/global/settings/')
|
||||
assert response.status_code == 302
|
||||
response = client.post('/control/sudo/')
|
||||
assert response['Location'] == '/control/'
|
||||
response = client.get('/control/global/settings/')
|
||||
assert response.status_code == 200
|
||||
client.post('/control/sudo/stop', follow=True)
|
||||
response = client.get('/control/global/settings/')
|
||||
assert response.status_code == 302
|
||||
assert user.staffsession_set.last().logs.filter(url='/control/global/settings/').exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_staff_session_require_recent_auth(user, client):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
t1 = int(time.time()) - 5 * 3600
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = t1
|
||||
session['pretix_auth_last_used'] = t1
|
||||
session.save()
|
||||
response = client.post('/control/sudo/')
|
||||
assert response['Location'].startswith('/control/reauth/')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_staff_session_require_staff(user, client):
|
||||
user.is_staff = False
|
||||
user.save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
t1 = int(time.time()) - 5
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = t1
|
||||
session['pretix_auth_last_used'] = t1
|
||||
session.save()
|
||||
response = client.post('/control/sudo/')
|
||||
assert response.status_code == 403
|
||||
|
||||
@@ -26,13 +26,20 @@ def env():
|
||||
|
||||
superuser_urls = [
|
||||
"global/settings/",
|
||||
"global/update/",
|
||||
"users/select2",
|
||||
"users/",
|
||||
"users/add",
|
||||
"users/1/",
|
||||
"users/1/impersonate",
|
||||
"users/1/reset",
|
||||
"sudo/sessions/",
|
||||
]
|
||||
|
||||
|
||||
staff_urls = [
|
||||
"global/update/",
|
||||
"sudo/",
|
||||
"sudo/2/",
|
||||
]
|
||||
|
||||
event_urls = [
|
||||
@@ -146,10 +153,26 @@ def test_logged_out(client, env, url):
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("url", superuser_urls)
|
||||
def test_superuser_required(perf_patch, client, env, url):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
env[1].is_staff = True
|
||||
env[1].save()
|
||||
response = client.get('/control/' + url)
|
||||
if response.status_code == 302:
|
||||
assert '/sudo/' in response['Location']
|
||||
else:
|
||||
assert response.status_code == 403
|
||||
env[1].staffsession_set.create(date_start=now(), session_key=client.session.session_key)
|
||||
response = client.get('/control/' + url)
|
||||
assert response.status_code in (200, 302, 404)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("url", staff_urls)
|
||||
def test_staff_required(perf_patch, client, env, url):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/' + url)
|
||||
assert response.status_code == 403
|
||||
env[1].is_superuser = True
|
||||
env[1].is_staff = True
|
||||
env[1].save()
|
||||
response = client.get('/control/' + url)
|
||||
assert response.status_code in (200, 302, 404)
|
||||
|
||||
@@ -99,8 +99,9 @@ class OrderSearchTest(SoupTest):
|
||||
assert 'FO1' not in resp
|
||||
assert 'FO2' not in resp
|
||||
|
||||
def test_suberuser(self):
|
||||
self.user.is_superuser = True
|
||||
def test_superuser(self):
|
||||
self.user.is_staff = True
|
||||
self.user.staffsession_set.create(date_start=now(), session_key=self.client.session.session_key)
|
||||
self.user.save()
|
||||
self.team.members.clear()
|
||||
resp = self.client.get('/control/search/orders/').rendered_content
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_update_notice_displayed(client, user):
|
||||
r = client.get('/control/')
|
||||
assert 'pretix automatically checks for updates in the background' not in r.content.decode()
|
||||
|
||||
user.is_superuser = True
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
r = client.get('/control/')
|
||||
assert 'pretix automatically checks for updates in the background' in r.content.decode()
|
||||
@@ -46,7 +46,7 @@ def test_update_notice_displayed(client, user):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_settings(client, user):
|
||||
user.is_superuser = True
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
@@ -71,7 +71,7 @@ def test_trigger(client, user):
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
user.is_superuser = True
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ def logged_in_client(client, event):
|
||||
)
|
||||
t.members.add(user)
|
||||
client.force_login(user)
|
||||
user.staffsession_set.create(date_start=now(), session_key=client.session.session_key)
|
||||
return client
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user