Spring LDAP - bind for successful connection

Bostone picture Bostone · Mar 10, 2011 · Viewed 32.7k times · Source

I'm trying to authenticate and then query our corporate LDAP using Spring LDAP and Spring security. I managed to make authentication work but when I attempt to run search I always get the following exception

In order to perform this operation a successful bind must be completed on the connection

After much research I have a theory that after I authenticate and before I can query I need to bind to connection. I just don't know what and how?

Just to mention - I can successfully browse and search our LDAP using JXplorer so my parameters are correct.

Here's section of my securityContext.xml

<security:http auto-config='true'>
    <security:intercept-url pattern="/reports/goodbye.html" 
            access="ROLE_LOGOUT" />
    <security:intercept-url pattern="/reports/**" access="ROLE_USER" />
    <security:http-basic />
    <security:logout logout-url="/reports/logout" 
            logout-success-url="/reports/goodbye.html" />
</security:http>
<security:ldap-server url="ldap://s140.foo.com:1389/dc=td,dc=foo,dc=com" />
<security:authentication-manager>
    <security:authentication-provider ref="ldapAuthProvider">
</security:authentication-provider>
</security:authentication-manager>
<!-- Security beans -->
<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://s140.foo.com:1389/dc=td,dc=foo,dc=com" />
</bean>
<bean id="ldapAuthProvider" 
   class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="foo.bar.reporting.server.security.ldap.LdapAuthenticatorImpl">
            <property name="contextFactory" ref="contextSource" />
            <property name="principalPrefix" value="TD\" />
            <property name="employee" ref="employee"></property>
        </bean>
    </constructor-arg>
    <constructor-arg>
      <bean class="foo.bar.reporting.server.security.ldap.LdapAuthoritiesPopulator" />
    </constructor-arg>
</bean>
<!-- DAOs -->
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
  <constructor-arg ref="contextSource" />

Here's code snippet from LdapAuthenticatorImpl that performs authentication. No problem here:

@Override
public DirContextOperations authenticate(final Authentication authentication) {
    // Grab the username and password out of the authentication object.
    final String name = authentication.getName();
    final String principal = this.principalPrefix + name;
    String password = "";
    if (authentication.getCredentials() != null) {
        password = authentication.getCredentials().toString();
    }
    if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
        final InitialLdapContext ldapContext = (InitialLdapContext)
     this.contextFactory.getContext(principal, password);
        // We need to pass the context back out, so that the auth provider 
        // can add it to the Authentication object.
        final DirContextOperations authAdapter = new DirContextAdapter();
        authAdapter.addAttributeValue("ldapContext", ldapContext);
        this.employee.setqId(name);
        return authAdapter;
    } else {
        throw new BadCredentialsException("Blank username and/or password!");
    }
}

And here's another code snippet from EmployeeDao with my futile attempt to query:

public List<Employee> queryEmployeesByName(String query) 
   throws BARServerException {
    AndFilter filter = new AndFilter();
    filter.and(new EqualsFilter("objectclass", "person"));
    filter.and(new WhitespaceWildcardsFilter("cn", query));
    try {
        // the following line throws bind exception
        List result = ldapTemplate.search(BASE, filter.encode(), 
            new AttributesMapper() {
            @Override
            public Employee mapFromAttributes(Attributes attrs) 
                throws NamingException {
                Employee emp = new Employee((String) attrs.get("cn").get(), 
                   (String) attrs.get("cn").get(),
                        (String) attrs.get("cn").get());
                return emp;
            }
        });
        return result;
    } catch (Exception e) { 
        throw new BarServerException("Failed to query LDAP", e);
    }
}

And lastly - the exception I'm getting

org.springframework.ldap.UncategorizedLdapException: 
    Uncategorized exception occured during LDAP processing; nested exception is 
    javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: 
    DSID-0C090627, comment: In order to perform this operation a successful bind 
    must be completed on the connection., data 0, vece]; remaining name 
    'DC=TD,DC=FOO,DC=COM'

Answer

Raghuram picture Raghuram · Mar 10, 2011

It looks like your LDAP is configured to not allow a search without binding to it (no anonymous bind). Also you have implemented PasswordComparisonAuthenticator and not BindAuthenticator to authenticate to LDAP.

You could try modifying your queryEmployeesByName() method to bind and then search, looking at some examples in the doc.