(Quick Reference)

Directory Service Plugin - Reference Documentation

Authors: Lucas Rockwell

Version: 0.5.0

1 Introduction

Overview

DirectoryService is a Grails plugin that allows you to interact with a v3-compliant LDAP server with minimal effort. It is built on top of the UnboundID LDAP SDK.

DirectoryService is inspired by GORM, but since this is LDAP, we really can only go as far as inspired, because there is no "R" (relational) in LDAP. Unlike a database, LDAP does not really have a structure (well, there is the DIT, but that is about it), so it does not seem reasonable or necessary to make concrete classes to represent LDAP objects. As you read more about this plugin, and start to use it, you will realize why concrete classes are unnecessary.

Furthermore, you can use Command Objects for your logic for your directory objects, i.e., you don't need to put them into a class that is specific to a tree in LDAP. (At least that is how I feel about this now, and Command Objects are just as powerful as Domain Objects.)

As mentioned above, DirectoryService is built on top of the UnboundID LDAP SDK, and therefore, that SDK is exposed through this plugin. However, it is best if you try to use the methods provided by the plugin as much as possible, as the SDK API may change. That is, we try to encapsulate the basic functionality that you need, but if you really need something you can go under the covers. Also, feel free to open an Enhancement Issue on GitHub.

This plugin assumes you have working knowledge of LDAP. If you need to get familiar with LDAP, please see the Resources section.

2 History

  • Pre-release 0.1.0
    • July 2012
  • Beta-release 0.5.0
    • August 2012

3 Installation

Overview

This section describes how to install the DirectoryService plugin.

Install Plugin

The DirectoryService plugin is installed like any other plugin. It can be added to BuildConfig.groovy like so:

plugins {
    compile ':directory-service:0.5.0'
}

Or you can install it from the command line from the root directory of your project:

grails install-plugin directory-service

4 Configuration

Overview

This section describes how to configure the DirectoryService plugin.

Define The DIT

Instead of crawling your LDAP directory, DirectoryService expects you to give it some hints about how your server is set up. Once you configure the plugin, it will become obvious to you how it works.

Since the DIT definition is a Map, you must put it in a .groovy file. The easiest place to put it is in Config.groovy, but you can put it into any config file you have defined.

For this example, we are going to assume that our LDAP tree has three branches that we are interested in mapping:

ou=people,dc=someu,dc=edu
ou=departments,dc=someu,dc=edu
ou=groups,dc=someu,dc=edu

So, we need to tell DirectoryService about these branches, including the singular and plural names of the objects in those branches, the RDN attribute for the objects in those branches, and the source, i.e., what server contains this information.

The above branches would be defined in the directoryService.dit as follows:

grails.plugins.directoryservice.dit = [
    'ou=people,dc=someu,dc=edu':[
        'singular':'person',
        'plural':'people',
        'rdnAttribute':'uid',
        'source':'directory'
    ],
    'ou=departments,dc=someu,dc=edu':[
        'singular':'department',
        'plural':'departments',
        'rdnAttribute':'ou',
        'source':'directory'
    ],
    'ou=groups,dc=someu,dc=edu':[
        'singluar':'group',
        'plural':'groups',
        'rdnAttribute':'uid',
        'source':'directory'
    ]
]

See the table below for definitions of the various elements of the map:

AttributeMeaningNotes/Example
singularThe singular spelling for the name of the tree.This does not have to match the name in the DN.
pluralThe plural spelling for the name of the tree.This does not have to even be the plural version of singular, but you probably what to keep these things consistent for your own sanity.
rdnAttributeThis is the attribute which makes up the RDN of the entry.If the DN of a person is uid=125236,ou=people,dc=someu,dc=edu, then the rdnAttribute would be "uid". If the DN of a person is cn=Rockwell, Lucas,ou=people,dc=someu,dc=edu, then the rdnAttribute would be "cn". This must be the real RDN attribute, i.e., you can't make this up.
sourceThis is the sourceThis points to an entry in grails.plugins.directoryservice.sources.

One Branch, Multiple Objects

Store more than one object type in the same branch? No problem! Map keys are case sensitive, so you can define multiple objects in the same branch by changing the case of at least one character in the dn. For example, let's say you have both people and accounts in the "people" branch (don't know why you would, but let's just say you do), and the rdnAttribute of people is "uid", and the rdnAttribute of accounts is "cn":

grails.plugins.directoryservice.dit = [
    'ou=people,dc=someu,dc=edu':[
        singular: 'person',
        plural: 'people',
        rdnAttribute: 'uid',
        source: 'directory'
    ],
    'ou=People,dc=someu,dc=edu':[
        singular: 'account',
        plural: 'accounts',
        rdnAttribute: 'cn',
        source: 'directory'
    ]
]

See the examples in the Usage section for details on how these various elements are utilized.

Define Sources

In the dit definition above, there is an attribute named "source". This points to a directory server configured in grails.plugins.directoryservice.sources. For instance:

grails.plugins.directoryservice.sources = [
    'directory':[
        address: 'server1,server2',
        port: '636,636',
        useSSL: true,
        trustSSLCert: true,
        followReferrals: true,
        bindDN: 'cn=Directory Manager',
        bindPassword: 'password'
    ]
]

See the table below for information on what each attribute means:

More Examples

For more examples of how to configure the dit and sources, see the Config.groovy file in the main project: .

5 Usage

Overview

As noted in the Introduction, DirectoryService is inspired by GORM. Therefore, the methods should be intuitive. This section gives you a brief overview, but please see the Reference Guide for details of each method.

How it Works

For more in-depth details of how DirectoryService works, please see the other sections of this guide, including the ref:DirectoryService pages.

Add DirectoryService to your class

Once you have DirectoryService configured, you can add it to a class the way you would any other service:

def directoryService

Search for an object

Now you can search for something in your directory (again, see the Configuration section) like this:

def people = directoryService.findPeopleWhere('departmentNumber':'12345', 'manager':'3786258')

The above will return a list of DirectoryServiceEntry objects. A DirectoryServiceEntry object is a wrapper around an UnboundID Entry object, so everything you can do with an Entry object is available to you.

Use the results

Once you perform a search, you can then use the object the way you would use a GORM object:

people.each { person ->
    println "${person.displayName}, ${person.telephoneNumber}"
}

Now you might say, but this is LDAP, so what happens if the person does not have a telephoneNumber defined in their entry? Nothing! The attribute doesn't exist, it doesn't print anything. This is possible because DirectoryService is based on the UnboundID LDAP SDK, and that SDK allows you to ask for attribute values on attributes that do not exist in the entry, with no ill effects, i.e., no exceptions are thrown. However, the call does return null if there is no attribute with the provided name, so it is best to use the "?" operator if you plan to do something with the value, if that something you plan to do does not like null objects.

To see how the UnboundID LDAP SDK is being used here, the above person.displayName could also be accomplished with the following:

person.getEntry().getAttributeValue("displayName")

As you can see, we are calling getAttributeValue, so if you want the attribute values, then you would have to use the special Values() method:

person.cnValues()

This returns a String array.

Operations Implemented

As of the current release, find (search), and save (modify) are implemented. add and delete will be added in upcoming releases. See the roadmap for details.

6 Roadmap

Overview

This page outlines what to expect in future releases of the DirectoryService plugin. If you have a feature request/enhancement, please create an "Issue" on GitHub and label it an enhancement: .

Summer 2012

This summer I hope I can include the ability to add, along with JSON and XML output for the DirectoryServiceEntry object.

Fall 2012

By Fall I hope to implement find*By* methods, for instance, findPeopleBySnAndGivenName, and findPeopleBySnLike, etc.

7 Resources

Overview

The DirectoryService Plugin is for interacting with an LDAP directory. If you are not familiar with LDAP, please read the Wikipedia LDAP page for starters.

API Docs

UnboundID LDAP SDK Docs

The DirectoryService plugin is based on the UnboundID LDAP SDK.

The UnboundID LDAP SDK is very powerful, and of course DirectoryService only uses a fraction of what it has to offer. However, we have tried to encapsulate in DirectoryService what the kinds of activities you would do with a directory most of the time, so if at all possible, try to avoid using the underlying UnboundID API because if it changes, then you will have to change your code, as well, and it will be up to you to keep up with any changes.

DirectoryService API Docs