[imp] Strange authentication/cookie problem

James Noyes jnoyes-horde@retrogeeks.com
Wed, 30 Jan 2002 15:50:50 -1000


Quoting Chuck Hagenbuch <chuck@horde.org>:
> Quoting James Noyes <jnoyes-horde@retrogeeks.com>:
> 
> > Warning: unserialize() failed at offset 0 of 35 bytes in
> > /root/of/horde/install/lib/Auth.php on line 227
> 
> These are silenced in CVS.
> 
This is good to know, but I believe I have found a (potential) solution of my
own.  I have spent several hours on this, so please read on for details.  Keep
in mind throughout that I am using "imp" authentication in order to avoid the
"double login" problem.

> > The ultimate question I NEED an answer to is:  How do I fix this?
> 
> I'm not sure if it made it into RELENG_ yet, but it will before the next 
> release. You can add an @ before the unserialize() call if you want to do it
> yourself.
> 
I considered this, too.  Call me uptight, but I was looking for a more elegant
solution, and my potential fix does not require doing this.

> > More specific questions I would LIKE answers to include:
> >   Can someone explain to me why is this happening?
> 
> Unfortunately, no. It doesn't make any sense to me whatsoever, and isn't
> always reproducible.
> 
Actually, as part of my troubleshooting, I have found a way to consistently
reproduce the behavior:

Shut down your browser.  Clear away/delete all cookies relating to horde/imp/et
al.  Start your browser fresh.  Load the main horde root URL (this loads
index.php from the horde/ directory of course).  Log in.  AFTER logging in,
select 'refresh' or 'reload', depending on whether you're using Netscape/IE. 
Witness 'unserialize' errors.

The half-assed workaround I initially came up with:

Shut down your browser.  Clear away/delete all cookies relating to horde/imp/et
al.  Start your browser fresh.  Load the main web root URL (loads index.php from
the /horde directory).  Do not log in.  BEFORE logging in, select 'refresh' or
'reload', depending on if you're using Netscape/IE.  NOW log in.  'Refresh' or
'reload' again.  Witness NO 'unserialize' errors.  Repeat if necessary to
convince yourself the problem is not present.  :)

Unfortunately, getting my end users to always reload/refresh at least once prior
to logging in just wasn't an option for me.

Now for the explanation and my possible "fix".

> >   Is this a result of a misconfiguration on my part?
> 
> I don't think so.
> 
I'm pretty confident now it isn't a configuration issue.

> >   I know it's unlikely, but is this possibly a bug in Horde/IMP?
> 
> Possibly. I'm starting to suspect php's serializer, since I'm currently
> having some other issues with it, but that could be off base, too.
> 
I hate calling something a bug when I'm not 100% sure of myself, but I'm in the
90%+ range, so I'll take a chance.  I think there's a bug in Horde, and here's
how I found what I think is the problem:

In horde/index.php there is an explicit call to Secret::setKey('auth');
(Note: I am assuming the "auth" key is required for the operation of the Horde
framework.  My troubleshooting tends to support this theory, but I don't know
Horde well enough to say for sure.)
I was able to determine that this call IS in fact occurring by adding some
echo's before and after the call, so that seems fine.  So then I investigated
Secret::setKey().

The setKey() function in horde/lib/Secret.php includes two nested if-else
clauses.  I placed an echo after each "if" or "else", with the strings A,B,C,and
D in them so I could tell how execution traced through the tree.  An initial
load of index.php from a fresh browser startup outputs only a "D", suggesting
that the code falls through to the "$key = md5(session_id()...." section without
setting a cookie.
*If I reload at this point*, I get different results.  The reload causes "A" "C"
to appear instead, suggesting that upon reload, the code falls through to the
"Secret::srand()..." section, where the "auth_key" cookie gets set.  If I turn
on cookie notification in my browser, I can confirm that at this point the
browser is in fact getting an "auth_key" cookie.

It appears that the reason for this is that upon fresh browser startup with no
cookies set, the index.php attempts to set both the sessioning, using the
"Horde" cookie, as well as the "auth" key.  The setKey function tries to
determine if it should use cookies or not based on the
"if (isset($GLOBALS['HTTP_COOKIE_VARS']) && (count($GLOBALS['HTTP_COOKIE_
VARS']) > 0)) {"
line.  The trouble with that is that during this first load, there are no
cookies set yet (the "Horde" cookie is being set at the same time by this same
code), the "if" fails, and it mistakenly doesn't generate an "auth_key" cookie. 
Upon a reload, the "Horde" cookie is set, the "if" succeeds, and the setKey
function then properly uses cookies for the "auth" key.
If you reload index.php prior to logging in, all of the cookies (Horde,
auth_key, and imp_key) are set cleanly, and the unserialize() error message
never shows up no matter how much you reload.  If you log in FIRST, a subsequent
re-load will set the "auth_key" cookie.  This appears to confuse the system and
cause the "unserialize()" errors.

My solution was to move the setting of the "auth" key to a different place where
I could be sure the "Horde" cookie was properly set PRIOR to the
Secret::setKey() routine's check.  I commented out the Secret::setKey('auth');
on line 28 of horde/index.php, and added the following to the top of
horde/login.php, at lines 14 and 15:

include_once './lib/Secret.php';
Secret::setKey('auth');

After making this change, my system seems to consistently set the "auth_key"
cookie correctly upon initial load, even on a fresh browser startup with no
cookies set.  This seems to eliminate the occurence of the "unserialize()" error
completely, no matter when or how you refresh/reload.

What I am NOT sure of, though, is if this change may have negative consequences
I'm not seeing.  For example, I do not know if this change will break sessioning
or keys for non-cookie-enabled users.  I also do not know if it will break
things for people not using "imp" authentication.  Hopefully someone who
understands Horde better than I do can tell me if I've broken something that I
haven't seen yet.

> >   Can someone explain the purpose and operation of the <whatever>_key
> > cookies?
> 
> They are for encrypting sensitive information that shouldn't be plaintext in
> the session.
> 
Also good to know, but I did eventually figure this one out myself as well after
studying the code.  Guess I should have looked more closely before I fired off a
zillion questions.

> >   Why does setting an additional <whatever>_key cookie generate an error?
> >   How do I (or can I?) prevent that second cookie being set?
> 
> If someone can shed light on this, I'd appreciate it; I don't have time to
> dig too deeply into it now, especially since silencing the messages seems to
> make it work.
> 
I still don't understand why setting the "auth_key" cookie after a successful
login generates the unserialize() error.  I haven't delved into the code far
enough to find the cause, I just know that it happens.

I'd like to think that even without fully understanding the operation of the
auth_key mechanism that my change has fixed this issue.  Trouble is, I'm not one
to pat myself on the back, especially since I don't know if my changes have
unforseen effects on other parts of the Horde framework.

Can someone that understands more about the inner workings of Horde determine
for me if I've generated more issues than I've fixed with my changes?  I'd
really like to know.  If I haven't made things worse, hopefully my fix will
prove useful to someone else.

Cheers,
James Noyes
(jnoyes@retrogeeks.com)

-------------------------------------------------
This mail sent via testmail.retrogeeks.com