Paranoid Penguin - Authenticate with LDAP
We've done everything we need (on the server end) for TLS encryption to work. Only one detail to consider remains. Should we force the use of TLS for all LDAP requests from the network or keep it optional?
By default, slapd listens for LDAP connections on TCP port 389 and accepts either clear text or TLS-encrypted connections on that port. However, if you're using LDAP for authentication, you probably don't want to make TLS optional. A better approach in that case is to have slapd listen for clear text-only LDAP connections on TCP 389 on the loopback interface only and have slapd listen for TLS-enabled (ldaps) connections on TCP 636 (the standard port for ldaps) for all other local addresses.
This behavior is controlled by slapd's startup option -h, used to specify the URLs to which slapd will respond. For example, slapd -h ldap://127.0.0.1/ ldaps:/// tells slapd to listen on the loopback address (127.0.0.1) for ldap connections to the default ldap port (TCP 389) and to listen on all local addresses for ldaps connections to the default ldaps port (TCP 636).
If you run Red Hat 7.3 or later, this actually is the default behavior: /etc/init.d/ldap checks /etc/openldap/slapd.conf for TLS configuration information and if it finds it, sets the -h option exactly like the one in the previous paragraph's example. If you run SuSE 8.1 or later, you can achieve the same thing by editing /etc/sysconfig/openldap such that the value for OPENLDAP_START_LDAPS is yes, and then editing /etc/init.d/openldap to set the value for SLAPD_URLS to ldap://127.0.0.1. This variable is defined early in the script, with a default value of ldap:///.
Other Linux distributions may have different ways of passing startup options like -h to slapd, but hopefully by now you get the idea and can figure out how to make slapd's listening ports work the way you want.
So, does our TLS-enabled LDAP server actually work? A quick local test will tell us. First, start LDAP:
bash-$ /etc/init.d/ldap start
Next, use the ldapsearch command to do a simple query via loopback:
bash-$ ldapsearch -x -H ldaps://localhost/ \ -b 'dc=wiremonkeys,dc=org' '(objectclass=*)'
Naturally, your own LDAP server will have a different base DN than dc=wiremonkeys,dc=org. If you prefer, you can run this last command from a remote host, specifying the LDAP server's name or IP address in place of localhost in the -h option. If the LDAP server returns a dump of the LDAP database, which actually is empty at this point, followed by the string result: 0 Success, your test has succeeded.
If you get an error about an invalid certificate, try adding this line to your client system's /etc/openldap/ldap.conf file:
This allows your OpenLDAP or OpenLDAP-based client software (for example, gq) to accept self-signed server certificates.
You're almost ready to start populating the LDAP database. On the one hand, tools like gq and ldapbrowser can reduce the ugliness and toil of LDAP data entry and administration greatly. But to get to the point where these tools can be used, you first have to settle on a combination of LDAP schema, and this is where things can get unpleasant.
For purposes of this discussion, two types of LDAP data matter, attributes and object classes. Attributes are the things that make up a record. A user's phone number, e-mail address, nicknames and so on are all attributes. You can use as many or as few attributes in your LDAP database as you like. You even can invent your own. But for a record to contain a given attribute, that record must be associated with the proper object class.
An object class describes the type of record you're trying to build. It defines which attributes are mandatory for each record and which attributes are optional. You might think, “that's easy, then I simply need to choose an object type that provides the group of attributes I want to store for my users and associate each user record with that object class.” If you thought that, you'd be only partly right.
In practice, you'll probably want to use attributes from a variety of object classes. “Well, fine”, you think, “I'll just specify multiple object classes in each user record and get my full complement of attributes à la carte. Whatever.” Right again, but there's more to it than that. Chances are the object classes that provide the attributes you need are spread across a number of schema files (these are text files, each of which contains a list of attributes and the object classes that reference them). So, even before you can begin composing your user records, each containing a stack of object class statements and a bigger stack of attribute settings, first you need to make sure /etc/openldap/slapd.conf contains include statements for all the schema files you need, usually present in /etc/openldap/schema.
For example, suppose that because we're going to use our sample LDAP server for authentication, we want to make sure that no matter what, we're able to specify the attributes userid and userPassword. Doing a quick grep of the files in /etc/openldap/schema shows that uid appears in the file inetorgperson.schema in the MAY list (of allowed attributes) for the object class inetOrgPerson. This has two ramifications. First, /etc/openldap/slapd.conf needs to contain this line: