[web] add support for HttpOnly cookie flag
And use it for session cookies. Closes #4142521.
--- a/devtools/fake.py Fri Oct 17 18:16:58 2014 +0200
+++ b/devtools/fake.py Tue Jul 15 16:07:59 2014 +0200
@@ -65,8 +65,8 @@
super(FakeRequest, self).__init__(*args, **kwargs)
self._session_data = {}
- def set_cookie(self, name, value, maxage=300, expires=None, secure=False):
- super(FakeRequest, self).set_cookie(name, value, maxage, expires, secure)
+ def set_cookie(self, name, value, maxage=300, expires=None, secure=False, httponly=False):
+ super(FakeRequest, self).set_cookie(name, value, maxage, expires, secure, httponly)
cookie = self.get_response_header('Set-Cookie')
self._headers_in.setHeader('Cookie', cookie)
--- a/web/application.py Fri Oct 17 18:16:58 2014 +0200
+++ b/web/application.py Tue Jul 15 16:07:59 2014 +0200
@@ -224,7 +224,7 @@
sessioncookie = self.session_cookie(req)
secure = req.https and req.base_url().startswith('https://')
req.set_cookie(sessioncookie, session.sessionid,
- maxage=None, secure=secure)
+ maxage=None, secure=secure, httponly=True)
if not session.anonymous_session:
self.session_manager.postlogin(req, session)
return session
--- a/web/http_headers.py Fri Oct 17 18:16:58 2014 +0200
+++ b/web/http_headers.py Tue Jul 15 16:07:59 2014 +0200
@@ -934,9 +934,13 @@
#### Cookies. Blech!
class Cookie(object):
- # __slots__ = ['name', 'value', 'path', 'domain', 'ports', 'expires', 'discard', 'secure', 'comment', 'commenturl', 'version']
+ # __slots__ = ['name', 'value', 'path', 'domain', 'ports', 'expires',
+ # 'discard', 'secure', 'httponly', 'comment', 'commenturl',
+ # 'version']
- def __init__(self, name, value, path=None, domain=None, ports=None, expires=None, discard=False, secure=False, comment=None, commenturl=None, version=0):
+ def __init__(self, name, value, path=None, domain=None, ports=None,
+ expires=None, discard=False, secure=False, httponly=False,
+ comment=None, commenturl=None, version=0):
self.name = name
self.value = value
self.path = path
@@ -945,6 +949,7 @@
self.expires = expires
self.discard = discard
self.secure = secure
+ self.httponly = httponly
self.comment = comment
self.commenturl = commenturl
self.version = version
@@ -955,7 +960,8 @@
if self.domain is not None: s+=", domain=%r" % (self.domain,)
if self.ports is not None: s+=", ports=%r" % (self.ports,)
if self.expires is not None: s+=", expires=%r" % (self.expires,)
- if self.secure is not False: s+=", secure=%r" % (self.secure,)
+ if self.secure: s+=", secure"
+ if self.httponly: s+=", HttpOnly"
if self.comment is not None: s+=", comment=%r" % (self.comment,)
if self.commenturl is not None: s+=", commenturl=%r" % (self.commenturl,)
if self.version != 0: s+=", version=%r" % (self.version,)
@@ -1213,6 +1219,8 @@
out.append("domain=%s" % cookie.domain)
if cookie.secure:
out.append("secure")
+ if cookie.httponly:
+ out.append("HttpOnly")
setCookies.append('; '.join(out))
return setCookies
@@ -1240,6 +1248,8 @@
out.append("Port=%s" % quoteString(",".join([str(x) for x in cookie.ports])))
if cookie.secure:
out.append("Secure")
+ if cookie.httponly:
+ out.append("HttpOnly")
out.append('Version="1"')
setCookies.append('; '.join(out))
return setCookies
--- a/web/request.py Fri Oct 17 18:16:58 2014 +0200
+++ b/web/request.py Tue Jul 15 16:07:59 2014 +0200
@@ -569,7 +569,7 @@
except KeyError:
return SimpleCookie()
- def set_cookie(self, name, value, maxage=300, expires=None, secure=False):
+ def set_cookie(self, name, value, maxage=300, expires=None, secure=False, httponly=False):
"""set / update a cookie
by default, cookie will be available for the next 5 minutes.
@@ -595,7 +595,7 @@
expires = None
# make sure cookie is set on the correct path
cookie = Cookie(str(name), str(value), self.base_url_path(),
- expires=expires, secure=secure)
+ expires=expires, secure=secure, httponly=httponly)
self.headers_out.addHeader('Set-cookie', cookie)
def remove_cookie(self, name, bwcompat=None):
--- a/web/test/unittest_web.py Fri Oct 17 18:16:58 2014 +0200
+++ b/web/test/unittest_web.py Tue Jul 15 16:07:59 2014 +0200
@@ -117,6 +117,10 @@
webreq = self.web_request('/%d' % admin_eid)
self.assertEqual(webreq.status, 200)
+ def test_session_cookie_httponly(self):
+ webreq = self.web_request()
+ self.assertIn('HttpOnly', webreq.getheader('set-cookie'))
+
class LogQueriesTC(CubicWebServerTC):
@classmethod