pingidentity / ldapsdk

UnboundID LDAP SDK for Java
Other
327 stars 79 forks source link

multihomed ldap server #166

Open f1-outsourcing opened 2 months ago

f1-outsourcing commented 2 months ago

I hope it is ok to ask this here via an issue. I have a multi homed ldap server, dig returns something like this

[@-]$ dig +short ldap.dev.example.net
192.168.110.240
10.10.130.20

However my java application is only on the 10.10.x.x network, it currently only tries to connect to 192.168.110.240 instead of 10.10.130.20.

I know this can be resolved with sorting in dns, but I don't have this currently available. Can this be resolved in unboundid?

dirmgr commented 2 months ago

The LDAP SDK doesn’t have anything that can do this by default. It typically relies on the operating system’s logic for routing requests to the appropriate destination. However, there are a couple of potential ways that you could address this by writing some custom code.

The easiest option would probably be to create a custom NameResolver implementation. Your implementation would probably just need to override the getByName method (and perhaps also the getAllByName method). They’d probably just use the InetAddress.getAllByName() method to get all addresses associated with a given name, and if one of the returned addresses is in the same network as an address on the local system, then you could prefer that one. You can use the LDAPConnectionOptions.setNameResolver method to set the name resolver to use for a set of connection options, and then create new connections (and connection pools) using that LDAPConnectionOptions object.

It may also be possible to accomplish with a custom ServerSet implementation. The RoundRobinDNSServerSet class provides some support for names that resolve to multiple addresses, but it’s designed more for cases in which all addresses are equally usable, which doesn’t sound like is the case in your environment. The DNSSRVRecordServerSet implementation provides even more in-depth DNS accesses for getting SRV records that allow for automatic discovery, but I don’t think you’d need anything as involved as that.

But really, I think that a custom NameResolver implementation is probably the easiest way to address the issue for your environment.

f1-outsourcing commented 2 months ago

Hi Neil thanks for the detailed advise!

The LDAP SDK doesn’t have anything that can do this by default. It typically relies on the operating system’s logic for routing requests to the appropriate destination.

So in theory (I don't think my CO currently supports this) I could try and add sortlist to resolv.conf and then the application (java springboot) should resolve this correctly?

/etc/resolv.conf
sortlist 10.10.130.0/255.255.255.0

But really, I think that a custom NameResolver implementation is probably the easiest way to address the issue for your environment.

Is this being called at some point when the connection fails? Eg. if my ldap server moves to a different host and changes its ip addresses, is this being caught? Eg currently I have clamav/spamassassing milters that need to be restarted for them to learn an application has been moved and resolves to different ip address.

Or does this require me to make a custom NameResolver and start using ServerSet?

dirmgr commented 2 months ago

Using a sortlist in resolv.conf might work, although I don’t have any experience with this particular kind of setup where DNS returns multiple addresses for a given name, but only some of them are reachable.

The LDAP SDK always uses a NameResolver instance when performing address lookups. If it needs to get the address for a given name, then it will use NameResolver.getByName instead of directly calling InetAddress.getByName, or instead of directly creating a socket with the provided name. If you have a NameResolver that always tries to choose an address in the same network as your local system, then that can ensure that the LDAP SDK uses that address when trying to establish a connection to a name that’s associated with multiple addresses in different networks.

If the LDAP server address changes (which generally isn’t a common thing), and if you need to be able to react to that immediately, then that’s something that could also be accomplished with a custom NameResolver, although it would need to forego the JVM’s default caching and trigger a name service lookup every time a given name is used (which you should be able to do by calling NameResolver.setJVMSuccessfulLookupCacheTTLSeconds(0), indicating that it should not perform any caching). Note, however, that this could be fragile and could cause your application to break if there’s a DNS outage. If you do that, you might want to have a custom NameResolver implementation that does its own caching, but only uses the cache if a lookup attempt fails. You can look at the CachingNameResolver implementation for a sample implementation that makes use of caching, but it isn’t suitable for your case because (A) it prefers using the cache whereas you only want to use the cache as a last resort, and (B) it doesn’t do what you want it to do for names that are associated with multiple IP addresses.