LDAP troubleshooting

How to do a nested group membership filter in Active Directory

The sample below demonstrates how to configure AD search to retrieve users that are members of a role that is a member of ROLE_OPENKM.

Field / PropertyTypeDescription

principal.ldap.user.search.filter

String

((objectclass=user)((memberOf:1.2.840.113556.1.4.1941:=CN=ROLE_OPENKM,OU=OpenKM,DC=company,DC=com))

No UserDetailsService registered error

If you see an exception like this "org.springframework.context.ApplicationContextException: No UserDetailsService registered," you might add this line to your openkm.xml:

<beans:bean id="userDetailService" class="com.openkm.spring.UserTenantDetailsService"/>

This issue only affects versions of OpenKM where the "remember me" feature was included. Take a look at the Changelog to check if your OpenKM is affected.

You can find more information about the "remember me" configuration in the Security configuration parameters.

javax.naming.PartialResultException error

If you see an exception like this "javax.naming.PartialResultException" you probably cannot use Active Directory basic configuration.

javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name 'cn=users,dc=company,dc=com'

Solution 1:

Use ports 3268 or 3269 (ldaps) in the AD connection.

Go to Administration > Configuration parameters:

Field / PropertyTypeDescription
principal.ldap.server String

ldap://192.168.xxx.xxx:3268

Solution 2:

Enable LDAP to ignore the partial results exception property.

Go to Administration > Configuration parameters:

Field / PropertyTypeDescription
ldap.ignore.partial.result.exception Boolean

true

Solution 3:

Enable the LDAP referral property.

Go to Administration > Configuration parameters:

Field / PropertyTypeDescription
principal.ldap.referral String

follow

Read these articles:

Can't connect to LDAP server

If your LDAP server is configured to use SSL, then you should use ldaps://.

Solution:

Go to Administration > Configuration parameters:

Change the server connection URL to ldaps.

Field / PropertyTypeDescription
principal.ldap.server String

ldaps://192.168.0.6:389

Slow login or unable to log in

It may be a problem with LDAP DNS name resolution.

Solution:

To prevent this issue - especially on the Windows OS family - it is good practice to add all subdomains to the application server's hosts file (/etc/hosts for Linux or C:/Windows/System32/drivers/etc/hosts for Windows).

Example based on Active Directory (LDAP) with distinguished base name dc=company,dc=com and server domain name SBSSERVER.

10.10.1.2 company.com
10.10.1.2 SBSSERVER SBSSERVER.company.com
10.10.1.2 Schema.Configuration.company.com
10.10.1.2 Configuration.company.com
10.10.1.2 DomainDnsZones.company.com
10.10.1.2 ForestDnsZones.company.com

More information is available at the OpenKM forum.

If, after adding these subdomains, the login continues to take a long time, check with your IT security team to see if they have enabled micro-segmentation policies. That may be another reason why login takes so long.

To check connections made by the application during the login process to AD, you can execute the following command:

$ tcpdump -A tcp port 389

Force all users to be members of ROLE_USER.

In large AD user repositories, it is not practical for the AD administrator to add a new group to all users; in this case, we can force via the XML login configuration that any logged-in user be a member of ROLE_USER. You must add the XML tag <beans:property name="defaultRole" value="ROLE_USER" />.

For example:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:security="http://www.springframework.org/schema/security"
             xmlns:task="http://www.springframework.org/schema/task"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security.xsd
                                 http://www.springframework.org/schema/task
                                 http://www.springframework.org/schema/task/spring-task.xsd">
 
<security:authentication-manager alias="authenticationManager">
     <security:authentication-provider ref="ldapAuthProvider" />
  </security:authentication-manager>
 
<beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <beans:constructor-arg value="ldap://192.168.xxx.xxx"/>
  <beans:property name="userDn" value="CN=connect,OU=OpenKM,DC=company,DC=com"/>
  <beans:property name="password" value="****"/>
  <beans:property name="baseEnvironmentProperties">
     <beans:map>
        <beans:entry>
          <beans:key>
            <beans:value>java.naming.referral</beans:value>
          </beans:key>
          <beans:value>follow</beans:value>
        </beans:entry>
      </beans:map>
   </beans:property>
</beans:bean>
 
<beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
  <beans:constructor-arg>
    <beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
      <beans:constructor-arg ref="contextSource"/>
      <beans:property name="userSearch" ref="userSearch"/>
    </beans:bean>
  </beans:constructor-arg>
  <beans:constructor-arg name="authoritiesPopulator" ref="defaultLdapAuthoritiesPopulator"/> 
</beans:bean>
 
<beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <beans:constructor-arg index="0" value="DC=company,DC=com" />
  <beans:constructor-arg index="1" value="(&amp;(sAMAccountName={0})(|(memberOf=CN=ROLE_ADMIN,OU=OpenKM,DC=company,DC=com)(memberOf=CN=ROLE_USER,OU=OpenKM,DC=company,DC=com)))" />
  <beans:constructor-arg index="2" ref="contextSource" />
  <beans:property name="searchSubtree" value="true" />
</beans:bean>

  <beans:bean id="defaultLdapAuthoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
		<beans:constructor-arg ref="contextSource"/>
      <beans:constructor-arg value="DC=company,DC=com"/>
      <beans:property name="groupSearchFilter" value="member={0}"/>
      <beans:property name="groupRoleAttribute" value="cn"/>
      <beans:property name="searchSubtree" value="true" />
      <beans:property name="convertToUpperCase" value="false" />
      <beans:property name="rolePrefix" value="" />
      <beans:property name="defaultRole" value="ROLE_USER" />
	</beans:bean>
	
	<!--Needed for remember-me services -->
	<beans:bean id="userDetailService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
		<beans:constructor-arg ref="userSearch"/>
		<beans:constructor-arg ref="defaultLdapAuthoritiesPopulator"/>
	</beans:bean>
 
</beans:beans> 

org.springframework.beans.factory.parsing.BeanDefinitionParsingException

If you see an error like this "org.springframework.beans.factory.parsing.BeanDefinitionParsingException" you probably have an incorrect Spring version set in openkm.xml:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema with Spring Security 3.2. Please update your schema declarations to the 3.2 schemas.
Offending resource: URL [file:/home/openkm/tomcat-8.5.69/openkm.xml]
    at org.springframework.beans.factory.parsing.FailFastProblemReporter.fatal(FailFastProblemReporter.java:59)

Solution:

Edit the openkm.xml file and remove the version numbers:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:security="http://www.springframework.org/schema/security"
             xmlns:task="http://www.springframework.org/schema/task"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                                 http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security-3.1.xsd
                                 http://www.springframework.org/schema/task
                                 http://www.springframework.org/schema/task/spring-task-3.1.xsd">

to

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:security="http://www.springframework.org/schema/security"
             xmlns:task="http://www.springframework.org/schema/task"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd
                                 http://www.springframework.org/schema/security
                                 http://www.springframework.org/schema/security/spring-security.xsd
                                 http://www.springframework.org/schema/task
                                 http://www.springframework.org/schema/task/spring-task.xsd">

LDAP: error code 8 - BindSimple: Transport encryption required

The transport encryption required error usually happens when you are trying to connect with ldaps (with SSL encryption), and you have not configured the trust certificate in the Java certificate store.

First, check that you are using "ldaps://" (ends with "s") in your openkm.xml file for the connection; when you get this error, use it.

The first step is to get the certificate from the server; to do so, follow the steps below:

$ openssl s_client -showcerts -connect  your.ldap.server.com:636

The OpenSSL Windows binaries https://wiki.openssl.org/index.php/Binaries (version tested https://indy.fulgan.com/SSL/).

The output will contain several entries delimited with the following:

-----BEGIN CERTIFICATE-----
aklfhskfadljasdl1340234234ASDSDFSDFSDFSDFSD
....
-----END CERTIFICATE-----

To prevent the loss of JKS after the Java upgrade, do not create the JKS under the JDK folders.

In the sample below, it is assumed that $TOMCAT_HOME is set to /home/openkm/tomcat.

Copy the last certificate entry into a file (ldapca.crt)
Then, add it to the Java keystore in $JRE_HOME/lib/security.

$ cd $TOMCAT_HOME

$ mkdir jks
$ keytool -import -alias ldapca_self_sign -keystore cacerts -storepass changeit -file ldapca.crt

Finally, enable the trust store in the file $TOMCAT_HOME/bin/setenv.sh.

# JAVA enable trust store
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=/home/openkm/tomcat/jks/cacerts -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=JKS"

LDAP error: Caused by java.security.cert.CertificateException: No subject alternative DNS name matching

The log may show some stack trace errors like:

Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching ldap.openkm.com found.
        at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214)
        at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
        at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459)
        at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:200)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
        ... 72 more

Or like:

Caused by: org.springframework.ldap.CommunicationException: simple bind failed: ldap.openkm.com:636; nested exception is javax.naming.CommunicationException: simple bind failed: email.ied.edu.hk:636 [Root exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching email.ied.edu.hk found.]
        at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:100)
        at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:285)
        at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:119)
        at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:138)
        at org.springframework.ldap.core.LdapTemplate.executeReadOnly(LdapTemplate.java:791)
        at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntry(SpringSecurityLdapTemplate.java:194)
        at org.springframework.security.ldap.search.FilterBasedLdapUserSearch.searchForUser(FilterBasedLdapUserSearch.java:116)
        at org.springframework.security.ldap.authentication.BindAuthenticator.authenticate(BindAuthenticator.java:90)
        at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:178)

Modify JVM configuration parameters in setenv.sh or setenv.bat by adding the following JVM configuration parameter:

-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true