From 000a0a66c3629ca0dff88b05d5b7063bfbfed938 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 5 Nov 2015 22:12:01 +0100 Subject: [PATCH 1/4] allow setting session durations (#8887) --- tests/test_sessions.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ wcs/qommon/sessions.py | 21 +++++++++++++++-- 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 tests/test_sessions.py diff --git a/tests/test_sessions.py b/tests/test_sessions.py new file mode 100644 index 0000000..fe339d1 --- /dev/null +++ b/tests/test_sessions.py @@ -0,0 +1,62 @@ +import os +import shutil +import time +import pytest + +from quixote import cleanup + +from wcs.qommon.ident.password_accounts import PasswordAccount + +from utilities import create_temporary_pub, clean_temporary_pub, get_app, login + +def setup_module(): + clean_temporary_pub() + + +def teardown_module(): + pass + + +@pytest.fixture(scope='function') +def pub(request): + pub = create_temporary_pub() + def fin(): + shutil.rmtree(pub.APP_DIR) + request.addfinalizer(fin) + pub.cfg['identification'] = {'methods': ['password']} + pub.cfg['misc'] = {'charset': 'utf-8'} + pub.cfg['language'] = {'language': 'en'} + pub.write_cfg() + return pub + + +@pytest.fixture +def user(pub): + user = pub.user_class() + user.email = 'foo@localhost' + user.store() + account = PasswordAccount(id='foo') + account.set_password('foo') + account.user_id = user.id + account.store() + return user + + +@pytest.fixture +def app(pub): + return get_app(pub) + + +def test_session_max_age(pub, user, app): + with file(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as cfg: + cfg.write('''[options] +session_max_age: 1 +''') + pub.load_site_options() + + login(app, username='foo', password='foo') + assert 'Logout' in app.get('/') + time.sleep(0.5) + assert 'Logout' in app.get('/') + time.sleep(0.6) + assert 'Logout' not in app.get('/') diff --git a/wcs/qommon/sessions.py b/wcs/qommon/sessions.py index a931b0d..6f80c76 100644 --- a/wcs/qommon/sessions.py +++ b/wcs/qommon/sessions.py @@ -84,6 +84,16 @@ class Session(QommonSession, CaptchaSession, StorableObject): username = None # only set on password authentication + def is_expired(self): + duration = get_publisher().get_site_option('session_max_age') + if duration is None: + return False + try: + duration = int(duration) + except ValueError: + return False + return (time.time() - self.get_access_time()) > duration + def has_info(self): return self.name_identifier or self.after_url or \ self.lasso_session_dump or self.message or \ @@ -248,13 +258,20 @@ class StorageSessionManager(QommonSessionManager): def __getitem__(self, session_id): try: - return BasicSession.get(session_id) + session = BasicSession.get(session_id) + if session.is_expired(): + try: + session.remove_self() + except OSError: + pass + raise KeyError + return session except KeyError: raise KeyError def get(self, session_id, default = None): try: - return BasicSession.get(session_id) + return self[session_id] except KeyError: return default except ValueError: # happens for "insecure string pickle" -- 2.1.4