Configuring LDAP user registries in Liberty

You can configure one or more Lightweight Directory Access Protocol (LDAP) servers with Liberty for authentication.

Before you begin

Ensure that your LDAP server is up and running, and that the host name and port number of the LDAP server are already in your known list.

About this task

You can use an existing LDAP server for application authentication on Liberty. You need to add the appSecurity-2.0 feature to the server.xml file and specify the ldapRegistry-3.0 feature in the server.xml file, and the configuration information for connecting to the LDAP server.

Avoid trouble: There are several security configuration examples on the Open Liberty website for reference when configuring security for your applications on Liberty. For more information, see the link in the related reference for config snippets.

Procedure

  1. Add the appSecurity-2.0 and ldapRegistry-3.0 Liberty features to the server.xml file.
  2. Optional: To communicate with an SSL-enabled LDAP server, add the transportSecurity-1.0 Liberty feature in the server.xml file.
  3. Optional: Copy the truststore to the server configuration directory.
    For example, you can use the ${server.config.dir} variable.

    For SSL communication with an LDAP server to succeed, the Signer certificate for the LDAP server must be added to the truststore that is referenced by the sslRef attribute of the <ldapRegistry> element. In the following examples, the Signer certificate must be added to the LdapSSLTrustStore.jks.

  4. Configure the LDAP entry for the server.

    If you do not want SSL for the LDAP server, remove all SSL and keystore-related lines from the following examples.

    You configure the LDAP server in the server.xml file or by using the WebSphere® Application Server Developer Tools for Eclipse. There are several security configuration examples on the Open Liberty website for reference when configuring security for your applications on Liberty.
    • For IBM® Directory Server:
      <ldapRegistry id="ldap" realm="SampleLdapIDSRealm"
          host="ldapserver.mycity.mycompany.com" port="389" ignoreCase="true"
          baseDN="o=mycompany,c=us"
          ldapType="IBM Tivoli Directory Server"
          sslEnabled="true"
          sslRef="LDAPSSLSettings">
          <idsFilters
          	userFilter="(&amp;(uid=%v)(objectclass=ePerson))"
          	groupFilter="(&amp;(cn=%v)(|(objectclass=groupOfNames)
                           (objectclass=groupOfUniqueNames)
      		     (objectclass=groupOfURLs)))"
          	userIdMap="*:uid"
          	groupIdMap="*:cn"
          	groupMemberIdMap="ibm-allGroups:member;ibm-allGroups:uniqueMember;
      			  groupOfNames:member;groupOfUniqueNames:uniqueMember">
          </idsFilters>
      </ldapRegistry>
      <ssl id="LDAPSSLSettings" keyStoreRef="LDAPKeyStore" trustStoreRef="LDAPTrustStore" />
      
      <keyStore id="LDAPKeyStore" location="${server.config.dir}/LdapSSLKeyStore.jks"
           type="JKS" password="{xor}CDo9Hgw=" />
      <keyStore id="LDAPTrustStore" location="${server.config.dir}/LdapSSLTrustStore.jks"
          type="JKS" password="{xor}CDo9Hgw=" />   
    • For Microsoft Active Directory Server:
      <ldapRegistry id="ldap" realm="SampleLdapADRealm"
          host="ldapserver.mycity.mycompany.com" port="389" ignoreCase="true"
          baseDN="cn=users,dc=adtest,dc=mycity,dc=mycompany,dc=com"
          bindDN="cn=testuser,cn=users,dc=adtest,dc=mycity,dc=mycompany,dc=com"
          bindPassword="testuserpwd"
          ldapType="Microsoft Active Directory"
          sslEnabled="true"
          sslRef="LDAPSSLSettings">
          <activedFilters
          userFilter="(&amp;(sAMAccountName=%v)(objectcategory=user))"
      groupFilter="(&amp;(cn=%v)(objectcategory=group))"
         userIdMap="user:sAMAccountName"
          groupIdMap="*:cn"
          groupMemberIdMap="memberOf:member" >
      </activedFilters>
          </ldapRegistry>
      
      <ssl id="LDAPSSLSettings" keyStoreRef="LDAPKeyStore" trustStoreRef="LDAPTrustStore" />
      
      <keyStore id="LDAPKeyStore" location="${server.config.dir}/LdapSSLKeyStore.jks"
                type="JKS" password="{xor}CDo9Hgw=" />
      <keyStore id="LDAPTrustStore" location="${server.config.dir}/LdapSSLTrustStore.jks"
                type="JKS" password="{xor}CDo9Hgw=" />
      

    If you use the WebSphere Application Server Developer Tools for Eclipse, the bindPassword password is encoded for you automatically. If you edit the server.xml file directly, you can use the securityUtility encode command to encode the bindPassword password for you. The securityUtility command-line tool is available in the $INSTALL_ROOT/bin directory. When you run the securityUtility encode command, you either supply the password to encode as an input from the command line or, if no arguments are specified, the tool prompts you for the password. The tool then outputs the encoded value. Copy the value output by the tool, and use that value for the bindPassword password.

  5. Optional: Configure certificate filter mode for the LDAP server.
    <ldapRegistry id="LDAP" realm="SampleLdapIDSRealm"
          host="myldap.ibm.com" port="389" ignoreCase="true"
          baseDN="o=ibm,c=us"
          ldapType="IBM Tivoli Directory Server" searchTimeout="8m"
          certificateMapMode="CERTIFICATE_FILTER"
          certificateFilter="uid=${SubjectCN}">
          <idsFilters
          userFilter="(&amp;(uid=%v)(objectclass=ePerson))"
          groupFilter="(&amp;(cn=%v)(|(objectclass=groupOfNames)
              (objectclass=groupOfUniqueNames)(objectclass=groupOfURLs)))"
          userIdMap="*:uid"
          groupIdMap="*:cn"
          groupMemberIdMap="ibm-allGroups:member;ibm-allGroups:uniqueMember;
              groupOfNames:member;groupOfUniqueNames:uniqueMember">
    </idsFilters>
          </ldapRegistry>
    For more information about certificate map mode in Liberty, see LDAP certificate map mode.
  6. Optional: You can define mapping between LDAP attributes and the user registry schema attributes.

    After the mapping is configured, when you use the user registry attribute for any operation for which the mapping is defined, the user registry attribute value will be the value of the LDAP attribute. In the following example, you can see that the mapping is defined for the LDAP attribute <userPassword> with the user registry property <password> in the server.xml file. The <defaultValue> attribute is optional.

    <ldapRegistry id="LDAP" realm="SampleLdapIDSRealm"
          host="myldap.ibm.com" port="389" ignoreCase="true"
          baseDN="o=ibm,c=us"
          ldapType="IBM Tivoli Directory Server" searchTimeout="8m">
          <attributeConfiguration>
                 <attribute name="userPassword" propertyName="password" entityType="PersonAccount" defaultValue="xyz123"/>
          </attributeConfiguration>
    </ldapRegistry>
  7. Add ldapEntityType elements to define LDAP object classes.
    1. Add the ObjectClass attributes or ObjectCategory attributes for your person or group entities.

      The defined ObjectClass or ObjectCategory are added to the user or group filter on searches. Examples of ObjectClass include inetOrgPerson or groupOfNames.

      <ldapEntityType name="PersonAccount">
           <objectClass>ePerson</objectClass>
      </ldapEntityType>
      
      <ldapEntityType name="Group">
            <objectClass>groupOfNames</objectClass>
      </ldapEntityType>

      If the correct ObjectClass or ObjectCategory are not defined, a ClassCastException can occur. Examples of ObjectClass include inetOrgPerson or groupOfNames. In other cases, the user is not found or a request to getSecurityName returns an empty string.

      For example, java.lang.ClassCastException: com.ibm.wsspi.security.wim.model.Entity is not compatible with com.ibm.wsspi.security.wim.model.LoginAccount.

  8. Optional: Add search bases or user or group search filters to ldapEntityType elements.
    1. Add a search base

      A search base specifies the sub tree of the LDAP server for the search call of the given entity type, which overrides the base DN in search operations. For example, if the base DN is o=ibm,c=us and the search base for the PersonAccount entity type is defined as ou=iUsers,o=ibm,c=us, then all search calls for PersonAccount are made under sub tree ou=iUsers,o=ibm,c=us.

      You can define a group ldapEntityType searchBase as ou=iGroups,o=ibm,c=us. With this definition, entities in other sub trees, such as ou=iThings,o=ibm,c=us, are ignored.

      Important: Multiple search bases should be used instead of creating multiple LDAP registries for the same LDAP server with different baseDNs.
      <ldapEntityType name="PersonAccount">
           <objectClass>ePerson</objectClass>
            <searchBase>ou=Users,o=ibm,c=us</searchBase>
      </ldapEntityType>
      
      <ldapEntityType name="Group">
            <objectClass>groupOfNames</objectClass>
            <searchBase>ou=Group,o=ibm,c=us</searchBase>
      </ldapEntityType>
    2. Add a search filter.
      A custom LDAP search expression used while searching for entity types. For example, searchFilter="(|(ObjectCategory=User)(ObjectClass=User))".
  9. Optional: You can define mapping between LDAP attributes and the user registry <externalId> attribute.

    You can define mapping between LDAP attributes and the user registry <externalId> attribute. After the mapping is configured, when you use the user registry <externalId> attribute for any operation, the value will be equivalent to the value of the LDAP attribute that is mapped. The following example code shows the mapping that is defined for the user registry <externalId> attribute with the LDAP <distinguishedName> attribute for the entity type <PersonAccount>. The <autoGenerate> attribute is optional, and the value is false by default.

    <ldapRegistry id="LDAP" realm="SampleLdapIDSRealm"
          host="myldap.ibm.com" port="389" ignoreCase="true"
          baseDN="o=ibm,c=us"
          ldapType="IBM Tivoli Directory Server" searchTimeout="8m">
          <attributeConfiguration>
                 <externalIdAttribute name="distinguishedName" entityType="PersonAccount" autoGenerate="false"></externalIdAttribute>
          </attributeConfiguration>
    </ldapRegistry>
  10. Optional: Configure failover for multiple LDAP servers.
    <ldapRegistry id="LDAP" realm="SampleLdapIDSRealm"
        	host="ldapserver1.mycity.mycompany.com" port="389" ignoreCase="true"
         	baseDN="o=ibm,c=us" ldapType="IBM Tivoli Directory Server" idsFilters="ibm_dir_server">
    	<failoverServers name="failoverLdapServersGroup1">
    		<server host="ldapserver2.mycity.mycompany.com" port="389" />
    		<server host="ldapserver3.mycity.mycompany.com" port="389" />
    	</failoverServers>
    	<failoverServers name="failoverLdapServersGroup2">
    		<server host="ldapserver4.mycity.mycompany.com" port="389" />
    	</failoverServers>
    </ldapRegistry>
    
    <idsLdapFilterProperties id="ibm_dir_server"
    	    userFilter="(&amp;(uid=%v)(objectclass=ePerson))"
    	    groupFilter="(&amp;(cn=%v)(|(objectclass=groupOfNames)
                     (objectclass=groupOfUniqueNames)(objectclass=groupOfURLs)))"
    	    userIdMap="*:uid" groupIdMap="*:cn"
    	    groupMemberIdMap="ibm-allGroups:member;ibm-allGroups:uniqueMember;
                          groupOfNames:member;groupOfUniqueNames:uniqueMember">
    </idsLdapFilterProperties>

    For more information about the ldapRegistry and failoverServers elements, see LDAP User Registry.

  11. Optional: Configure multiple LDAP registries. If multiple LDAP registries are configured in the server.xml file, they are federated automatically. Ensure that the users are unique across all federated repositories, otherwise the user registry operations are not successful.
    Note: When you use multiple federated LDAP repositories, each repository must define a unique baseDN.
    <ldapRegistry host="ldapserver1.mycity1.mycompany.com" baseDN="o=mycompany,c=us"
        port="123" ldapType="IBM Tivoli Directory Server">
    </ldapRegistry>
    
    <ldapRegistry host="ldapserver2.mycity2.mycompany.com"
        baseDN="cn=users,dc=secfvt2,dc=mycity2,dc=mycompany,dc=com"
        port="456"
        ldapType="Microsoft Active Directory"
        bindDN="cn=testuser,cn=users,dc=secfvt2,dc=mycity2,dc=mycompany,dc=com"
        bindPassword="{xor}KzosKyosOi0vKDs=">
    </ldapRegistry>
    
    Note:
    • It is best practice, but not mandatory, to specify the federatedRepository element to federate multiple LDAP registries because they are federated automatically. If the federatedRepository element is specified to configure the participatingBaseEntry and primaryRealm elements, then the user registry operations are performed only on the repositories that are defined in the primaryRealm element. You can define the input and output property mappings for different user registry APIs under the primaryRealm element.
    • The name attribute of the participatingBaseEntry element must be the same as the value of baseDN attribute that is specified in the ldapRegistry element. In the example follows, the baseDN and name attributes are configured for the LDAP registry on the host ldapserver1.mycity1.mycompany.com. The value of baseDN attribute must be the same as that of sub tree in your LDAP server and the value of name attribute must be the name of that sub tree in the federated user registry. It is optional to specify the name attribute. By default, the name attribute uses the same value as the baseDN attribute. If the name attribute is specified in the ldapRegistry element, then the name attribute in the participatingBaseEntry element must use the same value as the name attribute in the ldapRegistry element.
    <ldapRegistry host="ldapserver1.mycity1.mycompany.com" baseDN="o=mycompany,ou=myou,c=us"
        port="123" ldapType="IBM Tivoli Directory Server" name="o=mybaseentry">
    </ldapRegistry>
    
    <ldapRegistry host="ldapserver2.mycity2.mycompany.com"
        baseDN="cn=users,dc=secfvt2,dc=mycity2,dc=mycompany,dc=com"
        port="456"
        ldapType="Microsoft Active Directory"
        bindDN="cn=testuser,cn=users,dc=secfvt2,dc=mycity2,dc=mycompany,dc=com"
        bindPassword="{xor}KzosKyosOi0vKDs=">
    </ldapRegistry>
    
    <federatedRepository>
    	 <primaryRealm name="RealmName" delimiter="@" allowOpIfRepoDown="true">
    	 	<participatingBaseEntry name="o=mybaseentry"/>
    		 <participatingBaseEntry name="cn=users,dc=secfvt2,dc=mycity2,dc=mycompany,dc=com"/>
    	 	 <uniqueUserIdMapping inputProperty="uniqueName" outputProperty="uniqueName"/>
    	 	 <userSecurityNameMapping inputProperty="principalName" outputProperty="principalName"/>
            		 <userDisplayNameMapping inputProperty="principalName" outputProperty="principalName"/>
    		 <uniqueGroupIdMapping inputProperty="uniqueName" outputProperty="uniqueName"/>
            		 <groupSecurityNameMapping inputProperty="cn" outputProperty="cn"/>
            		 <groupDisplayNameMapping inputProperty="cn" outputProperty="cn"/>
            	</primaryRealm>
    </federatedRepository>

    For more information about the federated ldapRegistry elements, see LDAP User Registry.

  12. Optional: You can configure other optional attributes for the LDAP registry, such as contextPool or ldapCache, as given in the following example:
    <ldapRegistry id="IBMDirectoryServerLDAP"         realm="SampleLdapIDSRealm"
            host="host.domain.com" port="389" ignoreCase="true"
            baseDN="o=domain,c=us"
            bindDN="cn=testuser,o=domain,c=us"
            bindPassword="mypassword"
            ldapType="IBM Tivoli Directory Server"
            searchTimeout="8m">
        <contextPool enabled="true" initialSize="1" maxSize="0" timeout="0s" waitTime="3000ms" preferredSize="3"/>
        <ldapCache>
            <attributesCache size="4000" timeout="1200s" enabled="true" sizeLimit="2000"/>
            <searchResultsCache size="2000" timeout="600s" enabled="true" resultsSizeLimit="1000"/>
        </ldapCache>
    </ldapRegistry>
    Note:
    • Federated user registry uses the context pooling mechanism to improve the performance of concurrent access to an LDAP server. Context pooling works at a higher level than the connection pooling. Each context entry in the context pool corresponds to a socket connection to the LDAP server. The bind credentials that are used by this pool are specified when you configure the LDAP registry.
    • Federated repository uses the cache mechanism for performance enhancement. It caches information about the LDAP users and groups based on the user operations performed. For example, if you perform a search operation on the LDAP users and groups, the result of the operation is cached. You can enable the ldapCache element in the server.xml file as shown in the previous example.
    Troubleshooting tip: To troubleshoot any LDAP authentication issues, use the following trace specifications in the bootstrap.properties file:
    com.ibm.ws.security.wim.*=all:com.ibm.websphere.security.wim.*=all
  13. Optional: The SSL configuration that is used to connect to the LDAP server can be determined in the SSL configuration rather than by being specified with the sslRef attribute. The sslEnabled attribute needs to be set to true.

    If sslRef is not specified the SSL code looks to see if an outbound filter that matches the LDAP host and port, or if the SSL outbound default should be used. For more information on the outbound SSL options, see Configuring SSL Settings for outbound communications. For more information on outbound filters, see Outbound filters for SSL configurations

    <ldapRegistry id="ldap" realm="SampleLdapIDSRealm"
          host="ldapserver.mycity.mycompany.com" port="389" ignoreCase="true"
          baseDN="o=mycompany,c=us"
          ldapType="IBM Tivoli Directory Server"
          sslEnabled="true" >
          <idsFilters
          userFilter="(&amp;(uid=%v)(objectclass=ePerson))"
          groupFilter="(&amp;(cn=%v)(|(objectclass=groupOfNames)
                       (objectclass=groupOfUniqueNames)(objectclass=groupOfURLs)))"
          userIdMap="*:uid"
          groupIdMap="*:cn"
          groupMemberIdMap="ibm-allGroups:member;ibm-allGroups:uniqueMember;
          groupOfNames:member;groupOfUniqueNames:uniqueMember">
          </idsFilters>
    </ldapRegistry>