This document provides an example of using OpenLDAP's meta backend to provide a unified view of two distinct LDAP directory trees. I was frustrated by the lack of simple examples available when I went looking for information on this topic, so this is my attempt to make life easier for the next person looking to do the same thing.
The particular use case that motiviated my interest in this topic was the need to configure web applications to (a) authenticate against an existing Active Directory server while (b) also allowing new accounts to be provisioned quickly and without granting any access in the AD environment. A complicating factor is that the group managing the AD server(s) was not the group implementing the web applications.
Assumptions
I'm making several assumptions while writing this document:
- You have root access on your system and are able to modify files in /etc/openldap and elsewhere on the filesystem.
- You are somewhat familiar with LDAP.
- You are somewhat familiar with OpenLDAP.
Set up backend directories
Configure slapd
We'll first create two "backend" LDAP directories. These will represent the directories you're trying to merge. For the purposes of this example we'll use the ldif backend, which stores data in LDIF format on the filesystem. This is great for testing (it's simple and easy to understand), but not so great for performance.
We define one backend like this in /etc/openldap/slapd-be-1.conf:
database ldif suffix "ou=backend1" directory "/var/lib/ldap/backend1" rootdn "cn=ldif-admin,ou=backend1" rootpw "LDIF"
And a second backend like this in /etc/openldap/slapd-be-2.conf:
database ldif suffix "ou=backend2" directory "/var/lib/ldap/backend2" rootdn "cn=ldif-admin,ou=backend2" rootpw "LDIF"
Now, we need to load these configs into the main slapd configuration file. Open slapd.conf, and look for the following comment:
####################################################################### # ldbm and/or bdb database definitions #######################################################################
Remove anything below this comment and then add the following lines:
include /etc/openldap/slapd-be-1.conf include /etc/openldap/slapd-be-2.conf
Start up slapd
Start up your LDAP service:
# slapd -f slapd.conf -h ldap://localhost/
And check to make sure it's running:
# ps -fe | grep slapd root 15087 1 0 22:48 ? 00:00:00 slapd -f slapd.conf -h ldap://localhost/
Populate backends with sample data
We need to populate the directories with something to query.
Put this in backend1.ldif:
dn: ou=backend1 objectClass: top objectClass: organizationalUnit ou: backend1 dn: ou=people,ou=backend1 objectClass: top objectClass: organizationalUnit ou: people dn: cn=user1,ou=people,ou=backend1 objectClass: inetOrgPerson cn: user1 givenName: user1 sn: Somebodyson mail: user1@example.com
And this in backend2.ldif:
dn: ou=backend2 objectClass: top objectClass: organizationalUnit ou: backend2 dn: ou=people,ou=backend2 objectClass: top objectClass: organizationalUnit ou: people dn: cn=user2,ou=people,ou=backend2 objectClass: inetOrgPerson cn: user2 givenName: user2 sn: Somebodyson mail: user2@example.com
And then load the data into the backends:
ldapadd -x -H ldap://localhost -D cn=ldif-admin,ou=backend1 \ -w LDIF -f backend1.ldif
And:
ldapadd -x -H ldap://localhost -D cn=ldif-admin,ou=backend2 \ -w LDIF -f backend2.ldif
You can verify that the data loaded correctly by issuing a query to the backends. E.g.:
ldapsearch -x -H ldap://localhost -b ou=backend1 -LLL
This should give you something that looks very much like the contents of backend1.ldif. You can do the same thing for backend2.
Set up meta database
We're now going to configure OpenLDAP's meta backend to merge the two directory trees. Complete documentation for the meta backend can be found in the slapd-meta man page.
Put the following into a file called slapd-frontend.conf (we'll discuss the details in moment):
database meta suffix "dc=example,dc=com" uri "ldap://localhost/ou=backend1,dc=example,dc=com" suffixmassage "ou=backend1,dc=example,dc=com" "ou=backend1" uri "ldap://localhost/ou=backend2,dc=example,dc=com" suffixmassage "ou=backend2,dc=example,dc=com" "ou=backend2"
And then add to slapd.conf:
include /etc/openldap/slapd-frontend.conf
Restart slapd. Let's do a quick search to see exactly what we've accomplished:
$ ldapsearch -x -H 'ldap://localhost/' \ -b dc=example,dc=com objectclass=inetOrgPerson -LLL dn: cn=user1,ou=people,ou=backend1,dc=example,dc=com objectClass: inetOrgPerson cn: user1 givenName: user1 sn: Somebodyson mail: user1@example.com dn: cn=user2,ou=people,ou=backend2,dc=example,dc=com objectClass: inetOrgPerson cn: user2 givenName: user2 sn: Somebodyson mail: user2@example.com
As you can see from the output above, a single query is now returning results from both backends, merged into the dc=example,dc=com hierarchy.
A closer look
Let's take a closer look at the meta backend configuration.
database meta suffix "dc=example,dc=com"
The database statement begins a new database definition. The suffix statement identifies the namespace that will be served by this particular database.
Here is the proxy for backend1 (the entry for backend2 is virtually identical):
uri "ldap://localhost/ou=backend1,dc=example,dc=com" suffixmassage "ou=backend1,dc=example,dc=com" "ou=backend1"
The uri statement defines the host (and port) serving the target directory tree. The full syntax of the uri statement is described in the slapd-meta man page; what we have here is a very simple example. The naming context of the URI must fall within the namespace defined in the suffix statement at the beginning of the database definition.
The suffixmassage statement performs simple rewriting on distinguished names. It directs slapd to replace ou=backend1,dc=example,dc=com with ou=backend1 when communicating with the backend directory (and vice-versa).
You can perform simple rewriting of attribute and object classes with the map statement. For example, if backend1 used a sAMAccountName attribute and our application was expecting a uid attribute, we could add this after the suffixmassage statement:
map attribute uid sAMAccountName
Conclusion
The sample configuration files, data, and code referenced in this post are available online in a github repository:
http://github.com/larsks/OpenLDAP-Metadirectory-Example
I hope you've found this post useful, or at least informative. If you have any comments or questions regarding this post, please log them as issues on GitHub. This will make them easier for me to track.
1 comments: