Bug 1066470 - (6.3.0) LdapExtended login module: LDAP referrals not working despite earlier fix
Summary: (6.3.0) LdapExtended login module: LDAP referrals not working despite earlier...
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: JBoss Enterprise Application Platform 6
Classification: JBoss
Component: Security
Version: 6.2.1
Hardware: Unspecified
OS: Unspecified
urgent
urgent
Target Milestone: ER6
: EAP 6.3.0
Assignee: Peter Skopek
QA Contact: Josef Cacek
Russell Dickenson
URL:
Whiteboard:
Depends On:
Blocks: 1097859 1101272 1104976
TreeView+ depends on / blocked
 
Reported: 2014-02-18 13:43 UTC by Tom Fonteyne
Modified: 2018-12-06 15:54 UTC (History)
8 users (show)

Fixed In Version:
Clone Of:
: 1104976 (view as bug list)
Environment:
Last Closed: 2014-06-28 15:27:22 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
test war file (5.83 KB, application/x-webarchive)
2014-02-18 13:44 UTC, Tom Fonteyne
no flags Details
standalone test program (11.83 KB, application/x-java-archive)
2014-02-18 13:47 UTC, Tom Fonteyne
no flags Details
standalone test program main code (11.36 KB, text/x-java)
2014-02-18 13:48 UTC, Tom Fonteyne
no flags Details
standalone test program util class for certificates (799 bytes, text/x-java)
2014-02-18 13:49 UTC, Tom Fonteyne
no flags Details


Links
System ID Private Priority Status Summary Last Updated
Red Hat Bugzilla 966879 1 None None None 2021-01-20 06:05:38 UTC

Internal Links: 966879

Description Tom Fonteyne 2014-02-18 13:43:04 UTC
Description of problem:

LDAP referrals are not being followed for authentication

Version-Release number of selected component (if applicable):

EAP 6.2 CP01

How reproducible: always


Steps to Reproduce:
1. Setup two LDAP servers. I used 2x Sun DSEE 7
   Server 1:
     uid=tom,ou=people,dc=example,dc=com
     which is a member of the group:
     cn=JBossAdmin,ou=Groups,dc=example,dc=com

     A referral to the second LDAP server:
     version: 1
     dn: ou=RemoteLdap,dc=example,dc=com
     objectClass: organizationalUnit
     objectClass: referral
     objectClass: top
     ou: RemoteLdap
     ref: ldap://zen.usersys.redhat.com:391/dc=example,dc=com

   Server 2:
     uid=tomds3,ou=people,dc=example,dc=com
     which is a member of the group:
     cn=JBossAdmin,ou=Groups,dc=example,dc=com

2. configure a security domain
                <security-domain name="LdapRealm" cache-type="default">
                    <authentication>
                        <login-module code="LdapExtended" flag="required">
                            <module-option name="java.naming.provider.url" value="ldap://zen.usersys.redhat.com:389/"/>
                            <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
                            <module-option name="java.naming.security.authentication" value="simple"/>
                            <module-option name="bindDN" value="cn=Directory Manager"/>
                            <module-option name="bindCredential" value="12345678"/>
                            <module-option name="baseCtxDN" value="dc=example,dc=com"/>
                            <module-option name="baseFilter" value="(uid={0})"/>
                            <module-option name="rolesCtxDN" value="ou=Groups,dc=example,dc=com"/>
                            <module-option name="roleFilter" value="(uniqueMember={1})"/>
                            <module-option name="roleAttributeID" value="cn"/>
                            <module-option name="roleNameAttributeID" value="cn"/>
                            <module-option name="roleRecursion" value="0"/>
                            <module-option name="throwValidateError" value="true"/>
                            <module-option name="java.naming.referral" value="follow"/>
                        </login-module>
                    </authentication>
                </security-domain>

3. Deploy a form based authentication test app for testing the login.
   -> attachement "formlogin-LdapRealm.war"

   It's pre-configured to use the above domain.
   Note that the initial page contains a session invalidation call to make it easy to test several times

4. login with:  tom/tom => success
5. login with:  tomds3/tomds3 = fails:

13:23:30,769 TRACE [org.jboss.security] (http-orac.usersys.redhat.com/10.33.1.110:8080-1) PBOX000240: Begin login method
13:23:30,779 TRACE [org.jboss.security] (http-orac.usersys.redhat.com/10.33.1.110:8080-1) PBOX000220: Logging into LDAP server with env {java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.referral=follow, roleNameAttributeID=cn, java.naming.security.principal=cn=Directory Manager, roleRecursion=0, baseCtxDN=dc=example,dc=com, roleAttributeID=cn, roleFilter=(uniqueMember={1}), rolesCtxDN=ou=Groups,dc=example,dc=com, baseFilter=(uid={0}), jboss.security.security_domain=LdapRealm, throwValidateError=true, java.naming.provider.url=ldap://zen.usersys.redhat.com:389/, bindDN=cn=Directory Manager, java.naming.security.authentication=simple, bindCredential=******, java.naming.security.credentials=******}
13:23:31,134 DEBUG [org.jboss.security] (http-orac.usersys.redhat.com/10.33.1.110:8080-1) PBOX000283: Bad password for username tomds3
13:23:31,134 TRACE [org.jboss.security] (http-orac.usersys.redhat.com/10.33.1.110:8080-1) PBOX000244: Begin abort method
13:23:31,134 DEBUG [org.jboss.security] (http-orac.usersys.redhat.com/10.33.1.110:8080-1) PBOX000206: Login failure: javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required
        at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:284) [picketbox-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_45]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_45]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_45]
        at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_45]
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769) [rt.jar:1.6.0_45]
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) [rt.jar:1.6.0_45]
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683) [rt.jar:1.6.0_45]
        at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.6.0_45]
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) [rt.jar:1.6.0_45]
        at javax.security.auth.login.LoginContext.login(LoginContext.java:579) [rt.jar:1.6.0_45]
        at org.jboss.security.authentication.JBossCachedAuthenticationManager.defaultLogin(JBossCachedAuthenticationManager.java:408) [picketbox-infinispan-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.authentication.JBossCachedAuthenticationManager.proceedWithJaasLogin(JBossCachedAuthenticationManager.java:345) [picketbox-infinispan-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.authentication.JBossCachedAuthenticationManager.authenticate(JBossCachedAuthenticationManager.java:333) [picketbox-infinispan-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.authentication.JBossCachedAuthenticationManager.isValid(JBossCachedAuthenticationManager.java:146) [picketbox-infinispan-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.as.web.security.JBossWebRealm.authenticate(JBossWebRealm.java:216) [jboss-as-web-7.3.1.Final-redhat-3.jar:7.3.1.Final-redhat-3]
        at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:280) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:391) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169) [jboss-as-web-7.3.1.Final-redhat-3.jar:7.3.1.Final-redhat-3]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920) [jbossweb-7.3.0.Final-redhat-1.jar:7.3.0.Final-redhat-1]
        at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]
Caused by: javax.naming.NamingException: PBOX000038: Unable to follow referral for authentication: ldap://zen.usersys.redhat.com:391/uid=tomds3,%20ou=People,%20dc=example,dc=com
        at org.jboss.security.auth.spi.LdapExtLoginModule.bindDNAuthentication(LdapExtLoginModule.java:553) [picketbox-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.auth.spi.LdapExtLoginModule.createLdapInitContext(LdapExtLoginModule.java:465) [picketbox-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.auth.spi.LdapExtLoginModule.validatePassword(LdapExtLoginModule.java:340) [picketbox-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:281) [picketbox-4.0.19.SP3-redhat-1.jar:4.0.19.SP3-redhat-1]
        ... 26 more



Additional info:

It is fairly easy to see why this is not working:

org/jboss/security/auth/spi/LdapExtLoginModule.java

496    protected String bindDNAuthentication(InitialLdapContext ctx, String user, Object credential, String baseDN,
497          String filter) throws NamingException
498    {
499       SearchControls constraints = new SearchControls();
500       constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
501       constraints.setTimeLimit(searchTimeLimit);
502       String attrList[] = {distinguishedNameAttribute};
503       constraints.setReturningAttributes(attrList);
504 
505       NamingEnumeration results = null;
506 
507       Object[] filterArgs = {user};
508       
509       LdapContext ldapCtx = ctx;
510       
511       boolean referralsLeft = true;
512       SearchResult sr = null;
513       while (referralsLeft) {
514          try {
515             results = ldapCtx.search(baseDN, filter, filterArgs, constraints);
516             while (results.hasMore()) {
517                sr = (SearchResult) results.next();
518                break;
519             }
520             referralsLeft = false;
521          }
522          catch (ReferralException e) {
523             ldapCtx = (LdapContext) e.getReferralContext();
524             if (results != null) {
525                results.close();
526             }
527          }
528       }
529       
530       if (sr == null)
531       {
532          results.close();
533          throw PicketBoxMessages.MESSAGES.failedToFindBaseContextDN(baseDN);
534       }
535       
536       String name = sr.getName();
537       String userDN = null;
538       Attributes attrs = sr.getAttributes();
539       if (attrs != null)
540       {
541           Attribute dn = attrs.get(distinguishedNameAttribute);
542           if (dn != null)
543           {
544                   userDN = (String) dn.get();
545           }
546       }
547       if (userDN == null)
548       {
549           if (sr.isRelative() == true) {
550              userDN = name + ("".equals(baseDN) ? "" : "," + baseDN);
551           }
552           else {
553              throw PicketBoxMessages.MESSAGES.unableToFollowReferralForAuth(name);
554           }
555       }

In our case there is never a ReferralException thrown as we get an actual result.

During debugging it was found that by line 549, we had:

dn: was absolute: uid=tomds3, ou=People, dc=example,dc=com
name            : ldap://zen.usersys.redhat.com:391/uid=tomds3,%20ou=People,%20dc=example,dc=com
NameInNamespace : uid=tomds3, ou=People, dc=example,dc=com

hence the throw PicketBoxMessages.MESSAGES.unableToFollowReferralForAuth(name);

Test code was written that would replace line 553 above

    private boolean authUser(SearchResult result) throws IOException, NamingException
    {
        LdapContext ctx;

        if (result.getName().startsWith("ldap"))
        {
            //TODO: the big question.... is this the right way of doing this ?
            String ref_url = result.getName().substring(0, result.getName().indexOf("/", 8));
            String ref_binddn = result.getNameInNamespace();

            System.out.println("Following referral to: " + ref_url);
            ctx = this.getLdapContext(ref_url, ref_binddn, userPassword);
        }
        else
        {
            ctx = this.getLdapContext(url, binddn, bindCredentials);
        }

        return (ctx != null);
    }

While this worked fine, it is not clear if this is the proper way of doing this.

Comment 1 Tom Fonteyne 2014-02-18 13:44:52 UTC
Created attachment 864564 [details]
test war file

formlogin-LdapRealm.war used "/fl" as context

Comment 2 Tom Fonteyne 2014-02-18 13:47:56 UTC
Created attachment 864565 [details]
standalone test program

standalone test app usage:

java -jar ldaptest.jar

-> prints usage

java -jar ldaptest.jar -u ldap://zen.usersys.redhat.com -b dc=example,dc=com -f uid=tomds3 -rf -p tomds3

-rf: follow referrals
-p : the password for the user as specified in the -f filter

Expected output:
Connected to: ldap://zen.usersys.redhat.com
---------------------------------------------
dn was: absolute
dn             : uid=tomds3, ou=People, dc=example,dc=com
name           : ldap://zen.usersys.redhat.com:391/uid=tomds3,%20ou=People,%20dc=example,dc=com
NameInNamespace: uid=tomds3, ou=People, dc=example,dc=com
------------attributes-----------------------
l=FAB
mail=tomf
uid=tomds3
ou=People
givenName=Tom
objectClass=top
objectClass=person
objectClass=organizationalPerson
objectClass=inetOrgPerson
sn=on ds3
cn=tomds3
---------------------------------------------
Following referral to: ldap://zen.usersys.redhat.com:391
Binding with principal: uid=tomds3, ou=People, dc=example,dc=com
Connected to: ldap://zen.usersys.redhat.com:391
authentication successful

Comment 3 Tom Fonteyne 2014-02-18 13:48:38 UTC
Created attachment 864566 [details]
standalone test program main code

Comment 4 Tom Fonteyne 2014-02-18 13:49:29 UTC
Created attachment 864567 [details]
standalone test program util class for certificates

Comment 5 Tom Fonteyne 2014-02-18 14:10:54 UTC
see also bz-1066488

Comment 9 Peter Skopek 2014-05-23 12:51:01 UTC
I have the fix on my workspace. Currently working on backport and release of related components PicketBox and JBoss Negotiation.

Comment 11 Peter Skopek 2014-05-26 14:12:39 UTC
PR for PicketBox part: https://github.com/jbossas/jboss-eap/pull/1366

Comment 17 Tom Fonteyne 2014-06-10 12:59:31 UTC
as per above, re-opening

Comment 18 Peter Skopek 2014-06-11 15:40:51 UTC
The problem in C#17 is setup issue. rolesCtxDN is set to ou=Groups,dc=example,dc=com which causes that referral object exiting in context dc=example,dc=com is not examined by the query and therefore not followed nor throwing exception for further handling.
The setup is also missing option: <module-option name="referralUserAttributeIDToCheck" value="uniqueMember"/>

My working setup is:
               <security-domain name="LdapRealm" cache-type="default">
                    <authentication>
                        <login-module code="LdapExtended" flag="required">
                            <module-option name="java.naming.provider.url" value="ldap://zen.usersys.redhat.com:389/"/>
                            <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
                            <module-option name="java.naming.security.authentication" value="simple"/>
                            <module-option name="bindDN" value="cn=Directory Manager"/>
                            <module-option name="bindCredential" value="**"/>
                            <module-option name="baseCtxDN" value="dc=example,dc=com"/>
                            <module-option name="baseFilter" value="(uid={0})"/>
                            <module-option name="rolesCtxDN" value="dc=example,dc=com"/>
                            <!-- module-option name="rolesCtxDN" value="ou=Groups,dc=example,dc=com"/ -->
                            <module-option name="roleFilter" value="(uniqueMember={1})"/>
                            <module-option name="roleAttributeID" value="cn"/>
                            <module-option name="roleNameAttributeID" value="cn"/>
                            <module-option name="roleRecursion" value="0"/>
                            <module-option name="throwValidateError" value="true"/>
                            <module-option name="java.naming.referral" value="follow"/>
                            <module-option name="referralUserAttributeIDToCheck" value="uniqueMember"/>
                        </login-module>
                    </authentication>
                </security-domain>

Comment 19 Tom Fonteyne 2014-06-11 15:49:34 UTC
referralUserAttributeIDToCheck is not documented. I'll create a doc-bug

Comment 21 Hynek Mlnarik 2014-06-19 06:32:51 UTC
Verified in 6.3.0.ER7


Note You need to log in before you can comment on or make changes to this bug.