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