Multiple LDAP Servers Integration
Let's integrate a few LDAP servers!
When an administative solution (like Global Catalog) is not possible or wanted and we have to integrate more LDAP servers under one hood there is a simple way how to do it with MyVirtualDirectory.
MyVirtualDirectory (MyVD) offers much more than an integration of multiple LDAP servers, actually anything could be exposed as a LDAP service via MyVD. In this tutorial we focus only on LDAP.
Simple LDAP Integration
We begin with a simple example of two LDAP servers integration.
We have one LDAP running in server1.com
network on the port 398
and another running in server2.com
on the same port.
We integrate the server in out local network on the port 50983
as shows the following picture:
First, let's set up the MyVD server (HTTP in our case).
server.listener.port=50983
That's it. Now the integration of the servers:
server.nameSpaces=server1,server2 server.server1.nameSpace=dc=server1,dc=com server.server1.weight=100 server.server1.chain=ldap server.server1.ldap.className=net.sourceforge.myvd.inserts.ldap.LDAPInterceptor server.server1.ldap.config.host=server1.com server.server1.ldap.config.port=389 server.server1.ldap.config.remoteBase=dc=server1,dc=com server.server1.ldap.config.proxyDN=uid=testuser1,ou=people,dc=server1,dc=com server.server1.ldap.config.proxyPass=123 server.server2.nameSpace=dc=server2,dc=com server.server2.weight=100 server.server2.chain=ldap server.server2.ldap.className=net.sourceforge.myvd.inserts.ldap.LDAPInterceptor server.server2.ldap.config.host=server2.com server.server2.ldap.config.port=389 server.server2.ldap.config.remoteBase=dc=server2,dc=com server.server2.ldap.config.proxyDN=uid=testuser2,ou=people,dc=server2,dc=com server.server2.ldap.config.proxyPass=123
LDAP Client
As a non-trivial client example let's consider the Spring Security LDAP.
Simple said, the Spring Security LDAP does two search queries to the LDAP server:
- Get a user DN by its username (
(uid=<username>)
), - get groups by user's DN (
(member=<userDN>)
).
Spring allow the user to redefine the search bases and filters for different LDAP structures and uses placeholders (so the filter looks like (uid={0})
). For the MyVD setting above let's set our client as following:
user search base | dc=com |
user search filter | (uid={0}) |
groups search base | dc=com |
groups search filter | (uid={0}) |
Namespaces Integration
In our first example we had two server with one base in common dc=com
. But what happend when we have to integrate multiple server with different bases? This is what the property server.<server>.nameSpace
is meant for.
... server.server1.nameSpace=dc=mycom,dc=com ... server.server1.ldap.config.host=server1.org server.server1.ldap.config.remoteBase=dc=server1,dc=org server.server1.ldap.config.proxyDN=uid=testuser1,ou=people,dc=server1,dc=org ... server.server2.nameSpace=dc=mycom,dc=com ... server.server2.ldap.config.host=server2.net server.server2.ldap.config.remoteBase=dc=server2,dc=net server.server2.ldap.config.proxyDN=uid=testuser2,ou=people,dc=server2,dc=net ...
Now we can change our search base to dc=mycom,dc=com
. Unfortunately this doesn't work. The problem is the DN of the result user entity is mapped to the integration namespace. It means for the username testuser1
we get instead of uid=testuser1,ou=people,dc=server1,dc=com
a DN uid=testuser1,ou=people,dc=mycom,dc=com
and that doesn't match the value of the member
attribute of group entities.
MyVD brings a solution in Mapping Inserts:
... server.server1.chain=dnMapper,ldap ... server.server1.dnMapper.className=net.sourceforge.myvd.inserts.mapping.DNAttributeMapper server.server1.dnMapper.config.dnAttribs=member server.server1.dnMapper.config.remoteBase=dc=server1,dc=org server.server1.dnMapper.config.localBase=dc=mycom,dc=com ... server.server2.chain=dnMapper,ldap ... server.server2.dnMapper.className=net.sourceforge.myvd.inserts.mapping.DNAttributeMapper server.server2.dnMapper.config.dnAttribs=member server.server2.dnMapper.config.remoteBase=dc=server2,dc=net server.server2.dnMapper.config.localBase=dc=mycom,dc=com ...
The DN Attribute Mapper maps specified attributted back to the original namespace. Now the search works again.
Integration of Heterogeneous Services
As we mentioned in the beginning MyVD provides the possibility to integrate different services. So what happend when we integrate a standard LDAP server (e.g. OpenLDAP) and Active Directory (AD)? We are still on LDAP field but the details are different. For example AD's user entity holds the username in an sAMAccountName
attribute. This means we have to integrate those heterogeneous attributes to be searchable with one client search query.
Sure, we can compose the search filter like (|(uid={0})(sAMAccountName={0}))
, which will work fine, but it exposes implementation details to the client and breaks so the encapsulation principle. The client shouldn't know anything about the backend server, it should treat the service as a single LDAP server.
Fortunately, there is MyVD's Attribute Mapper:
... server.server2.chain=uidMapper,dnMapper,ldap ... server.server2.uidMapper.className=net.sourceforge.myvd.inserts.mapping.AttributeMapper server.server2.uidMapper.config.mapping=sAMAccountName=uid ...
Now works everything fine. The whole MyVD configuration file:
server.listener.port=50983 server.nameSpaces=server1,server2 server.server1.nameSpace=dc=mycom,dc=com server.server1.weight=100 server.server1.chain=dnMapper,ldap server.server1.ldap.className=net.sourceforge.myvd.inserts.ldap.LDAPInterceptor server.server1.ldap.config.host=server1.org server.server1.ldap.config.port=389 server.server1.ldap.config.remoteBase=dc=server1,dc=org server.server1.ldap.config.proxyDN=uid=testuser1,ou=people,dc=server1,dc=org server.server1.ldap.config.proxyPass=123 server.server1.dnMapper.className=net.sourceforge.myvd.inserts.mapping.DNAttributeMapper server.server1.dnMapper.config.dnAttribs=member server.server1.dnMapper.config.remoteBase=dc=server1,dc=org server.server1.dnMapper.config.localBase=dc=mycom,dc=com server.server2.nameSpace=dc=mycom,dc=com server.server2.weight=100 server.server2.chain=uidMapper,dnMapper,ldap server.server2.ldap.className=net.sourceforge.myvd.inserts.ldap.LDAPInterceptor server.server2.ldap.config.host=server2.net server.server2.ldap.config.port=389 server.server2.ldap.config.remoteBase=dc=server2,dc=net server.server2.ldap.config.proxyDN=uid=testuser2,ou=people,dc=server2,dc=net server.server2.ldap.config.proxyPass=123 server.server2.dnMapper.className=net.sourceforge.myvd.inserts.mapping.DNAttributeMapper server.server2.dnMapper.config.dnAttribs=member server.server2.dnMapper.config.remoteBase=dc=server2,dc=net server.server2.dnMapper.config.localBase=dc=mycom,dc=com server.server2.uidMapper.className=net.sourceforge.myvd.inserts.mapping.AttributeMapper server.server2.uidMapper.config.mapping=sAMAccountName=uid
Happy integrating!