~launchpad-pqm/launchpad/devel

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