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) |