I am trying to authenticate and then query our corporate LDAP using Spring LDAP Security and Spring. I managed to authenticate, but when I try to search, I always get the following exception.
To complete this operation, successful bind must be completed in the connection
After much research, I have a theory that after authentication and before I can fulfill the request, I need to bind to the 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 is the 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> <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> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" />
Here is a code snippet from LdapAuthenticatorImpl that performs authentication. There are no problems 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 is another piece of code from EmployeeDao with my useless attempt to request:
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 the last one is the exception I get
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'