Howto setup LDAP-Authentication for Wavemaker (Part 1)

You can leverage VMware Wavemaker to create a nice web-frontend for your users to start workflows.
(how? See the links at the end of this article!)

Typically you don’t let just everybody do that, but only identified users. So you have to implement some kind of User Authentication mechanism on the web-frontend.

The Good

Wavemaker provides included mechanisms to implement a login page, and authenticate the users against a database or a LDAP-directory, using a so called Security Service. This LDAP authentication also works against Active Directory.

The Security Service also allows a group-based distinction into different roles: you can show or hide different parts of the website to users, depending if they are in an AD-group or not.

This works very well, and is (as usual for Wavemaker  :-)) very well documented:
http://dev.wavemaker.com/wiki/bin/Authentication
http://dev.wavemaker.com/wiki/bin/SecurityTutorial

The Bad

The normal login page (automatically created when you activate this checkbox in the security service) does not allow you to re-use the user credentials “later” on webpage. But, you might need these credentials to authenticate against vCO for workflow execution. Then you have to rebuild the authentication mechanism manually, and create a JavaService to check if the user is in a specific LDAP-group.

Let’s see, how to do:

First of all, you have to configure the connection to your LDAP/AD Server. The easiest ways to do so is over the Wavemaker GUI.

 You can insert the LDAP/AD integration in the menu Services / Security.

 On the site you have to choose your Security Provider and to enable Security.

Important here:

  • Do NOT check the “Show Login Page”-checkbox! You will create your own login screen later…
  • Check the “Search User Role”-checkbox to activate the mechanism which does the association to LDAP-groups
***Very Useful Site Note***
You can test your settings using the “Test Connection”-Button. (Even this is not vCO-related (yet 😉 ): If you get an error, remember what you learned from vCO configuration 😀 e.g. the “Administrator” as Manager DN in AD is identified as “cn=Administrator,cn=Users,dc=lab,dc=local”
For troubleshooting: I’m sure you remember this post on how to troubleshoot LDAP issues?
http://www.vcoportal.de/2011/07/troubleshooting-ldap-erros-in-vco/ 
***Another Useful Site Note***
As frequent reader of this blog you remember adfind: A small, very powerful, very fast, very handy tool to figure out where and how to find objects in Active Directory…

To implement the group-checking manually you have to insert a JavaService into your project.

In the menu choose Services / Java Service:

 

In the popup you must enter a name and a package name for the java service.

 

In my case I choose the Service Name GroupAuth and LDAPGroupAuth.

Here is the java source code for that:

/**
 * This is a client-facing service class. All
 * public methods will be exposed to the client. Their return
 * values and parameters will be passed to the client or taken
 * from the client, respectively. This will be a singleton
 * instance, shared between all requests.
 *
 * To log, call the superclass method log(LOG_LEVEL, String) or log(LOG_LEVEL, String, Exception).
 * LOG_LEVEL is one of FATAL, ERROR, WARN, INFO and DEBUG to modify your log level.
 * For info on these levels, look for tomcat/log4j documentation
 */
 import com.wavemaker.runtime.RuntimeAccess;
 import com.wavemaker.runtime.security.SecurityService;

public class LDAPGroupAuth extends com.wavemaker.runtime.javaservice.JavaServiceSuperClass {
 /* Pass in one of FATAL, ERROR, WARN, INFO and DEBUG to modify your log level;
 * recommend changing this to FATAL or ERROR before deploying. For info on these levels, look for tomcat/log4j documentation
 */
 public String LDAPGroupAuth() {
 log(INFO,"ldapauth...");
 String LoginTrue= "Yes";
 String LoginFalse= "No";
 if (isUserInRole("VCOADMINS")){

 return LoginTrue;
 }else{

 return LoginFalse;
 }
 }

 private static boolean isUserInRole(String role){
 SecurityService srv = (SecurityService) RuntimeAccess.getInstance().getService("securityService");
 String[]uRoles = srv.getUserRoles();
 for(String uRole : uRoles){
 // log(INFO,"role: " + uRole);
 if(uRole.equals(role)){
 return true;
 }
 }
 return false;
 }

}

Important here: The name of the AD-group has to be typed in UPPERCASE!

Next, I had to create the “flow” of the login process, using different Layers in Wavemaker.

I copy the “Login Page” Box and the scripts into my Main site. There I work with different layer and I am able to use the “variables” on all layers.

For the integration of your GroupAuth into your project, you have to modify our “Login” Button.
During my tests for the project, I searched for a good solution to check the credentials (Username and password) against the AD Server and validate the group membership in one step. I didn’t find a, for me, robust solution.
If someone finds a better solution than the one below, please comment!  😎

Due that circumstance, I decided to use a temporary Auth_Layer. By clicking on the “Login” button, I check the credentials, on the Login site and after checking these where valid I check the group membership.

So, here is the code for checking the AD credentials:

loginButtonClick: function(inSender) {
dojo.cookie("user", this.usernameInput.getDataValue(), {expires: 365});
 this.loginErrorMsg.setCaption("");
 wm.login(
 [this.usernameInput.getDataValue(), this.passwordInput.getDataValue()],
 dojo.hitch(this, "loginSuccess"), dojo.hitch(this, "loginFailed"));
 },
 loginSuccess: function(inResponse) {
 try{
 // This will set the currently showing layer to the AuthLayer
 main.layers1.setLayer('Auth_layer');

 } catch(e) {
 console.error('ERROR IN loginSuccess: ' + e);
 }
 },
 loginFailed: function(inResponse) {
 this.loginErrorMsg.setCaption("Invalid username or password.");
 this.usernameInput.focus();
 },

When the user credentials where valid, the layer is changed to the “Auth_Layer”.

On this layer, the group membership is checked. Here is the code for the check (executed in the “onShow()”-Event of this Layer):

loginButtonClick: function(inSender) {
 dojo.cookie("user", this.usernameInput.getDataValue(), {expires: 365});
 this.loginErrorMsg.setCaption("");
 wm.login(
 [this.usernameInput.getDataValue(), this.passwordInput.getDataValue()],
 dojo.hitch(this, "loginSuccess"), dojo.hitch(this, "loginFailed"));
 },
 loginSuccess: function(inResponse) {
 try{
 // This will set the currently showing layer to the AuthLayer
 main.layers1.setLayer('Auth_layer');

 } catch(e) {
 console.error('ERROR IN loginSuccess: ' + e);
 }
 },
 loginFailed: function(inResponse) {
 this.loginErrorMsg.setCaption("Invalid username or password.");
 this.usernameInput.focus();
 },

So if the group membership of the user is okay, the user is redirected to the “Request_Layer”. If the group membership is not okay, the user is redirect to the “Denied_Layer”.

In sum, the system provides for three different conditions:

  • Username or Password is wrong: This shows an small “login unsuccessful”-message directly in the login-box
  • Username / Password is correct (so he is logged-in from the Wavemaker Security Service perspective), but the user is NOT in the AD-group. Then he’s redirected to the “Denied_Layer”.
  • Username / Password is correct (so he is logged-in from the Wavemaker Security Service perspective), AND he is in the AD-group. Then he’s redirected to the “Request_Layer”, which for instance contains the buttons that trigger Orchestrator Workflows.

The Ugly

Given some restrictions of the underlying mechanisms used for the Security Service implementation in Wavemaker, it only supports groups within one Organizational Unit (OU) in Active Directory.
However, there is a workaround for this, expect Part 2 of this article soon :mrgreen:

References

To give you an idea about it looks like at the end of the day, download the project below!
(It’s a Wavemaker 6.4 exported project, should be directly importable. Just make sure to adjust the LDAP-Settings of the Security Service!)

Aaaaand, some links:
http://www.vcoportal.de/2011/11/using-wavemaker-as-web-frontend-for-vco/
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-1.html
http://www.virtuallyghetto.com/2011/12/leveraging-vcd-vco-wavemaker-part-2.html
http://dev.wavemaker.com/wiki/bin/Learning/Mastering+LDAP+Security

Wavemaker-LDAP-Authentication
Wavemaker-LDAP-Authentication
vCO_WM_LDAP.1.Alpha.zip
160.2 KiB
Details...