LDAP Troubleshooting

The issues below are common when configuring LDAP.

Connecting

Before you can test your searches, you first need to successfully connect to an LDAP server. A shell script, which calls a small Java program, is attached that will allow you to test connection parameters before you use them in the Pentaho BI Server.

The parameters to the script are as follows:

  1. Pentaho application software LDAP administrative user Distinguished Name $(PentahoDN)
  2. administrative user password $(PentahoPassword)
  3. LDAP or ActiveDirectory protocol name $(LDAPProtocol)
  4. LDAP or ActiveDirectory host $(LDAPHost)
  5. LDAP or ActiveDirectory port number $(LDAPPort)
  6. LDAP base search $(BaseSearch)
  7. optional trust store path $(TrustStore)

An example for $(PentahoDN) is "cn=pentaho,ou=Users,dc=example,dc=com".

For $(PentahoPassword), "HardToGuess2+".

The value of $(LDAPHost) could be "ldap1.public-ldap.example.com" or
"ldap2.secure-ldap.example.com". $(LDAPProtocol) can be either "ldap" or "ldaps" and $(LDAPPort) will usually be "389".

An example $(BaseSearch) could be "ou=Users,dc=example,dc=com".

The parameter $(TrustStore) is relevant only when using secure LDAP. The trust store is necessary if the root of the certificate chain is not available in jre/lib/security/cacerts. An example is "/lib/security/cacerts".

Testing Connection

./LdapConnect.sh $(PentahoDN) $(PentahoPassword) $(LDAPProtocol)://$(LDAPHost):$LDAPPort)/$(BaseSearch)

Testing Connection using ldaps

./LdapConnect.sh $(PentahoDN) $(PentahoPassword) $(LDAPProtocol)://$(LDAPHost):$LDAPPort)/$(BaseSearch) $(TrustStore)

It is also possible to test the LDAP/ActiveDirectory credentials using the Linux utility "ldapsearch". An example equivalent to LdapConnect.sh would be:

Testing Connection using ldapsearch

ldapsearch -s one -P 3 -x -h $(LDAPHost) -b $(BaseSearch) -D $(PentahoDN) -w $(PentahoPassword) '(objectClass=*)' dn

Subtree Searching

When locating users and their roles within a directory, you can specify a search scope. Spring Security allows you to specify search scope by setting the searchSubtree property on either or both of FilterBasedLdapUserSearch and DefaultLdapAuthoritiesPopulator. By setting searchSubtree to true, the search scope is SearchControls.SUBTREE_SCOPE. Otherwise, the search scope is SearchControls.ONELEVEL_SCOPE.

If the objects for which you are searching (e.g. users or roles) are located directly under the node denoted by the search base, then set the searchSubtree property to false. Otherwise, tell Spring Security to search the entire subtree by setting the searchSubtree property to true.

Note: The search base for FilterBasedLdapUserSearch is specified via its constructor argument index 0. The search base for DefaultLdapAuthoritiesPopulator is specified via its constructor argument index 1.

applicationContext-spring-security-ldap.xml
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <!-- omitted -->
  <property name="searchSubtree" value="false" />
</bean>

<bean id="populator" class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
  <!-- omitted -->
  <property name="searchSubtree" value="false" />
</bean>

Just as DefaultLdapAuthoritiesPopulator has a configurable search scope via its searchSubtree property, LdapSearchParamsFactoryImpl provides a way to set a search scope by passing a SearchControls instance into the constructor. The XML below demonstrates this. If no SearchControls is supplied via the constructor, the default search scope is ONELEVEL_SCOPE.

<bean class="org.pentaho.platform.plugin.services.security.userrole.ldap.search.LdapSearchParamsFactoryImpl">
  <constructor-arg index="0" value="ou=users" />
  <constructor-arg index="1" value="objectClass=Person" />
  <constructor-arg index="2">
    <bean class="javax.naming.directory.SearchControls">
      <!-- 2 comes from http://java.sun.com/javase/6/docs/api/javax/naming/directory/SearchControls.html#SUBTREE_SCOPE -->
      <property name="searchScope" value="2" />
    </bean>
  </constructor-arg>
</bean>

Whitespace

You must be very careful when formatting the applicationContext-*.xml files. In particular, whitespace is not always stripped from string properties before they are used. While well-formed, the following FilterBasedLdapUserSearch example contains whitespace the will negatively impact its functioning.

Whitespace in value (Incorrect)
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <!-- omitted -->
  <constructor-arg index="1">
    <value>
      <![CDATA[(&(objectClass=organizationalPerson)(sAMAccountName={0}))]]>
    </value>
  </constructor-arg>
  <!-- omitted -->
</bean>
No whitespace in value (Correct)
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <!-- omitted -->
  <constructor-arg index="1"><value><![CDATA[(&(objectClass=organizationalPerson)(sAMAccountName={0}))]]></value></constructor-arg>
  <!-- omitted -->
</bean>

Special Characters

The ampersand character (i.e. &) appears commonly in LDAP search filters. However, this character has special meaning in XML. Therefore, the ampersand character must be escaped in one of two ways:

  • Replace the ampersand character with an entity reference.
    <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
      <!-- omitted -->
      <constructor-arg index="1"><value>(&amp;(objectClass=organizationalPerson)(sAMAccountName={0}))</value></constructor-arg>
      <!-- omitted -->
    </bean>
    
  • Wrap the LDAP search filter value in a CDATA tag.
    <bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
      <!-- omitted -->
      <constructor-arg index="1"><value><![CDATA[(&(objectClass=organizationalPerson)(sAMAccountName={0}))]]></value></constructor-arg>
      <!-- omitted -->
    </bean>
    

Root Distinguished Name (DN)

With some directory servers, you might need to use (non relative) DNs for your search bases even though you specified a root DN in your LDAP URL. (Spring Security calls an LDAP URL a "provider URL.")

For example, ou=system is the root DN in the LDAP URL ldap://localhost:10389/ou=system. In the default configuration, the user search base is ou=users; some directory servers might require a user search base of ou=users,ou=system.