"Defective Token Detected" Error (Ntlm Not Kerberos) with Kerberos/Spring Security/Ie/Active Directory

Defective token detected error (NTLM not Kerberos) with Kerberos/Spring Security/IE/Active Directory

This can happen when you are running the client and server on the same machine. When you use IE to talk to the machine running tomcat ensure that these are distinct machines.

Additionally you need to ensure that the server machine is joined to the domain specified in the keytab (testdomain.ourcompany.co.uk) or you might drop back to NTLM. Your keytab can still work even if your server is on a machine not joined to the domain (you'll see the nice keytab decrypt that you showed), but IE can get confused and not do the correct thing.

AD only really likes to speak arcfour-hmac for Server 2003 so you need to ensure that you set this up correctly in your krb5.ini file.

You can correctly create the keytab like this:

C:\>ktpass -princ HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK -mapuser ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK -crypto RC4-HMAC-NT -ptype K
RB5_NT_PRINCIPAL -pass * -out ourweb.keytab
Targeting domain controller: test-dc.ourcompany.co.uk
Using legacy password setting method
Successfully mapped HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK to ourweb.testdomain.ourcompany.co.uk.
Key created.
Output keytab to ourweb.keytab:
Keytab version: 0x502
keysize 75 HTTP/ourweb.testdomain.ourcompany.co.uk@TESTDOMAIN.OURCOMPANY.CO.UK ptype 1 (KRB5_NT_PRINCIPAL)
vno 3 etype 0x17 (RC4-HMAC) keylength 16 (0x0fd0e500225c4fca9a63a9998b17ca32)

I did not see that you had set up a krb5.ini file. You will need to have that set correctly on your server machine (default location C:\WINDOWS\krb5.ini):

[domain_realm]  
.testdomain.ourcompany.co.uk = TESTDOMAIN.OURCOMPANY.CO.UK
testdomain.ourcompany.co.uk = TESTDOMAIN.OURCOMPANY.CO.UK

[libdefaults]
default_realm = TESTDOMAIN.OURCOMPANY.CO.UK
permitted_enctypes = aes128-cts aes256-cts arcfour-hmac-md5
default_tgs_enctypes = aes128-cts aes256-cts arcfour-hmac-md5
default_tkt_enctypes = aes128-cts aes256-cts arcfour-hmac-md5

[realms]
VERDAD.LOCAL = {
kdc = test-dc.ourcompany.co.uk
admin_server = test-dc.ourcompany.co.uk
default_domain = TESTDOMAIN.OURCOMPANY.CO.UK
}

You might also need to set the following properties (if you are trying to run this from an IDE):

<systemProperties>
<java.security.krb5.kdc>test-dc.ourcompany.co.uk</java.security.krb5.kdc>
<java.security.krb5.realm>TESTDOMAIN.OURCOMPANY.CO.UK</java.security.krb5.realm>
</systemProperties>

I was using the org.codehaus.mojo plugin for maven which sets these in the pom file like this:

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<server>tomcat-development-server</server>
<port>8080</port>
<path>/SecurityTest</path>
<systemProperties>
<java.security.krb5.kdc>test-dc.ourcompany.co.uk</java.security.krb5.kdc
<java.security.krb5.realm>TESTDOMAIN.OURCOMPANY.CO.UK</java.security.krb5.realm>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>

GSSException Defective token detected - when trying to Authenticate to Tomcat running on Windows using Kerberos

The error “Defective token detected” likely means that an ntlm token was detected. That’s what the Negotiate mechanism uses inside popular web browsers if kerberos fails - when not instructed by the web server otherwise.  On windows operating systems, the IE web browser on it (and Firefox, if configured correctly) basically says, if you won’t do Kerberos, I’m going to send you an NTLM token.  And the server replies “no way” I don’t even know NTLM so I’m calling what you sent me defective.  Since you seem to be setting this up for the first time, you likely did not configure any fallback mechanism (such as NTLM) for when Kerberos fails, therefore, that error message. We solve this by understanding why Kerberos is failing.  I think I see the reason for the failure in your question, in two places, related to SPNs and Trusted Sites. Even if you resolve those two items, there is a third reason and fourth reason why it could continue to fail, related to encryption.

  1. The spn for the HTTP service does not match the URL entered by the browser. These need to match, otherwise Kerberos will fail. To work, the browser should be using: http://kerberos500.nickis.life:8080, not http://nickis.life:8080. I say that based on what I saw in your keytab creation syntax. In that you’ve coded the SPN as such: HTTP/kerberos500.nickis.life@NICKIS.LIFE. That’s why you need to use http://kerberos500.nickis.life:8080. The browser won’t know how to get to your web service when you tell it to go to http://nickis.life:8080. With that top URL, the browser assumes it needs to find a web service running on your Active Directorydomaincontroller (anything with just nickis.life is assumed to run on the Domain Controller). DCs should never run web servers for security reasons.
  2. You’ll need to add http://kerberos500.nickis.life as a Trusted Site under IE settings. Alternatively, *.nickis.life would work as well. (You called it Trusted Roles, when it’s actually called Trusted Sites).
  3. You are restricting the Kerberos encryption type to DES-CBC-MD5. Starting with Windows Server 2008 Active Directory R2, DES is disabled by default. DES is an outdated and generally insecure encryption type these days. Much better to use AES128 or even better, AES256. You can fix that by re-generating the keytab per my example below.
  4. In the AD user account kerberos500, go to the Account tab, scroll to the bottom, and check all the boxes for DES, AES 128, and AES 256, and OK you’re way out of the dialog boxes. You must check these boxes even if you did everything right above, or else Kerberos authentication will still fail.

How to properly re-generate the keytab: You should not run the setspn -a command to add an SPN to an AD user whenever you are planning to make a keytab associated with that user account.  The reason why is because the keytab creation command adds the SPN to the user account as part of the command.  If your scenario doesn’t work after following my advice above, then you’ll need to remove the SPN via setspn -D like below:

setspn -D HTTP/nickis.life@NICKIS.LIFE kerberos500

And the re-generate the keytab afterwards, my only change is that I told it to use all encryption types. The client and server will agree on the strongest common one during the authentication process. 

ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass XXXXpasswordforkerberos500userXXXX -crypto ALL -pType KRB5_NT_PRINCIPAL


Then replace the old keytab with the new one. For additional in-depth information on keytabs, you can read more from my technical article on how to create Kerberos keytabs here: Kerberos Keytabs – Explained. I frequently go back and edit it based on questions I see here in this forum.

By the way, HTTP/kerberos500.nickis.life is a service principal, not a user principal as you wrote in your question. I only use web browsers to test Kerberos in HTTP scenarios like this one, I don’t use cURL.

I am positive if you diligently go through all four points I’ve highlighted above, you will resolve this problem.

EDIT1: This answer assumes you have an HTTP service running on a host with the fully-qualified domain name of kerberos500.nickis.life. If you don't have such a host with that name, my answer will slightly change. Please let me know if any.

EDIT2: To achieve the objective of authentication using the URL of http://nickis.life:8080, then you may keep on using the same keytab you already created.

On the AD account NICKIS\kerberos500, go to the Account tab, scroll to the bottom, and check the box for "Use Kerberos DES encryption types for this account".

Then enable DES encryption itself at the AD domain level via Group Policy. To do that, conduct the following:

  1. Open up Group Policy Management Console (GPMC).
  2. Edit Default Domain Policy GPO. (Its safer to create a new domain-level GPO instead and edit that, but that's up to you).
  3. Navigate to Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options > “Network Security: Configure Encryption types allowed for Kerberos” and check the both checkboxes for DES_CBC_MD5 and DES_CBC_MD5. IMPORTANT: In that same Group Policy, also ensure the checkboxes for RC4, AES128, and AES256 are also checked. Those encryption types won't be used for tickets to your web site, but they will for everything else in the domain. and OK you're way out of the dialog boxes and close the GPMC.
  4. Run the 'gpupdate /force' command on both the DC server and the client.
  5. Run 'klist purge' on the client to purge all Kerberos tickets.
  6. In the web browser, clear the cache and delete all cookies.
  7. Ensure that the DC server allows port 8080 TCP inbound.
  8. Try it again.

Reference: Windows Configurations for Kerberos Supported Encryption Type

EDIT 3: Avoid running Kerberos KDC (the DC), client and server on the same machine. That is a classic recipe for getting the "Defective token error" even if you've done everything else right.

EDIT 4: (Final update which was verified by the OP): Looked at the new ktpass keytab creation output, and I saw this: Targeting domain controller: WIN-OVV6VHBGIB8.fusionis.life. Now, the defined SPN in the keytab is HTTP/kerberos500.nickis.life. The AD domain name is different from the SPN you defined, so this is not going to work unless you have some kind of trust setup between these domains. If you don't have a trust, you need to use an SPN of HTTP/kerberos500.fusionis.life instead.

Browsers keeps sending NTLM token instead of Kerberos - How to solve it?

Apparently, having client and server on two distinct virtual machines ( that are on the same physical server! ) can lead to a NTLM token.

I thought VM's would dodge the client-and-server-on-the-same-machine-issue.

So, if you

  • like me, are testing with VM's residing on the same physical machine, and
  • have set everything right but still getting a Defective token detected,

you should try to access the server from a different computer (as long as that machine is joined to the company domain).



Related Topics



Leave a reply



Submit