Latest Headlines
0

Regular Expression-Objects in vCO Scripts

Recently there was a great discussion on the forums about how to match Workflow input parameters against a Regular Expression: http://communities.vmware.com/message/2064306 (make sure to read through the complete thread to get Christophe’s (www.vcoteam.info) examples!)

Create RegExp Objects

Regular Expressions are used in JavaScript as objects of type ‘RegExp’. You can create them explicitly via constructor new RegExp() or directly with /pattern/modifiers-syntax:

//using the constructor
//new RegExp(pattern, modifiers);
var ipPattern= new RegExp("^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$");

//Or, to save a bit of typing, JavaScript provides a simpler syntax;
//var pattern = /pattern/modifiers;
var ipPattern= /^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$/;

(you might remember that from the E4X-syntax for XML-handling: http://www.vcoportal.de/2011/03/xml-handling-the-e4x-way/)

Use RegExp Objects

var ipPattern= /^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$/;
// as parameter for String-methods
var ip = "192.168.1.1";
var isValidIp = (ip.match(ipPattern) != null);
System.debug('Is the String ' + ip + ' a valid IP-address? ' + isValidIp);

ip = "192.168.1.678";
isValidIp = (ip.match(ipPattern) != null);
System.debug('Is the String ' + ip + ' a valid IP-address? ' + isValidIp);

//with the RegExp-object's own methods exec(), test()...
var validation = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/;
var creditCardNumber = "1234123412341234";
var isValidCreditCardNumber = validation.test(creditCardNumber); //returns a boolean
System.debug('isValidCreditCardNumber? :' + isValidCreditCardNumber);

(If you have a real world use case for the last example, let me know!  It’s on my todo-list next to an “How to integrate vCO with Paypal” article… :mrgreen:)

References

To feel the power of Regular Expressions (they even look very geeky  ;-) ) visit:
http://www.w3schools.com/js/js_obj_regexp.asp
http://www.w3schools.com/jsref/jsref_obj_regexp.asp
http://www.regular-expressions.info/examples.html

To become a Wizard, read following books (and :-)### grow a beard):
http://www.amazon.com/exec/obidos/ASIN/0596520689
http://www.amazon.com/exec/obidos/ASIN/0596528124/

And, as final pro-tips for the use of String.search(regexp):

  • It returns a number with the position of the first match (there is a mistake in the vCO API Explorer!), and
  • -1 is not false in JavaScript!!!
0

Orchestrator@VMworld2012

Summer’s coming, VMworld’s coming.  8-)

This year there is a impressing number of sessions targeting vCenter Orchestrator available for public voting on http://www.vmworld.com/cfp.jspa

That means a great choice for to vote for you (and quite a competition for me  :mrgreen: )…

If you want to hear about how to create a self-service portal for your IT-Services leveraging vCO and Wavemaker, vote for Session 1638! Together with James Bowling (www.vsential.com) we will show you strategies to drag-and-drop develop a Wavemaker-based frontend for vCO Workflows. (As frequent reader of this blog you already might got some ideas  ;-) )

In Session 1639 I will tell you something about using vCO as Integration Platform for your complete IT-Infrastructure. Based on real-life experiences I’ll show why and how you can use workflows to glue different systems together…

See you in San Francisco & Barcelona!

3

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>
4

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
): If you get an error, remember what you learned from vCO configuration :-D 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!  8-)

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
Wavemaker-LDAP-Authentication

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

The Dream of a self-healing Datacenter: Integrate vCenter Operations (vCOPS) with Orchestrator

Workflows in vCenter Orchestrator allow you to automate tasks in vCenter. That’s “Kindergarten“.

Workflows also allow you to orchestrate IT-Services all over the infrasctructure, leveraging all that generic or specific plugins (Wanna see the list? Go to VMware’s Solution Exchange: https://solutionexchange.vmware.com/store/category_groups/15/categories/21).
That’s the “Advanced to Master“-Level.

Kicking-off “healing” workflows based on “unhealthy” conditions in your datacenter fully-automated, using vCO as a headless orchestration platform? That sounds like a job for Wizards!
Well, let’s see……

Orchestrator Wizard (bearded)

The Basics

What is VMware vCenter Operations?
Quoting http://www.vmware.com/products/datacenter-virtualization/vcenter-operations-management/overview.html:
“… Automate performance, capacity, and configuration management with patented analytics and an integrated approach to management. Eliminate the finger pointing, improve team collaboration and reduce manual problem solving efforts by as much as 40% with automated root cause analysis… blah blah Marketing blah :roll:

In short: It’s great! 

VMware vCenter Operations (vCOPS)


What do we need in vCenter Orchestrator?
Just some basic facts
: Orchestrator Workflows are triggered mostly in one of these three ways:

  • Manually: By an administrator (using the vCO-Client), or an Helpdesk-Agent (using the weboperator Webview, or the Perspectives-Plugin) or  a customer/end-user (via a self-service portal (built in Wavemaker of course  ;-) )
  • As Scheduled Task in vCO: The workflow will be started by the vCO server on a regular base, e.g. for reporting, checking for exhausting snapshots, …… (It’s even possible to schedule a workflow programmatically, see a nice example here: http://communities.vmware.com/thread/318791)
  • By an external System: Another component of your Infrastructure kicks-off the workflow via the API. This could be an high-level Business-Process engine (like VMware Service Manager), a system to manage classroom-environments, a release management system, an I/S/P/X/Y/Z-aaS Manager, whatever…

And there is a fourth, not so well known way to start a workflow:

Policies in Orchestrator to start Workflows on signals

  • Event based: The workflow is started when a specific event occurs . You can either use a “Waiting event”-Element in the workflow, or you can create a Policy in vCO. For both vCO-Plugins can provide Triggers.
    Examples:  The AMQP-Plugin (which can be triggered e.g by a Blocking Task in vCloud Director), or the SNMP-Plugin (listens to SNMP-Traps, sent e.g. from vCenter or other systems…)
    Waiting Event in a workflow

Subtotal:

vCenter Operations (vCOPS) can send SNMP-Traps when unwanted situations occur.

vCO can start workflows when an SNMP-Trap is received.

So: Integrate (again)!

Step 1:  Install the SNMP-Plugin on your vCO-Server. RTFM on https://www.vmware.com/support/pubs/vco_plugins_pubs.html

Step 2: Run the Workflows Library / Trap Host Management / Set the SNMP trap port and Start the trap host to make vCO (exactly: the SNMP-Plugin) listen to SNMP traps.

Step 3: Run the Workflow Library / Device Management / Register an SNMP device and make vCO listen to SNMP traps exactly from vCOPS. Make sure you use the hostname / IP of the vCOPs Analytics VM, not the UI VM!

Run Workflows to setup the environment

Step 4: Configure vCOPS to send SNMP-Traps to the Orchestrator server. Open the vCOPS Manager Administration, and define your vCO-Server as (receiving) Host.

Enable SNMP notifications in vCenter Operations

Step 5: Configure vCOPS  to “activate” alerting: Open the menu “Notifications” in vCOPs usual webinterface (not the Administration anymore), and create a “New Rule” and enable all the Conditions you want to be notified on.
(I’m not sure if this step is really necessary,  I didn’t find any information if these rules are for email only, or if they are also used for SNMP notifications :-? )

Create Rules to enable alerting

Step 6: For a first test: Run the Workflow Library / SNMP Wait for a trap on an SNMP device. Select the vCOPS Analytics VM as SNMP Device, you registered it in Step 3!
The Workflow should stall at the “Waiting Element” for an SNMP trap from vCOPS. Now break something in your datacenter :twisted: , so that vCOPS sends a trap…

Waiting for something bad...

Once the trap is received by vCO, the workflow should continue and finish successfully. In the Logs-Tab of the Workflow-Token you can find some details about the trap.

Step 7To be the wizard: Create a new Policy based on the Policy Template which comes with the SNMP Plugin.
Apply a new  Orchestrator Policy

Then edit the created Policy to select the Workflow to be started when a trap is received:

Step 8: Start the Policy! (That’s something you will forget only once, after hours of senseless troubleshooting…)

DON'T FORGET TO START THE POLICY!

Finito!

Now every condition in your datacenter which leads to an alerting in vCenter Operations will trigger a Workflow in Orchestrator, which can deal with the problem. And the best: All that without writing a single line of code!

From there I leave it to you…

<site note>
Integrating a Systems Monitoring tool with vCenter Orchestrator is not a new:
up.time software provides a vCO plugin for years:
http://support.uptimesoftware.com/orchestrator.php
http://www.uptimesoftware.com/uptimeblog/uncategorized/cloud-computing-and-popular-culture/
</site note>

The Dream of a self-healing Datacenter

Proofing that it’s possible, consider what you can do (or better: what you can let do fully-automated) with an integration of vCenter Operations and vCenter Orchestrator:

  • Run a workflow that automatically creates a Ticket or updates the CMDB on vCOPS alerts
  • A datastore runs out of capacity? A workflow will fix it automatically, increase the LUN on the storage system and the VMFS partition. Or just full-stack provision a new datastore and add it to the storage cluster.
  • YourMightyStorageVendor(tm) provides an additional workflow: If now your storage system runs out of capacity, new disks will automatically be ordered by the workflow :-)
  • Response time for Outlook users to high? A workflow will deploy new Exchange CAS instances to scale-out (and leverage the Powershell-Plugin to adjust it settings)
  • Your web-app is getting “Slashdotted”? See how Radware already leverages vCO to scale it fully-automated: http://www.youtube.com/watch?v=4rkV3ebQens
  • “No worries, Captain! I already put 80% energy to the front shields to prepare for the Klingonian attack!”
  • With the brand-new vCenter Operations for VMware View and a View API/Plugin for vCO you could… … …

***RING – RING – YOUR WAKEUP CALL – RING – RING ***

SIGH! What a nice dream…  :mrgreen:

Page 7 of 21« First...56789...20...Last »