pyramid_cubicweb/session.py
changeset 11506 bfc1aa1dba30
child 11537 caf268942436
equal deleted inserted replaced
11505:eca6387f5b87 11506:bfc1aa1dba30
       
     1 import warnings
       
     2 import logging
       
     3 
       
     4 from pyramid.compat import pickle
       
     5 from pyramid.session import SignedCookieSessionFactory
       
     6 
       
     7 from cubicweb import Binary
       
     8 
       
     9 
       
    10 log = logging.getLogger(__name__)
       
    11 
       
    12 
       
    13 def logerrors(logger):
       
    14     def wrap(fn):
       
    15         def newfn(*args, **kw):
       
    16             try:
       
    17                 return fn(*args, **kw)
       
    18             except:
       
    19                 logger.exception("Error in %s" % fn.__name__)
       
    20         return newfn
       
    21     return wrap
       
    22 
       
    23 
       
    24 def CWSessionFactory(
       
    25         secret,
       
    26         cookie_name='session',
       
    27         max_age=None,
       
    28         path='/',
       
    29         domain=None,
       
    30         secure=False,
       
    31         httponly=False,
       
    32         set_on_exception=True,
       
    33         timeout=1200,
       
    34         reissue_time=120,
       
    35         hashalg='sha512',
       
    36         salt='pyramid.session.',
       
    37         serializer=None):
       
    38 
       
    39     SignedCookieSession = SignedCookieSessionFactory(
       
    40         secret,
       
    41         cookie_name=cookie_name,
       
    42         max_age=max_age,
       
    43         path=path,
       
    44         domain=domain,
       
    45         secure=secure,
       
    46         httponly=httponly,
       
    47         set_on_exception=set_on_exception,
       
    48         timeout=timeout,
       
    49         reissue_time=reissue_time,
       
    50         hashalg=hashalg,
       
    51         salt=salt,
       
    52         serializer=serializer)
       
    53 
       
    54     class CWSession(SignedCookieSession):
       
    55         def __init__(self, request):
       
    56             # _set_accessed will be called by the super __init__.
       
    57             # Setting _loaded to True inhibates it.
       
    58             self._loaded = True
       
    59 
       
    60             # the super __init__ will load a single value in the dictionnary,
       
    61             # the session id.
       
    62             super(CWSession, self).__init__(request)
       
    63 
       
    64             # Remove the session id from the dict
       
    65             self.sessioneid = self.pop('sessioneid', None)
       
    66             self.repo = request.registry['cubicweb.repository']
       
    67 
       
    68             # We need to lazy-load only for existing sessions
       
    69             self._loaded = self.sessioneid is None
       
    70 
       
    71         @logerrors(log)
       
    72         def _set_accessed(self, value):
       
    73             self._accessed = value
       
    74 
       
    75             if self._loaded:
       
    76                 return
       
    77 
       
    78             with self.repo.internal_cnx() as cnx:
       
    79                 session = cnx.find('CWSession', eid=self.sessioneid).one()
       
    80                 value = session.cwsessiondata
       
    81                 if value:
       
    82                     # Use directly dict.update to avoir _set_accessed to be
       
    83                     # recursively called
       
    84                     dict.update(self, pickle.load(value))
       
    85 
       
    86             self._loaded = True
       
    87 
       
    88         def _get_accessed(self):
       
    89             return self._accessed
       
    90 
       
    91         accessed = property(_get_accessed, _set_accessed)
       
    92 
       
    93         @logerrors(log)
       
    94         def _set_cookie(self, response):
       
    95             # Save the value in the database
       
    96             data = Binary(pickle.dumps(dict(self)))
       
    97             sessioneid = self.sessioneid
       
    98 
       
    99             with self.repo.internal_cnx() as cnx:
       
   100                 if not sessioneid:
       
   101                     session = cnx.create_entity(
       
   102                         'CWSession', cwsessiondata=data)
       
   103                     sessioneid = session.eid
       
   104                 else:
       
   105                     session = cnx.entity_from_eid(sessioneid)
       
   106                     session.cw_set(cwsessiondata=data)
       
   107                 cnx.commit()
       
   108 
       
   109             # Only if needed actually set the cookie
       
   110             if self.new or self.accessed - self.renewed > self._reissue_time:
       
   111                 dict.clear(self)
       
   112                 dict.__setitem__(self, 'sessioneid', sessioneid)
       
   113                 return super(CWSession, self)._set_cookie(response)
       
   114 
       
   115             return True
       
   116 
       
   117     return CWSession
       
   118 
       
   119 
       
   120 def includeme(config):
       
   121     secret = config.registry['cubicweb.config']['pyramid-session-secret']
       
   122     if not secret:
       
   123         secret = 'notsosecret'
       
   124         warnings.warn('''
       
   125 
       
   126             !! WARNING !! !! WARNING !!
       
   127 
       
   128             The session cookies are signed with a static secret key.
       
   129             To put your own secret key, edit your all-in-one.conf file
       
   130             and set the 'pyramid-session-secret' key.
       
   131 
       
   132             YOU SHOULD STOP THIS INSTANCE unless your really know what you
       
   133             are doing !!
       
   134 
       
   135         ''')
       
   136     session_factory = CWSessionFactory(secret)
       
   137     config.set_session_factory(session_factory)