Friday, February 10, 2012

Springify the LDAP application

       Spring LDAP makes LDAP operations so simple. Spring lets you write the code and structure the functionalities around LDAP just like any other data access functionality. It provides fine wrapped template to work with LDAP just like JDBC or JMS. Let me share some of the basic operations using spring’s LdapTemplate that are most common in any application. Spring source has put together a very nice and detailed documentation, so please refer http://static.springsource.org/spring-ldap/docs/1.3.x/reference/html/ for Spring LDAP and refer to open source LDAP http://www.openldap.org/ for more details.

First thing First
       Let’s categorize these basic LDAP operations into the following
         • Creating an entry or Binding.
         • Deleting an entry or unbinding.
         • Retrieving basic attributes.
         • Retrieving attributes using filter.
         • Retrieving operational attributes.

Create an Entry
        To add an entry into the LDAP all you have to do is to call bind method on ldapTemplate. There are two ways of binding the new entry.
First way is calling the bind(Name dn, Object obj, Attributes attributes). So create the Attributes with attributes to bind. Here you are creating a new person object with attributes to bind.


BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", “Vinay Shivaswamy”);
personAttributes.put("description", “some description here”);

Create the DistinguishedName by providing the path in string format.


DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", “Vinay Shivaswamy”);

Now call the bind method by passing the Attributes and DistinguishedName just created.

ldapTemplate.bind(newContactDN, null, personAttributes);

Second way is to call bind(DirContextOperations ctx). So create the DistinguishedName by providing the path in string format.


DistinguishedName newContactDN = new DistinguishedName("ou=users");

Create the DirContextOperations object by passing the DistinguishedName just created. Once context is created its just matter of setting attributes into this context as shown below.

DirContextOperations ctx = new DirContextAdapter(dn);
ctx.setAttributeValue("cn", "Vinay Shivaswamy");
ctx.setAttributeValue("description", "some description");

Now Call the bind method by passing the DirContextOperations just created.
ldapTemplate.bind(ctx);

Delete an entry
       Deleting an entry is lot easier than creating one. All you have to do is to call unbind method as shown below by passing DistinguishedName,

DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn",”Vinay Shivaswamy”);
ldapTemplate.unbind(newContactDN);

Retrieving basic attributes
       The basic attributes can be retrieved using lookup or search methods of LdapTemplate. Below is an example of using search to get the list of matching common name attributes only. Search would return a List and if you are interested in retrieving unique matching entry then use searchForObject method instead.

ldapTemplate.search(baseName, "(objectclass=person)", new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs) throws NamingException {
return attrs.get("cn").get();
}
});

If you simply want to retrieve all the available attributes then write your own AttributesMapper implementation, add all the attributes to return.

Retrieving attributes using filter
       Retrieving attributes based of search criteria would be helpful and you can do that with the help of Filter. Spring Ldap filter package provides various supporting filters. Look at the example below to see how easy it is to build and use the filter.


AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter("objectclass","person"));
andFilter.and(new EqualsFilter("cn",”Vinay Shivaswamy”));
andFilter.and(new EqualsFilter("sn",”Shivaswamy”));

Once the filter is built then it is just the matter of calling search by passing the filter to retrieve the matching email attribute,


ldapTemplate.search("baseName", andFilter.encode(),new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
return attrs.get("email").get();
}
});

Retrieving operational attributes
       Ldap Server maintains many operational attributes internally. Example entryUUID is an operational attribute assigns the Universally Unique Identifier (UUID) to the entry. The createTimestamp, modifyTimestamp are also operational attributes assigned to the entry on create or update. These operational attributes does not belong to an object class and hence they were not returned as part of your search or lookup. You need to explicitly request them by their name in your search or build the custom AttributeMapper implementation with matching attribute names.
Now let’s try to retrieve the entryUUID, first you need to build the search controls like this,


SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningObjFlag(false);
controls.setReturningAttributes(new String[]{"entryUUID"});

Once you have search control then it’s simply calling search method just like retrieving any other attributes.


ldapTemplate.search("baseName", "(objectclass=person)", controls, new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs) throws NamingException {
Attribute attrUuid = attrs.get("entryUUID");
return attrUuid;
}});

Here is another way to do the same using ContextMapper,


ldapTemplate.search("baseName","(objectclass=person)", 1, new String[]{"entryUUID"},
new ContextMapper(){
public Object mapFromContext(Object ctx) {
DirContextAdapter context = (DirContextAdapter)ctx;
return context.getStringAttributes("entryUUID");
}
});

Let’s add the filter based off of operational attributes like below,


OrFilter orFilter = new OrFilter();
orFilter.or(new GreaterThanOrEqualsFilter("createTimestamp", "YYYYMMDDHHMMSSZ"));
orFilter.or(new LessThanOrEqualsFilter("modifyTimestamp", "YYYYMMDDHHMMSSZ"));

Now call the above search with the filter


ldapTemplate.search("baseName", orFilter.encode(), controls, new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs) throws NamingException {
Attribute attrUuid = attrs.get("entryUUID");
return attrUuid;
}});

Final Note
       Spring simplifies the Ldap operations indeed. We just saw that but there is lot more to dig into if you need to and I hope this article serves as a quick reference to jump start your exploration. Good luck.

2 comments:

  1. Is there a way we can update operational attribute?

    ReplyDelete
  2. Is there a way we can update operational attribute?

    ReplyDelete