Problem with Beaker sessions and Apache 2.2.8

96 views
Skip to first unread message

Petko

unread,
Aug 27, 2008, 12:01:50 PM8/27/08
to web.py
Hi everybody!

To start, I am quite new to this group and to web.py in general. I
will be very thankful if somebody from the community can help me with
the problem that I have.

Basically, I am writing a web application that uses version 0.23
together with encrypted cookie-based beaker sessions (version 0.9.4).
The web application performs an authentication step
with a small login screen and saves the user info in the session
cookie. Furthermore,
all GET and POST methods in my controller classes are decorated with a
decorator that
looks in the session to check if the user is logged in. If not, then
it redirects to the login page.
Otherwise, it proceeds with the request. As far as I know, this is a
standard way for doing access control in web.py. So far, so good.

When I tested the application with the web.py's own web server
(CherryPy/3.0.1), everything
worked just fine. Then, I deployed it on Apache/2.2.8 (Ubuntu) with
mod_wsgi and without
any mod_rewrite rules and I encountered a very weird problem. After I
log in, the application sets
correctly the cookie in the browser that stores the user information,
but on any subsequent
XmlHttpRequest's (GET or POST) and sometimes when I reload the main
page the beaker
module does not like the cookie that is sent back to the web server.
It just creates
a new empty session, when I invoke session =
web.ctx.environ['beaker.session'] in my code (which
is essentially equal to a logout) and redirects me to the login
screen.

Here is a dump of the HTTP header of a request that is sent to the
server, where the problem occurs (the dump was made in the web.py
application by printing out web.ctx.environ):

ctx.environ: {'mod_wsgi.reload_mechanism': '0',
'mod_wsgi.listener_port': '80', 'HTTP_REFERER': 'http://test/
application.py/login', 'mod_wsgi.listener_host': '',
'beaker.get_session': <bound method SessionMiddleware._get_session of
<beaker.middleware.SessionMiddleware object at 0x12eb690>>,
'SERVER_SOFTWARE': 'Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/
2.5.2 mod_wsgi/1.3', 'SCRIPT_NAME': '/application.py',
'SERVER_SIGNATURE': '<address>Apache/2.2.8 (Ubuntu) mod_python/3.3.1
Python/2.5.2 mod_wsgi/1.3 Server at test Port 80</address>\n',
'REQUEST_METHOD': 'GET', 'HTTP_KEEP_ALIVE': '300', 'SERVER_PROTOCOL':
'HTTP/1.1', 'QUERY_STRING': 'type=topic&id=all&_=1219850978947',
'PATH': '/usr/local/bin:/usr/bin:/bin', 'HTTP_ACCEPT_CHARSET':
'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_USER_AGENT': 'Mozilla/5.0
(Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208
Firefox/3.0.1', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE':
'sid=2d7e109489665220b0342dd4fc7881ee40d277eaaa5c64af17f6cd7e018d216202a75646',
'SERVER_NAME': 'test', 'REMOTE_ADDR': '87.121.16.27',
'wsgi.url_scheme': 'http', 'mod_wsgi.output_buffering': '0',
'PATH_TRANSLATED': '/home/app/trunk/FeedFront/get_content',
'SERVER_PORT': '80', 'wsgi.multiprocess': True, 'SERVER_ADDR':
'209.20.83.113', 'DOCUMENT_ROOT': '/home/app/trunk/FeedFront',
'mod_wsgi.process_group': '', 'HTTP_X_REQUESTED_WITH':
'XMLHttpRequest', 'SCRIPT_FILENAME': '/home/app/trunk/FeedFront/
application.py', 'SERVER_ADMIN': 'webmaster@localhost', 'wsgi.input':
<mod_wsgi.Input object at 0x1f8e7b0>, 'HTTP_HOST': 'test',
'beaker.session': {'_accessed_time': 1219851139.6110289,
'_creation_time': 1219850922.7892039}, 'wsgi.multithread': False,
'mod_wsgi.callable_object': 'application', 'REQUEST_URI': '/
application.py/get_content?type=topic&id=all&_=1219850978947',
'HTTP_ACCEPT': '*/*', 'wsgi.version': (1, 0), 'GATEWAY_INTERFACE':
'CGI/1.1', 'mod_wsgi.case_sensitivity': '1', 'wsgi.errors':
<mod_wsgi.Log object at 0x1fcd150>, 'REMOTE_PORT': '4683',
'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', 'wsgi.run_once': False,
'mod_wsgi.application_group': 'test|/application.py',
'mod_wsgi.script_reloading': '1', 'HTTP_ACCEPT_ENCODING':
'gzip,deflate', 'PATH_INFO': '/get_content'}

The cookie is sent obviously since 'HTTP_COOKIE':
'sid=2d7e109489665220b0342dd4fc7881ee40d277eaaa5c64af17f6cd7e018d216202a75646'

but here is what the beaker session contains:
_accessed_time=1219851139.61, _creation_time=1219850922.79

and here is what it should contain:
loggedin=True, _accessed_time=1219851139.61,
user=<app.models.User.User instance at 0x1549830>, _cr
eation_time=1219850888.67

I feel very confused with this problem and I don't know what
additional information to provide, so please
ask.
Many thanks in advance!

Petko

Petko

unread,
Aug 27, 2008, 12:18:52 PM8/27/08
to web.py
It gets even more weird. I succeeded to make a XmlHttpRequest
that did not forget about the login. Here is a dump of the HTTP Header
from ctx.environ:

ctx.environ: {'mod_wsgi.reload_mechanism': '0',
'mod_wsgi.listener_port': '80', 'HTTP_REFERER': 'http://test/
application.py/', 'mod_wsgi.listener_host': '', 'beaker.get_session':
<bound method SessionMiddleware._get_session of
<beaker.middleware.SessionMiddleware object at 0x12ed690>>,
'SERVER_SOFTWARE': 'Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/
2.5.2 mod_wsgi/1.3', 'SCRIPT_NAME': '/application.py',
'SERVER_SIGNATURE': '<address>Apache/2.2.8 (Ubuntu) mod_python/3.3.1
Python/2.5.2 mod_wsgi/1.3 Server at test Port 80</address>\n',
'REQUEST_METHOD': 'POST', 'HTTP_KEEP_ALIVE': '300', 'SERVER_PROTOCOL':
'HTTP/1.1', 'QUERY_STRING': '', 'PATH': '/usr/local/bin:/usr/bin:/
bin', 'CONTENT_LENGTH': '64', 'HTTP_ACCEPT_CHARSET':
'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_USER_AGENT': 'Mozilla/5.0
(Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208
Firefox/3.0.1', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE':
'sid=2d7e109489665220b0342dd4fc7881ee40d277eaaa5c64af17f6cd7e018d216202a75646',
'SERVER_NAME': 'test', 'REMOTE_ADDR': '87.121.16.27',
'wsgi.url_scheme': 'http', 'mod_wsgi.output_buffering': '0',
'PATH_TRANSLATED': '/home/app/trunk/FeedFront/add_feed',
'SERVER_PORT': '80', 'wsgi.multiprocess': True, 'SERVER_ADDR':
'209.20.83.113', 'DOCUMENT_ROOT': '/home/app/trunk/FeedFront',
'mod_wsgi.process_group': '', 'HTTP_PRAGMA': 'no-cache',
'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest', 'SCRIPT_FILENAME': '/home/
app/trunk/FeedFront/application.py', 'SERVER_ADMIN':
'webmaster@localhost', 'wsgi.input': <mod_wsgi.Input object at
0x18dfc30>, 'HTTP_HOST': 'test', 'beaker.session': {'loggedin': True,
'_accessed_time': 1219853542.046757, 'user': <app.models.User.User
instance at 0x156b5a8>, '_creation_time': 1219850813.6006949},
'wsgi.multithread': False, 'mod_wsgi.callable_object': 'application',
'HTTP_CACHE_CONTROL': 'no-cache', 'REQUEST_URI': '/application.py/
add_feed', 'HTTP_ACCEPT': '*/*', 'wsgi.version': (1, 0),
'GATEWAY_INTERFACE': 'CGI/1.1', 'mod_wsgi.case_sensitivity': '1',
'wsgi.errors': <mod_wsgi.Log object at 0x1b0d1b0>, 'REMOTE_PORT':
'2074', 'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', 'wsgi.run_once':
False, 'CONTENT_TYPE': 'application/x-www-form-urlencoded;
charset=UTF-8', 'mod_wsgi.application_group': 'test|/application.py',
'mod_wsgi.script_reloading': '1', 'HTTP_ACCEPT_ENCODING':
'gzip,deflate', 'PATH_INFO': '/add_feed'}
2008-08-27 16:12:22,047 INFO checkaccess: session: loggedin=True,
_accessed_time=1219853542.05, user=<app.models.User.User instance at
0x156b5a8>, _creation_time=1219850813.6

Some seconds later the same request, but with a different parameter,
failed by redirecting me to the login page..

Graham Dumpleton

unread,
Aug 27, 2008, 7:26:09 PM8/27/08
to web.py
You do realise that Apache is a multi process web server. If the way
you have set session database is such that it is in memory things will
not work. This is because each process handling requests will be
referring to a different session database. When using Apache in multi
process configuration something like a session database has to be in a
shared resource accessible to all processes.

Graham
> 'sid=2d7e109489665220b0342dd4fc7881ee40d277eaaa5c64af17f6cd7e018d216202a756 46',

Petko

unread,
Aug 28, 2008, 11:58:58 AM8/28/08
to web.py
Hello Graham!
Thank you very much for your suggestion! I tried several things today
and it seems that
it does matter which one of the apache child processes receive the
request.

I still do not understand why this should be a problem, because my
session is kept entirely in the cookie
that is sent back and forth to the server. Here is how I create my
application in my main source code file:

import web
from beaker.middleware import SessionMiddleware
...
urls = (
# some url mappings...
)

def session_mw(app):
date_now = datetime.datetime.now()
expiration_period = datetime.datetime(date_now.year + 1,
date_now.month%12 + 1, date_now.day, date_now.hour, date_now.minute)
return SessionMiddleware(app, key = "sid", cookie_expires =
expiration_period,secret='randomsecret')

application = session_mw(web.wsgifunc(web.webpyfunc(urls, globals())))
...

Basically, I set implicitly the type of the session to a cookie-only
session. I also set the expiration period of the cookie to one month
and the secret key for the signing. In this way, the entire session
data is stored in the cookie and is sent to the
browser with the response and respectively to the server with the
request. In this situation, I think, it does not matter which one
of the apache child processes will receive the request, because it
should receive the cookie with all the data that is needed to
reconstruct the session correctly. Nevertheless, I am wrong somewhere
obviously, because it is not working. I printed the process id of the
apache child process
for each request, and I realized that if a request is received by the
same child process as the one that performed the login, the session is
reconstructed correctly and the request is carried on as it should.
Otherwise, if a request is received by some of the other apache
processes, the application rejects the cookie and redirects to the
login screen (as if the user was not logged in).

Although it sounds a little improbable, but is it possible that Beaker
uses some of the process information (like the PID) to verify the
cookies? In such way, if the cookie was created by the child process
X, it will not be accepted by the child process Y.

Or do I have to put something in the configuration files of apache and/
or mod_wsgi to resolve this?
I feel very confused..

Petko

On Aug 28, 2:26 am, Graham Dumpleton <Graham.Dumple...@gmail.com>
wrote:

Graham Dumpleton

unread,
Aug 28, 2008, 7:34:34 PM8/28/08
to web.py
I don't know anything about Beaker itself.

You can though avoid the problem if related to multi process nature of
Apache by using daemon mode of mod_wsgi and have your application run
in a single process. Add the following to your Apache configuration:

WSGIDaemonProcess myapp threads=15
WSGIProcessGroup myapp

This will run your application in a single process with 15 threads.
All requests will thus be handled by same process and so if it is
dependent on pid or on in memory session data, should work.

Graham

Petko

unread,
Sep 2, 2008, 5:07:26 AM9/2/08
to web.py
Thanks for the suggestion!
I tried that and it worked indeed. When I switch to daemon mode
and all requests are handled by a single multi-threaded process,
the cookies are handled as they should and the session is working..
I still do not understand why the problem arises.. and I will keep
trying ,
because we need the embedded mode of WSGI due to performance
requirements.

I started a similar discussion in the Pylons' google group at
http://groups.google.bg/group/pylons-discuss/browse_thread/thread/98864efadc8c9020/77c7ab664818726d?lnk=gst&q=beaker#77c7ab664818726d

Petko




On Aug 29, 2:34 am, Graham Dumpleton <Graham.Dumple...@gmail.com>

paul jobs

unread,
Sep 2, 2008, 5:26:31 AM9/2/08
to we...@googlegroups.com
beaker is awesome
it should become part of webpy like flup
Reply all
Reply to author
Forward
0 new messages