GSSAPI Defective Ticket

648 views Asked by At

I apologise if there's something really straight forward I'm getting wrong with this - I've been finding it really hard to find much information about GSSAPI and JAAS.

I'm writing a program that makes a request to an IIS server and authenticates using Kerberos.

I have two VMs: the first is an Active Directory domain controller. The other other is running IIS server.

From my machine, I'm running a program that uses GSSAPI and JAAS to authenticate. It's pretty heavily based on the Oracle tutorials for GSSAPI, since, at this stage, I'm just sort of trying to get my head around it. It logs in using the KrbLoginModule to create a subject based on some given test user from the domain, which all appears to be working fine. In the network trace, there's an AS-REQ, AS-REP, TGS-REQ and TGS-REP (which, if I'm correct, is as it should be) between my machine and the domain controller VM.

My program then uses the subject generated above to run some GSSAPI code that's mostly based on the code from the GSSAPI/JAAS tutorial. It creates the names/credential/context without any errors, but when it tries to establish the context, things start to go wrong.

I was originally doing the context loop how it's done in the tutorial (linked above), but when it tried to start reading the token from the server (i.e. token = new byte[inStream.readInt()];) the length int it read was huge (1213486160, the few times I check it - it seemed like it was that every time). This caused an OutOfMemoryError.

I then started using the "Stream version" of the initSecContext which takes an input and output stream (I gave the in/out streams of the socket I had open to my server - I assume that's what it wants). This seems to work pretty well at first. It establishes over one iteration, but when you try to wrap/unwrap messages, things start to go wrong again. When you try to unwrap a message, it throws an error:

org.ietf.jgss.GSSException, major code: 10, minor code: 0
    major string: Defective token
    minor string: Bad token tag: 7284

The network trace for this shows a TCP message with the same length as the token generated (I'm assuming that it would be the wrapped token being sent). Then there's an ICMP Redirect. I'm not sure if this is nothing, but I thought I'd mention it (I've noticed it contains almost the entirety of the first TCP message).

Then there's an HTTP response. It's a 400 Bad Request. In the body of the response it says that it's an Invalid Verb (I'm assuming when it says verb it's meaning like "GET" or "POST etc. Is this the case?). The trace also notes that it's an acknowledgement to the first TCP message. With a bit of googling, I found a guy who had a similar problem. It turned out that it was about an antivirus messing with the headers of the request that was being sent (maybe it's related to the redirect?).

There's then a few more TCP messages (three in a row) from my machine (they contain the data I'm sending in the message with the wrap method) followed by a length=0 TCP acknowledgement from the server.

So I'm not sure what it could be (maybe it's the redirect, but that doesn't seem likely).

UPDATE:

I'm running it on the another VM (on the same Active Directory domain) but it's still getting a HTTP 400 Bad Request response. Unlike before, it's now definitely using Kerberos (above, it was sending NTLM requests).

The network trace shows the AS and TGS request and responses, then the ticket being sent. The IIS server then throws back the 400 Bad Request (again, invalid verb). There is a subtle difference: the Bad Request response is no longer in acknowledgement to the token being sent, though there is an empty ack TCP message which comes just before the 400.

The program still thinks that its context is established, but if you try to wrap a message, it breaks with:

General failure, unspecified at GSSAPI level
    minor string: Error in method wrap, error: java.net.SocketException:
        Unrecognized Windows Sockets error: 0: socket write error

UPDATE:

As mentioned earlier, when I read in the token with initSecContext, I'm expecting a length first (i.e. token = new byte[inStream.readInt()];) based on the tutorial. What I'm getting is 1213486160 which caused an OutOfMemoryError. I realised, though, that 1213486160 is 0x48545450 which, in ASCII, is "HTTP". So I read the next bunch of characters and the "response token" is the HTTP 400 Bad Request.

This makes me question whether I'm supposed to read an integer for the length as shown in the tutorial. I feel like this question is somewhat different, so I've made a new question here. That might not be the issue though (like, not what's causing it to send "Bad Request" in the first place), so I'll keep this question open for now.

ANOTHER UPDATE:

So I looked at the token that's getting spit out by initSecContext and encoded to Base64, it's YII... (i.e. a Negotiate token).

I've also had a closer look at the network trace when I log in through chrome and after the AS and TGS messages, it sends a HTTP GET request with a header line of Authorization: Negotiate YII....., as opposed to my program which sends a TCP message with the length of the token, then the token.

This suggest to me that I don't need to do the establish context step (at least, as it's shown in the tutorial), or that I need to grab the token and send it in a HTTP request rather than a straight TCP message. Is there anyone (or any examples of people - I can't seem to find any really) who has used GSSAPI/Kerberos to authenticate for IIS who can confirm this?

2

There are 2 answers

0
T-Heron On

Ensure the client machine is joined to the same Active Directory domain as the IIS server in order for Kerberos authentication to work. "Defective token" generally means the client machine sent an NTLM authentication token while the server wanted a Kerberos one. There are reasons why this undesired behavior occurs.

  1. If the client machine is not in the same AD domain, then it must be in domain having a 2-way trust relationship with the domain of the IIS server. That happens by default if the AD domains are in the same forest.
  2. Permissions to access the IIS server from the other domain must be configured. Summary: If answers to these questions are no then that explains why Basic Auth fallback is occurring. Basic authentication is tried only after Kerberos authentication fails.
2
Nico On

So There are a couple things to check. First assure the things @T-Heron said are validated. If those are and it still is not working consider these things:

  1. Validate that you get a kerberos token at all by using the command klist in cmd. (You should see a HTTP/[email protected] entry fitting your IIS host)
  2. Be sure the KDC is active and knows the service you are requesting.
  3. Validate that the IIS knows it's service principal
  4. Double check your login.conf and your krb5.conf ( or these parts in the source code if you set them programatically)

This is the best answer for Kerberos I ever found so be sure to check it out: SO answer