From eb18df89e43018ceeef1f907e26f8d727e60c2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 26 Jun 2018 16:29:04 +0200 Subject: [PATCH] misc: expose session identifier in substitution variables (#24778) --- tests/test_form_pages.py | 2 -- tests/test_sessions.py | 22 ++++++++++++++++++++++ wcs/forms/root.py | 4 ++++ wcs/qommon/sessions.py | 10 ++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py index eeb93707..a16346d8 100644 --- a/tests/test_form_pages.py +++ b/tests/test_form_pages.py @@ -4239,14 +4239,12 @@ def test_session_cookie_flags(pub): formdef = create_formdef() app = get_app(pub) resp = app.get('/test/', status=200) - resp = resp.form.submit('submit') assert resp.headers['Set-Cookie'].startswith('wcs-') assert 'httponly' in resp.headers['Set-Cookie'] assert not 'secure' in resp.headers['Set-Cookie'] app = get_app(pub, https=True) resp = app.get('/test/', status=200) - resp = resp.form.submit('submit') assert resp.headers['Set-Cookie'].startswith('wcs-') assert 'httponly' in resp.headers['Set-Cookie'] assert 'secure' in resp.headers['Set-Cookie'] diff --git a/tests/test_sessions.py b/tests/test_sessions.py index cd8dccf1..a5983bb2 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -7,6 +7,8 @@ from quixote import cleanup from wcs.qommon.ident.password_accounts import PasswordAccount from wcs.qommon.http_request import HTTPRequest +from wcs.formdef import FormDef +from wcs import fields from utilities import create_temporary_pub, clean_temporary_pub, get_app, login @@ -159,3 +161,23 @@ def test_session_do_not_reuse_id(pub, user, app): resp = login_form.submit() assert resp.status_int == 302 assert pub.session_manager.session_class.count() == 2 + +def test_session_substitution_variables(pub, user, app): + pub.session_manager.session_class.wipe() + resp = app.get('/') + + formdef = FormDef() + formdef.name = 'foobar' + formdef.fields = [fields.CommentField(id='7', label='Hello [session_var_id]', type='comment')] + formdef.store() + + resp = app.get('/foobar/') + assert pub.session_manager.session_class.count() == 1 + session_id = pub.session_manager.session_class.select()[0].id + assert 'Hello %s' % session_id in resp.body + + login(app, username='foo', password='foo') + assert pub.session_manager.session_class.count() == 2 + session_id = [x for x in pub.session_manager.session_class.select() if x.id != session_id][0].id + resp = app.get('/foobar/') + assert 'Hello %s' % session_id in resp.body diff --git a/wcs/forms/root.py b/wcs/forms/root.py index 1d5ef693..7ff5dd59 100644 --- a/wcs/forms/root.py +++ b/wcs/forms/root.py @@ -286,6 +286,10 @@ class FormPage(Directory, FormTemplateMixin): displayed_fields = [] session = get_session() + if not session.id: + # force session to be written down, this is required so + # [session_var_id] is available on the first page. + session.force() if page_no > self.formdef.get_start_page(): magictoken = get_request().form['magictoken'] diff --git a/wcs/qommon/sessions.py b/wcs/qommon/sessions.py index b37d838f..987268ee 100644 --- a/wcs/qommon/sessions.py +++ b/wcs/qommon/sessions.py @@ -89,11 +89,19 @@ class Session(QommonSession, CaptchaSession, StorableObject): jsonp_display_values = None extra_variables = None expire = None + forced = False # should only be overwritten by authentication methods extra_user_variables = None username = None # only set on password authentication + def force(self): + # add some data in the session, it will force a cookie to be set, this + # is used so we get a session identifier fixed even on the first page + # of a form. + self.forced = True + get_session_manager().maintain_session(self) + def set_expire(self, expire): self.expire = expire @@ -126,6 +134,7 @@ class Session(QommonSession, CaptchaSession, StorableObject): CaptchaSession.has_info(self) or \ self.expire or \ self.extra_user_variables or \ + self.forced or \ QuixoteSession.has_info(self) is_dirty = has_info @@ -315,6 +324,7 @@ class Session(QommonSession, CaptchaSession, StorableObject): def get_substitution_variables(self, prefix='session_var_'): d = {} + d[prefix + 'id'] = self.id if self.extra_variables: for k, v in self.extra_variables.items(): d[prefix + k] = v -- 2.17.1