SmartLdapGroupStore

The SmartLdapGroupStore is an implementation of the uPortal Groups and Permissions (GaP) API developed by Johns Hopkins University for their portal. JHU contributed this technology to the community which has been incorporated into uPortal since version 3.1.

Purpose

The SmartLdapGroupStore is designed to discover groups of users maintained within an LDAP directory server. It queries an LDAP data source for a collection of group objects and uses their attributes to re-organize them into a hierarchy. As users log in and use the portal, it uses Person Attributes to determine which groups each user belongs to. This behavior is similar to PAGS

Several other implementations of GaP also leverage information from LDAP - PAGS, LDAPGroupStore, JitLDAPGroupStore - and each of these is useful in its own way. The role of SmartLdapGroupStore is to host in the portal groups that are defined and maintained entirely in LDAP. You don't have to state explicitly the groups you want to pull in; SmartLdap will automatically fetch all the groups that match the filter expression.

Configuration

SmartLdapGroupStore must coordinate both with your directory server and Person Attributes in the portal, so it's easy to make a mistake setting it up. The following sections describe the necessary steps for using SmartLdap in the portal.

Step 1. Add SmartLdapGroupStore to Composite Group Services

Add the following entry in uportal-impl/src/main/resources/properties/groups/compositeGroupServices.xml:

<service>
  <name>smartldap</name>
  <service_factory>org.jasig.portal.groups.ReferenceIndividualGroupServiceFactory</service_factory>
  <entity_store_factory>org.jasig.portal.groups.smartldap.SmartLdapEntityStore$Factory</entity_store_factory>
  <group_store_factory>org.jasig.portal.groups.smartldap.SmartLdapGroupStore$Factory</group_store_factory>
  <entity_searcher_factory>org.jasig.portal.groups.smartldap.SmartLdapEntitySearcher$Factory</entity_searcher_factory>
  <internally_managed>false</internally_managed>
  <caching_enabled>true</caching_enabled>
</service>
Step 2. Configure SmartLdapGroupStore

Next, you must configure SmartLdapGroupStore itself in the uportal-impl/src/main/resources/properties/groups/SmartLdapGroupStoreConfig.xml file.

Here is a summary of the settings in this file:

  • LDAP directory server connection information
    • URL
    • User DN (manager username)
    • Password
  • Refresh interval (seconds): how frequently should SmartLdap check for changes to the groups hierarchy?
  • Base DN under which you want to query for group records (e.g. 'DC=my,DC=university,DC=edu')
  • Filter expression that returns the group records you want (e.g. '(objectCategory=group)')
  • Whether you want to resolve member groups outside the original Base DN (true/false)
  • Resolve DN: another Base DN for resolving member groups if resolve (above) it true
  • Name of the Person Attribute on each user that contains the distinguishedName of each group he/she is a member of (e.g. 'memberOf')
  • (see Note below) Name of the LDAP attribute on each group that contains its distinguishedName (e.g. 'distinguishedName')
  • (see Note below) Name of the LDAP attribute on each group that contains its human-readable name (e.g. 'cn')
  • (see Note below) Name of the LDAP attribute on each group that contains the distinguishedName of each of its members (e.g. 'member')

Note

If your LDAP schema doesn't manage groups and their relationships to each other in this way, you can implement a custom org.springframework.ldap.core.AttributesMapper class that bridges the difference.

Example SmartLdapGroupStoreConfig.xml
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!--
     | This bean is the ContextSource instance that will be used to connect to LDAP.
     +-->
    <bean id="ldapContext" class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="changeme"/>
        <property name="userDn" value="changeme"/>
        <property name="password" value="changeme"/>
    </bean>

    <!--
     | Period, in seconds, after which SmartLdap will drop and re-init the groups
     | tree.  A value of zero or less (negative) disables this feature.
     +-->
    <bean id="groupsTreeRefreshIntervalSeconds" class="java.lang.Long">
        <constructor-arg><value>900</value></constructor-arg>
    </bean>

    <!--
     | BaseDn that will be passed to the search (not to the context).
     |
     | WARNING:  If you get an error like this...
     |   ...PartialResultException: [LDAP: error code 10...
     | it probably means your baseDn isn't correct!
     +-->
    <bean id="baseDn" class="java.lang.String">
        <constructor-arg><value>changeme</value></constructor-arg>
    </bean>

    <!--
     | NOTE:  The remaining examples in this file are configured correctly for
     | Active Directory servers.
     +-->

    <!--
     | LDAP query string that will be passed to the search.
     +-->
    <bean id="filter" class="java.lang.String">
        <constructor-arg><value>(objectCategory=group)</value></constructor-arg>
    </bean>

    <!--
     | These beans tell smartLdap whether to gather additional groups that are
     | members of groups returned by the first baseDn and filter, and where to
     | look if so.
     |
     |   - resolveMemberGroups=[true|false]
     |   - resolveDn={a different, broader baseDn than the one above}
     |
     | Here's how it works:  smartLdap will first collect all groups under the
     | baseDn specified above.  If 'resolveMemberGroups' is enabled, it will
     | also search for additional groups (found within the 'resolveDn' specified
     | here) that are members of groups in the first collection.
     +-->
    <bean id="resolveMemberGroups" class="java.lang.Boolean">
        <constructor-arg><value>false</value></constructor-arg>
    </bean>
    <bean id="resolveDn" class="java.lang.String">
        <constructor-arg><value>changeme</value></constructor-arg>
    </bean>

    <!--
     | This bean identifies the name of the Person Attribute that
     | lists the SmartLdap groups each person is a member of.
     +-->
    <bean id="memberOfAttributeName" class="java.lang.String">
        <constructor-arg><value>memberOf</value></constructor-arg>
    </bean>

    <!--
     | This bean identifies the org.springframework.ldap.core.AttributesMapper
     | implementation used in reading the groups records from LDAP.
     +-->
    <bean id="attributesMapper" class="org.jasig.portal.groups.smartldap.SimpleAttributesMapper">
        <!--
         | Name of the group attribute that tells you its key.
         +-->
        <property name="keyAttributeName">
            <value>distinguishedName</value>
        </property>
        <!--
         | Name of the group attribute that tells you its name.
         +-->
        <property name="groupNameAttributeName">
            <value>cn</value>
        </property>
        <!--
         | Name of the group attribute that lists its members.
         +-->
        <property name="membershipAttributeName">
            <value>member</value>
        </property>
    </bean>

</beans>
Step 3. Configure personDirectoryContext.xml

You must define a Person Attribute that contains the distinguishedName of each group he/she is a member of, and it must have the name provided above.

Information on configuring personDirectoryContext.xml and ldapContext.xml can be found at LDAP User Attribute Sources

Having problems with these instructions?

Please send us feedback at uportal-user@lists.ja-sig.org