Bug 57022 - Tomcat Spnego authentication against Active Directory fails with Java 8
Summary: Tomcat Spnego authentication against Active Directory fails with Java 8
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 7.0.55
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-26 13:33 UTC by Detelin Yordanov
Modified: 2014-09-30 20:04 UTC (History)
0 users



Attachments
Tomcat JAAS configuration (610 bytes, text/plain)
2014-09-26 13:33 UTC, Detelin Yordanov
Details
Tomcat Kerberos configuration (359 bytes, text/plain)
2014-09-26 13:34 UTC, Detelin Yordanov
Details
Tomcat configuration (6.85 KB, text/xml)
2014-09-26 13:35 UTC, Detelin Yordanov
Details
Error log (16.33 KB, text/plain)
2014-09-26 13:35 UTC, Detelin Yordanov
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Detelin Yordanov 2014-09-26 13:33:32 UTC
Created attachment 32059 [details]
Tomcat JAAS configuration

Hello everyone,
   I'm successfully using Tomcat 7.0.55 configured with Spnego authentication against Active Directory running Windows 2008 Server and Java 1.7.0.51. 
After switching to Java 1.8.0_20, authentication does not work anymore, Tomcat logs the following error message:

SEVERE: Exception performing authentication
javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (
Mechanism level: Failed to find any Kerberos tgt)]]; remaining name 'CN=Users,DC=example,DC=com'
        at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(LdapSasl.java:169)
        at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:236)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2788)
        at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2696)
        at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2670)
        at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1941)
        at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1844)
        at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1769)
        at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358)
        at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:341)
        at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:267)
        at org.apache.catalina.realm.JNDIRealm.getUserBySearch(JNDIRealm.java:1446)
        at org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:1297)
        at org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:1233)
        at org.apache.catalina.realm.JNDIRealm.getPrincipal(JNDIRealm.java:2049)
        at org.apache.catalina.realm.JNDIRealm.getPrincipal(JNDIRealm.java:1965)
        at org.apache.catalina.realm.RealmBase.authenticate(RealmBase.java:513)
        at org.apache.catalina.realm.CombinedRealm.authenticate(CombinedRealm.java:309)
        at org.apache.catalina.realm.LockOutRealm.authenticate(LockOutRealm.java:249)
        at org.apache.catalina.authenticator.SpnegoAuthenticator.authenticate(SpnegoAuthenticator.java:255)
 
Tomcat is configured according to the "Windows Authentication How-To" document, I'm attaching the krb5.ini, jaas.conf and server.xml that contains the JNDIRealm definition.

I have investigated the problem and I believe it is related to the Kerberos constraint delegation support added in Java 8, see:

http://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/jgss-features.html
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6355584

It seems that per default, GSS API in Java 8 will attempt constraint delegation on the acceptor side, see referenced changes and in particular the getCredDelegState() method:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/a1bbb8805e22

The result of this, is that Tomcat's JNDIRealm now finds the delegated credential delivered with the constraint delegation and switches GSSAPI security mechanism for JNDI/LDAP (this was not the case on Java 7). However, the Kerberos initiation during LDAP authentication does not find the Kerberos TGT in the Subject. After digging further, I noticed that the Subject used during the LDAP authentication is not set. Though the SpnegoAuthenticator initializes a Subject instance using Kerberos login via JAAS and this contains the obtained TGT, this Subject instance is not used for performing the LDAP authentication. I saw the following comment in JNDIRealm.getPrincipal:

// Note: Subject already set in SPNEGO authenticator so no need for Subject.doAs() here

So I decided to modify this and execute the getPrincipal using Subject.doAs() and the Subject instance available after the Kerberos login. This lead to successful authentication to LDAP and I was able to access the Spnego-secured webapp again.

Please note that this setup is not using any file-system Kerberos credential cache, so it requires that the Kerberos TGT is available in the Subject instance associated with current ACC.
Comment 1 Detelin Yordanov 2014-09-26 13:34:45 UTC
Created attachment 32060 [details]
Tomcat Kerberos configuration
Comment 2 Detelin Yordanov 2014-09-26 13:35:19 UTC
Created attachment 32061 [details]
Tomcat configuration
Comment 3 Detelin Yordanov 2014-09-26 13:35:39 UTC
Created attachment 32062 [details]
Error log
Comment 4 Detelin Yordanov 2014-09-29 22:05:52 UTC
I managed to overcome this error by setting -Djavax.security.auth.useSubjectCredsOnly=false
Still, I would like to know if there is a reason not to use Subject.doAs when doing GSSAPI authentication against LDAP.
Comment 5 Mark Thomas 2014-09-30 12:49:55 UTC
A short update.

I can reproduce this with Tomcat 8 and both the latest Java 7 and Java 8 releases.

I have a patch that fixes this but it currently depends on an internal Sun API. I am looking at ways to work around that.
Comment 6 Mark Thomas 2014-09-30 19:17:53 UTC
I've done a little svn archeology.

Originally, the SPNEGO authenticate did call Realm.authenticate using Subject.doAs(). That was removed as it wasn't necessary early in the SPNEGO development.

I have just restored this behaviour.

At one point Tomcat automatically set javax.security.auth.useSubjectCredsOnly=false but this was removed to enable SPNEGO to work with IBM JREs.

This fix has been made to 8.0.x and will be included in 8.0.15 onwards.

It still needs to be back-ported to 7.0.x
Comment 7 Detelin Yordanov 2014-09-30 19:54:20 UTC
Thanks Mark,
   The patch I tested with that proved to work was similar, I have not done any tests with IBM JDK though. Should the following note in "Windows Auth How-to" be removed then:

"The system property javax.security.auth.useSubjectCredsOnly is automatically set to the required value of false if a web application is configured to use the SPNEGO authentication method."

Detelin
Comment 8 Mark Thomas 2014-09-30 20:04:22 UTC
This has now been fixed in 7.0.x for 7.0.57 onwards.
Comment 9 Mark Thomas 2014-09-30 20:04:44 UTC
I'll update the 7.0.x docs to remove that comment.