Andy Pemberton Rotating Header Image

Nested LDAP Groups in JBoss Portal with Active Directory

While JBoss Portal supports Active Directory for authentication and authorization, as of versions 2.6.X and the 2.7 CR, the product does not support nested groups for a given user when the LDAP server itself does not provide recursive capabilities. Unfortunately, Microsoft Active Directory does not support recursive queries for nested groups.

In this article, I’ll describe the limitation of the JBoss Portal API and describe my solution complete with working code. It may be helpful to read the JBoss.org community wiki on integrating Portal with Active Directory.

The Problem

Take a look at the nested groups implied in the following example LDAP structure:


ou=users,dc=example,dc=com
  cn=john.doe,ou=users,dc=example,dc=com
    [memberOf: cn=employee,ou=profiles,ou=groups,dc=example,dc=com]
  cn=jane.doe,ou=users,dc=example,dc=com
    [memberOf: cn=manager,ou=profiles,ou=groups,dc=example,dc=com]
ou=groups,dc=example,dc=com
  ou=profiles,ou=groups,dc=example,dc=com
    cn=manager,ou=profiles,ou=groups,dc=example,dc=com
      [memberOf: cn=person_read,ou=accessroles,ou=groups,dc=example,dc=com]
      [memberOf: cn=person_update,ou=accessroles,ou=groups,dc=example,dc=com]
    cn=employee,ou=profiles,ou=groups,dc=example,dc=com
      [memberOf: cn=person_read,ou=accessroles,ou=groups,dc=example,dc=com]
  ou=accessroles,ou=groups,dc=example,dc=com
    cn=person_read,ou=accessroles,ou=groups,dc=example,dc=com
    cn=person_update,ou=accessroles,ou=groups,dc=example,dc=com</code>

Out of the box, JBoss’s LDAP identity implementation will only return the first-layer of user groups - so, for user john.doe, only the employee group would be returned. This type of LDAP structure requires a recursive query to determine all of the groups the a given user actually belongs to. Because Active Directory doesn’t support nested, recursive queries like these, the recursion must be handled with code.

The other large Portal vendors have this supported built into their product; as an example, while IBM has recursive queries built into their directory server, they also have code to handle their support for Active Directory built into WebSphere Portal (see an IBM InfoCenter article on Active Directory’s lack of recursion support).

JBoss API

JBoss has a fairly flexible, JAAS-based LDAP identity configuration. It is well documented in section 19.3 of the JBoss Portal documentation. While the user and role modules do support SUBTREE_SCOPE, the membership module doesn’t support any kind of recursion. The membership module is the identity module that actually allows finding the groups that a given user belongs to.

The Limitation

In researching this issue, I found that the identity modules are packaged and released independent of Portal. Version 2.6.5 of Portal shipped with version 1.0.3 of the identity module while the 2.7 CR uses 1.0.4 - from browsing around the JBoss Portal SVN Repo, this problem looks like it will be around for a while.

The important class from the Portal API is LDAPStaticRoleMembershipModuleImpl.

This class has a getRoles method with the following code:


if (isUidAttributeIsDN()){
    roles.add(getRoleModule().findRoleByDN(name));
}else{
    roles.add(getRoleModule().findRoleByName(name));
}

What’s important to note here is that there’s no recursive search going on for groups that the given group belongs to.

The Solution

Basically, we want to extend the JBoss LDAPStaticRoleMembershipModuleImpl and override the getRoles method to add the appropriate recursive logic:


public void addRoles(String roleName, Set roles, Integer roleNestedLevel) throws IdentityException {
	...
	addRole(roleName, roles);
	...
	while (nestedRoles.hasMoreElements()) {
		addRoles(nestedRoles.nextElement().toString(), roles, (roleNestedLevel + 1));
	}
	...
  • Download the LDAPNestedStaticRoleMembershipModuleImpl
  • JAR the LDAPNestedStaticRoleMembershipModuleImpl class and store it at jboss-portal.sar/lib
  • add a roleRecursion option to your ldap_identity-config.xml (0 is the default and will disable recursion):
    
    <option>
        <name>roleRecursion</name>
        <value>1</value>
    </option>
    
  • change the Membership module implementation in ldap_identity-config.xml:
    
    <module>
        <type>Membership</type>
        <implementation>LDAP</implementation>
       <class>com.andypemberton.jboss.portal.identity.ldap.LDAPNestedStaticRoleMembershipModuleImpl</class>
        <config/>
    </module>
    

Limitations

This class extends the LDAPStaticRoleMembershipModuleImpl, so it is designed for LDAP structures where the user stores information about the groups that he belongs to - see the JBoss docs for more info. Also, currently this class assumes that the memberOf attribute is the same for a user belonging to a group as a group belonging to a group - this could easily be modified with an additional identity option.

Conclusion

I spent some time digging around on this, but I’m overworked and sleep-deprived - so if you have any comments, criticisms, or better ideas, plz share. Otherwise, hopefully this is helpful to you.

3 Comments on “Nested LDAP Groups in JBoss Portal with Active Directory”

  1. #1 Thomas Heute
    on Oct 28th, 2008 at 8:21 pm

    Nice and probably helpful article for people in the same situation.

    For your information, we are working on a new identity model common to several JBoss projects, a proposal is being discussed here:
    http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4184792#4184792

    Comments are welcome.

  2. #2 Andrew Buchan
    on Nov 10th, 2009 at 11:09 pm

    Hi this seems like exactly the issue I am haveing with Jboss portal and AD. However I am a bit new to the entire java world and the exact methods need to jar up the LDAPNestedStaticRoleMembershipModuleImpl
    any chance you could lend a hand….please….

  3. #3 James
    on Feb 2nd, 2010 at 6:54 pm

    Actually you can resolve nested groups with an LDAP search filter. See the Search Filter Syntax topic on MSDN, http://msdn.microsoft.com/en-us/library/aa746475(VS.85).aspx . To give an example of finding all groups for the user Jack Sprat, you would use the following LDAP search filter:

    (&(objectClass=group)(member:1.2.840.113556.1.4.1941:=CN=Jack Sprat,OU=MyOrg,DC=mydomain,DC=com))

    A similar search modifier is available for searching memberOf to get all users for a specific group:

    (&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=CN=MyGroup,OU=Groups,DC=mydomain,DC=com))

Leave a Comment