--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyramid_cubicweb/session.py Fri Sep 19 14:26:55 2014 +0200
@@ -0,0 +1,137 @@
+import warnings
+import logging
+
+from pyramid.compat import pickle
+from pyramid.session import SignedCookieSessionFactory
+
+from cubicweb import Binary
+
+
+log = logging.getLogger(__name__)
+
+
+def logerrors(logger):
+ def wrap(fn):
+ def newfn(*args, **kw):
+ try:
+ return fn(*args, **kw)
+ except:
+ logger.exception("Error in %s" % fn.__name__)
+ return newfn
+ return wrap
+
+
+def CWSessionFactory(
+ secret,
+ cookie_name='session',
+ max_age=None,
+ path='/',
+ domain=None,
+ secure=False,
+ httponly=False,
+ set_on_exception=True,
+ timeout=1200,
+ reissue_time=120,
+ hashalg='sha512',
+ salt='pyramid.session.',
+ serializer=None):
+
+ SignedCookieSession = SignedCookieSessionFactory(
+ secret,
+ cookie_name=cookie_name,
+ max_age=max_age,
+ path=path,
+ domain=domain,
+ secure=secure,
+ httponly=httponly,
+ set_on_exception=set_on_exception,
+ timeout=timeout,
+ reissue_time=reissue_time,
+ hashalg=hashalg,
+ salt=salt,
+ serializer=serializer)
+
+ class CWSession(SignedCookieSession):
+ def __init__(self, request):
+ # _set_accessed will be called by the super __init__.
+ # Setting _loaded to True inhibates it.
+ self._loaded = True
+
+ # the super __init__ will load a single value in the dictionnary,
+ # the session id.
+ super(CWSession, self).__init__(request)
+
+ # Remove the session id from the dict
+ self.sessioneid = self.pop('sessioneid', None)
+ self.repo = request.registry['cubicweb.repository']
+
+ # We need to lazy-load only for existing sessions
+ self._loaded = self.sessioneid is None
+
+ @logerrors(log)
+ def _set_accessed(self, value):
+ self._accessed = value
+
+ if self._loaded:
+ return
+
+ with self.repo.internal_cnx() as cnx:
+ session = cnx.find('CWSession', eid=self.sessioneid).one()
+ value = session.cwsessiondata
+ if value:
+ # Use directly dict.update to avoir _set_accessed to be
+ # recursively called
+ dict.update(self, pickle.load(value))
+
+ self._loaded = True
+
+ def _get_accessed(self):
+ return self._accessed
+
+ accessed = property(_get_accessed, _set_accessed)
+
+ @logerrors(log)
+ def _set_cookie(self, response):
+ # Save the value in the database
+ data = Binary(pickle.dumps(dict(self)))
+ sessioneid = self.sessioneid
+
+ with self.repo.internal_cnx() as cnx:
+ if not sessioneid:
+ session = cnx.create_entity(
+ 'CWSession', cwsessiondata=data)
+ sessioneid = session.eid
+ else:
+ session = cnx.entity_from_eid(sessioneid)
+ session.cw_set(cwsessiondata=data)
+ cnx.commit()
+
+ # Only if needed actually set the cookie
+ if self.new or self.accessed - self.renewed > self._reissue_time:
+ dict.clear(self)
+ dict.__setitem__(self, 'sessioneid', sessioneid)
+ return super(CWSession, self)._set_cookie(response)
+
+ return True
+
+ return CWSession
+
+
+def includeme(config):
+ secret = config.registry['cubicweb.config']['pyramid-session-secret']
+ if not secret:
+ secret = 'notsosecret'
+ warnings.warn('''
+
+ !! WARNING !! !! WARNING !!
+
+ The session cookies are signed with a static secret key.
+ To put your own secret key, edit your all-in-one.conf file
+ and set the 'pyramid-session-secret' key.
+
+ YOU SHOULD STOP THIS INSTANCE unless your really know what you
+ are doing !!
+
+ ''')
+ session_factory = CWSessionFactory(secret)
+ config.set_session_factory(session_factory)