I’ve got Tomcat configured with a JNDI Realm talking to Microsoft Active Directory over LDAP. It works perfectly when ActiveDirectory works; but when ActiveDirectory gets flaky (which it sometimes does), Tomcat doesn’t handle it well. In one particular case, I’ve got one thread stuck trying to talk to ActiveDirectory and 199 additional threads waiting for the first thread to release its lock on the JNDIRealm. Relevant bits of the stack dump are below.
My first question is: is there a way to configure the JNDIRealm to be more fault-tolerant? It looks like I could add an alternateURL attribute -- but in this case, it seems like the connection is hung and the JNDIRealm doesn't recognize a failure, so it wouldn't fail over to the alternateURL. Is there anything else I can do to allow the JNDIRealm to recover from this situation? My second question is: really -- authentication is serialized? Then I realized that the big bold TODO in the docs would address this problem. ( http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/realm/JNDIRealm.html). Bummer. I ought to get coding on that... Any thoughts appreciated! Thanks, Pat. Here’s one of the 199 blocked threads: "http-8080-200" daemon prio=10 tid=0x00007f1de0073800 nid=0x7f1e waiting for monitor entry [0x00007f1dbcd8c000] java.lang.Thread.State: BLOCKED (on object monitor) at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:1044) - waiting to lock <0x0000000780053fe0> (a org.apache.catalina.realm.JNDIRealm) at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:945) at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:181) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:523) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:679) Here’s the blocking thread: "http-8080-4" daemon prio=10 tid=0x00007f1de000d800 nid=0x2332 in Object.wait() [0x00007f1e1c2d9000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007843fdc38> (a com.sun.jndi.ldap.LdapRequest) at com.sun.jndi.ldap.Connection.readReply(Connection.java:447) - locked <0x00000007843fdc38> (a com.sun.jndi.ldap.LdapRequest) at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:358) - locked <0x00000007843fdbd8> (a com.sun.jndi.ldap.LdapClient) at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:210) - locked <0x00000007843fdbd8> (a com.sun.jndi.ldap.LdapClient) at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2685) at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2593) at com.sun.jndi.ldap.LdapCtx.ensureOpen(LdapCtx.java:2567) at com.sun.jndi.ldap.LdapCtx.doSearch(LdapCtx.java:1932) at com.sun.jndi.ldap.LdapCtx.doSearchOnce(LdapCtx.java:1924) at com.sun.jndi.ldap.LdapCtx.c_getAttributes(LdapCtx.java:1317) at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:231) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:139) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:127) at javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:140) at org.apache.catalina.realm.JNDIRealm.bindAsUser(JNDIRealm.java:1562) at org.apache.catalina.realm.JNDIRealm.checkCredentials(JNDIRealm.java:1416) at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:1092) - locked <0x0000000780053fe0> (a org.apache.catalina.realm.JNDIRealm) at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:977) at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:181) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:523) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:679) * * * *