mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
[SECURITY] Enforce session validation on oauth authorize endpoint
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from pretix.base.models import Organizer
|
||||
@@ -48,6 +50,19 @@ def test_session_auth_with_teams(client, user, team):
|
||||
assert len(resp.data['results']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_session_auth_relative_timeout(client, user, team):
|
||||
client.login(email=user.email, password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = int(time.time()) - 3600 * 6
|
||||
session['pretix_auth_last_used'] = int(time.time()) - 3600 * 3 - 60
|
||||
session.save()
|
||||
|
||||
resp = client.get('/api/v1/organizers/')
|
||||
assert resp.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_token_invalid(client):
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ABCDE')
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
from urllib.parse import quote
|
||||
|
||||
import pytest
|
||||
@@ -87,9 +88,81 @@ def test_authorize_require_login(client, application: OAuthApplication):
|
||||
assert resp['Location'].startswith('/control/login')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_require_login_after_absolute_timeout(client, admin_user, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = int(time.time()) - 3600 * 12 - 60
|
||||
session.save()
|
||||
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote('https://example.org')
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
assert resp['Location'].startswith('/control/login')
|
||||
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_require_recent_auth(client, admin_user, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = True
|
||||
session['pretix_auth_login_time'] = int(time.time()) - 3600 - 60
|
||||
session['pretix_auth_last_used'] = int(time.time())
|
||||
session.save()
|
||||
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote('https://example.org')
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
assert resp['Location'].startswith('/control/reauth')
|
||||
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_require_login_after_relative_timeout(client, admin_user, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_long_session'] = False
|
||||
session['pretix_auth_login_time'] = int(time.time()) - 3600 * 3 - 60
|
||||
session.save()
|
||||
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote('https://example.org')
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
assert resp['Location'].startswith('/control/reauth')
|
||||
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
assert resp.status_code == 302
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_invalid_redirect_uri(client, admin_user, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote('https://example.org')
|
||||
))
|
||||
@@ -99,6 +172,9 @@ def test_authorize_invalid_redirect_uri(client, admin_user, application: OAuthAp
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_missing_response_type(client, admin_user, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -109,6 +185,9 @@ def test_authorize_missing_response_type(client, admin_user, application: OAuthA
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_require_organizer(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -128,6 +207,9 @@ def test_authorize_require_organizer(client, admin_user, organizer, application:
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_denied(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -146,6 +228,9 @@ def test_authorize_denied(client, admin_user, organizer, application: OAuthAppli
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_disallow_response_token(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=token' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -156,6 +241,9 @@ def test_authorize_disallow_response_token(client, admin_user, organizer, applic
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_read_scope(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -180,6 +268,9 @@ def test_authorize_read_scope(client, admin_user, organizer, application: OAuthA
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_state(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&state=asdadf' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -200,6 +291,9 @@ def test_authorize_state(client, admin_user, organizer, application: OAuthApplic
|
||||
@pytest.mark.django_db
|
||||
def test_authorize_default_scope(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -225,6 +319,9 @@ def test_authorize_default_scope(client, admin_user, organizer, application: OAu
|
||||
@pytest.mark.django_db
|
||||
def test_token_from_code_without_auth(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -252,6 +349,9 @@ def test_token_from_code_without_auth(client, admin_user, organizer, application
|
||||
@pytest.mark.django_db
|
||||
def test_token_from_code(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -291,6 +391,9 @@ def test_use_token_for_access_one_organizer(client, admin_user, organizer, appli
|
||||
t2.members.add(admin_user)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -335,6 +438,9 @@ def test_use_token_for_access_two_organizers(client, admin_user, organizer, appl
|
||||
t2.members.add(admin_user)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -376,6 +482,9 @@ def test_use_token_for_access_two_organizers(client, admin_user, organizer, appl
|
||||
@pytest.mark.django_db
|
||||
def test_token_refresh(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -418,6 +527,9 @@ def test_token_refresh(client, admin_user, organizer, application: OAuthApplicat
|
||||
@pytest.mark.django_db
|
||||
def test_allow_write(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -450,6 +562,9 @@ def test_allow_write(client, admin_user, organizer, application: OAuthApplicatio
|
||||
@pytest.mark.django_db
|
||||
def test_allow_read_only(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -482,6 +597,9 @@ def test_allow_read_only(client, admin_user, organizer, application: OAuthApplic
|
||||
@pytest.mark.django_db
|
||||
def test_token_revoke_refresh_token(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -526,6 +644,9 @@ def test_token_revoke_refresh_token(client, admin_user, organizer, application:
|
||||
@pytest.mark.django_db
|
||||
def test_token_revoke_access_token(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -574,6 +695,9 @@ def test_token_revoke_access_token(client, admin_user, organizer, application: O
|
||||
@pytest.mark.django_db
|
||||
def test_user_revoke(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -603,6 +727,9 @@ def test_user_revoke(client, admin_user, organizer, application: OAuthApplicatio
|
||||
|
||||
at = OAuthAccessToken.objects.get(token=access_token)
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.post('/control/settings/oauth/authorized/{}/revoke'.format(at.pk), data={
|
||||
})
|
||||
assert resp.status_code == 302
|
||||
@@ -621,6 +748,9 @@ def test_user_revoke(client, admin_user, organizer, application: OAuthApplicatio
|
||||
@pytest.mark.django_db
|
||||
def test_allow_profile_only(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=profile' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
@@ -655,6 +785,9 @@ def test_allow_profile_only(client, admin_user, organizer, application: OAuthApp
|
||||
@pytest.mark.django_db
|
||||
def test_reject_other_response_types(client, admin_user, organizer, application: OAuthApplication):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
resp = client.get('/api/v1/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code+id_token' % (
|
||||
application.client_id, quote(application.redirect_uris)
|
||||
))
|
||||
|
||||
@@ -757,7 +757,7 @@ class SessionTimeOutTest(TestCase):
|
||||
# Regression test added after a security problem in 1.9.1
|
||||
# The problem was that, once the relative timeout happened, the user was redirected
|
||||
# to /control/reauth/, but loading /control/reauth/ was already considered to be
|
||||
# "session activitiy". Therefore, after loding /control/reauth/, the session was no longer
|
||||
# "session activity". Therefore, after loding /control/reauth/, the session was no longer
|
||||
# in the timeout state and the user was able to access pages again without re-entering the
|
||||
# password.
|
||||
session = self.client.session
|
||||
|
||||
Reference in New Issue
Block a user