AbstractLDAPUtils X-Ray

This section explains the structure of the AbstractLDAPUtils class. This is the core class of the LDAP Utils API. It's a large, dense class that might seem intimidating at the first look. Inspecting the class carefully might reveal some structure among the method bulk.

Class outline

The different sections will be presented individually but the entire class will be presented firstly. Here's the outline:

abstract public class AbstractLDAPUtils implements ILDAPUtils {

 // Attribute names that MIGHT be redefined on other implementations
 protected String getNameAttributeName();
 protected String getMailAttributeName();
 protected String getUserLoginAttributeName();
 protected String getGroupAttribute();
 protected String getPasswordAttributeName();
 protected String getDisplayNameAttributeName();
 protected String getGivenNameAttributeName();
 protected String getDescriptionAttributeName();

 // Attribute names that are common to all know LDAP implementations and that MUST NOT be changed 
 final protected String getCommonName();
 final protected String getObjectClassName(); 
 final protected String getUserIdentifierName(); 
 final protected String getGroupIdentifierName();
    
 // Attribute names that are specific to the different LDAP implementations and that MUST  be defined
 abstract protected String getUserClassName();
 abstract protected String getGroupClassName();
 abstract protected String getUserParentGroupAttributeName();
 abstract protected String getGroupParentGroupAttributeName();
    
 // LDAP server configurations accessor
 public LDAPConfigurations getConfigurations();
        
 // User-related operations
 public void addUser(LDAPUser newUser) throws LDAPOperationException;
 public void removeUser(String loginName) throws LDAPOperationException;
 public void updateUser(LDAPUser userToUpdate, String userLogin) throws LDAPOperationException;
 public LDAPUser findUserByLogin(String loginName) throws LDAPOperationException;
 public boolean userExists(String loginName) throws LDAPOperationException;
 public Set<LDAPGroup> getGroupsOfUser(String loginName) throws LDAPOperationException;
 public boolean isIdentityValid(String loginName, String suppliedPassword) throws LDAPOperationException;
 public void changePassword(String loginName, String newPassword) throws LDAPOperationException;
        
 // Group-related operations
 public void addGroup(LDAPGroup newGroup) throws LDAPOperationException;
 public void removeGroup(String groupCN) throws LDAPOperationException;
 public void updateGroup(LDAPGroup groupToUpdate, String groupCN) throws LDAPOperationException;
 public LDAPGroup findGroupByCommonName(String cn) throws LDAPOperationException;
 public boolean groupExists(String groupCN) throws LDAPOperationException;
 public Set<LDAPGroup> getChildGroups(String commonName) throws LDAPOperationException;

 // User-group relations operations
 public void addUserToGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public void removeUserFromGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public boolean isUserInGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public Map<String, LDAPUser> findUsersInGroup(String groupCN) throws LDAPOperationException;

 // User attributes management operations (lower-level)
 public Map<String, Object> getUserAttributes(String loginName) throws LDAPOperationException;
 public boolean userContainsAttribute(String id, String loginName) throws LDAPOperationException;
 public Object getUserAttribute(String attributeName, String loginName) throws LDAPOperationException;
 public void setUserAttribute(String loginName, String attributeName, Object value) throws LDAPOperationException;
 public void addUserAttribute(String loginName, String attributeName, Object value) throws LDAPOperationException;
 public void removeUserAttribute(String loginName, String attributeName) throws LDAPOperationException;
        
 // Group attributes management operations (lower-level)
 public Map<String, Object> getGroupAttributes(String commonName) throws LDAPOperationException;
 public boolean groupContainsAttribute(String attributeName, String commonName) throws LDAPOperationException;
 public Object getGroupAttribute(String attributeName, String commonName) throws LDAPOperationException;
 public void setGroupAttribute(String commonName, String attributeName, Object value) throws LDAPOperationException;
 public void addGroupAttribute(String commonName, String attributeName, Object value) throws LDAPOperationException;
 public void removeGroupAttribute(String commonName, String attributeName) throws LDAPOperationException;

 // Multiple key/value pairs on an attribute operation (lower-level) 
 public void storeParameterOnUserAttribute(String loginName, String attributeName, String key, String value);
 public void removeParameterFromUserAttribute(String loginName, String attributeName, String key);
 public String getParameterFromUserAttribute(String loginName, String attributeName, String key);
        
 // Technology-specific algorithm
 abstract protected String calculateDistinguishedName(String commonName, String mainGroupCommonName) throws LDAPOperationException;
          
 // LDAP context ancillary methods
 final protected LdapContext getLDAPContext() throws LDAPOperationException;
 final protected LdapContext getSecureLDAPContext() throws LDAPOperationException;
 final private void createSubcontext(String distinguishedName, Attributes attributes) throws LDAPOperationException;
 final private void destroySubcontext(String distinguishedName) throws LDAPOperationException;
 private LdapContext login(String loginName, String password, boolean secureConnection) throws NamingException;
    
 // LDAP search-related ancillary methods
 protected SearchResult getByLogin(String loginName) throws LDAPOperationException;
 protected SearchResult getByCommonName(String cn) throws LDAPOperationException;
 protected SearchResult getByDistinguishedName(String distinguishedName) throws LDAPOperationException;
 protected SearchResult getUserInGroup(String userLogin, String groupCN) throws LDAPOperationException;
 protected NamingEnumeration<SearchResult> getUsersInGroup(String groupCN) throws LDAPOperationException;
    
 //  LDAP search-related ancillary methods (lower level)
 private SearchResult doLDAPSearchSingleReturn(LdapContext context, String search) throws LDAPOperationException;
 private NamingEnumeration<SearchResult> doLDAPSearchMultipleReturns(LdapContext context, String baseNode, String searchCriteria) throws NamingException;
    
 // Conversion methods
 protected LDAPUser convertFromSearchResultToLDAPUser(SearchResult searchResult);
 protected LDAPGroup convertFromSearchResultToLDAPGroup(SearchResult searchResult);
 final protected Map<String, Object> convertFromSearchResultToMap(SearchResult searchResult) throws LDAPOperationException;
     
 // Attribute-related lower level operations
 final private void replaceAttribute(String distinguishedName, String attributeName, String value) throws LDAPOperationException;
 final private void removeAttribute(String distinguishedName, String attributeName) throws LDAPOperationException;
 final private void removeAttributeWithValue(String distinguishedName, String attributeName, String value) throws LDAPOperationException;
 final private void addAttribute(String distinguishedName, String attributeName, String value) throws LDAPOperationException;
 final protected void modifyAttributes(String distinguishedName, ModificationItem[] mods, boolean secure) throws LDAPOperationException;
    
 // Other helper methods
 final static private String getCNFromDN(String distinguishedName);
 protected Attributes getAttributesForUserAddition(LDAPUser newUser) throws LDAPOperationException;
 protected Attributes getAttributesForGroupAddition(LDAPGroup newGroup) throws LDAPOperationException;
 
}

Attribute names

LDAP records can be thought of as key-value pairs. The attribute values are the user's main concern, but the path to the value is the key. The key is referred as 'attribute name' on the LDAP jargon. There are some LDAP attributes that share a common name across different technologies. Some other LDAP implementations use specific names for the attributes. Still other LDAP implementations use some common attribute names and define different ones themselves. All these scenarios are considered on the AbstractLDAPUtils class. Some syntax rules regarding the attribute name construction are also addressed.

To allow the use of Java's flexible polymorphic behavior the attribute names are encapsulated in methods. This idiom offers the user the capability to supply it's own implementation names if needed and to use inheritance mechanisms to save the attribute name redefinition on subclasses.

On the AbstractLDAPUtils class there are three method sections that cover these issues: the first three method sections.

The previous three categories translate into the possibility of changing the attribute names or not.

The attribute names that are common across the different technologies (such as the 'cn' and 'objectClass' attribute names) must not be redefined. As such, they are declared 'final'.

The attribute names that are specific to a given technology must be defined on the matching implementation. Those attribute names are encapsulated on abstract methods that force the user to supply it's own names.

The final category is addressed by a set of convenience methods that offer the 'standard' (that is OpenLDAP) attribute names. These methods don't have any special qualification so the developer might choose to use the supplied ones or to override them.

Here's the sections detailed above:

...

 // Attribute names that MIGHT be redefined on other implementations
 protected String getNameAttributeName();
 protected String getMailAttributeName();
 protected String getUserLoginAttributeName();
 protected String getGroupAttribute();
 protected String getPasswordAttributeName();
 protected String getDisplayNameAttributeName();
 protected String getGivenNameAttributeName();
 protected String getDescriptionAttributeName();

 // Attribute names that are common to all know LDAP implementations and that MUST NOT be changed 
 final protected String getCommonName();
 final protected String getObjectClassName(); 
 final protected String getUserIdentifierName(); 
 final protected String getGroupIdentifierName();
    
 // Attribute names that are specific to the different LDAP implementations and that MUST  be defined
 abstract protected String getUserClassName();
 abstract protected String getGroupClassName();
 abstract protected String getUserParentGroupAttributeName();
 abstract protected String getGroupParentGroupAttributeName();

... 

Accessing the LDAP server configurations

Different users will have different LDAP servers. As such, there should be a way to define access configurations (such as IP, port, base search DN, etc.) for distinct users. To address those needs a configuration object was created. It provides methods to define and to read several server parameters and it's based on Digitalis own Configurations Utils.

Please refer to the LDAPConfigurations API for a complete description of the class.

For the AbstractLDAPUtils user it suffices to say that such a configurations object must exist. There's an accessor method to provide that all configurations are done on the same object. Here's the code:

 ...
 
 // LDAP server configurations accessor
 public LDAPConfigurations getConfigurations();
 
 ...

User and group-related operations

There is a set of operations related to user and group management. Among these are the common addition, remotion and update operations. There is also search-related operations, such as checking if a given group or user exists and other specific to either users or groups. Two major players among the search methods are findUserByLogin(String loginName) and findGroupByCommonName(String cn). Those methods return the user associated to a given login name or the group with a given common name and are useful on a great deal of situations.

Here are the user and group-related operations methods signatures:

 ...
 
 // User-related operations
 public void addUser(LDAPUser newUser) throws LDAPOperationException;
 public void removeUser(String loginName) throws LDAPOperationException;
 public void updateUser(LDAPUser userToUpdate, String userLogin) throws LDAPOperationException;
 public LDAPUser findUserByLogin(String loginName) throws LDAPOperationException;
 public boolean userExists(String loginName) throws LDAPOperationException;
 public Set<LDAPGroup> getGroupsOfUser(String loginName) throws LDAPOperationException;
 public boolean isIdentityValid(String loginName, String suppliedPassword) throws LDAPOperationException;
 public void changePassword(String loginName, String newPassword) throws LDAPOperationException;
        
 // Group-related operations
 public void addGroup(LDAPGroup newGroup) throws LDAPOperationException;
 public void removeGroup(String groupCN) throws LDAPOperationException;
 public void updateGroup(LDAPGroup groupToUpdate, String groupCN) throws LDAPOperationException;
 public LDAPGroup findGroupByCommonName(String cn) throws LDAPOperationException;
 public boolean groupExists(String groupCN) throws LDAPOperationException;
 public Set<LDAPGroup> getChildGroups(String commonName) throws LDAPOperationException;

 
 ...

User-group relations

On an LDAP tree the users and groups relate to each other with "belonging" relations. A user belongs to a group and a group contains zero, one or more users. AbstractLDAPUtils mimics these behaviors with methods that relate user to groups. These relations include adding/removing a user to/from a group and querying the server to find if a user belongs to a group, or to find the users on a group.

Here's the full user-group relations operations set:

 ...
 
 // User-group relations operations
 public void addUserToGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public void removeUserFromGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public boolean isUserInGroup(String groupCN, String userLogin) throws LDAPOperationException;
 public Map<String, LDAPUser> findUsersInGroup(String groupCN) throws LDAPOperationException;
 
 ...

Attribute management operations

Sometimes there's a need to access LDAP entries on a finer level, that is, on attribute level. There are methods that allow the addition, remotion and edition of user and group attributes. There are also methods that fetch all or one attribute and that check if the attribute is contained on the entity (user/group). The afforementioned methods offer an easier alternative to LDAP attribute direct manipulation, which tends to be cluttered, complex and done with a lot of boiler plate code.

There's also an extra feature, which is being able to store multiple key/value pairs on a single LDAP attribute. Check the Storing multiple key/value pairs on an LDAP attributes section on the usage page.

Here's the attribute management method subset:

 ...
 
 // User attributes management operations (lower-level)
 public Map<String, Object> getUserAttributes(String loginName) throws LDAPOperationException;
 public boolean userContainsAttribute(String id, String loginName) throws LDAPOperationException;
 public Object getUserAttribute(String attributeName, String loginName) throws LDAPOperationException;
 public void setUserAttribute(String loginName, String attributeName, Object value) throws LDAPOperationException;
 public void addUserAttribute(String loginName, String attributeName, Object value) throws LDAPOperationException;
 public void removeUserAttribute(String loginName, String attributeName) throws LDAPOperationException;
        
 // Group attributes management operations (lower-level)
 public Map<String, Object> getGroupAttributes(String commonName) throws LDAPOperationException;
 public boolean groupContainsAttribute(String attributeName, String commonName) throws LDAPOperationException;
 public Object getGroupAttribute(String attributeName, String commonName) throws LDAPOperationException;
 public void setGroupAttribute(String commonName, String attributeName, Object value) throws LDAPOperationException;
 public void addGroupAttribute(String commonName, String attributeName, Object value) throws LDAPOperationException;
 public void removeGroupAttribute(String commonName, String attributeName) throws LDAPOperationException;
 
 // Multiple key/value pairs on an attribute operation (lower-level) 
 public void storeParameterOnUserAttribute(String loginName, String attributeName, String key, String value);
 public void removeParameterFromUserAttribute(String loginName, String attributeName, String key);
 public String getParameterFromUserAttribute(String loginName, String attributeName, String key);
 
 ...

Technology-specific algorithms

Some LDAP technologies might have some other specific issues apart from the attribute names. The distinguished name, for example, might be calculated differently from implementation to implementation. To address this situation the methods that define these specific issues were qualified with 'abstract' to force the user to define them on the subclasses.

At the time of this writing just the DN calculation algorithm was made abstract. Here's the matching section method signature:

 ...
 
 // Technology-specific algorithm
 abstract protected String calculateDistinguishedName(String commonName, String mainGroupCommonName) throws LDAPOperationException;
 
 ...

LDAP context auxiliary methods

On Java, the operations on LDAP servers are done through an entity called 'context'. The AbstractLDAPUtils class offers a set of methods to access LDAP contexts without the JNDI boiler-plate code. There are methods for accessing secure connection contexts and regular contexts. Other methods for subcontext management and LDAP server login are supplied as convenience methods but might not be used on other implementations directly.

Here's the context-related method set:

 ...
 
 // LDAP context ancillary methods
 final protected LdapContext getLDAPContext() throws LDAPOperationException;
 final protected LdapContext getSecureLDAPContext() throws LDAPOperationException;
 final private void createSubcontext(String distinguishedName, Attributes attributes) throws LDAPOperationException;
 final private void destroySubcontext(String distinguishedName) throws LDAPOperationException;
 private LdapContext login(String loginName, String password, boolean secureConnection) throws NamingException;
 
 ...

LDAP search-related methods

The bulk operations on LDAP servers are searches. As such, there's also a method family that addresses those issues. These methods act as a middle layer to the user and group search methods and are available to the other implementations as well. They relate closely to the conversion methods described below because the latter are fed with these methods return values.

Here's the lower-level search methods:

 ...
 
 // LDAP search-related ancillary methods
 protected SearchResult getByLogin(String loginName) throws LDAPOperationException;
 protected SearchResult getByCommonName(String cn) throws LDAPOperationException;
 protected SearchResult getByDistinguishedName(String distinguishedName) throws LDAPOperationException;
 protected SearchResult getUserInGroup(String userLogin, String groupCN) throws LDAPOperationException;
 protected NamingEnumeration<SearchResult> getUsersInGroup(String groupCN) throws LDAPOperationException;
  
 ...

Conversion methods

JNDI returns LDAP records as SearchResult type objects. Since this type is generic and can hold a great deal of objects there must be a means to convert the data to a format that can be consumed by the AbstractLDAPUtils. There are methods to convert the data returned by the server to the user and group types. There's also a method to convert from a SearchResult object into a Map. This method can be useful to implement conversions to new types. These methods are available for the subclasses.

Here's the conversion methods signatures:

 ...
 
  // Conversion methods
 protected LDAPUser convertFromSearchResultToLDAPUser(SearchResult searchResult);
 protected LDAPGroup convertFromSearchResultToLDAPGroup(SearchResult searchResult);
 final protected Map<String, Object> convertFromSearchResultToMap(SearchResult searchResult) throws LDAPOperationException;

 ...    

Other helper methods

There are some extra methods that help the AbstractLDAPUtils. For example, these methods set the attributes for group and user addition and extract the CN from the DN.

Here's the helper methods:

...

 // Other helper methods
 final static private String getCNFromDN(String distinguishedName);
 protected Attributes getAttributesForUserAddition(LDAPUser newUser) throws LDAPOperationException;
 protected Attributes getAttributesForGroupAddition(LDAPGroup newGroup) throws LDAPOperationException;
 
...