1
# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Simple paste-y session manager tuned for the needs of launchpad-loggerhead.
9
from paste.auth.cookie import AuthCookieHandler, AuthCookieSigner
12
class MyAuthCookieSigner(AuthCookieSigner):
13
"""Fix a bug in AuthCookieSigner."""
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
21
r = AuthCookieSigner.sign(self, content)
22
return r.replace('\n', '')
25
class SessionHandler(object):
26
"""Middleware that provides a cookie-based session.
28
The session dict is stored, pickled (and HMACed), in a cookie, so don't
29
store very much in the session!
32
def __init__(self, application, session_var, secret=None):
33
"""Initialize a SessionHandler instance.
35
:param application: This is the wrapped application which will have
36
access to the ``environ[session_var]`` dictionary managed by this
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
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
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)
55
def _process(self, environ, start_response):
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
63
if self.session_var in environ:
64
session = pickle.loads(environ[self.session_var])
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
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)