From 2d9390fd73fee560a72d600f846befcb9e140ad0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 24 May 2018 18:33:29 -0400 Subject: [PATCH 1/9] Set the samesite flag to Lax by default on session cookies Also make it possible to set it to other values --- pyramid/session.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pyramid/session.py b/pyramid/session.py index 4a9c8c1005..70af990858 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -135,6 +135,7 @@ def BaseCookieSessionFactory( domain=None, secure=False, httponly=False, + samesite='Lax', timeout=1200, reissue_time=0, set_on_exception=True, @@ -187,6 +188,9 @@ def BaseCookieSessionFactory( Hide the cookie from Javascript by setting the 'HttpOnly' flag of the session cookie. Default: ``False``. + ``samesite`` + The 'samesite' option of the session cookie. Default ``'Lax'``. + ``timeout`` A number of seconds of inactivity before a session times out. If ``None`` then the cookie never expires. This lifetime only applies @@ -229,6 +233,7 @@ class CookieSession(dict): _cookie_domain = domain _cookie_secure = secure _cookie_httponly = httponly + _cookie_samesite = samesite _cookie_on_exception = set_on_exception _timeout = timeout if timeout is None else int(timeout) _reissue_time = reissue_time if reissue_time is None else int(reissue_time) @@ -367,6 +372,7 @@ def _set_cookie(self, response): domain=self._cookie_domain, secure=self._cookie_secure, httponly=self._cookie_httponly, + samesite=self._cookie_samesite, ) return True @@ -382,6 +388,7 @@ def UnencryptedCookieSessionFactoryConfig( cookie_domain=None, cookie_secure=False, cookie_httponly=False, + cookie_samesite='Lax', cookie_on_exception=True, signed_serialize=signed_serialize, signed_deserialize=signed_deserialize, @@ -434,6 +441,9 @@ def UnencryptedCookieSessionFactoryConfig( ``cookie_httponly`` The 'httpOnly' flag of the session cookie. + ``cookie_samesite`` + The 'samesite' option of the session cookie. Default: ``'Lax'``. + ``cookie_on_exception`` If ``True``, set a session cookie even if an exception occurs while rendering a view. @@ -469,6 +479,7 @@ def dumps(self, appstruct): domain=cookie_domain, secure=cookie_secure, httponly=cookie_httponly, + samesite=cookie_samesite, timeout=timeout, reissue_time=0, # to keep session.accessed == session.renewed set_on_exception=cookie_on_exception, @@ -491,6 +502,7 @@ def SignedCookieSessionFactory( domain=None, secure=False, httponly=False, + samesite='Lax', set_on_exception=True, timeout=1200, reissue_time=0, @@ -553,6 +565,9 @@ def SignedCookieSessionFactory( Hide the cookie from Javascript by setting the 'HttpOnly' flag of the session cookie. Default: ``False``. + ``samesite`` + The 'samesite' option of the session cookie. Default: ``'Lax'``. + ``timeout`` A number of seconds of inactivity before a session times out. If ``None`` then the cookie never expires. This lifetime only applies @@ -608,6 +623,7 @@ def SignedCookieSessionFactory( domain=domain, secure=secure, httponly=httponly, + samesite=samesite, timeout=timeout, reissue_time=reissue_time, set_on_exception=set_on_exception, From 3d3deebb926a2b7e3f1c1f25fb207858e9677d29 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 24 May 2018 18:40:23 -0400 Subject: [PATCH 2/9] fix tests --- pyramid/tests/test_session.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index ade6027991..e3d819944e 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -145,13 +145,14 @@ def test__set_cookie_options(self): response = Response() self.assertEqual(session._set_cookie(response), True) cookieval = response.headerlist[-1][1] - val, domain, path, secure, httponly = [x.strip() for x in - cookieval.split(';')] + val, domain, path, secure, httponly, samesite = [x.strip() for x in + cookieval.split(';')] self.assertTrue(val.startswith('abc=')) self.assertEqual(domain, 'Domain=localhost') self.assertEqual(path, 'Path=/foo') self.assertEqual(secure, 'secure') self.assertEqual(httponly, 'HttpOnly') + self.assertEqual(samesite, 'SameSite=Lax') def test_flash_default(self): request = testing.DummyRequest() @@ -503,7 +504,7 @@ def test_serialize_option(self): expected_cookieval = dummy_signed_serialize( (session.accessed, session.created, {'key': 'value'}), secret) response = Response() - response.set_cookie('session', expected_cookieval) + response.set_cookie('session', expected_cookieval, samesite='Lax') expected_cookie = response.headerlist[-1][1] self.assertEqual(cookie, expected_cookie) From bd1cfa871d2abf006a1ab8ae606f7eaf0663a170 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 24 May 2018 18:44:02 -0400 Subject: [PATCH 3/9] python 3 fix --- pyramid/session.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyramid/session.py b/pyramid/session.py index 70af990858..25ed298789 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -135,7 +135,7 @@ def BaseCookieSessionFactory( domain=None, secure=False, httponly=False, - samesite='Lax', + samesite=b'Lax', timeout=1200, reissue_time=0, set_on_exception=True, @@ -189,7 +189,7 @@ def BaseCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default ``'Lax'``. + The 'samesite' option of the session cookie. Default ``b'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If @@ -388,7 +388,7 @@ def UnencryptedCookieSessionFactoryConfig( cookie_domain=None, cookie_secure=False, cookie_httponly=False, - cookie_samesite='Lax', + cookie_samesite=b'Lax', cookie_on_exception=True, signed_serialize=signed_serialize, signed_deserialize=signed_deserialize, @@ -442,7 +442,7 @@ def UnencryptedCookieSessionFactoryConfig( The 'httpOnly' flag of the session cookie. ``cookie_samesite`` - The 'samesite' option of the session cookie. Default: ``'Lax'``. + The 'samesite' option of the session cookie. Default: ``b'Lax'``. ``cookie_on_exception`` If ``True``, set a session cookie even if an exception occurs @@ -502,7 +502,7 @@ def SignedCookieSessionFactory( domain=None, secure=False, httponly=False, - samesite='Lax', + samesite=b'Lax', set_on_exception=True, timeout=1200, reissue_time=0, @@ -566,7 +566,7 @@ def SignedCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default: ``'Lax'``. + The 'samesite' option of the session cookie. Default: ``b'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If From bc8728ae183f04fd0ce7e261fb7731a61163ebbe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 24 May 2018 18:45:51 -0400 Subject: [PATCH 4/9] oops, py3 here too --- pyramid/tests/test_session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index e3d819944e..3dd82b5f33 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -504,7 +504,7 @@ def test_serialize_option(self): expected_cookieval = dummy_signed_serialize( (session.accessed, session.created, {'key': 'value'}), secret) response = Response() - response.set_cookie('session', expected_cookieval, samesite='Lax') + response.set_cookie('session', expected_cookieval, samesite=b'Lax') expected_cookie = response.headerlist[-1][1] self.assertEqual(cookie, expected_cookie) From 2c5e19954f252cbdb30842140d45df33b1dbe62b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 24 May 2018 19:26:14 -0400 Subject: [PATCH 5/9] Sign CONTRIBUTORS.txt --- CONTRIBUTORS.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 60e4e5732a..69ed023b0c 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -319,4 +319,6 @@ Contributors - Hunter Senft-Grupp, 2018/05/14 -- Junhak Lee, 2018/05/14 \ No newline at end of file +- Junhak Lee, 2018/05/14 + +- Alex Gaynor, 2018/05/24 From 967a06c2f5fe3d510dc825ec7b5ecd3934f93bad Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 5 Jun 2018 18:51:10 -0600 Subject: [PATCH 6/9] Bump version of WebOb required --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1873612c58..17a18f3b5a 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ def readfile(name): 'setuptools', 'translationstring >= 0.4', # py3 compat 'venusian >= 1.0', # ``ignore`` - 'webob >= 1.8.0', # acceptparse.create_accept_header + 'webob >= 1.8.2', # cookies.make_cookie allows non-bytes samesite 'zope.deprecation >= 3.5.0', # py3 compat 'zope.interface >= 3.8.0', # has zope.interface.registry ] From 6c8ad427ee2f99c30e52667d5a90226de18d2b2d Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 5 Jun 2018 19:00:21 -0600 Subject: [PATCH 7/9] samesite no longer requires bytes --- pyramid/session.py | 12 ++++++------ pyramid/tests/test_session.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyramid/session.py b/pyramid/session.py index 25ed298789..70af990858 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -135,7 +135,7 @@ def BaseCookieSessionFactory( domain=None, secure=False, httponly=False, - samesite=b'Lax', + samesite='Lax', timeout=1200, reissue_time=0, set_on_exception=True, @@ -189,7 +189,7 @@ def BaseCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default ``b'Lax'``. + The 'samesite' option of the session cookie. Default ``'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If @@ -388,7 +388,7 @@ def UnencryptedCookieSessionFactoryConfig( cookie_domain=None, cookie_secure=False, cookie_httponly=False, - cookie_samesite=b'Lax', + cookie_samesite='Lax', cookie_on_exception=True, signed_serialize=signed_serialize, signed_deserialize=signed_deserialize, @@ -442,7 +442,7 @@ def UnencryptedCookieSessionFactoryConfig( The 'httpOnly' flag of the session cookie. ``cookie_samesite`` - The 'samesite' option of the session cookie. Default: ``b'Lax'``. + The 'samesite' option of the session cookie. Default: ``'Lax'``. ``cookie_on_exception`` If ``True``, set a session cookie even if an exception occurs @@ -502,7 +502,7 @@ def SignedCookieSessionFactory( domain=None, secure=False, httponly=False, - samesite=b'Lax', + samesite='Lax', set_on_exception=True, timeout=1200, reissue_time=0, @@ -566,7 +566,7 @@ def SignedCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default: ``b'Lax'``. + The 'samesite' option of the session cookie. Default: ``'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index 3dd82b5f33..e3d819944e 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -504,7 +504,7 @@ def test_serialize_option(self): expected_cookieval = dummy_signed_serialize( (session.accessed, session.created, {'key': 'value'}), secret) response = Response() - response.set_cookie('session', expected_cookieval, samesite=b'Lax') + response.set_cookie('session', expected_cookieval, samesite='Lax') expected_cookie = response.headerlist[-1][1] self.assertEqual(cookie, expected_cookie) From beafcc9edd5568a7e4c1bd28f1d6cab376aff64c Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 11 Jun 2018 00:47:51 -0500 Subject: [PATCH 8/9] add versionchanged markers --- pyramid/session.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pyramid/session.py b/pyramid/session.py index 70af990858..d05ac66eb2 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -189,7 +189,8 @@ def BaseCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default ``'Lax'``. + The 'samesite' option of the session cookie. Set the value to ``None`` + to turn off the samesite option. Default: ``'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If @@ -220,6 +221,10 @@ def BaseCookieSessionFactory( while rendering a view. Default: ``True``. .. versionadded: 1.5a3 + + .. versionchanged: 1.10 + + Added the ``samesite`` option and made the default ``'Lax'``. """ @implementer(ISession) @@ -442,7 +447,8 @@ def UnencryptedCookieSessionFactoryConfig( The 'httpOnly' flag of the session cookie. ``cookie_samesite`` - The 'samesite' option of the session cookie. Default: ``'Lax'``. + The 'samesite' option of the session cookie. Set the value to ``None`` + to turn off the samesite option. Default: ``'Lax'``. ``cookie_on_exception`` If ``True``, set a session cookie even if an exception occurs @@ -457,6 +463,10 @@ def UnencryptedCookieSessionFactoryConfig( A callable which takes a signed and serialized data structure in bytes and a secret and returns the original data structure if the signature is valid. Default: ``signed_deserialize`` (using pickle). + + .. versionchanged: 1.10 + + Added the ``samesite`` option and made the default ``'Lax'``. """ class SerializerWrapper(object): @@ -566,7 +576,8 @@ def SignedCookieSessionFactory( session cookie. Default: ``False``. ``samesite`` - The 'samesite' option of the session cookie. Default: ``'Lax'``. + The 'samesite' option of the session cookie. Set the value to ``None`` + to turn off the samesite option. Default: ``'Lax'``. ``timeout`` A number of seconds of inactivity before a session times out. If @@ -604,6 +615,10 @@ def SignedCookieSessionFactory( the :class:`pyramid.session.PickleSerializer` serializer will be used. .. versionadded: 1.5a3 + + .. versionchanged: 1.10 + + Added the ``samesite`` option and made the default ``Lax``. """ if serializer is None: serializer = PickleSerializer() From 57ee91a9f0e3769a725280c3db351fb466bd7431 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 11 Jun 2018 00:56:53 -0500 Subject: [PATCH 9/9] add changelog for #3300 --- CHANGES.rst | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 334a9b62fc..7c442aa1a5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -21,8 +21,8 @@ Features instead of ``pyramid.util.Request``. See https://github.com/Pylons/pyramid/pull/3129 -- In ``cherrypy_server_runner``, prefer imports from the ``cheroot`` package over the legacy - imports from `cherrypy.wsgiserver`. +- In ``cherrypy_server_runner``, prefer imports from the ``cheroot`` package + over the legacy imports from `cherrypy.wsgiserver`. See https://github.com/Pylons/pyramid/pull/3235 - Add a context manager ``route_prefix_context`` to the @@ -30,6 +30,13 @@ Features route_prefix for ``include`` and ``add_route`` calls inside the context. See https://github.com/Pylons/pyramid/pull/3279 +- Modify the builtin session implementations to support SameSite options on + cookies and set the default to ``'Lax'``. This affects + ``pyramid.session.BaseCookieSessionFactory``, + ``pyramid.session.SignedCookieSessionFactory``, and + ``pyramid.session.UnencryptedCookieSessionFactoryConfig``. + See https://github.com/Pylons/pyramid/pull/3300 + Bug Fixes --------- @@ -54,6 +61,12 @@ Backward Incompatibilities depending on it directly within your project. See https://github.com/Pylons/pyramid/pull/3140 +- Modify the builtin session implementations to set ``SameSite='Lax'`` on + cookies. This affects ``pyramid.session.BaseCookieSessionFactory``, + ``pyramid.session.SignedCookieSessionFactory``, and + ``pyramid.session.UnencryptedCookieSessionFactoryConfig``. + See https://github.com/Pylons/pyramid/pull/3300 + Documentation Changes ---------------------