Page tree
Viewable by the world
Skip to end of metadata
Go to start of metadata

This document has recently been updated to reflect recent changes to the enterprise directory.

Application handling of usernames and passwords, as well as direct access to the enterprise directory for authentication, will no longer be permitted after September 30, 2013 (at the earliest). After that date, all applications will be expected to be able to use our web SSO implementation for users to sign-in. Alternatives are still being considered for non-web applications.

Usage and Best Practices for the Laboratory LDAP Service

Background

Introduction

The IT Division provides the laboratory with a central "enterprise directory" service, which is made accessible to the community through the Lightweight Directory Access Protocol (LDAP). The directory currently provides information about members of the laboratory community and widely used authentication services. This document provides background on the enterprise directory, best practices for using the enterprise directory service, and common practices being used by members of the community.

Structure of the Directory

Directory servers are used to provide applications with access to information. The information in a typical directory server is represented in a tree-like hierarchy. Information is bundled into objects; user accounts, groups, DNS records, and other bundles of information are referred to as objects. As one progresses down the tree in the directory, objects are uniquely identified by a "distinguished name" or "DN". Distinguished names are the unique representation of an object in the directory. That is, attributes of an object or identifiers of a user, such as a username or an employee's employee number do not uniquely represent a person in the directory. While they may be – and in our case, are – unique to each top-level naming context, they are merely more data that is stored inside of an object.

The enterprise directory's main branch is dc=lbl,dc=gov, which represents, in directory-speak, that the namespace ("naming context") is rooted at the domain represented by domain component ("dc") lbl and domain component gov, or lbl.gov. You may be familiar with our previous hierarchy, located at o=lawrence berkeley laboratory,c=us. In mid-2012, we restructured the directory and its data to bring it more in line with contemporary practices.

Under dc=lbl,dc=gov, there are currently only two branches. The most important of these is ou=People, where we currently place all laboratory people. The other is ou=Groups, where we populate (or delegate population of) groups, so that applications and systems may have access to centralized group information.

Objects in the directory that represent employees and affiliates are all found in ou=People. These account objects are identified principally by their laboratory employee number (i.e., the number you'll find on your ID badge.) Therefore, the "Relative Distinguished Name" (RDN) of user objects is an attribute called lblEmpNum. The DN of a user account object, like any other object in the directory, is comprised of the RDN plus all of the other branches to the top of the tree. As a result, an object's DN looks like this: lblEmpNum=012345,ou=People,dc=lbl,dc=gov.

User Object Structure

Objects in LDAP consists of bundles of data, stored in "attributes." Acceptable attributes for any particular object derive from the types of an object. Types of an object are cumulative and are called "object classes," represented in the object's attributes by one or more "objectClass" attributes. The most common requirements for users in the laboratory community are the attributes described in the person, inetOrgPerson, lblPerson, and lblAccount object classes.

Key attributes spread among these objectclasses are:

  • lblEmpNum - a person's employee number, as generated by the HR system
  • lblAccountStatus - Will either be "Active" or "Inactive", to indicate the status of the user's account
  • uid - the user's uid. Note that this may potentially be multi-valued
  • mail - the email address used by systems; typically, this is the same as lblEPO, and it is the recommended attribute to reference
  • cn - a multi-valued attribute consisting of full names and alternatives for a person
  • telephoneNumber - a multi-valued list of a person's telephone numbers
  • lblPrimaryTelephoneNumber - among the list of a person's telephone numbers, the one the person has designated as the primary
  • lblLocation - a multi-valued list of a person's physical locations
  • lblPrimaryLocation - among t he list of a person's locations, the one the person has designated as the primary
  • givenName - first name
  • sn - surname

For more details on the structure of user objects, see User Object Creation Specification.

Authentication

Authentication in LDAP is performed by "binding" to the LDAP server using a DN (not a uid!) and password. If you are attempting to bind and you do not know the user's DN, you must first search for it using what you do know, which is typically a uid.

To be clearer on this, most applications that utilize the directory may take care of this step transparently, so that you don't even know what's happened. However, the process, as demonstrated in the source code examples below, is that the application first searches for the user's object based on at attribute that it's given. From there, it takes the user's DN and performs an LDAP BIND operation to authenticate.

Groups in the Enterprise Directory

The enterprise directory supports group objects. The group implementation supported by the enterprise directory is groupOfUniqueNames , as defined in RFC 2256. Members in groups of unique names are added directly to the group object using the uniqueMember attribute. All groups are stored in the Groups organizational unit. uniqueMember attributes contain full the DN for the desired group member.

Note that we have implemented the ability to delegate administration of group members. By specifying an owner attribute in the group object, groups may be owned by another account that exists in the enterprise directory, or by another group in the enterprise directory.

Requesting the Creation of a New Group

To request the creation of a new group, contact the IT Division Help Desk. Please be sure to specify the name of the group you wish to have created. If you also want management of your principle group deleted to an owner or another group, be sure to specify that information. If control is not delegated to you and you need to add users, please contact the Help Desk.

Please note that the names you request should follow this naming convention:
<Division abbreviation><Department/Group Abbreviation><Short, descriptive name>

For example, a group for the IT Division's Collaborative Services water polo team might be:
IT-CS-WaterPoloTeam

The DN for the IT-CS-WaterPoloTeam group would be cn=IT-CS-WaterPoloTeam,ou=Groups,dc=lbl,dc=gov.

Modifying a delegated group

If you are the owner of a delegated group, you may modify the membership of the group by adding or deleting uniqueMember attributes. You should be able to use any tool capable of modifying LDAP to make these changes. The most common tool, available on Macintosh OS X systems and most Linux systems in ldapmodify . If you prefer a graphical interface to modify directory information, you should be able to choose a graphical LDAP browser that works best for you. Neither the Identity Management team not the IT Division Help Desk have specific recommendations, nor can they support the wide array of graphical LDAP browsers. If you do want to use such a tool, some have reported success with Apache Directory Studio.

Here is a demonstration of how to add and remove users from a group using ldapmodify . First, you'll need an LDIF file containing the modification instructions. To add a user, create a file like this, which we'll call add-user.ldif:

dn: cn=IT-CS-WaterPoloTeam,ou=Groups,dc=lbl,dc=gov
changetype: modify
add: uniqueMember
uniqueMember: lblEmpNum=9876543,ou=People,dc=lbl,dc=gov

If you need to add more than one uniqueMember, you may add as many as you need.

Then, run ldapmodify :

ldapmodify -x -W -H ldaps://identity.lbl.gov -D 'lblempnum=0909091,ou=People,dc=lbl,dc=gov' -f add-user.ldif

To remove a user from a group, create an LDIF file, remove-user.ldif, for ldapmodify :

dn: cn=IT-CS-WaterPoloTeam,ou=Groups,dc=lbl,dc=gov
changetype: modify
delete: uniqueMember
uniqueMember: lblEmpNum=9876543,ou=People,dc=lbl,dc=gov

Then, run ldapmodify as before:

ldapmodify -x -W -H ldaps://identity.lbl.gov -D 'lblempnum=0909091,ou=People,dc=lbl,dc=gov' -f add-user.ldif

Best Practices

Join the [email protected] Mailing List

If you are going to be making production use of the LDAP service, it is important that you are kept abreast of upcoming maintenance, service changes, or other issues regarding the enterprise directory. From a management standpoint, it is also very useful if we are able to contact users of the service for feedback.

You can join the list at lists.lbl.gov.

If Authenticating, Use Encryption

If you intend to the use the LDAP service as an authentication service, you must encrypt your communications with the LDAP service. This is laboratory policy:

c.iv. Except in the case of anonymous FTP servers and embedded systems that use only cleartext passwords, any password sent over the network is encrypted through use of secure shell (SSH), secure sockets layer (SSL), or an equivalent protocol . . . .

Connecting to the Enterprise Directory

The enterprise directory is presented through a hardware load balancer. You should connect via LDAP to the enterprise directory at the URL ldaps://identity.lbl.gov.

If you are simply doing LDAP searches, you may connect to either ldap://identity.lbl.gov or ldaps://identity.lbl.gov.

If you are authenticating, you must connect to either ldaps://identity.lbl.gov.

Handling Credentials

When you operate a system that authenticates against the enterprise directory, that system has access to user credentials. You must be aware of this and take appropriate measures to safeguard those credentials. That includes encrypting the passage of those credentials from the user to your application, safe passage through your system, and encrypting communications between your application and the enterprise directory.

Under no circumstances should you log, cache, or otherwise store user credentials.

Uniqueness and Persistence

The only absolutely unique attributes used to identify objects in the enterprise directory are the DNs of the objects. User UIDs are subject to change, as are CNs. If your goal is to persistently link an account or object in your system to an object in the LDAP directory, you should, at this time, link to the DN of the user, or, at the very least, the user's lblEmpNum.

Note that it is possible that this will change in the future. We recommend that you design your application's usage of the enterprise directory such that you can update the appropriate linking information in the future.

Take Only What You Need

The enterprise directory is highly trafficked throughout every business day. If you are performing directory searches, it is advisable that you limit the list of attributes to be returned to your application to only those that you require for your application. This will speed your application's response, reduce bandwidth consumption by the directory servers, and increase the overall performance of the servers.

Future-Proofing

Consider designing your application so that its dependencies upon LDAP as an authentication mechanism, and particularly the structure of the data in the enterprise directory, are limited. In the near future, we will be limiting access to the ability to authenticate against the enterprise directory using LDAP. While we will be providing other mechanisms to accomplish authentication, those mechanisms will not utilize the LDAP protocol.

Common Practices

Computer login

Linux

Not sure if this all you need to do, but I changed these files to be able to use ldap with pam:

/etc/ldap.conf
base	ou=People,dc=lbl,dc=gov
uri ldaps://identity.lbl.gov
bind_policy	soft
pam_password md5
pam_password_prohibit_message	Please visit http://password.lbl.gov
nss_initgroups_ignoreusers	root,ldap
ldap_version	3
ssl on
/etc/openldap/ldap.conf
TLS_REQCERT     never
uri   ldaps://identity.lbl.gov
base  ou=People,dc=lbl,dc=gov

Then you need to tell pam to use ldap:

/etc/pam.d/common-auth and /etc/pam.d/common-auth-pc
auth    required        pam_env.so
auth    sufficient      pam_ldap.so
auth    required        pam_unix2.so  

If you want to only allow login via LDAP and not via local password for a certain group of people: create a new group, called for example "ldaponly" and add the following additional lines:

/etc/pam.d/common-auth and /etc/pam.d/common-auth-pc
auth    required        pam_env.so
auth    sufficient      pam_ldap.so
#people in group ldaponly can't log in via unix password
auth    [default=1 success=ignore] pam_succeed_if.so user notingroup ldaponly
auth    required        pam_unix2.so  
/etc/pam.d/common-password and /etc/pam.d/common-password-pc
password        requisite       pam_pwcheck.so  cracklib
password        sufficient      pam_ldap.so
password        required        pam_unix2.so    use_authtok
/etc/pam.d/common-session
session required        pam_limits.so
session required        pam_unix2.so
session optional        pam_umask.so
session optional        pam_ldap.so

Web Servers

Apache

Got LDAP working by changing the following:

Make sure that apache load these two modules: ldap authnz_ldap. For me (running openSUSE linux), I added those two names to the APACHE_MODULES in /etc/sysconfig/apache2.

Download the GoDaddy CA certificate for identity.lbl.gov server (use this link to download it https://certs.godaddy.com/anonymous/repository.seam;jsessionid=E9D1325F911F17C90B8C8BFEA9AAEB85.web001?streamfilename=gd_bundle.crt&actionMethod=anonymous%2Frepository.xhtml%3Arepository.streamFile%28%27%27%29&cid=386) and save it somewhere (I used /etc/cert/gd_bundle.crt)

Add this to your httpd.conf or some other file that does get included (this enables LDAP authorization for all webpages , that is everything under / )

apache configuration for ldap
LDAPTrustedGlobalCert CA_BASE64 /etc/cert/gd_bundle.crt

<Location / >
     AuthType Basic
     AuthName "Please, log in using your LDAP credentials"

     AuthLDAPURL "ldaps://identity.lbl.gov/ou=People,dc=lbl,dc=gov?uid"
     AuthBasicProvider ldap
     AuthzLDAPAuthoritative off

     require ldap-user <white space separated list of user names>

</Location>

Don't forget to restart apache after you made the changes.

Testing

One problem is that a webbrowser likes to remember the login/password you entered, so once you entered it, it won't ask you again. In case you are using firefox you can install the "web developer" add-on and then use "Miscellaneous->Clear Private Data->HTTP Authentication" to clear the login/password. This makes testing easier.

IIS

Programming Languages/Frameworks

As is so  often the case, there are many ways to accomplish these goals.  Here are a few  examples.  If you have examples in other languages or using specific frameworks for these or other languages, please feel free to contribute them.

PHP

$dn="ou=people,dc=lbl,dc=gov";
$filter = "(&(uid=$username)(lblAccountStatus=Active))";

// dn's not actually an attribute, but we want to to give it something
// to limit what it returns.
$attrs = array("dn");


$ldapconn = ldap_connect("ldaps://identity.lbl.gov") or fail();

if ($ldapconn) {
	$userdn="";

	$ldapbind = ldap_bind($ldapconn);

	// First, look up the user's DN
	if ($ldapbind) {
		$search_results = ldap_search($ldapconn, $dn, $filter, $attrs);
		if ($search_results) {
			$entry = ldap_first_entry($ldapconn, $search_results);
			$userdn = ldap_get_dn($ldapconn, $entry);
		} else {
			fail();
		}
	} else {
		fail();
	}

	// Now that we have the dn, let's we'll attempt to bind
	$ldapbind = ldap_bind($ldapconn, $userdn, $userpass);

	// verify binding
	if ($ldapbind) {
		pass();
	} else {
		fail();
	}
} else {
	fail();
}

Java

The most common library for accessing LDAP in Java is to use the Java Naming and Directory Interface (JNDI) interface and LDAP implementation.  JNDI's nice, because it ships with Java.  On the other hand, it's relatively clunky to use.  For most of my work, I've been using the UnboundID LDAP SDK for Java .  It's LDAP-specific and has a lot of useful utility functions.  Here's some code to perform an authentication like that above.

LDAPConnection c = null;

// Trust the remote cert, whatever it is.
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
try {
	c = new LDAPConnection(sslUtil.createSSLSocketFactory(), "ldapauth.lbl.gov", 636);
} catch (Exception e) {
	return "Unable to contact LDAP server.";
}

// Look up user
SearchResult searchResult = null;
String filter = "(&(uid=" + username + ")(lblAccountStatus=Active))";
try {
	searchResult = c.search("dc=lbl,dc=gov", SearchScope.SUB, filter, "dn");
	if (searchResult.getEntryCount() < 1) { throw new LDAPSearchException(searchResult); }
} catch (LDAPSearchException e) {
	return "No such user found in LDAP.";
}

// There shouldn't be more than one, and we'll be foolhardy
// and just take the first one.
List<SearchResultEntry> entries = searchResult.getSearchEntries();
String userDN = entries.get(0).getDN();

// Now bind as user
try {
	BindResult br = c.bind(userDN, currentPassword);
	if (br.getResultCode() != ResultCode.SUCCESS) { throw new LDAPException(br.getResultCode(), br.getDiagnosticMessage()); }
} catch (LDAPException e) {
	return "Username or password provided are invalid.";
}

Perl

The principal module for interfacing with LDAP using Perl is Net::LDAP