Howto setup LDAP-Authentication for Wavemaker (Part 2)

Remember Part 1:

http://www.vcoportal.de/2012/05/howto-setup-ldap-authentication-for-wavemaker-part-1/

The Workaround

In the solution of Part 1, you can only find groups in one OU. In the wavemaker community, there are some links to additional documentation, were this post is based on.

Let’s have a look to the AD. In the Wavemaker examples a “flat” AD Structure is used

Whow, I have never seen an AD like this….. In the Wavemaker community examples always a “flat” AD environment is used. In such an environment it is easy to setup a Group Authentication…but in the environments, where I work I never had such an easy AD. So let’s have a look to a “real” AD:

When you use Wavemaker to configure your AD you are limited in the GUI. You cannot point your configuration to different OUs. Your only option is to get user out of one OU. But how do you configure your application if your users were sprawl in different OUs?

So when your people are from different OUs you have a problem….
For this problem, there is a solution, but therefore you have to make your LDAP configuration manually. First of all, you have to configure your AD Server connection. I assume that you have done this already. After that, we need some configuration changes…

First we have do modify the file project-security.xml. This is located under:

%PROJECTPATH%\webapproot\WEB-INF\project-security.xml

Insert the following code

<bean id="userSearch">

<constructor-arg index="0">

<value>cn=users</value> --> Here you must put the parent directory were to start the user search

</constructor-arg>

<constructor-arg index="1">

<value>(sAMAccountName={0})</value>

</constructor-arg>

<constructor-arg index="2">

<ref local="initialDirContextFactory"/>

</constructor-arg>

<property name="searchSubtree">

<value>true</value>

</property>

</bean>

One word to the code above, I was not able to start my search onto the root of the domain. I didn’t find a solution to start the search from there! I had to choose a OU or subfolder.

After that, you have to change some code in the file… See the screenshot for the “summary” of all changes, and find the complete before/after .xml-files below.

Be aware: After that, you cannot use the  LDAP configuration page in Wavemaker anymore! If you do so, everything will be overwritten and you have to start from scratch again!

The limitation above is not a Wavemaker limitation but comes from the used ACEGI Security which is used in Wavemaker. Additional information can be found here:

http://www.opennms.org/wiki/Acegi_Security_and_LDAP

So have fun with Orchestrator, Wavemaker and your Active Directory!

Complete before/after-xml-files

Change this…

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <bean id="filterChainProxy">
 <property name="filterInvocationDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /**=httpSessionContextIntegrationFilter,logoutFilter,formAuthenticationProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterSecurityInterceptor
 </value>
 </property>
 </bean>
 <bean id="httpSessionContextIntegrationFilter"/>
 <bean id="logoutFilter">
 <constructor-arg value="/index.html"/>
 <constructor-arg>
 <list>
 <bean/>
 </list>
 </constructor-arg>
 <property value="/j_acegi_logout" name="filterProcessesUrl"/>
 </bean>
 <bean id="formAuthenticationProcessingFilter">
 <property name="filterProcessesUrl">
 <value>/j_acegi_security_check</value>
 </property>
 <property name="authenticationFailureUrl">
 <value>/login.html?login_error=1</value>
 </property>
 <property name="defaultTargetUrl">
 <value>/</value>
 </property>
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 </bean>
 <bean id="jsonExceptionTranslationFilter">
 <property name="authenticationEntryPoint">
 <ref bean="formLoginAuthenticationEntryPoint"/>
 </property>
 </bean>
 <bean id="formLoginAuthenticationEntryPoint">
 <property name="loginFormUrl">
 <value>/login.html</value>
 </property>
 <property name="forceHttps">
 <value>false</value>
 </property>
 </bean>
 <bean id="anonymousProcessingFilter">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 <property name="userAttribute">
 <value>anonymousUser,ROLE_ANONYMOUS</value>
 </property>
 </bean>
 <bean id="anonymousAuthenticationProvider">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 </bean>
 <bean id="filterSecurityInterceptor">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="accessDecisionManager">
 <ref bean="accessDecisionManager"/>
 </property>
 <property name="objectDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /*.upload=IS_AUTHENTICATED_FULLY
 /*.download=IS_AUTHENTICATED_FULLY
 /index.html=IS_AUTHENTICATED_FULLY
 /=IS_AUTHENTICATED_FULLY
 /securityservice.json=IS_AUTHENTICATED_ANONYMOUSLY
 /*.json=IS_AUTHENTICATED_FULLY
 </value>
 </property>
 </bean>
 <bean id="authenticationManager">
 <property name="providers">
 <list>
 <ref bean="ldapAuthProvider"/>
 <ref bean="anonymousAuthenticationProvider"/>
 </list>
 </property>
 </bean>
 <bean id="daoAuthenticationProvider">
 <property name="userDetailsService">
 <ref bean="inMemoryDaoImpl"/>
 </property>
 </bean>
 <bean id="inMemoryDaoImpl">
 <property name="userMap">
 <value>
 demo=demo,ROLE_DEFAULT_NO_ROLES
 </value>
 </property>
 </bean>
 <bean id="jdbcDaoImpl">
 <property name="dataSource">
 <ref bean="jdbcDataSource"/>
 </property>
 <property name="usersByUsernameQuery">
 <value>SELECT first_name, last_name, 1 FROM employee WHERE first_name = ?</value>
 </property>
 <property name="authoritiesByUsernameQuery">
 <value>SELECT first_name, "DEFAULT_NO_ROLES" FROM employee WHERE first_name = ?</value>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="usernameBasedPrimaryKey">
 <value>true</value>
 </property>
 </bean>
 <bean id="jdbcDataSource"/>
 <bean id="ldapAuthProvider">
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="userDnPatterns">
 <list>
 <value>cn={0},ou=people</value>
 </list>
 </property>
 </bean>
 </constructor-arg>
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <constructor-arg>
 <value>ou=groups</value>
 </constructor-arg>
 <property name="groupSearchDisabled">
 <value>false</value>
 </property>
 <property name="roleProvider">
 <value>LDAP</value>
 </property>
 <property name="groupRoleAttribute">
 <value>cn</value>
 </property>
 <property name="groupSearchFilter">
 <value>(member={0})</value>
 </property>
 </bean>
 </constructor-arg>
 </bean>
 <bean id="initialDirContextFactory">
 <constructor-arg value="ldap://localhost:389/dc=wavemaker,dc=com"/>
 <property name="managerDn">
 <value>cn=manager,dc=wavemaker,dc=com</value>
 </property>
 <property name="managerPassword">
 <value>7b6a43524a282c146a6b626e425c32205754</value>
 </property>
 </bean>
 <bean id="accessDecisionManager">
 <property name="allowIfAllAbstainDecisions">
 <value>false</value>
 </property>
 <property name="decisionVoters">
 <list>
 <bean/>
 <bean/>
 </list>
 </property>
 </bean>
 <bean id="roleVoter">
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 </bean>
 <bean id="autoProxyCreator">
 <property name="proxyTargetClass">
 <value>true</value>
 </property>
 <property name="interceptorNames">
 <list>
 <value>securityInterceptor</value>
 </list>
 </property>
 </bean>
 <bean id="securityInterceptor">
 <property ref="authenticationManager" name="authenticationManager"/>
 <property ref="accessDecisionManager" name="accessDecisionManager"/>
 <property name="objectDefinitionSource">
 <value>
 </value>
 </property>
 </bean>
 <bean scope="singleton" id="securityService">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="noRolesMarkerRole">
 <value>DEFAULT_NO_ROLES</value>
 </property>
 <property name="roles">
 <list/>
 </property>
 </bean>
</beans>

…to this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <bean id="filterChainProxy">
 <property name="filterInvocationDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /**=httpSessionContextIntegrationFilter,logoutFilter,formAuthenticationProcessingFilter,anonymousProcessingFilter,jsonExceptionTranslationFilter,filterSecurityInterceptor
 </value>
 </property>
 </bean>
 <bean id="httpSessionContextIntegrationFilter"/>
 <bean id="logoutFilter">
 <constructor-arg value="/index.html"/>
 <constructor-arg>
 <list>
 <bean/>
 </list>
 </constructor-arg>
 <property value="/j_acegi_logout" name="filterProcessesUrl"/>
 </bean>
 <bean id="formAuthenticationProcessingFilter">
 <property name="filterProcessesUrl">
 <value>/j_acegi_security_check</value>
 </property>
 <property name="authenticationFailureUrl">
 <value>/login.html?login_error=1</value>
 </property>
 <property name="defaultTargetUrl">
 <value>/</value>
 </property>
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 </bean>
 <bean id="jsonExceptionTranslationFilter">
 <property name="authenticationEntryPoint">
 <ref bean="formLoginAuthenticationEntryPoint"/>
 </property>
 </bean>
 <bean id="formLoginAuthenticationEntryPoint">
 <property name="loginFormUrl">
 <value>/login.html</value>
 </property>
 <property name="forceHttps">
 <value>false</value>
 </property>
 </bean>
 <bean id="anonymousProcessingFilter">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 <property name="userAttribute">
 <value>anonymousUser,ROLE_ANONYMOUS</value>
 </property>
 </bean>
 <bean id="anonymousAuthenticationProvider">
 <property name="key">
 <value>sharedsecret</value>
 </property>
 </bean>
 <bean id="filterSecurityInterceptor">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="accessDecisionManager">
 <ref bean="accessDecisionManager"/>
 </property>
 <property name="objectDefinitionSource">
 <value>
 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
 PATTERN_TYPE_APACHE_ANT
 /*.upload=IS_AUTHENTICATED_FULLY
 /*.download=IS_AUTHENTICATED_FULLY
 /index.html=IS_AUTHENTICATED_FULLY
 /=IS_AUTHENTICATED_FULLY
 /securityservice.json=IS_AUTHENTICATED_ANONYMOUSLY
 /*.json=IS_AUTHENTICATED_FULLY
 </value>
 </property>
 </bean>
 <bean id="authenticationManager">
 <property name="providers">
 <list>
 <ref bean="ldapAuthProvider"/>
 <ref bean="anonymousAuthenticationProvider"/>
 </list>
 </property>
 </bean>
 <bean id="daoAuthenticationProvider">
 <property name="userDetailsService">
 <ref bean="inMemoryDaoImpl"/>
 </property>
 </bean>
 <bean id="inMemoryDaoImpl">
 <property name="userMap">
 <value>
 demo=demo,ROLE_DEFAULT_NO_ROLES
 </value>
 </property>
 </bean>
 <bean id="jdbcDaoImpl">
 <property name="dataSource">
 <ref bean="jdbcDataSource"/>
 </property>
 <property name="usersByUsernameQuery">
 <value>SELECT first_name, last_name, 1 FROM employee WHERE first_name = ?</value>
 </property>
 <property name="authoritiesByUsernameQuery">
 <value>SELECT first_name, "DEFAULT_NO_ROLES" FROM employee WHERE first_name = ?</value>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="usernameBasedPrimaryKey">
 <value>true</value>
 </property>
 </bean>
 <bean id="userSearch">
 <constructor-arg index="0">
 <value>cn=users</value>
 </constructor-arg>
 <constructor-arg index="1">
 <value>(sAMAccountName={0})</value>
 </constructor-arg>
 <constructor-arg index="2">
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="searchSubtree">
 <value>true</value>
 </property>
 </bean>

<bean id="jdbcDataSource"/>
 <bean id="ldapAuthProvider">
<constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <property name="userSearch">
 <ref bean="userSearch"/>
 </property>
 </bean>
 </constructor-arg>
 </constructor-arg>
 <constructor-arg>
 <bean>
 <constructor-arg>
 <ref local="initialDirContextFactory"/>
 </constructor-arg>
 <constructor-arg>
 <value>ou=groups</value>
 </constructor-arg>
 <property name="groupSearchDisabled">
 <value>false</value>
 </property>
 <property name="roleProvider">
 <value>LDAP</value>
 </property>
 <property name="groupRoleAttribute">
 <value>cn</value>
 </property>
 <property name="groupSearchFilter">
 <value>(member={0})</value>
 </property>
 </bean>
 </constructor-arg>
 </bean>
 <bean id="initialDirContextFactory">
 <constructor-arg value="ldap://localhost:389/dc=wavemaker,dc=com"/>
 <property name="managerDn">
 <value>cn=manager,dc=wavemaker,dc=com</value>
 </property>
 <property name="managerPassword">
 <value>7b6a43524a282c146a6b626e425c32205754</value>
 </property>
 </bean>
 <bean id="accessDecisionManager">
 <property name="allowIfAllAbstainDecisions">
 <value>false</value>
 </property>
 <property name="decisionVoters">
 <list>
 <bean/>
 <bean/>
 </list>
 </property>
 </bean>
 <bean id="roleVoter">
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 </bean>
 <bean id="autoProxyCreator">
 <property name="proxyTargetClass">
 <value>true</value>
 </property>
 <property name="interceptorNames">
 <list>
 <value>securityInterceptor</value>
 </list>
 </property>
 </bean>
 <bean id="securityInterceptor">
 <property ref="authenticationManager" name="authenticationManager"/>
 <property ref="accessDecisionManager" name="accessDecisionManager"/>
 <property name="objectDefinitionSource">
 <value>
 </value>
 </property>
 </bean>
 <bean scope="singleton" id="securityService">
 <property name="authenticationManager">
 <ref bean="authenticationManager"/>
 </property>
 <property name="rolePrefix">
 <value>ROLE_</value>
 </property>
 <property name="noRolesMarkerRole">
 <value>DEFAULT_NO_ROLES</value>
 </property>
 <property name="roles">
 <list/>
 </property>
 </bean>
</beans>