3

We use an LdapRepository<MyUser> within a Spring Boot project. The repo is auto-generated with a few additional query methods. We now have a second Active Directory domain server, and would like to add that to our Spring configuration. Before the .properties file looked like this:

spring.ldap.base=cn=Users,dc=company,dc=local
spring.ldap.password=really_save_password
spring.ldap.username=ldapuser@company.local
spring.ldap.urls=ldap://172.16.36.82:389

So I changed the last line to:

spring.ldap.urls=ldap://172.16.36.80:389 ldap://172.16.36.82:389

Because from other Stackoverflow questions I understood that multiple urls should be supplied with separating spaces.

But using userRepo.findAll() (or any query method) then leads to an exception:

Exception in thread "main" java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:784)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1258)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
    at com.company.product.web.WebApp.main(WebApp.java:22)
Caused by: org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-0310021B, problem 2001 (NO_OBJECT), data 0, best match of:
    ''
 ]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-0310021B, problem 2001 (NO_OBJECT), data 0, best match of:
    ''
 ]; remaining name '/'
    at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:183)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:376)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:309)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:642)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:578)
    at org.springframework.ldap.core.LdapTemplate.find(LdapTemplate.java:1840)
    at org.springframework.ldap.core.LdapTemplate.findAll(LdapTemplate.java:1806)
    at org.springframework.ldap.core.LdapTemplate.findAll(LdapTemplate.java:1814)
    at org.springframework.data.ldap.repository.support.SimpleLdapRepository.findAll(SimpleLdapRepository.java:183)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:629)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:593)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:578)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy173.findAll(Unknown Source)
    at com.company.product.web.Foo.run(Foo.java:22)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800)
    ... 5 more
Caused by: javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-0310021B, problem 2001 (NO_OBJECT), data 0, best match of:
    ''
 ]; remaining name '/'
    at java.naming/com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3284)
    at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3205)
    at java.naming/com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2996)
    at java.naming/com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1875)
    at java.naming/com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1798)
    at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:392)
    at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:358)
    at java.naming/javax.naming.directory.InitialDirContext.search(InitialDirContext.java:305)
    at org.springframework.ldap.core.LdapTemplate$3.executeSearch(LdapTemplate.java:303)
    at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:363)
    ... 33 more

It does work when I use just the second domain server, so either server works when used by its own in the .properties file.

What am I doing wrong?

Stefan Fischer
  • 363
  • 4
  • 19

1 Answers1

2

If you want to use multiple ldap urls, you must declare them as a string array according to official spring-ldap document:

It is possible to configure multiple alternate LDAP servers using the urls property. In this case, supply all server urls in a String array to the urls property.

In your case try:

spring.ldap.urls=ldap://172.16.36.80:389,ldap://172.16.36.82:389
fukit0
  • 924
  • 1
  • 11
  • 35
  • During my reading of various sources previously (not just Stack Overflow), I also had it stuck in my head that I needed spaces between the fallback URLs (forgetting the official documentation you reference, which I had also read a lot of, though it isn't clear if this is a fallback-only situation). I ran some tests with the space version and proved that the URLs worked as expected as fallbacks (e.g. if the first was invalid and the second was valid, a connection was still established). So that is (semi-)valid. I guess it ends up using the underlying JNDI fallback support then. – Dex Nov 03 '22 at 21:03
  • However, and this is what brought me here, the space separated version exhibited a quirk: my configured search base was now being ignored. My searches still worked, because it presumable searched the entire directory (and I didn't have data elsewhere I was trying to ignore). This was true even if I configured an invalid search base that should have returned no results. Also, when I did a dirCtx.getDn(), I now got the whole DN back, instead of just the relative DN (which follows with the search base being ignored). – Dex Nov 03 '22 at 21:07
  • When I changed the url separator to a comma, as specified here, the connection still seemed to work as a fallback, except now my configured search base worked again. I'm confused why the space version would cause the search base configuration to be ignored (unless maybe that configuration isn't actually being used in the search base portion of a search, as one would expect based on the name). Even a failure (because it isn't needed/can't be used?) would be better than just silently ignoring it. So, I leave this here for others, in case they find themselves with the same odd behavior. – Dex Nov 03 '22 at 21:12