Kerberos Authentication question(s)

Michael B Allen ioplex at gmail.com
Wed Jun 24 23:36:15 EDT 2015


On Wed, Jun 24, 2015 at 2:07 PM, Albert C. Baker III <albert at voltage.com> wrote:
> I am using the Java class org.apache.hadoop.security.
> authentication.server.AuthenticationFilter from Apache
> Hadoop 2.5.0 as a filter in front of a Tomcat 6 Servlet we
> wish to add Kerberos authentication to.
>
> I am attempting to write some test cases against this filter
> so that we have a better understanding of how it
> works and what it does.
>
> In order for the filter to authenticate a user, it is reading the
> 'Authorization' header of the HTTP request,
> expecting the value to contain 'Negotiate <base64 encoded data>'
>
> My understanding of how Kerberos works leads me to believe that I
> should be able to write code while creating my
> HTTP request that looks something like this:
>
>   // normally the server principal keytab is not available from the
> client side,
>   // but for the purpose of making test cases I see no problem with
> sharing the keytab
>   // between the client side and the server side
>   javax.security.auth.kerberos.Keytab kt = KeyTab.getInstance("keytab");
>   KerberosKey keys[] = kt.getKeys("HTTP/voltage-pp-
> 0000.albert.int at ALBERTS.INT");

Hi Albert,

This *should* be possible but unfortunately it's not. Last I checked
(which was probably several years ago), you actually cannot initiate
Kerberos authentication from just a raw Kerberos key using the builtin
Java API in a platform independent way. Specifically, on Windows you
MUST use the Kerberos LoginModule to "login" first. Otherwise, you
will get an error when you try to use the security context. The above
code would work fine on non-Windows platforms like Linux but on
Windows, the builtin Java Kerberos library uses the Windows credential
cache and SSPI (the security API for Windows) so that the Java program
will use the system credential cache (instead of a ccache file),
identity of the user and existing system Kerberos configuration. In
theory it should still be possible to initiate auth using only a
Kerberos key like in your code but again, last I checked, it
unfortunately does not work and I have no explanation as to why other
than to recall that the builtin Java Kerberos library has been a point
of criticism and outright failure since forever (although it has
gotten better over the years). Note that the reason the Windows SSPI
is used by Java is largely because there is otherwise no way to insert
credentials into the Windows credential cache. It actually used to be
possible but at some point early on MS decided this was probably not a
good idea and so now Java and MIT or Heimdal or whoever cannot insert
creds into the Windows credential cache. They have to just use the
Windows Kerberos SSPI.

>   SomeTokenType token = new SomeTokenType();
>   <code to set token parameters>
>
>   // my understanding of Kerberos is that the only cyphertext key
>   // needed on this token
>   // is one of the server principal's keys from the Keytab file
>   // (which does contain ~5
>   // keys of different sizes and types, I've checked)
>   EncryptedTokenType etoken = <encrypt token with a key from keys>
>   byte[] array = etoken.getBytes();

First, note that the "token" in the Authorization / WWW-Authenticate
headers in HTTP are not quite the same as the "token" as defined in
the Kerberos protocol documentation. Technically, the HTTP "token" is
the Base64 encoded product of the InitializeSecurityContext function
of the Microsoft Windows SSPI of which there are several but could be
Kerberos or NTLM but in practice almost always SPNEGO which is a
little binary wrapper used to NEGOtiate Keberos or NTLMSSP where
NTLMSSP is a little binary wrapper around NTLM. Lost yet? Anyway, with
respect to Windows HTTP clients (including Firefox and Chrome running
on Windows which just tap into the Windows SSPI), the HTTP "token" is
almost certainly an SPNEGO token. However, if you're just trying to
initiate authentication (meaning you're the client), you can
*probably* skip SPNEGO and feed the server a raw Kerberos token. At
least Windows servers like IIS should detect this and handle it
correctly. And Apache's mod_auth_kerb would almost certainly handle it
correctly as well.

Regarding the keytab, yes, it contains the target principal keys
although technically you only need the one with the principal name
that matches the target you're trying to authenticate with
(HTTP/www.example.com).

>   httprequest.addHeader("Authorization","Negotiate " + new
> Base64(0).encode(array));
>
> So, questions here:
>   1) What is the Java Class that embodies the Kerberos Auth Token sent
>      in "Authorization Negotiate"?

Again I am not familiar with your "token" code but fortunately, even
though the Authorization: Negotiate ... token is an Internet
Explorer-ism, it's SPNEGO payload is largely compatible with the
Kerberos token and more generally the GSSAPI token where GSSAPI is the
RFC definition of this type of authentication which is meaningful
because JGSS is the Java implementation of this and this is a run-on
sentence. Meaning GSSAPI's GSS_Init_sec_context() is largely
compatible with Windows' InitializeSecurityContext().

So with respect to actually coding a Java HTTP client to do Kerberos,
something would ultimately need to call GSSManager.createContext with
the Kerberos OID and then GSSContext.initSecContext and then the
result of looping over that consumes and emits a "token" (which
*should* then be wrapped in the SPNEGO business) and Base64 encoded /
decoded. Maybe the "Hadoop" library is doing that for you. I'm not
familiar with it. Personally I would be very skeptical of libraries
that do this type of stuff. HTTP authentication is actually a lot
harder than it looks because HTTP is stateless and so technically
trying to do authentication (which is inherently stateful) over a
stateless protocol is something of an oxymoron. So test your code
carefully using all of the possible environmental parameters like
different servers or whatever.

>   2) What fields of that auth token have to be set to what values?
>   3) What is the encryption algorithm used to encrypt the auth token
>      against the keytab key?
>   4) What is the best keytab key to use?
>   5) What is the mechanism for byte-serializing the auth token, once
>      encrypted?

As described above, fortunately you probably don't have to worry about
the actual content of the token as it is largely handled by GSSAPI /
JGSS.

Mike

-- 
Michael B Allen
Java Active Directory Integration
http://www.ioplex.com/


More information about the Kerberos mailing list