[Zope] Re: Z2.log user name problem
Paul Tiemann
pault@center7.com
20 Sep 2002 11:26:04 -0600
> I'm using out-of-the-box user authentication with
> CookieCrumbler. Everything seems fine except that
> the identified user in the Z2.log file is wrong.
I've got a "fix" for your problem. It wouldn't have
been my first choice to do it the way I did, but it
works, and it's quicker than my other options were...
(Some history)
I had the same problem with cookie-based authentication.
The root of the problem lies in the log() method of the
file ZServer/medusa/http_server.py. That method uses the
'Authorization' header of the request to determine the
name of the user. Due to the architecture of the internal
objects used to represent the request at this level (not
the "REQUEST" we're usually used to using, but another
lower-level request object) the 'Authorization' header
is a read-only field. I believe it's the __get_item__
and __set_item__ methods that are custom for that request
object, so that all attempts to "set" the Authorization
HTTP header will just be dumped into the list of response
headers. Since I could see no other way to get around the
problem by making a change in the 'CookieCrumbler', or in my
case 'LDAPUserFolder' products, I decided to just fix the
problem by monkey-patching the log() method in the
http_server.py file itself.
To do that, you can do something like this:
1) Add two lines like these to the top of http_server.py
for the import you'll need below to make parsing
the cookies easier.
# PAUL DID THIS SHAMEFUL THING
from ZPublisher.HTTPRequest import parse_cookie
2) Down near line 290, you have the part that determines
the name that will go to the Z2.log file. Here, you
see 'name' being set to 'Anonymous', then there is
an 'if auth is not None:' block which determines
the name from the "Authorization" header. In my case,
I added an 'else:' block below the if which has this
dirty patch of code:
try:
auth_cookie_name = "my_auth" # probably '__ac'?
cookie = None
try:
cookies = {}
header_value = self.get_header("Cookie")
if header_value:
parse_cookie(header_value, cookies)
cookie = cookies.get(auth_cookie_name, None)
except:
name = "Anonymous"
if cookie is not None:
cookie = unquote( cookie )
try:
cookie = base64.decodestring( cookie )
name, password = tuple( cookie.split( ':', 1 ) )
except: name = "Unknown (bad auth cookie)"
except:
name = "Failure!"
Note that the way I solved the problem is "brittle" because
should you ever change your auth_cookie_name, and forget
to change it in http_server.py as well, you'll stop
seeing correct values in your logs.
One more important note: Since you have more than one
acl_users, you might want to put the 'Cookie' based
name-fetch code before the 'Authorization' header based
stuff. It would be possible for you to log in as admin,
then use the cookie-based login page to authenticate as
a normal user, in which case your browser will be sending
the 'Authorization' header, as well as the cookie, and
that would cause the standard acl_users username to be
logged...
> I assume there is some method which needs to be called
> to update the username for logging purposes when the
> login is upgraded, but I've been unable to find it. Or
> is this a problem caused by the lack of a CookieCrumbler
> in the root folder....
I tried to find a method like the one you're describing, and
one alternative to my solution would have been to add that
kind of facility to the low-level request object, and make
different changes to http_server.py so it would get the
user's name from that new variable instead of from the
Authorization header, but I couldn't find it, and it
didn't appear that CookieCrumbler was doing that either...
If there is an alternative solution that is more desirable
than my own, I would love to hear about it... Maybe someone
on the list knows another way...
Good luck, I hope I've helped,
;) Paul