From 075519a3e8304c4fd4b1c5fab819ea6796a54bf8 Mon Sep 17 00:00:00 2001 From: Joel Kleier Date: Wed, 1 Apr 2026 07:56:44 -0500 Subject: [PATCH 1/2] add httponly and secure settings to secure login auth cookie --- castle/cms/authentication.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/castle/cms/authentication.py b/castle/cms/authentication.py index 685ed8a9e..d8078b2ca 100644 --- a/castle/cms/authentication.py +++ b/castle/cms/authentication.py @@ -130,7 +130,10 @@ def get_supported_auth_schemes(self): def set_login_session_id(self): self.login_session_id = uuid4() - self.request.response.setCookie('__sl__', self.login_session_id) + self.request.response.setCookie( + '__sl__', self.login_session_id, + HttpOnly=True if self.registry.get('castle.use_httponly_cookie', 'yes').lower().strip() == 'yes' else False, + Secure=True if self.registry.get('castle.use_secure_cookie', 'yes').lower().strip() == 'yes' else False) def get_secure_flow_key(self): return '{id}-secure-state'.format(id=self.login_session_id) From 66485e97a0cef4a82bcc553b35cf68ffedcc4c87 Mon Sep 17 00:00:00 2001 From: Adam McNevin Date: Wed, 1 Apr 2026 11:35:39 -0700 Subject: [PATCH 2/2] ensure HttpOnly flag is added to cookie on login --- castle/cms/authentication.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/castle/cms/authentication.py b/castle/cms/authentication.py index d8078b2ca..0714aeb9c 100644 --- a/castle/cms/authentication.py +++ b/castle/cms/authentication.py @@ -24,6 +24,7 @@ from zope.component import adapter from zope.component import getGlobalSiteManager from zope.component import getUtility +from zope.component.hooks import getSite from zope.component.interfaces import ComponentLookupError from zope.event import notify from zope.interface import Interface @@ -130,10 +131,35 @@ def get_supported_auth_schemes(self): def set_login_session_id(self): self.login_session_id = uuid4() - self.request.response.setCookie( - '__sl__', self.login_session_id, - HttpOnly=True if self.registry.get('castle.use_httponly_cookie', 'yes').lower().strip() == 'yes' else False, - Secure=True if self.registry.get('castle.use_secure_cookie', 'yes').lower().strip() == 'yes' else False) + + if not self.is_zope_root and self.registry: + use_secure = ( + self.registry.get('castle.use_secure_cookie', 'yes') + .lower().strip() == 'yes' + ) + + use_http_only = ( + self.registry.get('castle.use_httponly_cookie', 'yes') + .lower().strip() == 'yes' + ) + + site = getSite() + site_path = '/'.join(site.getPhysicalPath()).lstrip('/') + cookie_path = '/' + site_path if site_path else '/' + + cookie = '__sl__=%s; Path=%s;' % (self.login_session_id, cookie_path) + + if use_secure: + cookie += '; Secure' + + if use_http_only: + cookie += '; HttpOnly' + + self.request.response.addHeader('Set-Cookie', cookie) + + else: + self.request.response.setCookie('__sl__', self.login_session_id) + def get_secure_flow_key(self): return '{id}-secure-state'.format(id=self.login_session_id)