Home > Articles

  • Print
  • + Share This
  • 💬 Discuss
This chapter is from the book

LDAP Classes and Attributes

Although LDAP entries are really just a collection of attributes, LDAP has the concept of classes. Every LDAP entry has an attribute called objectClass that lists the class hierarchy for an object. Not only does objectClass contain the object's class, it must contain the entire list of superclasses all the way back to the top class. Fortunately, the classes aren't nested too deeply, so the objectClass list is usually fairly small.

One other thing to keep in mind: The class hierarchy doesn't dictate the structure of the directory tree. A node in the directory tree can contain one of its superclasses as a child.

Table 18.1 lists some of the common LDAP classes. The complete set of classes is defined in the standard RFC2256, which you can view at http://www.ietf.org/rfc/rfc2256.txt.

Table Some Common LDAP Classes

Classname Parent Class Required Attribute(s)
top None ObjectClass
country top c
locality top none
organization top o
organizationalUnit top ou
person top sn, cn
organizationalPerson top none

The LDAP specification also lists some common attribute names. These attribute names tend to look confusing at first glance because many of them are only one or two characters long. You see these attributes in other places too, such as in X.509 certificates (for digital signatures and encryption). One of the reasons for the similarity is that LDAP uses many of the items defined in the X.500 series of recommendations (standards), which includes X.509.

Table 18.2 lists some of the common attributes and their meanings.

Table Some Common LDAP Attributes

Attribute Name Meaning
objectClass The classname of the object and its superclasses
dc A domain context-a part of a domain name
cn Common name, usually the name of the object
sn Surname-a person's family name (the last name in most Western cultures)
c The standard two-letter country code
l Locality (city, county, or other region)
st State or province
o Organization
ou Organizational unit
title A person's job title
personalTitle A person's personal (not job-related) title
description A description of the object
mail A person's email address

One other concept you should be aware of is that a context is really a set of names. You can create a context that is a subset of names by calling createSubcontext in the DirContext object. Essentially, a subcontext is just the set of names starting at a particular node in the directory tree.

The interesting thing is, you create a new node in the tree by creating a new subcontext. Listing 18.2 shows a program that adds two entries to the LDAP directory. Notice that the program must supply a username in the form of a SECURITY_PRINCIPAL and a password in the form of SECURITY_CREDENTIALS to make changes to the LDAP directory. Most servers let you read the directory anonymously but require a username and password to make changes.

Listing 18.2 Source Code for AddPerson.java

package usingj2ee.naming;

import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;

public class AddPerson
{
    public static void main(String[] args)
    {
        try
        {
// Pass the security information to the directory context
// The LDAP server requires a username (SECURITY_PRINCIPAL)
// and password (SECURITY_CREDENTIALS) to add/remove
// items.
            Hashtable props = new Hashtable();
            props.put(Context.SECURITY_PRINCIPAL,
                "cn=Manager,dc=wutka,dc=com");
            props.put(Context.SECURITY_CREDENTIALS,
                "secret");

// Get the initial context
            InitialDirContext ctx = new InitialDirContext(props);


// Create a new set of attributes
            BasicAttributes attrs = new BasicAttributes();

// The item is an organizationalPerson, which is a subclass of person.
// Person is a subclass of top. Store the class hierarchy in the
// objectClass attribute
            Attribute classes = new BasicAttribute("objectclass");
            classes.add("top");
            classes.add("person");
            classes.add("organizationalPerson");

// Add the objectClass attribute to the attribute set
            attrs.put(classes);

// Store the other attributes in the attribute set
            attrs.put("sn", "Tippin");
            attrs.put("title", "Computer Expert");
            attrs.put("mail", "samantha@wutka.com");

// Add the new entry to the directory server
            ctx.createSubcontext("ldap://ldap.wutka.com/cn=Samantha Tippin,"+
                "o=Wutka Consulting,dc=wutka,dc=com", attrs);

// Create another set of attributes
            attrs = new BasicAttributes();

// Use the same objectClass attribute as before
            attrs.put(classes);

// Set the other attributes
            attrs.put("sn", "Tippin");
            attrs.put("title", "Computer Expert");
            attrs.put("mail", "kaitlynn@wutka.com");

// Add another entry to the directory server
            ctx.createSubcontext("ldap://ldap.wutka.com/cn=Kaitlynn Tippin,"+
                "o=Wutka Consulting,dc=wutka,dc=com", attrs);
         }
         catch (Exception exc)
         {
            exc.printStackTrace();
         }
    }
}
					

It's fairly easy to search through an LDAP directory using JNDI. You just call the search method in the DirContext. There are two main ways to search: by specifying either a set of attributes to match or an LDAP filter string.

Attribute matching is very straightforward, as you can see in Listing 18.3.

Listing 18.3 Source Code for Name Search.java

package usingj2ee.naming;

import javax.naming.*;
import javax.naming.directory.*;

public class NameSearch
{
    public static void main(String[] args)
    {
        try
        {
// Get the initial context
            InitialDirContext ctx = new InitialDirContext();

// Create the search attributes - look for a surname of Tippin
            BasicAttributes searchAttrs = new BasicAttributes();

            searchAttrs.put("sn", "Tippin");

// Search for items with the specified attribute starting
// at the top of the search tree
            NamingEnumeration objs = ctx.search(
                "ldap://ldap.wutka.com/o=Wutka Consulting, dc=wutka, dc=com",
                searchAttrs);

// Loop through the objects returned in the search
            while (objs.hasMoreElements())
            {
// Each item is a SearchResult object
                SearchResult match = (SearchResult)objs.nextElement();

// Print out the node name
                System.out.println("Found "+match.getName()+":");

// Get the node's attributes
                Attributes attrs = match.getAttributes();
                NamingEnumeration e = attrs.getAll();

// Loop through the attributes
                while (e.hasMoreElements())
                {
// Get the next attribute
                    Attribute attr = (Attribute) e.nextElement();

// Print out the attribute's value(s)
                    System.out.print(attr.getID()+" = ");
                    for (int i=0; i < attr.size(); i++)
                    {
                        if (i > 0) System.out.print(", ");
                        System.out.print(attr.get(i));
                    }
                    System.out.println();
                }
                System.out.println("---------------------------------------");
            }
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
        }
    }
}
					

Searching by filter is a little more complicated. Any LDAP filter string must be surrounded by parentheses. To match all objects in the directory, you can use a filter string, such as (objectClass=*).

You can do comparisons using =, >=, <=, and ~= (approximately), like (age>=18).

The syntax for and, or, and not is a little strange. If you want to test age>=18 and sn=Smith, the expression is (&(age>=18)(sn=Smith)). Use & for and, | for or, and ! for not. For and and or, you can list as many expressions as you want to after the & or | characters. For not, you can only have a single expression.

For example, because you can only do a greater-than-or-equal-to comparison (>=), you do a greater-than by doing not-less-than-or-equal-to. For example, if age must be strictly greater than 18, use (!(age<=18)). If you need to combine the and and or operators, you must use parentheses to separate the expressions.

For example, you might want to search for age>=18 or (age >=13 and parentalPermission=true). The expression would be (|(age>=18)(&(age>=13)(parentalPermission=true))). The two expressions being ored together are (age>=18) and (&(age>=13)(parentalPermission=true)).

You can find a full definition of the LDAP search filter syntax in RFC1558 (http://www.ietf.org/rfc/rfc1558.txt).

Listing 18.4 shows a program that performs a simple filter search to dump out the entire contents of the directory.

Listing 18.4 Source Code for AllSearch.java

package usingj2ee.naming;

import javax.naming.*;
import javax.naming.directory.*;

public class AllSearch
{
    public static void main(String[] args)
    {
        try
        {
// Get the initial context
            InitialDirContext ctx = new InitialDirContext();

            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// Search for items with the specified attribute starting
// at the top of the search tree
            NamingEnumeration objs = ctx.search(
                "ldap://ldap.wutka.com/o=Wutka Consulting, dc=wutka, dc=com",
                "(objectClass=*)", searchControls);

// Loop through the objects returned in the search
            while (objs.hasMoreElements())
            {
// Each item is a SearchResult object
                SearchResult match = (SearchResult) objs.nextElement();

// Print out the node name
                System.out.println("Found "+match.getName()+":");

// Get the node's attributes
                Attributes attrs = match.getAttributes();

                NamingEnumeration e = attrs.getAll();

// Loop through the attributes
                while (e.hasMoreElements())
                {
// Get the next attribute
                    Attribute attr = (Attribute) e.nextElement();

// Print out the attribute's value(s)
                    System.out.print(attr.getID()+" = ");
                    for (int i=0; i < attr.size(); i++)
                    {
                        if (i > 0) System.out.print(", ");
                        System.out.print(attr.get(i));
                    }
                    System.out.println();
                }
                System.out.println("---------------------------------------");
            }
        }
        catch (Exception exc)
        {
            exc.printStackTrace();
        }
    }
}
					
  • + Share This
  • 🔖 Save To Your Account

Discussions

comments powered by Disqus