OpenKM v6.2.3 -> Active Directory Integration

By | April 18, 2013

There have been lots of changes to OpenKM since I last wrote about it. Working on getting Active Directory integration and OCR rock solid on a CentOS 6.4 x64 platform running under Hyper-V on Windows Server 2008 R2 SP1. Here’s what I’ve learned…

Active Directory

I’m running Active Directory on a pair of Windows Server 2012 Enterprise servers. Instead of giving some vague configuration info, I’ll supply the configuration points in their entirety. The first is the /opt/tomcat-7.0.27/OpenKM.xml file which should be edited to look exactly like this one (before the 4 changes outlines in bold and covered below):

<?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”>

<!– Tasks configuration –>
<!–
<task:scheduler id=”taskScheduler” pool-size=”1″/>
<task:scheduled-tasks scheduler=”taskScheduler”>
    <task:scheduled ref=”textExtractorWorker” method=”work” fixed-delay=”60000″/>
</task:scheduled-tasks>
<beans:bean id=”textExtractorWorker” class=”com.openkm.extractor.TextExtractorWorker” />
–>

<security:authentication-manager alias=”authenticationManager”>
    <security:authentication-provider ref=”ldapAuthProvider”/>
</security:authentication-manager>

<beans:bean id=”ldapAuthProvider” class=”org.springframework.security.ldap.authentication.LdapAuthenticationProvider”>
    <beans:constructor-arg ref=”ldapBindAuthenticator”/>
    <beans:constructor-arg ref=”ldapAuthoritiesPopulator”/>
</beans:bean>

<beans:bean id=”contextSource” class=”org.springframework.security.ldap.DefaultSpringSecurityContextSource”>
    <!– MS Active Directory –>
    <beans:constructor-arg value=”ldap://LDAPSERVERFQDN:389/ADROOTCONTAINER“/>
    <beans:property name=”userDn” value=”LDAPACCOUNT“/>
    <beans:property name=”password” value=”LDAPACCOUNTPASSWORD“/>
    <beans:property name=”baseEnvironmentProperties”>
        <beans:map>
            <beans:entry key=”java.naming.referral” value=”follow” />
        </beans:map>
    </beans:property>
</beans:bean>

<beans:bean id=”ldapBindAuthenticator” class=”org.springframework.security.ldap.authentication.BindAuthenticator”>
    <beans:constructor-arg ref=”contextSource”/>
    <beans:property name=”userSearch” ref=”userSearch”/>
</beans:bean>

<beans:bean id=”userSearch” class=”org.springframework.security.ldap.search.FilterBasedLdapUserSearch”>
    <!– MS Active Directory –>
    <!– user-search-base; relative to base of configured context source –>
    <beans:constructor-arg index=”0″ value=””/>
    <!– user-search-filter –>
    <beans:constructor-arg index=”1″ value=”(sAMAccountName={0})”/>
    <beans:constructor-arg index=”2″ ref=”contextSource”/>
</beans:bean>

<beans:bean id=”ldapAuthoritiesPopulator” class=”org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator”>
    <beans:constructor-arg ref=”contextSource” />
    <beans:constructor-arg value=”” />
    <beans:property name=”groupSearchFilter” value=”(member={0})”/>
    <beans:property name=”groupRoleAttribute” value=”CN” />
    <beans:property name=”rolePrefix” value=””/>
    <beans:property name=”searchSubtree” value=”true”/>
    <beans:property name=”convertToUpperCase” value=”false”/>
    <beans:property name=”ignorePartialResultException” value=”true”/>
</beans:bean>

</beans:beans>

Next we need to set values under Administration, Config:

Key Value
principal.adapter com.openkm.principal.LdapPrincipalAdapter
principal.database.filter.inactive.users TRUE
principal.hide.connection.roles FALSE
principal.ldap.mail.attribute mail
principal.ldap.mail.search.base USERCONTAINER
principal.ldap.mail.search.filter (&(objectclass=person)(sAMAccountName={0}))
principal.ldap.referral follow
principal.ldap.role.attribute CN
principal.ldap.role.search.base GROUPCONTAINER
principal.ldap.role.search.filter (objectClass=group)
principal.ldap.roles.by.user.attribute memberOf
principal.ldap.roles.by.user.search.base USERCONTAINER
principal.ldap.roles.by.user.search.filter (&(objectclass=person)(sAMAccountName={0}))
principal.ldap.security.credentials LDAPACCOUNTPASSWORD
principal.ldap.security.principal LDAPACCOUNT
principal.ldap.server ldap://LDAPSERVERFQDN:389
principal.ldap.user.attribute sAMAccountName
principal.ldap.user.search.base USERCONTAINER
principal.ldap.user.search.filter (&(objectclass=person)(|(memberOf=CN=OPENKMUSERROLE)(memberOf=CN=OPENKMADMINROLE)))
principal.ldap.username.attribute CN
principal.ldap.username.search.base USERCONTAINER
principal.ldap.username.search.filter (&(objectclass=person)(sAMAccountName={0}))
principal.ldap.users.by.role.attribute sAMAccountName
principal.ldap.users.by.role.search.base USERCONTAINER
principal.ldap.users.by.role.search.filter (&(objectCategory=user)(memberof:1.2.840.113556.1.4.1941:=CN={0},GROUPCONTAINER)(|(memberOf=CN=OPENKMUSERROLE)(memberOf=CN=OPENKMADMINROLE)))
principal.ldap.users.from.roles TRUE

Both of the above code examples use the following variable strings. Simply replace the following strings with your actual values:

  • LDAPSERVERFQDN: SERVERNAME.DOMAINNAME.TOPLEVELDOMAIN like “domaincontroller.contoso.com”.
  • ADROOTCONTAINER: DC=DOMAINNAME,DC=TOPLEVELDOMAIN like “CN=Users,DC=contoso,DC=com”.
  • LDAPACCOUNT: CN=LDAPACCOUNT,CN=LDAPACCOUNTCONTAINER,DC=DOMAINNAME,DC=TOPLEVELDOMAIN like “CN=Administrator,CN=Users,DC=contoso,DC=com”. Many LDAP tools allow you to get this information from your Active Directory.
  • LDAPACCOUNTPASSWORD: The password for the LDAPACCOUNT.
  • USERCONTAINER: OU=USERCONTAINER,DC=DOMAINNAME,dc=TOPLEVELDOMAIN like “OU=Contoso Users,DC=contoso,DC=com”.
  • GROUPCONTAINER: OU=GROUPCONTAINER,DC=DOMAINNAME,dc=TOPLEVELDOMAIN like “”.
  • OPENKMUSERROLE: CN=OpenKMUserRole,OU=GROUPCONTAINER,DC=DOMAINNAME,dc=TOPLEVELDOMAIN like “CN=OpenKMUserRole,OU=Contoso Groups,DC=contoso,DC=com”.
  • OPENKMADMINROLE: CN=OpenKMAdminRole,OU=GROUPCONTAINER,DC=DOMAINNAME,dc=TOPLEVELDOMAIN like “CN=OpenKMAdminRole,OU=Contoso Groups,DC=contoso,DC=com”.

Once you have made the changes to both of these, you should restart tomcat so the OpenKM.xml changes are used. I also moved the installation to MySQL and used phpMyAdmin to aid in troubleshooting and getting access to the GUI configuration values. This configuration appears to return all values correctly regardless of using the default Active Directory locations for users and groups or if you use a custom user OU and/or group OU location.

NOTE 1: I had to create a group in Active Directory called ROLE_ADMIN because I believe the value is hard coded in some of the code. All of the code should lookup the value in default.admin.role, however I did see this value in the logs while troubleshooting my configuration.

NOTE 2: If you need to turn on ldap troubleshooting, edit the /opt/tomcat-7.0.27/conf/log4j.properties file and add log4j.logger.org.springframework.security=TRACE to the end of the file. You will need to restart tomcat for this change to take effect.

One thought on “OpenKM v6.2.3 -> Active Directory Integration

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.