I got hit with an IM out of the blue this morning that kicked off a bunch of conversations about how Kerberos works with HTTP. As I was working my way around the org it became clear that lots of people say "and Kerberos happens here" and move on, but most didn't have a good understanding of how it actually worked "on the wire".
If you want my description read on. If you want to see more authoritative info you should check out Wikipedia's page on SPNEGO.
First a quick lesson in HTTP to make sure everyone's on the same page. Sorry if you know this already... When your browser (or anything really) makes an HTTP call it sends a message like this:
GET /path/file.html HTTP/1.0 Host: www.mydomain.com
followed by a blank line. The server responds in kind:
HTTP/1.1 200 OK Date: Thu, 27 Jan 2011 17:21:03 GMT Content-Length: 680 Connection: close Content-Type: text/html; charset=UTF-8
followed by a blank line and then the content. In this case 680 bytes of HTML. The first line begins with the four letters HTTP (to tell you that it's HTTP) followed by a slash and the version number of the protocol that the server supports. Immediately after that is a numeric code called that indicates whether the result is "everything's OK", a redirect or an error of some sort. After that comes a "human readable" string that matches up with that status code number.
If the server wants you to authenticate with a username and password it can ask your browser to pop up that ugly grey box by demanding what are called "Basic Credentials". To do that it responds with the status code 401 and an additional HTTP header that says "WWW-Authenticate" with the value Basic and a friendly name to show in the box. So something like this:
HTTP/1.1 401 Authorization Required Date: Sat, 27 Nov 2004 10:18:15 GMT WWW-Authenticate: Basic realm="Super secret stuff" Content-Type: text/html Content-Length: 482
Your browser will show an ugly grey box something like this:
The idea in the spec is that if you hit cancel you should see the 482 bytes of HTML that the server sent (not all browsers do this, some show you a "friendly" page instead. If you type your username and password and hit OK your browser will repeat the original request, but this time it will add on your credentials to that request. The resulting request looks something like this:
GET /path/file.html HTTP/1.0 Host: www.mydomain.com Authorization: Basic Y2hyaXM6bm90cmVhbGx5bXlwYXNzd29yZA==
Basic tells the server that the credentials immediately following are of type "Basic" and then the actual credentials are sent. The HTTP spec says that for Basic credentials you take the username plus a colon plus the password and Base64 encode them.
Incidentally in Apache and most other servers the REMOTE_USER header is populated by the server automatically with whatever is before the colon in that block of text above.
OK, now on to the actual info you came to this post to read!
When the server wants to do Kerberos it has to tell your browser that it supports Kerberos. Back in 2006 (I feel so old) Microsoft implemented a mechanism to do Kerberos between Internet Explorer (IE) and Internet Information Server (IIS) and documented it in an RFC. The spec extends the "WWW-Authenticate" with a new type of token called "Negotiate" and the semantics of how you're supposed to use that to to Kerberos. I'll spare you reading through a boring RFC and distill it down to an example:
HTTP/1.1 401 Authorization Required Date: Sat, 27 Nov 2004 10:18:15 GMT WWW-Authenticate: Negotiate [token] Content-Type: text/html Content-Length: 482
[token] is actually a base64 encoded block of data that you're supposed to look at and use to get your Kerberos Service Ticket. Your browser is supposed to respond with something like
GET /path/file.html HTTP/1.0 Host: www.mydomain.com Authorization: Negotiate [response]
And the [response] is your Service Ticket (and some other junk).
OK, one last little detail and I promise I'll stop.
When you make your first HTTP call the server has no idea whether your browser knows how to get a Service Ticket or even if you know how to deal with the Negotiate header at all. Generally this isn't a big deal because the server would only send that header if you accessed something that's protected and configured to request Kerberos tokens. And the HTTP spec actually allows you to say "send me a Negotiate token OR a Basic token"; it even goes so far as to say that the client needs to order the authentication methods so that it will try the "more secure" mechanism first - or in other words that a Negotiate token is preferred to a Basic token (for example).
This all can lead to some interesting behaviors if your client doesn't know how to handle WWW-Authenticate set to "Negotiate", if your client doesn't know what to do if it gets more than one WWW-Authenticate HTTP header in the response. The latter is more common than you'd think!
And there's another interesting story about how WebLogic's SPNEGO Identity Asserter hooks into all of this. But that's a story for another time. ;-)