[Freeipa-devel] session authentication issues

John Dennis jdennis at redhat.com
Tue Jan 31 14:35:22 UTC 2012


Good news, bad news. I had mistakenly believed the session 
authentication was working properly, but it's not. The good news is that 
the session code seems to work flawlessly and has for a while. The bad 
news is that the approach we took with using redirects to a login url 
seems to be fundamentally flawed. Also the introduction of S4U2proxy has 
changed some assumptions about what we see in the Kerberos ccache on the 
server (but this should be easy to address).

I'll try to be brief (I know not my usual :-)

The fundamental problem is that using redirects cause the POST data to 
be lost. This was a bit tricky to diagnose because using Firebug on the 
browser didn't show the redirect activity and because so much on the 
client side happens in javascript code. And on the server we don't have 
a way to show the complete HTTP request, just what handlers it hits and 
the HTTP headers the handlers see. So from both the browser and server 
perspective it appeared the redirects were working as expected, but 
there wasn't enough information to (easily) see where things were going 
astray. The diagnosis was further complicated by the fact the problem 
would clear itself on the next request (after credentials had been 
established eliminating the need for a redirect).

Simple explanation:

A redirect seen by XMLHttpRequest (i.e. Ajax) causes a POST to be 
converted to a GET.

The web UI uses Ajax to send POST (wrapped by JQerry). Using a redirect 
breaks our whole RPC mechanism.

More detail:

(skip to Bottom line simple summary if don't want the details)

XMLHttpRequest appears to be somewhat underspecified, this is compounded 
by XMLHttpRequest implementation differences in different browsers. As 
best as I can understand at the moment Javascript does not implement 
XMLHttpRequest in native Javascript using networking primitives, rather 
it's leverages the XMLHttpRequest implmentation in the browser, thus 
it's at the mercy of the browser implementation.

The HTTP protocol also specifies certain behavior with respect to 
redirects for security reasons. You're not supposed to send POST data to 
another server on a redirect unless the user is prompted and OK's the 
re-transmission. But Ajax operates a layer below and is not in a good 
position to prompt the user, nor would that necessarily be desired 
behavior from Javascript code.

This page gives some good explanations and provides Javascript test code 
to see how compliant your browser is: 
http://www.mnot.net/javascript/xmlhttprequest/

One might think that the decision to convert from POST to GET on a 
redirect would be governed by whether the new URL was located on the 
same origin server as the original URL (the idea is to avoid sending 
POST data to a different server), but apparently thats not how it works, 
the mere fact it's a redirect triggers the conversion (is this 
XMLHttpRequest implementation specific??)

What happens with F16 Firefox is the original post to /ipa/json gets 
redirected to /ipa/login as a GET (because Firefox won't send POST 
during a redirect). Then /ipa/login redirect again after obtaining 
credentials back to the original /ipa/json, but what arrives at the RPC 
interface is a GET not a post (again due to redirects). The POST data 
has been lost. As best I can tell all this is happening inside Firefox's 
XMLHttpRequest implementation and the Javascript making the Ajax call 
never sees it (not 100% sure about this though). Thus our Javascript 
code thinks it sent something it never actually did.

The RPC code on the server doesn't complain it received a GET instead of 
a POST, instead it tries to read the RPC data from query parameters on 
the URL. It fails to find RPC data and sends an IPA error back stating 
the command is unknown. From an Ajax/HTTP perspective this was 100% 
successful, it got back a good response, that we later interpret as an 
IPA error and put up a dialog box. Then our Javascript issues the next 
RPC, none of the redirects occur and everything works wonderfully.

The fact the redirects are occurring in the XMLHttpRequest layer also 
seems to induce another undesirable behavior. Despite the fact we send 
back a session cookie on the first request that session cookie is not 
sent back in the subsequent redirects. Each time one of the redirects 
hits the server we allocate a new session because we think none exists 
yet. Thus for the first request we end up creating two sessions that 
will never be used (they will eventually get purged but it's not optimal).

Bottom line simple summary:

We tried to hide the new authentication mechanism behind clever 
redirects so our existing code would be ignorant of it, instead 
everything would happen at the HTTP protocol level and from the 
perspective of the web UI code nothing would be different.

But Ajax does not have consistent behavior with redirects across 
implementations, even if one version of Firefox did what we wanted it 
would probably break on another browser.

Also, it doesn't appears as if there are enough hooks in the 
XMLHttpRequest and Javascript implementations to hook the redirect and 
modify behavior. I don't think the designers of XMLHttpRequest 
anticipated this, not 100% sure though.

Thus I don't think we can hide the new authentication mechanism at the 
HTTP protocol level.

I believe instead we have to handle this inside our RPC layer. If we 
issue an RPC and get a IPA error back stating we need credentials we 
will need to send a (synchronous) Ajax request to the /ipa/login URL to 
obtain credentials and store them in the session. If that succeeds we 
need to resubmit the exact same RPC call that previously failed. This 
also would have the nice benefit of not creating empty unused sessions 
during redirects.

S4U2proxy issue:

My implementation would check the validity of the TGT if the session 
contained a Kerberos ccache for the user and redirect to login if it 
expired. But with S4U2proxy there is no TGT. But shouldn't we have 
service ticket for HTTP that should be checked? I'm not sure we do. In 
the past we've said it's OK for a client to access the RPC URL without 
Kerberos ticket because we always will need a service ticket for LDAP to 
process the RPC. I'm not sure the assumption every RPC will touch LDAP 
is true nor do I believe leaving the RPC URL unsecured is a good 
practice. Rather I believe the entrance to the RPC needs to be 
authenticated which can only be done by checking the ccache stored in 
the session. Kerberos experts feel free to chime in here.

Ha, so much for being brief :-)

John



-- 
John Dennis <jdennis at redhat.com>

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/




More information about the Freeipa-devel mailing list