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 <jden...@redhat.com>

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

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to