From d00990c389e98dc62a59020e4a79cfe657f88f89 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 16 Sep 2014 17:07:18 -0400 Subject: [PATCH] Add abstraction class to handle cookies This handles secure cokies with useful helpers and defaults. Signed-off-by: Simo Sorce Reviewed-by: Patrick Uiterwijk --- ipsilon/login/common.py | 18 +++++------ ipsilon/util/cookies.py | 67 +++++++++++++++++++++++++++++++++++++++++ quickrun.py | 2 ++ 3 files changed, 78 insertions(+), 9 deletions(-) create mode 100755 ipsilon/util/cookies.py diff --git a/ipsilon/login/common.py b/ipsilon/login/common.py index e59085f..f2254c9 100755 --- a/ipsilon/login/common.py +++ b/ipsilon/login/common.py @@ -23,6 +23,7 @@ from ipsilon.util.user import UserSession from ipsilon.util.plugin import PluginLoader, PluginObject from ipsilon.util.plugin import PluginInstaller from ipsilon.info.common import Info +from ipsilon.util.cookies import SecureCookie import cherrypy @@ -67,13 +68,10 @@ class LoginManagerBase(PluginObject, Log): # save username into a cookie if parent was form base auth if auth_type == 'password': - cherrypy.response.cookie[USERNAME_COOKIE] = username - cherrypy.response.cookie[USERNAME_COOKIE]['path'] = \ - cherrypy.config.get('base.mount', '/') - cherrypy.response.cookie[USERNAME_COOKIE]['secure'] = True - cherrypy.response.cookie[USERNAME_COOKIE]['httponly'] = True + cookie = SecureCookie(USERNAME_COOKIE, username) # 15 days - cherrypy.response.cookie[USERNAME_COOKIE]['max-age'] = 1296000 + cookie.maxage = 1296000 + cookie.send() raise cherrypy.HTTPRedirect(ref) @@ -180,9 +178,11 @@ class LoginFormBase(LoginPageBase): if self.lm.next_login is not None: next_url = self.lm.next_login.path - username = '' - if USERNAME_COOKIE in cherrypy.request.cookie: - username = cherrypy.request.cookie[USERNAME_COOKIE].value + cookie = SecureCookie(USERNAME_COOKIE) + cookie.receive() + username = cookie.value + if username is None: + username = '' context = { "title": 'Login', diff --git a/ipsilon/util/cookies.py b/ipsilon/util/cookies.py new file mode 100755 index 0000000..cd68242 --- /dev/null +++ b/ipsilon/util/cookies.py @@ -0,0 +1,67 @@ +#!/usr/bin/python +# +# Copyright (C) 2014 Ipsilon project Contributors, for licensee see COPYING + +from ipsilon.util.log import Log +import cherrypy +import uuid + + +class SecureCookie(Log): + + def __init__(self, name=None, value=None, maxage=None, expires=None): + if name is None: + self.name = str(uuid.uuid4()) + else: + self.name = str(name) + self.path = None + self.secure = cherrypy.config.get('tools.sessions.secure', True) + self.httponly = cherrypy.config.get('tools.sessions.httponly', True) + self.maxage = maxage + self.expires = expires + self.value = value + + def _get_cookie_attr(self, name): + return getattr(cherrypy.request.cookie[self.name], name, None) + + def _set_cookie_attr(self, name, value): + if value is not None and value is not False: + cherrypy.response.cookie[self.name][name] = value + + def receive(self): + if self.name not in cherrypy.request.cookie: + return + + self.value = cherrypy.request.cookie[self.name].value + self.path = self._get_cookie_attr('path') + self.secure = self._get_cookie_attr('secure') + self.httponly = self._get_cookie_attr('httponly') + self.maxage = self._get_cookie_attr('max-age') + self.expires = self._get_cookie_attr('expires') + + def _store(self): + if self.value is None: + raise ValueError('Cookie has no value') + if self.maxage is None and self.expires is not 0: + # 5 minutes should be enough ... + self.maxage = 300 + cherrypy.response.cookie[self.name] = str(self.value) + if self.path: + path = self.path + else: + path = cherrypy.config.get('base.mount', '/') + self._set_cookie_attr('path', path) + self._set_cookie_attr('secure', self.secure) + self._set_cookie_attr('httponly', self.httponly) + self._set_cookie_attr('max-age', self.maxage) + self._set_cookie_attr('expires', self.expires) + self.debug('Cookie op: %s' % cherrypy.response.cookie[self.name]) + + def delete(self): + self.expires = 0 + self.debug('Deleting cookie %s' % self.name) + self._store() + + def send(self): + self.debug('Sending cookie %s' % self.name) + self._store() diff --git a/quickrun.py b/quickrun.py index 5ec6e53..8157f80 100755 --- a/quickrun.py +++ b/quickrun.py @@ -48,6 +48,8 @@ tools.sessions.on = True tools.sessions.storage_type = "file" tools.sessions.storage_path = "${WORKDIR}/sessions" tools.sessions.timeout = 60 +tools.sessions.secure = False +tools.sessions.httponly = False ''' ADMIN_TEMPLATE=''' -- 2.20.1