Thursday, November 27, 2014


In your Web App you will need to authenticate users using federated authenticators, IS supports many federated authenticators including, Google, Yahoo, Facebook, etc. So in this post I will explain how to add multiple federated authenticators to your web app, when multiple authenticators are added IS will render a intermediary page to the user to select the required authenticator, I will also explain you how to get rid of this page and how to directly authenticate from your webapp through WSO2IS


IS version I'm using is IS : 5.0




I will be using google and yahoo as federated authenticators and as the sample client (WebApp) I will be using travelocity.com example you can download it from here.

First Lets create necessary Identity providers.

First download and start the IS server. You can download WSO2 IS from here.

Step 1 - Starting the server

- Start the IS server by navigating to <IS_home>/bin/wso2server.sh)


Step 2 - Adding Google Authenticator


In order add Google as a federated authenticator you need to Register Google authenticator as a new IDP by following below steps;

Navigate to;

- Home > Identity > Identity Providers > Add

- Fill the Basic Information I will Give the Identity provider name as googleOpenID, you can enter any name you wish.



-  Now add "Home Realm Identifier" name as "google", make sure this name is unique.




- Then go to Federated Authenticators tab and select “Google Configuration” menu there. Enable the given options as shown in the below image.



 
 - Click on Register button.

Step 3 - Adding Yahoo as a authenticator

Now create a new IDP for yahoo. You can follow the above steps to do this, in the last step use yahoo as the federated authenticator.

The final configs will be as following,






Step 4 - Registering Service Provider


Next you need to register a service provider. you can follow the steps given below to do this.

- Home > Identity > Service Providers > Add






- Give a Service provider name hen click on “Register” button. i.e. Service provider Name as travelocity.com.


- Then you will redirect to the registered Service Providers editable view.


- Tick on the Saas Application option given in the Basic information section and select the “Inbound Authentication Configuration” there. (When you select the saas option you can use the travelocity.com service provider from tenant domains as well.)



- Among the given options, select “SAML2 Web SSO Configuration” option and click on given “Configure” link.






- Then you will redirect to SSO configuration view.

- Fill the given fields accordingly.

  
Issuer : travelocity.com
Assertion Consumer URL : http://localhost:8080/travelocity.com/home.jsp


Tick on following options as well;

- Use fully qualified username in the NameID
- Enable Response Signing
- Enable Assertion Signing
- Enable Single Logout


- Then click on “Local & Outbound Authentication Configuration” tab and select “Advanced Configuration” 



- Now Add a new Authentication step



- Now add the federated authenticators you created as shown below,


And then click "Update" and then on “Register” button.

Step 5 - Adding the Client Application to Tomcat

- Placed the travelocity.com webapplication file inside the webapp folder of the tomcat server and start the tomcat server (version 7. +). (Get the travelocity sample svn checkout from here.)


- Access the travelocity.com webapp using following link.



- Since we have configured our service provider for a SAML request, select the SAML option as shown in the given image.



- Now it will redirect you to the IS login page and from there you will have to select the Login type. In the Next step I will explain you how to get rid of this login page.



- If you select the Google option it will be redirected to google.



 















- Once you have entered valid Google credentials you will get authorized and get permitted to access the requested travelocity webapp. 


By-parsing the IS authenticator selection page

In most cases you will not require IS to render a intermediary page when authenticating with multiple federated authenticators. In order to by parse the Authenticator selection screen the SAML request should tell IS which federated authenticator to use.

For this you can add a new parameter in the SAML request header. The parameter name is "fidp" this should be equal to the "Home Realm Identifier" defined in the step 2 when creating IDPs, The authenticator will be identified by this name by the IS.

- Inorder to simulate this with travelocity.com application stop the tomcat server.

- Navigate to <TOMCAT_HOME> > webapps > travelocity.com > WEB-INF > classes > travelocity.properties

- Go to the end of the file add the following parameter.

SAML.Request.Query.Param=&fidp=yahoo

The final content will look like following



The above will add the "fidp" parameter to the SAML request header. You can enable SSO tracing and look into this. The final SAML request will look like following,




- Now if you go to the travelocity App and click on the SAML request, you will be directed to the yahoo login page.

- Now you can change the "fidp" parameter to google and do the same, It will be directed to the google page.

SAML.Request.Query.Param=&fidp=google

In your web-application, depending on the users selection; "fidp" should be generated dynamically. So IS will direct the request to the correct authenticator.


If you have any queries please feel free to drop a comment. :)


Wednesday, September 17, 2014

Hi, in this post I will explain how to develop a simple web application with Leaflet.js where device locations will be updated real-time and I will add quite a few extra features to the UI as well :)

What is Leaflet.js


"Leaflet is a modern open-source JavaScript library for mobile-friendly interactive maps. It is developed by Vladimir Agafonkin with a team of dedicated contributors. Weighing just about 33 KB of JS, it has all the features most developers ever need for online maps."


Functions that are included in the application.

  1. Ability to switch Maps.
  2. Updating device location real-time.
  3. Drawing the route when the device is moving.
  4. Clearing layers and routes.
  5. Hiding different layers.
  6. Resetting the Map
  7. Maintaining the focus on a specific marker.

I will add everything in a simple HTML page, There won't be any themes so it won't look pretty.

Downloading and setting up of leaflet is pretty straight forward, its all well documented here.

In order to demonstrate marker movements I have written a small JavaScript to generate coordinates and device IDs.

So lets get started. :)

The following folder structure will be followed when storing the resources.



So lets create a new html file called index.html

Add the following code to the file.

I have explain the codes snippets within the code it self via comments.



<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Real Time Updating Map</title>

<!-- Addning Leaflet Style Sheets -->
<link rel="stylesheet" href="CSS/leaflet.css" />

</head>

<body style="background-color: white;">

 <div id="wrapper" style="background-color: #EBD6EB;">
  <div id="page-wrapper">
   Display Settings

   <li>Draw Paths : &nbsp;&nbsp;</a> <input id="drawPath"
    type="checkbox" name="drawPath">
    <button type="button" onclick="checkCheckBox();">DRAW</button>
   </li>
   <li><a style="text-decoration: none">Clear All Paths :
     &nbsp;&nbsp;</a>
    <button type="button" onclick="clearMarkers();">CLEAR</button></li>

   <li>Focuss on a Device : <input id="followID"
    class="form-control" placeholder="Enter ID"> <input
    id="followId" type="checkbox" name="drawPath" disabled="disabled">

    <button type="button" onclick="followID(); checkBoxFollow();">Follow</button></li>
   <li>Reset Map : &nbsp;&nbsp;
    <button type="button" onclick="resetMap();">Reset</button>

   </li>
  </div>

 </div>

 <div align="center" style="padding: 0px">
  <div id="map" style="width: 1100px; height: 600px"></div>
 </div>

 <h4>Connected Device IDs</h4>
 <textarea class="form-control" id="idListArea" readonly></textarea>
 <h4>Output Console</h4>

 <textarea id="messagesTextArea" rows="17" cols="150" readonly></textarea>

 <br>

 <button type="button" onclick="messagesTextArea.value=null;">Clear
  Console</button>

 <!-- Adding the leaflet JS -->
 <script src="JS/leaflet.js"></script>

 <script>
  //Creating a Layers for the markers and Polylines and Creating the Main map
  var markerLayer = new L.layerGroup();
  var polylineLayer = new L.layerGroup();

  var mbAttr = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, '
    + '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, '
    + 'Imagery © <a href="http://mapbox.com">Mapbox</a>', mbUrl = 'https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png';

  var grayscale = L.tileLayer(mbUrl, {
   id : 'examples.map-20v6611k',
   attribution : mbAttr
  }), streets = L.tileLayer(mbUrl, {
   id : 'examples.map-i86knfo3',
   attribution : mbAttr
  });

  var map = L.map('map', {
   center : [ 6.88869, 79.85878 ],
   zoom : 13,
   layers : [ streets, markerLayer, polylineLayer ]
  });

  var baseLayers = {
   "Grayscale" : grayscale,
   "Streets" : streets
  };

  var overlays = {
   "Marker Layer" : markerLayer,
   "Path Layer" : polylineLayer
  };

  L.control.layers(baseLayers, overlays).addTo(map);
 </script>

 <script type="text/javascript">
  // This script is to simmulate a dataset to demonstrate 
  var j = 0;
  var lat = 6.88869;
  var lon = 79.85878;
  var speedflag = "false";

  function myLoop() {
   setTimeout(function() {

    lat = lat + 0.0001;
    lon = lon + 0.0001;

    lat2 = lat + 0.0001;
    lon2 = lon + 0.0002;

    var id = Math.floor((Math.random() * 2) + 1);

    mapUpdater("" + id, lat, lon);

    j++;
    if (j < 1000) {
     myLoop();
    }
   }, 500)
  }

  myLoop();
 </script>

 <script type="text/javascript">
  //Marker Icon List Class
  var markers = L.Icon.extend({
   options : {
    shadowUrl : 'images/marker-shadow.png',

    iconSize : [ 41, 41 ],
    shadowSize : [ 41, 41 ],
    iconAnchor : [ 20, 40 ],
    shadowAnchor : [ 10, 40 ],
    popupAnchor : [ 0, -30 ]
   }
  });

  var defIcon = L.Icon.Default.extend({
   options : {
    iconUrl : 'images/marker-icon.png'
   }
  });
 </script>

 <script type="text/javascript">
  //Main Map Related Scripts
  var idList = [];

  function checkCheckBox() {

   var check = document.getElementById("drawPath");
   if (check.checked == true) {
    check.checked = false;
   } else {
    check.checked = true;
   }
  }

  function mapUpdater(id, lat, lon) {

   var proxi = true;
   var len = null;
   var poly = null;
   var mark = null;

   //If the list doesn't contain anything Adding The Markers and PolyLines
   if (idList.length == 0) {

    mark = L.marker([ lat, lon ]).bindPopup("Vehicle ID : " + id, {
     autoPan : false
    });
    markerLayer.addLayer(mark);
    poly = L.polyline([], {
     color : 'green'
    });
    polylineLayer.addLayer(poly).addTo(map);

    idList.push([ id, mark, poly, false ]);

    idListArea.value += id + ", ";
    return;
   }

   for (var i = idList.length; i > 0; i--) {

    if (id == idList[i - 1][0]) {
     len = i - 1;
     break;
    }
    // If the ID is not in the list initiate new entry
    else if ((i - 1) == 0) {

     mark = L.marker([ lat, lon ]).bindPopup(
       "Vehicle ID : " + id, {
        autoPan : false
       });
     markerLayer.addLayer(mark);
     poly = L.polyline([], {
      color : 'green'
     });
     polylineLayer.addLayer(poly).addTo(map);
     len = idList.length - 1;

     idList.push([ id, mark, poly, false ]);
     idListArea.value += id + ", ";
     return;
    }
   }

   if (idList[len][3] == true) {
    idList[i - 1][2].addLatLng([ lat, lon ]);
    poly = L.polyline([], {
     color : 'Green'
    });
    polylineLayer.addLayer(poly).addTo(map);
    idList[len][2] = poly;
    idList[len][3] = false;
   }

   idList[len][1].setLatLng([ lat, lon ]).update(); // updating the marker

   // Drawing the Path if the check box is checked
   if (document.getElementById('drawPath').checked) {
    idList[len][2].addLatLng([ lat, lon ]); // updating the poly-line
   }

   // Maintaining the focus on a selected device
   if (document.getElementById("followId").checked
     && document.getElementById("followID").value == id) {
    map.panTo([ lat, lon ], {
     duration : 0.5
    });
   }

   //Updating the Output Console
   messagesTextArea.value += "ID : " + id + " Longtitute : " + lon
     + " Latitude : " + lat + "\n";
   var textarea = document.getElementById('messagesTextArea');
   textarea.scrollTop = textarea.scrollHeight;

  }

  // Function too Clear all the markers from the map
  function clearMarkers() {

   polylineLayer.clearLayers();

   for (var i = idList.length; i > 0; i--) { // Re adding the polylines since clear Layers remove all the objects
    poly = L.polyline([], {
     color : 'green'
    });
    polylineLayer.addLayer(poly).addTo(map);
    idList[i - 1][2] = poly;
   }
  }

  //Function to maintain focuss on a device
  function followID() {
   var id = document.getElementById("followID").value;
   if (id != "") {
    for (var i = idList.length; i > 0; i--) {
     if (idList[i - 1][0] == id) {
      idList[i - 1][1].openPopup();
      break;
     }
    }
   }
  }

  //toggling the check box
  function checkBoxFollow() {
   var fid = document.getElementById("followID").value;
   var checkbox = document.getElementById("followId");

   if (fid != "") {

    if (checkbox.checked) {
     checkbox.checked = false;
    } else {
     checkbox.checked = true;
    }
   }
  }

  // Function to Reset the Map
  function resetMap() {
   polylineLayer.clearLayers();
   markerLayer.clearLayers();
   idList.length = 0;
   idListArea.value = "";
  }
 </script>
</body>
</html>


Now in the folders I have mentioned above add necessary resources. leaflet JS/CSS files. Marker images etc. You can find everything from the following Git Repo as well.

https://github.com/ycrnet/Real_Time_Updating_Map

Just clone the above repository and you can find everything in it.

The Final output will look like following



As you can see, you can play around with the top control panel. It will provide all the added functionality I have mentioned above.

This project was done for a different integration and the UI was updated with web-sockets. You can Find the details about the project from here.

Hope this post will help someone interested. Thanks for reading and drop a comment if you have any Queries :)

Installing Puppet is pretty Simple, but installing the latest Puppet version in linux might be bit tricky. Some times you may have outdated puppet repositories, so to make sure you are installing the latest version of puppet follow the following steps.



How to install 

First lets add latest puppet repository.

Download the “puppetlabs-release” package for your OS version. The complete list of packages are available at following location.

https://apt.puppetlabs.com/

Now copy the link of the package that suits you, and execute following commands, lets say the package I selected is available at "https://apt.puppetlabs.com/puppetlabs-release-precise.deb"

execute following commands;

$ wget https://apt.puppetlabs.com/puppetlabs-release-precise.deb $ sudo dpkg -i puppetlabs-release-precise.deb $ sudo apt-get update

Now simply install puppet

$ sudo apt-get install puppet

In-order to check which version of puppet you have installed you can execute the following command;

$ puppet --version

How to uninstall puppet

Execute the following to uninstall puppet,

$ sudo apt-get --purge remove puppet

If puppet still exists. You can search for any puppet related packages in the system by executing the following command,

$ dpkg --get-selections | grep -v deinstall

If there are any puppet packages e.g: "puppet-commons". Then select the package name you want to remove and execute the following command;

$ sudo apt-get --purge remove <PACKAGE-NAME>



Sunday, September 14, 2014


What is Puppet?

Puppet is automation software for IT system admins, consultants etc. It allows you to automate repetitive tasks such as the installation of applications and services, patch management, and deployments. but it has many bottlenecks when it comes to do some standalone deployments.

You can read more about puppet from here.


Why Unorthodox?

So why do I call this Unorthodox? Simply because puppet was not built to do deployments the way I'm trying to do. What I'm trying to achieve is, no Puppet Master, no modules in the /etc/puppet directory and no need run the scripts as the root user.

Does this make any sense? So if you are not sure what the heck I'm trying to do, following is a use case where I need to do something like above.

The Use Case :

I need to setup a application cluster which have multiple Manager/Worker nodes, and the user can parse puppet manifest the number of nodes that is required as a parameter. The setup process will include two repetitive tasks 

  1. Copying Files
  2. Changing Configurations

I want to do this in a single go, I don't want to re-run the scripts to match the number of nodes. So in-order to do the repetitive tasks I need loops, so one loop has to copy necessary files and create required number of nodes and the other nested loop should push all the configuration templates. 
Please note that I'm writing these scripts to be executed without the PUPPET MASTER. All the resources and classes will be defined inline so I don't have to include the resources as puppet modules. I believe you get the point here. The deployment will be done on a local machine and can be transferred to remote machines if required by simply copying the setup.

 Lets Get Started.


The first challenge is to get a loop working, puppet doesn't have native support for loops so you will have to follow a work around in order to create a loop.

So lets start!!!

How do we create a loop!!! Hmm this took lots of Googling and lot of trying-out :).

Following is a for loop where you can parse the loop starting value and the max count to the loop.

So lets create a puppet.pp manifest and include the following code within,


class loop_test {
  #Invoking the loop resource name is the loop starting point.
  loop{"1":
    count=>"5", # Loop ending index
  }

}

define loop($count) {

  if ($name > $count) {
    notice("Loop Iteration Finished!!!\n")
  }
  else
  {
    notice("The Iteration Number : $name \n")


    $next = $name + 1
    loop { $next:
      count => "${count}",
    }
  }
}

include loop_test


You can run the above manifest by "puppet apply puppet.pp" command.  VOILA, the output will look like the following. 

Notice: Scope(Loop[1]): The Iteration Number : 1 

Notice: Scope(Loop[2]): The Iteration Number : 2 

Notice: Scope(Loop[3]): The Iteration Number : 3 

Notice: Scope(Loop[4]): The Iteration Number : 4 

Notice: Scope(Loop[5]): The Iteration Number : 5 

Notice: Scope(Loop[6]): Loop Iteration Finished!!!


So there you go, you have a working "for loop" in puppet now. Now lets see how can we have a nested loop in this loop. There are two ways you can do this, one is simply iterate over an array or define another resource that you can recursively call.

Here I will iterate over an Array because I find it less complicated :) I have defined all the config changes (paths of .erb templates) in an array so I will simply iterate over the array after copying the necessary files.

The following code segment can be used to achieve this.

class loop_test {
  #Invoking the loop resource name is the loop starting point.
  loop{"1":
    count=>"5", # Loop ending index
  }

  $config_array = ["Value 01","Value 02","Value 03","Value 04","Value 05"]

}


define loop($count) {

  if ($name > $count) {
    notice("Loop Iteration Finished!!!\n")
  }
  else
  {
    notice("The Iteration Number : $name \n")

    # This is to avoid any resource name duplications
    $local_names = regsubst($loop_test::config_array, '$', "-$name")

    # Invoking the second iteration
    push_templates{$local_names:
      loop_index => $name,
    }

    $next = $name + 1
    loop { $next:
      count => "${count}",
    }
  }
}

define push_templates($loop_index) {

  $orig_name = regsubst($name, '-[0-9]+$', '') # Extract the Original name

  # Do something Here

  notice("The Loop Index : ${loop_index} \n The Array Content : $orig_name \n")
}

include loop_test

The output Will look like following after executing the above script.

Notice: Scope(Loop[1]): The Iteration Number : 1 

Notice: Scope(Push_templates[Value 01-1]): The Loop Index : 1 
 The Array Content : Value 01 

Notice: Scope(Push_templates[Value 02-1]): The Loop Index : 1 
 The Array Content : Value 02 

Notice: Scope(Push_templates[Value 03-1]): The Loop Index : 1 
 The Array Content : Value 03 

Notice: Scope(Push_templates[Value 04-1]): The Loop Index : 1 
 The Array Content : Value 04 

Notice: Scope(Push_templates[Value 05-1]): The Loop Index : 1 
 The Array Content : Value 05 

Notice: Scope(Loop[2]): The Iteration Number : 2 

Notice: Scope(Push_templates[Value 01-2]): The Loop Index : 2 
 The Array Content : Value 01 

Notice: Scope(Push_templates[Value 02-2]): The Loop Index : 2 
 The Array Content : Value 02 

Notice: Scope(Push_templates[Value 03-2]): The Loop Index : 2 
 The Array Content : Value 03 

Notice: Scope(Push_templates[Value 04-2]): The Loop Index : 2 
 The Array Content : Value 04 

Notice: Scope(Push_templates[Value 05-2]): The Loop Index : 2 
 The Array Content : Value 05 

Notice: Scope(Loop[3]): The Iteration Number : 3 

Notice: Scope(Push_templates[Value 01-3]): The Loop Index : 3 
 The Array Content : Value 01 

Notice: Scope(Push_templates[Value 02-3]): The Loop Index : 3 
 The Array Content : Value 02 

Notice: Scope(Push_templates[Value 03-3]): The Loop Index : 3 
 The Array Content : Value 03 

Notice: Scope(Push_templates[Value 04-3]): The Loop Index : 3 
 The Array Content : Value 04 

Notice: Scope(Push_templates[Value 05-3]): The Loop Index : 3 
 The Array Content : Value 05 

Notice: Scope(Loop[4]): The Iteration Number : 4 

Notice: Scope(Push_templates[Value 01-4]): The Loop Index : 4 
 The Array Content : Value 01 

Notice: Scope(Push_templates[Value 02-4]): The Loop Index : 4 
 The Array Content : Value 02 

Notice: Scope(Push_templates[Value 03-4]): The Loop Index : 4 
 The Array Content : Value 03 

Notice: Scope(Push_templates[Value 04-4]): The Loop Index : 4 
 The Array Content : Value 04 

Notice: Scope(Push_templates[Value 05-4]): The Loop Index : 4 
 The Array Content : Value 05 

Notice: Scope(Loop[5]): The Iteration Number : 5 

Notice: Scope(Push_templates[Value 01-5]): The Loop Index : 5 
 The Array Content : Value 01 

Notice: Scope(Push_templates[Value 02-5]): The Loop Index : 5 
 The Array Content : Value 02 

Notice: Scope(Push_templates[Value 03-5]): The Loop Index : 5 
 The Array Content : Value 03 

Notice: Scope(Push_templates[Value 04-5]): The Loop Index : 5 
 The Array Content : Value 04 

Notice: Scope(Push_templates[Value 05-5]): The Loop Index : 5 
 The Array Content : Value 05 

Notice: Scope(Loop[6]): Loop Iteration Finished!!!


Everything is done, and working as expected :)

I have written some scripts using above concepts to deploy WSO2 products to setup test environments. You can find puppet scripts I have written from the following Git Repository.

https://github.com/ycrnet/Puppet-Scripts

Please feel free to drop a comment if you have any queries!!

Thanks for Reading.

Wednesday, August 20, 2014

Puppet is an excellent configuration automation scripting language that is really flexible and effective,

In a puppet manifest if you are not running your script in the default puppet directory you may need to get the current Manifest location where its running from, So this can be easily achieved by embedding a ruby code snippets within the manifest it self. The code will look like the following.

$var1 = inline_template("<%= Dir.pwd %>")

notice ("This Current Location : ${var1}")


The output will look like the following,

Notice: Scope(Class[main]): This Current Location  /home/yasassri/Desktop/QA_Resources/puppet/mySCripts/ascluster
Notice: Compiled catalog for yasassri-thinkpad-t540p.private.wso2.com in environment production in 0.01 seconds
Notice: Finished catalog run in 0.03 seconds
Subscribe to RSS Feed Follow me on Twitter!