System Authentication using LDAP

Brad Marshall
brad.marshall@member.sage-au.org.au
Plugged In Software

Index
  1. Introduction
  2. What is LDAP
  3. Implementation
    1. Architecture
    2. Migration
    3. Server Configuration
    4. Client Configuration
  4. Usage
  5. Future Directions
  6. Conclusion
Appendixes

1.0 Introduction

As we started getting more users into our network, it became obvious that an authentication solution was required---all users had accounts on multiple machines, and were finding it difficult to change passwords on all the hosts easily. After looking around it became obvious that a centralised authentication scheme was necessary. There were a few options:

NIS was out of the question, as there were problems with Linux's implementation, and NIS+ had only started being worked on. After a web search to see what other products were available that solved this problem returned only alpha- or beta-quality software, the search narrowed to LDAP.

Further searches were promising, with many useful results, such as David Begley's Authentication Project Report1, and many others. However, the real find was PADL2 who have an open sourced PAM3 and NSS4 authentication module, as well as a commercial NIS / LDAP gateway5. (They also had some migration scripts6 that take existing flat files and create a basic LDAP schema.)

This solved the question of the client side - now remained the server side. There were a few options here:

All of our servers were run Linux, putting Microsoft and Novell out of the race. The OpenLDAP server seemed much better maintained than the UMICH software.

2.0 What is LDAP

LDAP (Lightweight Directory Access Protocol) is a directory service defined in RFC 177712, which runs over TCP/IP. It stores information, similar to a database, but contains more descriptive, attribute based data. The data is optimised for reading, so it doesn't handle frequently changing data well. The information is arranged in a hierarchical structure, which allows for separation of the data based on different criteria.

LDAP uses a client-server model, where one or more LDAP servers present a consistent view of the data---either by answering the request, or by pointing to a server that contains the data. Each entry is referenced by its distinguished name, or DN---see RFC 177913 for the full format. It is created by taking the name of the entry (or RDN - relative distinguished name), and tracing back through its ancestors, concatenating them together.

As well as providing ways of adding, deleting and modifying data, search filters are provided to search the LDAP database. These allow you to specify criteria for the attributes, and what part of the directory to check. See RFC 225414 for complete details about the search filters. LDAP implements client authentication and access control lists (ACLs) to prevent the data being both seen or modified by unwanted people.

LDIF (or LDAP Data Interchange Format) is a representation of the database in a text format. The format is line delimited, colon separated attribute value pairs, as follows:

dn: cn=bmarshal,ou=People,dc=pisoftware,dc=com
uid: bmarshal
cn: Brad Marshall
objectClass: account
objectClass: posixAccount
objectClass: top
....

This format is good for transferring data between LDAP servers, for backups, and for bulk changes to data.

3.0 Implementation

3.1 Architecture

We still had to decide how to use LDAP to solve our user authentication problems---would a given process query LDAP directly, or would some other process run to dump out the necessary authentication details to flat file (eg, /etc/passwd)?

The architecture we chose is pretty simple - applications on the machine pass their query through to either a PAM (Pluggable Authentication Modules) or NSS (Name Service Switch), which then queries the LDAP server. Additionally, it does not take advantage of all the other information that can be provided---the only files migrated initially were /etc/passwd and /etc/group.

3.2 Migration

PADL provides tools to help migrate from flat file databases to LDAP. These include the following:

Script Migrates
migrate_fstab.pl /etc/fstab
migrate_group.pl /etc/group
migrate_hosts.pl /etc/hosts
migrate_networks.pl /etc/networks
migrate_passwd.pl /etc/passwd
migrate_protocols.pl /etc/protocols
migrate_rpc.pl /etc/rpc
migrate_services.pl /etc/services

These scripts are called on the appropriate file in /etc in the following manner:

     # ./migrate_passwd.pl /etc/passwd ./passwd.ldif

Also provided are migration shell scripts that call the perl scripts for each file that it can migrate. They come in a version for when you have the LDAP database up and running, or online, and one for when the database is offline. The offline scripts use ldif2ldbm, and the online scripts use ldapadd.

See the README provided with the MigrationTools for more information on these tools.

3.3 Server Configuration

The Openldap server consists of two daemons - slapd, which is the stand alone ldap daemon, and slurpd, the stand alone replication daemon. The server is configured by slapd.conf, which is divided into two main sections - global configuration options, and zero or more database definitions and configuration options.

The configuration file begins with global options, which can optionally be overridden in a back end. Lines beginning with white space continue previous lines, and it uses standard #-style comments. For full details of all possible options, see slapd.conf(5), which is included in the distribution.

OpenLDAP has several installation options; the easiest is to down load a precompiled package for your operating system / distribution---there are packages available for Redhat, Debian and many others. If you can't find a precompiled package for your chosen operating system, it is a simple matter of downloading the source from the OpenLDAP website and compiling it. Further details about installation are left for the reader to discover---see the README distributed with the source for more details.

The root DN, which is specified in slapd.conf, is equivalent to the root account under unix, or the Administrator account under Windows. It is allowed to read and write to all entries in the database, so it is important to choose a secure password for it.

Now it's a simple matter of generating the data structure - or schema - for the server. This is mostly generated by PADL's Migration tools, all you need to decide on initially is the base DN. As per RFC237715, it should be set from the dns domain name of your location - ie, for Plugged In, we used dc=pisoftware,dc=com.

3.3.1 ACLs

The OpenLDAP server provides an access control syntax for protecting access to the various fields. This is very important in this case where we are storing passwords in an attribute, albeit in a crypted form.

access to attr=userpassword
    by self write
    by * read

access to *
    by self write
    by dn=".+" read
    by * read

As you can see from the slapd.conf extract above, the ACL syntax is quite easy. It shows how you specify access to an attribute, and the different ways of allowing reading and writing.

3.3.2 Replication

As mentioned previously, LDAP has a global directory view with it being possible for data to exist on multiple servers. This increases the availability of the system, by allowing queries to go to the server that is closest, reducing response time. One of the design decisions was that it was ok for different servers to have different, conflicting views of this data while replication was taking place, as long as it eventually came into sync.

The next obvious question is how the data is transferred between the servers. It happens by a process called replication, which is managed by slurpd, the replication daemon. After a modify operation, slapd writes the changes to a replication logfile, which slurpd notices and sends to the slave slapd, which then actually performs the modification on the slave database.

3.4 Client Configuration

The configuration on the client side for this is almost trivial - there are 3 locations that need things changed - /etc/pam.d/*, /etc/nsswitch.conf, and /etc/ldap.conf. There are also a few packages that are required to be installed - OpenLDAP client utilities, pam_ldap and nss_ldap.

3.4.1 Pam_ldap

PAM, or Pluggable Authentication Modules, frees applications from the requirement of dealing with authentication by providing an API that allows them to pass authentication requirements off to the library. The main advantage of this is it is easy to configure applications to use different authentication modules by simply modifying the configuration files. See pam(8) and associated man pages for more information.

Configuring PAM is reasonably straight forward - all that was necessary was to add a line to the pam configuration for each program that we desired to use LDAP.

Linux stores its PAM configuration in /etc/pam.d in a file named after the program. An example configuration for ssh follows:

#%PAM-1.0
auth       sufficient   /lib/security/pam_ldap.so
auth       required     /lib/security/pam_pwdb.so shadow try_first_pass
auth       required     /lib/security/pam_nologin.so
account    sufficient   /lib/security/pam_ldap.so
account    required     /lib/security/pam_pwdb.so
password   required     /lib/security/pam_cracklib.so
password   sufficient   /lib/security/pam_ldap.so
password   required     /lib/security/pam_pwdb.so shadow nullok use_authtok
session    sufficient   /lib/security/pam_ldap.so
session    required     /lib/security/pam_pwdb.so

3.4.2 Nss_ldap

Name Service Switch (or NSS) is used by various functions in the C library to control where information was looked for. GNU's C library 2.x (or glibc), which is used in Linux, is modelled after Sun's C library from Solaris 2. The configuration file, /etc/nsswitch.conf, specifies the sources for the ``databases'' and their lookup order.

To allow these databases to use LDAP, we require PADL's nss_ldap which gives us a source to use in nsswitch.conf that queries LDAP. To use this with user accounts and passwords from LDAP, use the following nsswitch.conf:

passwd:     ldap files nisplus nis
shadow:     ldap files nisplus nis
group:      ldap files nisplus nis

This configuration shows that LDAP is queried first, then it falls back to files, then NIS / NIS+. This allows for certain accounts to be local.

3.4.3 Ldap.conf

Both PAM and Name Service Switch need certain information before being able to query LDAP - namely the base DN, and the host. This information is contained in /etc/ldap.conf, as follows:

BASE       dc=pisoftware,dc=com
HOST       ldap
pam_crypt  local

The pam_crypt line specifies that the passwords are crypted locally before being transferred over the network rather than passing them in clear text.

4.0 Usage

OpenLDAP comes with many utilities for modifying the LDAP database, including ldapmodify, ldappasswd, ldapsearch, ldapadd, and ldapdelete, which do as their name suggests. Additionally, there are Perl modules (eg Net::LDAP, available from CPAN) which allow access to LDAP which facilitate writing of local programs.

To change passwords, it is simply a matter of running the following command:

    $ ldappasswd -W -D 'cn=bmarshal,ou=People,dc=pisoftware,dc=com' 'uid=bmarshal'

This command binds as the user specified, asks for a password, then applies the search filter 'uid=bmarshal', which will find the appropriate account then changes the password.

For more generic modifications, or for bulk data changes ldapmodify is more useful. It is used in the following manner:

    $ ldapmodify -W -r -D "cn=Manager,dc=pisoftware,dc=com" < bmarshal.ldif

As above, this binds as the given distinguished name, asks for a password, and then replaces the entries with the data in the ldif file.

To view the data in LDIF format, for example for doing backups, or creating a skeleton for bulk modifications, ldapsearch is used as follows:

   $ ldapsearch -L -W -D "cn=Manager,dc=pisoftware,dc=com" 'uid=*'

This binds as the manager, prompts for the password, outputs in LDIF format, and applies the search filter (in this case 'uid=*').

If you need more flexibility than this, the Perl module Net::LDAP allows you to use the full power of Perl's text processing with the queries. It is certain possible, in fact the author has, to write scripts that replicate the standard adduser etc functionality in Perl.

5.0 Future Directions

LDAP can be used for much more than simple user authentication and this allows for much future expansion room. For sites with multiple locations, the ability to allow each location to administer its authentication by running a LDAP server that replicates back to the ``master'' would be a good way of allowing local administrators to control their part of the network, yet allow the users access from the other locations, if necessary.

Perhaps the most interesting possibility is that of LDAP routing of email, which the latest (8.10.x) version of Sendmail has just started supporting. This would allow much easier additions of email accounts, and the ability to allow others to administer it. Apache can also use LDAP for authentication - this would simplify restricting access to certain areas of the company intranet, for example. Another possibility is to use LDAP for authentication for Squid, which would ensure only local users could use the proxy. LDAP can also be used as a company wide contact database as well, as there are many APIs available for a wide variety of languages.

6.0 Conclusion

An important part of this migration was to ensure that it didn't simply trade off the problems - that is, make creation of accounts easier while making some other facet much difficult. While there has been some learning curve, it has generally been worth while, as the usefulness of creating accounts in one location has definitely outweighed any problems that have occurred.



Example Configuration Files

/etc/openldap/slapd.conf

#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include         /etc/openldap/slapd.at.conf
include         /etc/openldap/slapd.oc.conf
schemacheck     off

pidfile         /var/run/slapd.pid
argsfile        /var/run/slapd.args

defaultaccess read

access to attr=userpassword
    by self write
    by * read

access to *
    by self write
    by dn=".+" read
    by * read

#######################################################################
# ldbm database definitions
#######################################################################

database        ldbm
suffix          "dc=pisoftware, dc=com"
rootdn          "cn=Manager, dc=pisoftware, dc=com"
rootpw          {crypt}sefjKaLm7zybE
replica host=cox.staff.plugged.com.au:389
    binddn="cn=Manager,dc=pisoftware,dc=com"
    bindmethod=simple credentials=secret
replogfile /var/lib/openldap/replication.log
# cleartext passwords, especially for the rootdn, should
# be avoid.  See slapd.conf(5) for details.
directory       /var/lib/openldap/



Users LDIF extract

dn: uid=bmarshal,ou=People,dc=pisoftware,dc=com
uid: bmarshal
cn: Brad Marshall
objectclass: account
objectclass: posixAccount
objectclass: top
loginshell: /bin/bash
uidnumber: 500
gidnumber: 120
homedirectory: /mnt/home/bmarshal
gecos: Brad Marshall,,,,
userpassword: {crypt}lnbDaz4nb9aQp



/etc/pam.d/ssh

#%PAM-1.0
auth       sufficient   /lib/security/pam_ldap.so
auth       required     /lib/security/pam_pwdb.so shadow
auth       required     /lib/security/pam_nologin.so
account    sufficient   /lib/security/pam_ldap.so
account    required     /lib/security/pam_pwdb.so
password   required     /lib/security/pam_cracklib.so
password   sufficient   /lib/security/pam_ldap.so
password   required     /lib/security/pam_pwdb.so shadow nullok use_authtok
session    sufficient   /lib/security/pam_ldap.so
session    required     /lib/security/pam_pwdb.so


/etc/nsswitch.conf extract

passwd:     ldap files nisplus nis
shadow:     ldap files nisplus nis
group:      ldap files nisplus nis


/etc/ldap.conf

BASE      dc=pisoftware,dc=com
HOST      ldap
pam_crypt local


References

[1] David Begley, Authentication Project Report
QUESTnet99, http://www.nepean.uws.edu.au/users/david/qn99/

[2] PADL,
http://www.padl.com/

[3] PADL's pam_ldap,
http://www.padl.com/pam_ldap.html

[4] PADL's nss_ldap,
http://www.padl.com/nss_ldap.html

[5] PADL's Ypldapd,
http://www.padl.com/ldap-nis_gateway.html

[6] PADL's Migration scripts,
http://www.padl.com/tools.html

[7] Netscape Directory Server,
http://www.iplanet.com/products/infrastructure/dir_security/dir_srvr/index.html

[8] Microsoft Active Directory Server,
http://www.microsoft.com/

[9] Novell NDS,
http://www.novell.com/products/nds/ldap.html

[10] University of Michigan LDAP Server,
http://www.umich.edu/~dirsvcs/ldap/

[11] Openldap,
http://www.openldap.org/

[12] RFC 1777 - Lightweight Directory Access Protocol,
http://www.ietf.org/rfc/rfc1777.txt

[13] RFC 1779 - A String Representation of Distinguished Names,
http://www.ietf.org/rfc/rfc1779.txt

[14] RFC 2254 - The String Representation of LDAP Search Filters,
http://www.ietf.org/rfc/rfc2254.txt

[15] RFC 2377 - Naming Plan for Internet Directory-Enabled Applications,
http://www.ietf.org/rfc/rfc2377.txt


Other Resources

RFC 2307 - An Approach for Using LDAP as a Network Information Service,
http://www.ietf.org/rfc/rfc2307.txt

The SLAPD and SLURPD Administrators Guide,
http://www.umich.edu/~dirsvcs/ldap/doc/guides/slapd/

The Linux-PAM System Administrators' Guide,
http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/pam.html

A System Administrator's View of LDAP,
http://people.netscape.com/bjm/whyLDAP.html

Linux Directory Services,
http://www.rage.net/ldap/