<login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="sufficient">
<module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option>
<module-option name="java.naming.provider.url">ldap://ldaphost.company.com:389</module-option>
<module-option name="java.naming.security.authentication">simple</module-option>
<module-option name="bindDN">userToBindToLDAP</module-option>
<module-option name="bindCredential">password</module-option>
<module-option name="baseCtxDN">dc=company,dc=com</module-option>
<module-option name="baseFilter">(sAMAccountName={0})</module-option>
<module-option name="rolesCtxDN">dc=company,dc=com</module-option>
<module-option name="roleFilter">(sAMAccountName={0})</module-option>
<module-option name="roleAttributeID">memberOf</module-option>
<module-option name="roleAttributeIsDN">true</module-option>
<module-option name="roleNameAttributeID">cn</module-option>
<module-option name="roleRecursion">0</module-option>
<module-option name="searchTimeLimit">5000</module-option>
<module-option name="allowEmptyPasswords">false</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName">java:/DS_SECURITY</module-option>
<module-option name="principalsQuery">SELECT PASSWD_TX FROM REP WHERE upper(USER_ID)=upper(?)</module-option>
<module-option name="rolesQuery">SELECT ROLE_NM_TX,'Roles' FROM REP_ROLE WHERE upper(USER_ID)=upper(?)</module-option>
</login-module>
I turned JBoss logging to TRACE to find the root cause of the issue but unfortunately JBoss is reporting misleading exception error that has nothing to do with the credentials I'm using to bind to our LDAP server (I'm using jxplorer to confirm the user I'm binding to our LDAP is valid).
2011-01-15 08:48:47,804 TRACE [org.jboss.security.plugins.auth.JaasSecurityManagerBase.cap_corp_ldap_connection] (http-0.0.0.0-8080-1) Login failure
javax.security.auth.login.FailedLoginException: Password Incorrect/Password Required
at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:252)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
at org.jboss.security.plugins.auth.JaasSecurityManagerBase.defaultLogin(JaasSecurityManagerBase.java:553)
at org.jboss.security.plugins.auth.JaasSecurityManagerBase.authenticate(JaasSecurityManagerBase.java:487)
at org.jboss.security.plugins.auth.JaasSecurityManagerBase.isValid(JaasSecurityManagerBase.java:365)
at org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:160)
at org.jboss.web.tomcat.security.JBossWebRealm.authenticate(JBossWebRealm.java:399)
at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:181)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:491)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:95)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:451)
at java.lang.Thread.run(Thread.java:619)
This issue drove me crazy the whole morning in the office trying to pin down the root cause, grrr...
As I'm about to go for lunch, I thought why not one more try but instead use JUnit to see if I'll get more details of the error. It turns out that I'm right. Cool... I'm back in business.
javax.security.auth.login.FailedLoginException: Password Incorrect/Password Required
at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:213)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
... 18 more
Caused by: javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name 'dc=company,dc=com'
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2820)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2794)
at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:129)
at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:198)
at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:171)
at org.jboss.security.auth.spi.LdapExtLoginModule.rolesSearch(LdapExtLoginModule.java:424)
at org.jboss.security.auth.spi.LdapExtLoginModule.createLdapInitContext(LdapExtLoginModule.java:351)
at org.jboss.security.auth.spi.LdapExtLoginModule.validatePassword(LdapExtLoginModule.java:232)
at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:210)
... 27 more
So the issue has nothing to do with the credentials I'm binding to LDAP (which I already know) but rather a partial return set back to client. To resolve this, I had to inject another line on the config.
<module-option name="java.naming.referral">follow</module-option>
Phew!!! What a morning to start the day... Here's the complete configuration.
<login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="sufficient">
<module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option>
<module-option name="java.naming.provider.url">ldap://ldaphost.company.com:389</module-option>
<module-option name="java.naming.security.authentication">simple</module-option>
<module-option name="java.naming.referral">follow</module-option>
<module-option name="bindDN">userToBindToLDAP</module-option>
<module-option name="bindCredential">password</module-option>
<module-option name="baseCtxDN">dc=company,dc=com</module-option>
<module-option name="baseFilter">(sAMAccountName={0})</module-option>
<module-option name="rolesCtxDN">dc=company,dc=com</module-option>
<module-option name="roleFilter">(sAMAccountName={0})</module-option>
<module-option name="roleAttributeID">memberOf</module-option>
<module-option name="roleAttributeIsDN">true</module-option>
<module-option name="roleNameAttributeID">cn</module-option>
<module-option name="roleRecursion">0</module-option>
<module-option name="searchTimeLimit">5000</module-option>
<module-option name="allowEmptyPasswords">false</module-option>
</login-module>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName">java:/DS_SECURITY</module-option>
<module-option name="principalsQuery">SELECT PASSWD_TX FROM REP WHERE upper(USER_ID)=upper(?)</module-option>
<module-option name="rolesQuery">SELECT ROLE_NM_TX,'Roles' FROM REP_ROLE WHERE upper(USER_ID)=upper(?)</module-option>
</login-module>