By following the steps outlined below you will be able to:
- Install and setup the IBM Tivoli Directory Server on Windows.
- Add, modify and delete LDAP entries and attributes in the tree using a LDAP browser and the command line.
- Understand the contents of a LDIF (Lightweight Data Interchange Format) file.
- Write a simple Java program to access the information stored in your LDAP server.
LDAP is used to store relatively static information. The phrase "write once read many times" describes the best use of LDAP. LDAP is structured as a directory optimized for lookups. Its tree structure is useful for conceptualizing organizational structures.
Each entry in the LDAP tree is composed of one or more object classes. Every object class has attributes stored in name value pairs. An example of an LDAP attribute name value pair is uid=c0001.
The LDAP schema specifies:
- The object classes and names used for the entries in the LDAP tree.
- The names of the attributes and the types of operations supported by each attribute.
The structure of your LDAP tree will be based on a schema.
Figure 1. General structure of an LDAP tree
An entry can be located in LDAP by specifying either the distinguished name (dn) or the relative distinguished name (rdn). The dn is the full LDAP tree path whereas the rdn is just a unique identifier for a specific entry in the tree.
One way to easily conceptualize the difference between the dn and rdn is to think of the difference between directions and an address. The dn would be equivalent to giving directions from the airport to a hotel. The rdn would just be the address of the hotel. Similar to an address a rdn must be unique. It would be very difficult to find your hotel on a city map if its address was not unique.
For your project, the LDAP setup will be relatively simple—a linear list of employee entries.
Build the distinguished names for the employees using the uid attribute in the distinguished name (dn). For example, the dn for the manager Barbara Jensen is uid=c0001,ou=people,dc=ibm,dc=com. The value for the uid is a unique company id. By using a company id instead of the name you can more easily maintain your LDAP. For example, if Barbara gets married and changes her name to Barbara Jensen-Howard, you only need to change two attributes: cn=Barbara Jensen-Howard and sn=Jensen-Howard. If you used cn=Barbara Jensen,ou=people,dc=ibm,dc=com for the distinguished name then you would have to delete the entire LDAP entry and regenerate it as cn=Barbara Jensen-Howard,ou=people,dc=ibm,dc=com. Also consider the case where you have two employees with the same name. The use of a company id prevents name collisions in your LDAP tree.
Below is a table of employee names in the Billing Department and their corresponding name found in LDAP. The second column lists the employee's dn. The third column shows the employee's rdn
Table 1. Employees distinguished and relative distinguished names in LDAP
| Employee Name |
Distinguished Name (dn) in LDAP
|
Relative Distinguished Name (rdn) in LDAP
|
| Barbara Jensen | uid=c0001,ou=people,dc=ibm,dc=com | uid=c0001 |
| Stu Pretzman | uid=c0002,ou=people,dc=ibm,dc=com | uid=c0002 |
| Varad Singh | uid=c0003,ou=people,dc=ibm,dc=com | uid=c0003 |
| Steven Moyer | uid=c0004,ou=people,dc=ibm,dc=com | uid=c0004 |
| Carla VanDyke | uid=c0005,ou=people,dc=ibm,dc=com | uid=c0005 |
| Billy Parker | uid=c0006,ou=people,dc=ibm,dc=com | uid=c0006 |
Barbara Jensen is the manager of the Billing Department. The other five entries are her employees. Each entry in LDAP contains useful employee information such as a telephone number, mailing address and email.
You will use these employee records from the Billing Department to populate the LDAP tree. During the course of the article you will add, modify and delete LDAP entries for these employee records.
Setup of IBM Tivoli Directory Server
In order to learn about LDAP, it is useful to have an LDAP server installed on your computer. The following steps demonstrate how to install the IBM Tivoli Directory Server on Windows.
Download IBM Tivoli Directory Server for Windows from IBM.
Unzip the install zip file to a temp directory. In the ismp folder, double-click the setup.exe icon to launch the wizard. Choose English as the install wizard language. Accept the license agreement.
Figure 2. Welcome Screen
Choose English as the language. On the subsequent panels, you will be prompted for installation of the directory server components.
Figure 3. Language
If you already have DB2, the GSKit or the WebSphere Application Server - Express edition installed, then the wizard will detect it. However, DB2 must be installed on the same server as your LDAP server. Otherwise you will have to install these components. Install the Web Administration Tool and the IBM WebSphere Application Server – Express although you will not need them to complete the exercise in this article. Click Next.
Figure 4. Features
The LDAP server install will commence. When you get to this panel, click the Next button until you get to the restart your computer panel.
Figure 5. Additional screens
On the penultimate panel, the setup will ask you to restart your computer. Select the Yes radio button. Click Next.
Figure 6. Restart computer
Click the Finish button. Your computer will restart.
Figure 7. Required restart of computer
After your computer restarts, you should login again using the same user id. The IBM Tivoli Directory Server Configuration Tool will automatically launch.
Figure 8. Directory Server Configuration Tool
Click on the Administrator DN/password task. Set the administrator id to cn=root Enter ibm4root for the password. Click on the OK button.
Figure 9. Change administrator DN and password
The administrator id cn=root is the master LDAP user id and should only be used for tasks such as modifications to the LDAP tree. It should never be given to LDAP users.
Then choose the Configure database task. Choose Create a new database. Click on the Next button. Enter a user id and password for the database. Click Next. Name the database pcldap. Make sure the default (UTF-8/UCS-2) code set is selected. Click Next. Select a drive letter. Click the Next button and then Finish. After the database installation is complete, press the Close button.
Figure 10. Configure database
Select Manage suffixes in the task bar. Enter dc=ibm, dc=com. This is suffix of the schema. Press the Add button. You will designate dc=ibm,dc=com as the base suffix for your LDAP group. Click OK to save the changes. In the future you could insert additional base suffixes.
Figure 11. Manage suffixes
At this point you will populate your LDAP with the employee entries. Select Import LDIF data. A LDIF (Lightweight Directory Interchange Format) file is an ASCII file format used to load and save the data contained in a LDAP tree. In addition to containing the actual data entries, an LDIF file will also contain the objects used to form the schema.
Browse to the setup.ldif file. Select the Remove trailing spaces in Standard Import or Bulkload check box. This is a Standard import. Click the Import button. After the import completes, press Clear results. Then press the Close button. The LDAP server cannot be running when you are importing LDIF data using the Directory Configuration Tool.
Figure 12. Import LDIF (Lightweight Directory Interchange Format) data
Close the Directory Server Configuration Tool by selecting in the menu bar File => Close.
Before you start the LDAP server you must have a defined IP address for your server. If your server has a static IP address you can ignore this step. If you are not using a static IP address then you have two options. For either option, you must know the name of your server. Enter hostname from the command line. To use the first option, launch a command prompt and enter ipconfig.
Figure 13. Command prompt - ipconfig output
Enter this IP address in your <window os directory>\system32\drivers\etc\hosts file. Restart your server. This will allow your LDAP server to run and other servers to connect your LDAP as long as that dynamic IP address remains bound to your computer. Remember to remove this entry from the hosts file after you are done with your testing. If you are just using your LDAP server for local development, then you can implement the second option. Just add an alias for your server name to local host address 127.0.0.1. In the <window os directory>\system32\drivers\etc\hosts file, add the following entry. This local host alias can remain in your hosts file.
| # for LDAP testing | |
| 127.0.0.1 | <your server name goes here> |
If you do not heed this warning you will forever be plagued with bind errors and the LDAP server will never start.
You can start the LDAP server from the command line using the <ldapinstalldir>\bin\ibmslapd.exe command or use the Services panel. The LDAP server is the IBM Tivoli Directory Server V5.2 entry shown below. For some configuration changes using the IBM Tivoli Directory Server Configuration Tool you must stop the Directory Server. The Admin Daemon should never be stopped.
Figure 14. Admin Daemon is for LDAP administration; Directory Server is the LDAP server.
The Tivoli Directory Server has a web client that can be run from the WebSphere Express Server. The war file can also be installed on a WebSphere server.
Adding an entry from the command line
IBM hires a new employee named Susan Baker. Although you could use the LDAP browser, an employee entry has too many attributes. You can add the employee using the ldapadd command and the addemployee.ldif file. In the <ldapserver directory>\bin directory, enter on the command line:
ldapadd -h ldap://<ldaphostname> -D "cn=root" -w ibm4root -f <ldif_directory_path>addemployee.ldif |
The LDIF file used to add the employee Susan Baker is shown below.
Listing 1. addemployee.ldif file
# this is a comment the # must be in FIRST column
version: 1
## ------------------------------------------------------------------------------------
## ePerson is an AUXILLIARY objectclass from IBM and must
## have a STRUCTURAL objectclass (inetOrgPerson in this case)
##
## this is an entry sequence and is preceded by a blank line
dn: uid=c0007,ou=people,dc=ibm,dc=com
objectclass: ePerson
objectclass: inetOrgPerson
cn: Susan Baker
sn: Baker
givenName: Susan
initials: SAB
title: Billing worker
uid: c0007
userpassword: hellome1
mail: sbaker@ibm.com
mail: susan.baker@ibm.com
homephone: +1 999 111 3425
telephoneNumber: +1 999 555 1262
facsimileTelephoneNumber: +1 999 555 1292
mobile: +1 999 555 141
roomNumber: 0220
carLicense: 6ABDE3
o: ibm
ou: Billing
departmentNumber: 2604
registeredAddress: 348 Parkside Dr Anywhere, IL 23480
postalAddress: 347 Parkside Dr. Anywhere, IL 23480
employeeNumber: 9899
employeeType: full time
preferredLanguage: en
labeledURI: http://www-1.ibm.com/servers/eserver/iseries/ldap/schema/
|
There are several benefits to using the command line for loading LDIF files versus the Tivoli Directory Server Configuration Tool. The command line is much faster than the graphical user interface. You also do not have to stop the LDAP server to load the LDIF file. Stopping a production LDAP server may cause some excitement amongst the users. After running ldapadd you must refresh the directory tree in the LDAP browser if you want to see the updates. Select the dc=ibm,dc=com entry and press the Refresh icon.
Viewing an Entry from the Command line
View your update using ldapsearch. From a command line enter:
ldapsearch -h ldap://<ldaphostname> -D "cn=root" -w ibm4root -b "ou=people,dc=ibm,dc=com" "uid=c0007" |
The –b indicates where you want to start your search of the tree. Since you added the entry for Susan Baker at ou=people,dc=ibm,dc=com you begin the search at that level in the tree. You can also search the entire tree dc=ibm,dc=com for Susan’s record using:
ldapsearch -h ldap://<ldaphostname> -D "cn=root" -w ibm4root -b "dc=ibm,dc=com" "uid=c0007" |
Deleting an Entry from the Command line
Employee Billy Parker spent several days trying to install the IBM Tivoli Directory Server on a server that did not have a static IP address and he did not update his hosts file. His manager, Barbara, discovered his incompetence and Billy is fired. You remove him from the company LDAP using the ldapdelete command.
ldapdelete -h ldap://<ldaphostname> -D "cn=root" -w ibm4root "uid=c0006,ou=people,dc=ibm,dc=com" |
Modifying an Entry from the Command line
Billing Department manager Barbara Jensen moves to a new house and her new home phone number also changes to +1 999 222 3423. She also adds another telephone line at work, +1 999 243 2312, and places her picture on the company’s web site. You update her employee record using the following line.
ldapadd -h ldap://<ldaphostname> -D "cn=root" -w ibm4root -f <ldif_directory_path>modifyemployee.ldif |
The LDIF file for modifying Barbara Jensen’s entry is shown below. The – in the file allows multiple attribute updates.
Listing 2. modifyemployee.ldif file
# this is a comment the # must be in first column
version: 1
## -----------------------------------------------------------
## ePerson is an AUXILLIARY objectclass from IBM and must
## have a STRUCTURAL objectclass (inetOrgPerson in this case)
## - Modify the Barbara Jensen entry setup in setup.ldif.
#
# Change her telephones and add a jpg.
#
## this is an entry sequence and is preceded by a blank line
dn: uid=c0001,ou=people,dc=ibm,dc=com
changetype: modify
add: telephonenumber +1 999 243 2312
telephonenumber: +1 999 243 2312
-
replace: homephone
homephone: +1 999 222 3423
-
add: jpegphoto
jpegphoto: http://www.ibm.com/photo/babs.jpg
|
Format of the Command line Operations
The general format of the LDAP commands discussed is shown in the table below.
Table 2. LDAP command line operations
| Operation | Format |
| Add or Modify | ldapadd -h ldap://<ldaphostname> -D <root DN> -w <root password> -f <ldif_file_path> |
| Search | ldapsearch -h ldap://<ldaphostname> -D <root DN> -w <root password> -b <base search DN> <search DN> |
| Delete | ldapdelete -h ldap://<ldaphostname> -D <root DN> -w <root password> <DN to be deleted> |
Displaying the LDAP data from Internet Explorer
An interesting feature associated with Internet Explorer is an Address Book that ties into your LDAP server. Launch Internet Explorer and type the following URL in your address bar.
ldap://<ldaphostname>/ou=people,dc=ibm,dc=com??one?(objectclass=*) |
The Address Book program in Internet Explorer will launch allowing you to view the employees in your address book.
Figure 15. Internet Explorer Address
Overview of the LDIF File Format
The Lightweight Data Interchange Format (LDIF) is used to represent LDAP entries in a simple text format. This section provides a brief description of the LDIF entry format.
The basic form of an entry is shown below. An entry sequence is preceded by a blank line. A comment is denoted by a # in the first column. Also a space must follow the : in an attribute.
# comment line
|
dn: <distinguished name>
|
<attrdesc>: <attrvalue>
|
<attrdesc>: <attrvalue>
|
<attrdesc>: <attrvalue>
|
...
|
Review the addemployee.ldif file for Susan Baker.
Listing 3. addemployee.ldif file
# this is a comment the # must be in FIRST column
version: 1
## -----------------------------------------------------------------
## ePerson is an AUXILLIARY objectclass from IBM and must
## have a STRUCTURAL objectclass (inetOrgPerson in this case)
##
## this is an entry sequence and is preceded by a blank line
dn: uid=c0007,ou=people,dc=ibm,dc=com
objectclass: ePerson
objectclass: inetOrgPerson
cn: Susan Baker
sn: Baker
givenName: Susan
initials: SAB
title: Billing worker
uid: c0007
userpassword: hellome1
mail: sbaker@ibm.com
mail: susan.baker@ibm.com
homephone: +1 999 111 3425
telephoneNumber: +1 999 555 1262
facsimileTelephoneNumber: +1 999 555 1292
mobile: +1 999 555 141
roomNumber: 0220
carLicense: 6ABDE3
o: ibm
ou: Billing
departmentNumber: 2604
registeredAddress: 348 Parkside Dr Anywhere, IL 23480
postalAddress: 347 Parkside Dr. Anywhere, IL 23480
employeeNumber: 9899
employeeType: full time
preferredLanguage: en
labeledURI: http://www-1.ibm.com/servers/eserver/iseries/ldap/schema/
|
The lines starting with a # character are comments. You can have multiple # characters but they must be followed by a space. The version number is so you can keep track of changes to this file. The first line of the entry sequence is the distinguished name (dn). The uid attribute is the key used to locate this entry in the tree. Hence the relative distinguished name (rdn) for this entry would be uid=c0007. The entry for Susan Baker is located under the people organization unit (ou). The people organizational unit is located under the base dc=ibm,dc=com entry.
The next two lines define the object class for the entry containing Susan Baker’s information. The base LDAP schemas provide you with the inetOrgPerson object for storing information about a person. However, it lacks many attributes needed in today’s business environment. For example, inetOrgPerson does not have a mobile telephone attribute. The IBM Tivoli Directory Server provides an auxiliary class, ePerson, which has many useful attributes such as mobile and postalAddress. A full list of all the schemas provided by IBM can be downloaded from the Tivoli schema repository.
The remainder of the LDIF file contains various personal attributes for Susan Baker.
Accessing LDAP Data Using Java
Java provides an excellent framework for accessing the data stored in LDAP. The procedure is similar to other types of access to a remote resource. You open a connection to the LDAP server. You perform the operation such as read, write or delete. You close the connection.
The Java Naming and Directory Interface (JNDI) is used to access an LDAP server. A DirContext object is the conduit for your Java program to attach to LDAP. Using the DirContext is simple. You construct a Properties object with the URL of the LDAP server, the root user name and password and several Java housekeeping items (context factory, security principal and referral). This Properties object is passed into the constructor for the DirContext.
All of the snippets mentioned below refer to source code in the TestLDAP.java program.
//-------------------------------------------------- // Set up the environment for creating the initial context //-------------------------------------------------- Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); props.setProperty(Context.PROVIDER_URL, "ldap://<lpadserver>:389"); props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url"); props.setProperty(Context.REFERRAL, "ignore"); props.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); // -------------------------------------------------- //specify the root username // -------------------------------------------------- props.setProperty(Context.SECURITY_PRINCIPAL, "cn=root"); //-------------------------------------------------- //specify the root password // -------------------------------------------------- props.setProperty(Context.SECURITY_CREDENTIALS, "ibm4root"); //-------------------------------------------------- // Get the environment properties (props) for creating initial // context and specifying LDAP service provider parameters. //-------------------------------------------------- DirContext ctx = new InitialDirContext(props); |
Once you have established a connection to the LDAP server, you can search the tree for either a matching entry or attributes.
First you need to setup some constraints for your search. In the TestLDAP.java program, the constraints are all set to SUBTREE_SCOPE.
SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); |
Below is a table of all the scope parameter variables supported by setSearchScope().
Table 3. setSearchScope() parameters
Values for setSearchScope()
| What it does |
SUBTREE_SCOPE
| Starts at the base entry and searches the base entry and everything below it. This is the slowest and most extensive search. |
ONELEVEL_SCOPE
| Searches on the entries below the base entry. |
OBJECT_SCOPE
| Searches only the base entry. This is the fastest and least extensive search. |
The next step is to configure the entity attributes that will be filled in as a result of the search. Since all the interesting entities belong to the ePerson schema, the returning attributes field is set to an array of all the possible ePerson attributes.
constraints.setReturningAttributes(EPERSON_ATTRIBUTE_LIST); |
Next is the search. The BASE_SEARCH define is just set to ou=people,dc=ibm,dc=com, which is the parent of the tree of employees. Different formats of search filters are also specified in the source.
NamingEnumeration results = ctx.search(BASE_SEARCH, filter, constraints); |
The search filter can have any of the following formats.
Table 4. Search filters
| Symbol | Filter | Example | Example matches |
~=
| Approximate |
sn~=Jensen
| Any variations in Jensen |
=
| Equality |
sn=Jensen
| Only matches surname Jensen. This is the most common search format. |
>
| Greater Than |
sn>Jensen
| Any surname that alphabetically follows Jensen. e.g. Pretzman. |
>=
| Greater Than or Equal |
sn>=Jensen
| Surname matching Jensen or following it alphabetically. |
<
| Less Than |
sn<Jensen
| Surname that precedes Jensen. e.g. Baker |
<=
| Less Than or Equal |
sn<=Jensen
| Surname matching or preceding Jensen. |
=*
| Presence of Attribute |
sn=*
| Any entry that contains a sn attribute. |
*
| Wildcard String Match |
sn=Jen*n
| Any matching string, substring, or superstring that matches Jensen. |
&
| And |
(&(sn=Jensen) (initials=BJJ))
| Any entry that matches all the conditions. In this case, surname of Jensen with the initials of BJJ. |
|
| Or |
(|(sn=Jensen) (initials=BJJ))
| Any entry that matches either condition. The surname of Jensen or the initials of BJJ |
!
| Not |
(sn=Jensen)
| The negative of the enclosed condition. All surnames except Jensen. |
After the search, the program iterates through the result set using the NamingEnumeration returned by the context. Each attribute is printed out.
if (results.hasMoreElements())
{
System.out.println(" has returned results..\n");
bFoundIt = true;
// Since UID is unique across the entire directory,
// the search results should contain only one entry.
SearchResult sr = (SearchResult) results.next();
// ---------------------------------------------
// Get all available attribute types and their associated
// values and print them out.
// ---------------------------------------------
printAttributes(sr.getAttributes());
}
else
{
System.out.println(" has returned no results..");
}
|
The code for updating the attributes of an entry is similar to the search. First the program must find the entry to be updated in the same search manner as described above. At that point the attributes for an entry may be changed, added or removed. The ModificationItem object is used to alter the attribute represented by the BasicAttribute object.
// Get all available attribute types and their associated
// values.
Attributes attributes = sr.getAttributes();
// Specify the changes to make
ModificationItem[] mods = new ModificationItem[1];
// -------------------------------------------
// remove the attribute
// -------------------------------------------
if (bRemoveAttribute) {
// eliminate the attribute
if (null != attributes.get(attrName)) {
mods[0] = new ModificationItem(
DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute(attrName, attrVal));
}
}
// -------------------------------------------
// replace or add the attribute
// -------------------------------------------
else {
// do a replace of the attribute
if (null != attributes.get(attrName)) {
mods[0] = new ModificationItem(
DirContext.REPLACE_ATTRIBUTE,
new BasicAttribute(attrName, attrVal));
}
// add the attribute
else {
mods[0] = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute(
attrName, attrVal));
}
}
ctx.modifyAttributes(updateDN + "," + BASE_SEARCH, mods);
|
After performing any operation to the LDAP server you must close the connection. By placing the close call in a finally block you are guaranteed that the LDAP connection will always be closed.
//always close the directory context when you are done
finally {
try {
if (null != ctx)
ctx.close();
} catch (Exception e2) {
}
}
|
To run the LDAP sample program, enter java -jar createLDAP.jar on a command line.
If you have made it to this point you should have a working knowledge of LDAP. You understand the concept of distinguished and relative distinguished names. You know the steps to install the IBM Tivoli Directory Server. You can add, modify or delete LDAP entries using the LDAP Browser and from the command line. You understand the format of an LDIF file. Finally you have learned how to use JNDI to programmatically access your LDAP server.
Learn
-
The IBM Tivoli Directory Server for Windows is available from IBM.
-
The IBM Tivoli schema web site contains information about all the schemas included in the IBM Tivoli Directory Server.
-
The IBM Redbook Understanding LDAP - Design and Implementation can provide you with some practical guidance.
-
To learn more about the exciting world of LDAP become a LDAP Guru. This is the definitive LDAP resource on the web.
-
Get more information regarding the IBM Tivoli Directory Server in the developerWorks community by participating in developerWorks forum.
Discuss
- Follow developerWorks on Twitter.
- Get involved in the My developerWorks community.




