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:
- Pentaho application software LDAP administrative user Distinguished Name $(PentahoDN)
- administrative user password $(PentahoPassword)
- LDAP or ActiveDirectory protocol name $(LDAPProtocol)
- LDAP or ActiveDirectory host $(LDAPHost)
- LDAP or ActiveDirectory port number $(LDAPPort)
- LDAP base search $(BaseSearch)
- 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".
./LdapConnect.sh $(PentahoDN) $(PentahoPassword) $(LDAPProtocol)://$(LDAPHost):$LDAPPort)/$(BaseSearch)
./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:
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 forDefaultLdapAuthoritiesPopulator
is specified via its constructor argument index 1.
<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.
<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>
<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>(&(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
.