~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/launchpad_loggerhead/session.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-12-22 04:55:30 UTC
  • mfrom: (14577.1.1 testfix)
  • Revision ID: launchpad@pqm.canonical.com-20111222045530-wki9iu6c0ysqqwkx
[r=wgrant][no-qa] Fix test_publisherconfig lpstorm import. Probably a
        silent conflict between megalint and apocalypse.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2009-2010 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Simple paste-y session manager tuned for the needs of launchpad-loggerhead.
 
5
"""
 
6
 
 
7
import pickle
 
8
 
 
9
from paste.auth.cookie import AuthCookieHandler, AuthCookieSigner
 
10
 
 
11
 
 
12
class MyAuthCookieSigner(AuthCookieSigner):
 
13
    """Fix a bug in AuthCookieSigner."""
 
14
 
 
15
    def sign(self, content):
 
16
        # XXX 2008-01-13 Michael Hudson: paste.auth.cookie generates bogus
 
17
        # cookies when the value is long:
 
18
        # http://trac.pythonpaste.org/pythonpaste/ticket/257.  This is fixed
 
19
        # now, so when a new version is released and packaged we can remove
 
20
        # this class.
 
21
        r = AuthCookieSigner.sign(self, content)
 
22
        return r.replace('\n', '')
 
23
 
 
24
 
 
25
class SessionHandler(object):
 
26
    """Middleware that provides a cookie-based session.
 
27
 
 
28
    The session dict is stored, pickled (and HMACed), in a cookie, so don't
 
29
    store very much in the session!
 
30
    """
 
31
 
 
32
    def __init__(self, application, session_var, secret=None):
 
33
        """Initialize a SessionHandler instance.
 
34
 
 
35
        :param application: This is the wrapped application which will have
 
36
            access to the ``environ[session_var]`` dictionary managed by this
 
37
            middleware.
 
38
        :param session_var: The key under which to store the session
 
39
            dictionary in the environment.
 
40
        :param secret: A secret value used for signing the cookie.  If not
 
41
            supplied, a new secret will be used for each instantiation of the
 
42
            SessionHandler.
 
43
        """
 
44
        self.application = application
 
45
        self.cookie_handler = AuthCookieHandler(
 
46
            self._process, scanlist=[session_var],
 
47
            signer=MyAuthCookieSigner(secret))
 
48
        self.session_var = session_var
 
49
 
 
50
    def __call__(self, environ, start_response):
 
51
        # We need to put the request through the cookie handler first, so we
 
52
        # can access the validated string in the environ in `_process` below.
 
53
        return self.cookie_handler(environ, start_response)
 
54
 
 
55
    def _process(self, environ, start_response):
 
56
        """Process a request.
 
57
 
 
58
        AuthCookieHandler takes care of getting the text value of the session
 
59
        in and out of the cookie (and validating the text using HMAC) so we
 
60
        just need to convert that string to and from a real dictionary using
 
61
        pickle.
 
62
        """
 
63
        if self.session_var in environ:
 
64
            session = pickle.loads(environ[self.session_var])
 
65
        else:
 
66
            session = {}
 
67
        existed = bool(session)
 
68
        environ[self.session_var] = session
 
69
        def response_hook(status, response_headers, exc_info=None):
 
70
            session = environ.pop(self.session_var)
 
71
            # paste.auth.cookie does not delete cookies (see
 
72
            # http://trac.pythonpaste.org/pythonpaste/ticket/139).  A
 
73
            # reasonable workaround is to make the value empty.  Therefore,
 
74
            # we explicitly set the value in the session (to be encrypted)
 
75
            # if the value is non-empty *or* if it was non-empty at the start
 
76
            # of the request.
 
77
            if existed or session:
 
78
                environ[self.session_var] = pickle.dumps(session)
 
79
            return start_response(status, response_headers, exc_info)
 
80
        return self.application(environ, response_hook)