JBoss.orgCommunity Documentation

Chapter 20. LDAP

20.1. How to enable LDAP usage in JBoss Portal
20.2. Configuration of LDAP connection
20.2.1. Connection Pooling
20.2.2. SSL
20.2.3. ExternalContext
20.3. LDAP Identity Modules
20.3.1. Common settings
20.3.2. UserModule
20.3.3. RoleModule
20.3.4. MembershipModule
20.3.5. UserProfileModule
20.4. LDAP server tree shapes
20.4.1. Keeping users membership in role entries
20.4.2. Keeping users membership in user entries
20.5. Synchronizing LDAP configuration
20.6. Supported LDAP servers

This chapter describes how to setup LDAP support in JBoss Portal

Note

To be able to fully understand this chapter you should also read JBoss Portal Identity management and Authentication chapters before

We'll describe here the simple steps that you will need to perform to enable LDAP support in JBoss Portal. For additional information you need to read more about configuration of identity and specific implementations of identity modules

There are two ways to achieve this:

After doing one of the above changes you need to edit configuration file that you choose to use (identity-config.xml or ldap_identity-config.xml) and configure LDAP connection options in section:

<datasource>
   <name>LDAP</name>
   <config>
      <option>
         <name>host</name>
         <value>jboss.com</value>
      </option>
      <option>
         <name>port</name>
         <value>10389</value>
      </option>
      <option>
         <name>adminDN</name>
         <value>cn=Directory Manager</value>
      </option>
      <option>
         <name>adminPassword</name>
         <value>qpq123qpq</value>
      </option>
   </config>
</datasource>

You also need to specify options for your LDAP tree (described in configuration documentation) like those:

<option-group>
   <group-name>common</group-name>
   <option>
      <name>userCtxDN</name>
      <value>ou=People,dc=portal26,dc=jboss,dc=com</value>
   </option>
   <option>
      <name>roleCtxDN</name>
      <value>ou=Roles,dc=portal26,dc=jboss,dc=com</value>
   </option>
</option-group>

JBoss Portal uses connection pooling provided by JNDI, and is enabled by default. Use the following options to configure connection pooling settings:

<datasource>
   <name>LDAP</name>
   <config>
      ...
      <!-- com.sun.jndi.ldap.connect.pool -->
      <option>
         <name>pooling</name>
         <value>true</value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.protocol -->
      <option>
         <name>poolingProtocol</name>
         <value>plain ssl</value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.timeout -->
      <option>
         <name>poolingTimeout</name>
         <value>300000</value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.debug -->
      <option>
         <name>pooling</name>
         <value> ... </value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.initsize -->
      <option>
         <name>poolingInitsize</name>
         <value> ... </value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.maxsize -->
      <option>
         <name>poolingMaxsize</name>
         <value> ... </value>
      </option>

      <!-- com.sun.jndi.ldap.connect.pool.prefsize -->
      <option>
         <name>poolingPrefsize</name>
         <value> ... </value>
      </option>

      ...
   </config>
</datasource>

Remember, as it is described in the JNDI documentation, these options are system properties, not environment properties, and as such, they affect all connection pooling requests in the Java runtime environment™.

The setup is very similar to the one described in LdapLoginModule wiki page

You need to modify your identity configuration file and add "protocol"

<datasource>
   <name>LDAP</name>
   <config>
      ...
      <option>
         <name>protocol</name>
         <value>ssl</value>
      </option>
      ...
   </config>
</datasource>

Then you need to have LDAP server certificate imported into your keystore. You can use following command:

keytool -import -file ldapcert.der -keystore ldap.truststore

Now you need to change the settings to use the alternative truststore. That can be done in the properties-service.xml in deploy directory:

<attribute name="Properties">
   javax.net.ssl.trustStore=../some/path/to/ldap.truststore
   javax.net.ssl.trustStorePassword=somepw
</attribute>

Instead of configuring your own connection you can use JNDI context federation mechanism in JBoss Application Server. Configuration of ExternalContext is described in JBoss Application Server documentation

When you have ExternalContext configured you can use it in JBoss Portal by providing proper JNDI name in the configuration:

<datasource>
   <name>LDAP</name>
   <config>
      <option>
         <name>externalContextJndiName</name>
         <value>external/ldap/jboss</value>
      </option>
   </config>
</datasource>

Note

When using "externalContextJndiName" you don't need to specify any other option for this datasource

JBoss Portal comes with base LDAP implementation of all identity modules.


This is the base implementation of LDAP UserModule. It supports user creation, but will retrieve users and create them in strictly specified place in LDAP tree.

To enable it in your configuration you should have:

<module>
   <!--type used to correctly map in IdentityContext registry-->
   <type>User</type>
   <implementation>LDAP</implementation>
   <config/>
</module>

org.jboss.portal.identity.ldap.LDAPUserModuleImpl configuration option-groups options:

Example configuration:

                  
<option-group>
   <group-name>common</group-name>
   <option>
      <name>userCtxDN</name>
      <value>ou=People,o=portal,dc=my-domain,dc=com</value>
   </option>
   <option>
      <name>uidAttributeID</name>
      <value>uid</value>
   </option>
   <option>
      <name>passwordAttributeID</name>
      <value>userPassword</value>
   </option>
</option-group>
<option-group>
   <group-name>userCreateAttibutes</group-name>
   <option>
      <name>objectClass</name>
      <!--This objectclasses should work with Red Hat Directory-->
      <value>top</value>
      <value>person</value>
      <value>inetOrgPerson</value>
   </option>
   <!--Schema requires those to have initial value-->
   <option>
      <name>cn</name>
      <value>none</value>
   </option>
   <option>
      <name>sn</name>
      <value>none</value>
   </option>
</option-group>


Aim of this implementation is to give more flexibility for roless retrieval. You can specify LDAP filter that will be used for searches. This module doesn't support role creation and removal

This module doesn't support role creation and removal

To enable it in your configuration you should have:

<module>
   <!--type used to correctly map in IdentityContext registry-->
   <type>Role</type>
   <implementation>LDAP</implementation>
   <class>org.jboss.portal.identity.ldap.LDAPExtRoleModuleImpl</class>
   <config/>
</module>
               

org.jboss.portal.identity.ldap.LDAPExtRoleModuleImpl configuration option-groups options:


JBoss Portal supports full user/role management for simple LDAP tree shapes. Some more flexible trees can be supported by LdapExtUserModuleImpl and LdapExtRoleModuleImpl - but without user/role creation and removal capabilities. However if you have complex LDAP tree you should consider using SynchronizingLoginModule described in Authentication chapter along with dedicated tools for user provisioning provided with LDAP server.

In following subsections we will describe two base LDAP tree shapes along with example LDIFs and portal identity modules configurations. Those two examples differ only by using different MembershipModule implementations and describe only tree shapes with supported user/role creation and removal capabilities.

In this example, information about users/roles assignment is stored in roles entries using LDAP "member". Of course any other attribute that comes with schema can be used for this.

Example tree shape in LDAP browser

 <modules>
   <module>
      <!--type used to correctly map in IdentityContext registry-->
      <type>User</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
   <module>
      <type>Role</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
   <module>
      <type>Membership</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
   <module>
      <type>UserProfile</type>
      <implementation>DELEGATING</implementation>
      <config>
         <option>
            <name>ldapModuleJNDIName</name>
            <value>java:/portal/LDAPUserProfileModule</value>
         </option>
      </config>
   </module>
   <module>
      <type>DBDelegateUserProfile</type>
      <implementation>DB</implementation>
      <config>
         <option>
            <name>randomSynchronizePassword</name>
            <value>true</value>
         </option>
      </config>
   </module>
   <module>
      <type>LDAPDelegateUserProfile</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
</modules>

<options>
   <option-group>
      <group-name>common</group-name>
      <option>
         <name>userCtxDN</name>
         <value>ou=People,dc=example,dc=com</value>
      </option>
      <option>
         <name>roleCtxDN</name>
         <value>ou=Roles,dc=example,dc=com</value>
      </option>
   </option-group>
   <option-group>
      <group-name>userCreateAttibutes</group-name>
      <option>
         <name>objectClass</name>
         <!--This objectclasses should work with Red Hat Directory-->
         <value>top</value>
         <value>person</value>
         <value>inetOrgPerson</value>
      </option>
      <!--Schema requires those to have initial value-->
      <option>
         <name>cn</name>
         <value>none</value>
      </option>
      <option>
         <name>sn</name>
         <value>none</value>
      </option>
   </option-group>
   <option-group>
      <group-name>roleCreateAttibutes</group-name>
      <!--Schema requires those to have initial value-->
      <option>
         <name>cn</name>
         <value>none</value>
      </option>
      <!--Some directory servers require this attribute to be valid DN-->
      <!--For safety reasons point to the admin user here-->
      <option>
         <name>member</name>
         <value>uid=admin,ou=People,dc=example,dc=com</value>
      </option>
   </option-group>
</options>

In this example, information about users/roles assignment is stored in user entries using LDAP "memberOf". Of course any other attribute that comes with schema can be used for this.

Example tree shape in LDAP browser

 <modules>
   <module>
      <!--type used to correctly map in IdentityContext registry-->
      <type>User</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
   <module>
      <type>Role</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
   <module>
      <type>Membership</type>
      <implementation>LDAP</implementation>
      <class>org.jboss.portal.identity.ldap.LDAPStaticRoleMembershipModuleImpl</class>
      <config/>
   </module>
   <module>
      <type>UserProfile</type>
      <implementation>DELEGATING</implementation>
      <config>
         <option>
            <name>ldapModuleJNDIName</name>
            <value>java:/portal/LDAPUserProfileModule</value>
         </option>
      </config>
   </module>
   <module>
      <type>DBDelegateUserProfile</type>
      <implementation>DB</implementation>
      <config>
         <option>
            <name>randomSynchronizePassword</name>
            <value>true</value>
         </option>
      </config>
   </module>
   <module>
      <type>LDAPDelegateUserProfile</type>
      <implementation>LDAP</implementation>
      <config/>
   </module>
</modules>

<options>
   <option-group>
      <group-name>common</group-name>
      <option>
         <name>userCtxDN</name>
         <value>ou=People,dc=example,dc=com</value>
      </option>
      <option>
         <name>roleCtxDN</name>
         <value>ou=Roles,dc=example,dc=com</value>
      </option>
      <option>
         <name>membershipAttributeID</name>
         <value>memberOf</value>
      </option>
   </option-group>
   <option-group>
      <group-name>userCreateAttibutes</group-name>
      <option>
         <name>objectClass</name>
         <!--This objectclasses should work with Red Hat Directory-->
         <value>top</value>
         <value>person</value>
         <value>inetOrgPerson</value>
      </option>
      <!--Schema requires those to have initial value-->
      <option>
         <name>cn</name>
         <value>none</value>
      </option>
      <option>
         <name>sn</name>
         <value>none</value>
      </option>
   </option-group>
   <option-group>
      <group-name>roleCreateAttibutes</group-name>
      <!--Schema requires those to have initial value-->
      <option>
         <name>cn</name>
         <value>none</value>
      </option>
      <!--Some directory servers require this attribute to be valid DN-->
      <!--For safety reasons point to the admin user here-->
      <option>
         <name>member</name>
         <value>uid=admin,ou=People,dc=example,dc=com</value>
      </option>
   </option-group>
</options>

Like it was described in previous section, you can meet some limitations in identity modules support for more complex LDAP tree shapes. To workaround this you can use identity synchronization on JAAS level. JBoss Portal comes with SynchronizingLoginModule that can be easily configured with other authentication solutions that support JAAS framework. Here we want to provide a simple example on how it can be integrated with LdapExtLoginModule from JBossSX framework.

First of all portal identity modules should be configured to work with portal database - default configuration. This is important as we will leverage them, and we want to synchronize users identity into default portal storage mechanism. So lets look at simple configuration that should take place in jboss-portal.sar/conf/login-config.xml

<policy>
   <!-- For the JCR CMS -->
   <application-policy name="cms">
      <authentication>
         <login-module code="org.apache.jackrabbit.core.security.SimpleLoginModule"
                       flag="required"/>
      </authentication>
   </application-policy>

   <application-policy name="portal">
      <authentication>

         <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required">
            <module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory
            </module-option>
            <module-option name="java.naming.provider.url">ldap://example.com:10389/
            </module-option>
            <module-option name="java.naming.security.authentication">simple</module-option>
            <module-option name="bindDN">cn=Directory Manager</module-option>
            <module-option name="bindCredential">lolo</module-option>
            <module-option name="baseCtxDN">ou=People,dc=example,dc=com</module-option>
            <module-option name="baseFilter">(uid={0})</module-option>
            <module-option name="rolesCtxDN">ou=Roles,dc=example,dc=com</module-option>
            <module-option name="roleFilter">(member={1})</module-option>
            <module-option name="roleAttributeID">cn</module-option>
            <module-option name="roleRecursion">-1</module-option>
            <module-option name="searchTimeLimit">10000</module-option>
            <module-option name="searchScope">SUBTREE_SCOPE</module-option>
            <module-option name="allowEmptyPasswords">false</module-option>
         </login-module>

         <login-module code="org.jboss.portal.identity.auth.SynchronizingLoginModule"
                       flag="optional">
            <module-option name="synchronizeIdentity">true</module-option>
            <module-option name="synchronizeRoles">true</module-option>
            <module-option name="additionalRole">Authenticated</module-option>
            <module-option name="defaultAssignedRole">User</module-option>
            <module-option name="userModuleJNDIName">java:/portal/UserModule</module-option>
            <module-option name="roleModuleJNDIName">java:/portal/RoleModule</module-option>
            <module-option name="membershipModuleJNDIName">java:/portal/MembershipModule
            </module-option>
            <module-option name="userProfileModuleJNDIName">java:/portal/UserProfileModule
            </module-option>
         </login-module>

      </authentication>
   </application-policy>
</policy>

Few things are important in this configuration:

  • LdapExtLoginModule has flag="required" set which means that if this single LoginModule return fail from authentication request whole process will fail. SynchronizingLoginModule has flag="optional". Such combination is critical as SynchronizingLoginModule always authenticates user sucessfully no matter what credentials were provided. You always must have at least one LoginModule that you will rely on.
  • SynchronizingLoginModule is always the last one in whole authentication chain. This is because in commit phase it will take users Subject and its Principals (roles) assigned by previous LoginModules and try to synchronize them. Roles assigned to authenticated user by LoginModules after it won't be handled.

LDAP servers support depends on few conditions. In most cases they differ in schema support - various objectClass objects are not present by default in server schema. Sometimes it can be workarounded by manually extending schema.

Servers can be