September 19, 2008

Back in May 2007, I wrote a blog post discussing hypothetical mechanisms for integrating the JWChat web-based Jabber client with a web SSO solution such as WWW-Negotiate or cosign. In my not-so-copious spare time, I’ve been working on implementing this, and now have a working solution to share. Skip to the end of this post if you’re just interested in the code.

Web-based jabber clients such as JWchat differ from many other web applications in that the application actually lives on the client side. Javascript running in the user’s browser communicates with the Jabber server, via a proxy. The proxy takes XMPP (the Jabber protocol) data encapsulated in an HTTP tunnel, and relays it directly to the Jabber server. For this project, I’ve concentrated on the Punjab python-based proxy server, and the http-binding (BOSH) encapsulation technique.

In order to perform SSO, the client must authenticate the encapsulated HTTP connection in the usual way. The proxy must then hijack the client’s authentication step with the Jabber server, and replace it with one that uses credentials delegated to it as part of the HTTP connection establishment. Our credentials are all Kerberos based, which simplifies this step hugely. Here’s a rough description of how it all works when using the WWW-Negotiate HTTP authentication mechansim

The client makes an HTTP connection to the proxy, which is authenticated using the client’s Kerberos credentials. The proxy performs this negotiate, and stores the delegated credentials

The client and the jabber server start up the XMPP connection via the proxy

Providing the authentication step succeeded, the proxy intercepts the server’s list of acceptable authentication mechanisms. If the server indiciates that GSSAPI is acceptable, the proxy adds the SASL EXTERNAL mechanism to the list. (EXTERNAL is a trivial mechanism which just indiciates that the server is prepared to accept an out-of-band authentication method)

The client initiates an authentication using the EXTERNAL method

The proxy intercepts the first EXTERNAL authentication stanza, and replaces it with a GSSAPI stanza, created using the stored credentials that were delegated in the first step.

The proxy and the server continue to exchange stanzas, without involving the client, until the connection establishment either succeeds or fails.

The proxy returns the success or failure stanza to the client – which views this as the result of its attempt at EXTERNAL authentication.

Normal operation resumes

However, as I’ve discussed previously, the level of client side configuration required by WWW-Negotiate, especially when credential delegation is required, makes it difficult to deploy in a heterogeneous environment. That’s why we use Cosign as our WebSSO solution, rather than using Kerberos directly, and pretty much requires this solution to work with Cosign.

Cosign complicates things because it’s based on redirects, and (ultimately) on user interaction following those redirects. It also has a pretty complicated web-server side module which can’t be easily implemented within the python-based Punjab (rewriting the cosign client as a python Twisted module might be an interesting side project, but not for today). Cosign’s redirects means that you can’t easily use it to authenticate XMLHttpRequest connections, especially when those connections are POSTd. Instead, what we must do is use Cosign to authenticate the fetch of the HTML landing page. Once this page is fetched, and authenticated, Apache has taken care of populating the cosign cookie on the client, and placed a ticket file containing the delegated credentials on the server.

This all actually simplifies things for the proxy. Instead of having to accept a WWW-Authenticate GSSAPI handshake from the client, it just has to check for the presence of a cosign cookie. Having found the cookie, it can then locate the ticket file on the server, and tell the proxy to use that file to obtain credentials with which to authenticate to the server.

Code

Enough talk, now for the patches …

JWChat, or more correctly, the JSJaC connection library that it uses requires a couple of small patches. The first fixes a bug with session restarts, which would otherwise break Punjab’s XML parser. The second adds support for using the EXTERNAL SASL authentication mechanism

The major changes are to Punjab. This patch adds support for doing both cosign and WWW-Authenticate authentication (if you aren’t interested in cosign, the patch should still function correctly – it will just skip the cosign parts when cosign cookies aren’t present with the incoming connection). In order to do GSSAPI authentication from punjab, you will also need my python-gss module.

Configuration wise, in order to use cosign, punjab must be accessed as a proxy through a cosign authenticated location on your web server. The JWChat html pages must also be served through a cosign authenticated location, which requires delegated tickets.