[WSO2 IS] Display the service providers in dashboard app

Jenananthan
6 min readJun 2, 2017

--

In the last post discussed about how to create a gadget and add it to dashboard of identity server. In this post going to discuss about creating a gadget to display all the service providers configured in identity server in a gadget and providing SSO for end users. i.e When an end user login to the dashboard , there will be a gadget which will list all configured service providers and user can access the apps in single portal.

Implementation details of SSO-APPs gadget

  1. Create the gadget.xml with require feature pubsub-2
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="SSO Apps">
<Require feature="pubsub-2" />
</ModulePrefs>
</Module>

2. Add the content to display in the gadget when it is appear in the dashboard listing view

<Module><ModulePrefs title="SSO Apps">
<Require feature="pubsub-2" />
</ModulePrefs>
<Content type="html" view="default"><![CDATA[<link rel="stylesheet" type="text/css" href="js/ui/css/main.css"><link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jquery-ui-1.10.3.custom.min.css"><link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jqueryui-themeroller.css"><link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.css"><link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.min.css"><link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap-theme.css"><script src="js/ui/js/jquery.min.js" type="text/javascript"></script><script type="text/javascript" src="serverinfo.jag"></script><script>var headID = document.getElementsByTagName("head")[0];var cssNode = document.createElement('link');cssNode.type = 'text/css';cssNode.rel = 'stylesheet';cssNode.href = PROXY_CONTEXT_PATH + '/portal/gadgets/sso-apps/js/ui/font-awesome/css/font-awesome.min.css';headID.appendChild(cssNode);</script><script>$(function() {$('.max_view').click(function() {gadgets.Hub.publish('org.wso2.is.dashboard', {msg : 'A message from SSO apps',id: "sso_apps .expand-widget"});});});</script><div class='icon-rotate-left icon-rotate-left-dashboard icon-marketing-styles'></div><p>Access SSO Apps.</p><p><a class='btn btn-default max_view' href=''>View details</a></p>]]></Content></Module>

3. Add the content to list the service providers in expanded view of gadget.

(When expand the gadget view, an api to list the services providers will be called and then page will be drawn with the result)

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="SSO Apps">
<Require feature="pubsub-2" />
</ModulePrefs>
<Content type="html" view="default">
<![CDATA[

<link rel="stylesheet" type="text/css" href="js/ui/css/main.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jquery-ui-1.10.3.custom.min.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jqueryui-themeroller.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap-theme.css">

<script src="js/ui/js/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="serverinfo.jag"></script>
<script>
var headID = document.getElementsByTagName("head")[0];
var cssNode = document.createElement('link');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.href = PROXY_CONTEXT_PATH + '/portal/gadgets/sso-apps/js/ui/font-awesome/css/font-awesome.min.css';
headID.appendChild(cssNode);
</script>
<script>
$(function() {
$('.max_view').click(function() {
gadgets.Hub.publish('org.wso2.is.dashboard', {
msg : 'A message from SSO apps',
id: "sso_apps .expand-widget"
});
});
});
</script>

<div class='icon-rotate-left icon-rotate-left-dashboard icon-marketing-styles'></div>
<p>Access SSO Apps.</p>
<p><a class='btn btn-default max_view' href=''>View details</a></p>
]]>
</Content>
<Content type="html" view="home">
<![CDATA[
<script type="text/javascript" src="/portal/csrf.js"></script>
<script type="text/javascript" src="js/ui/js/jquery.min.js"></script>
<script type="text/javascript" src="serverinfo.jag"></script>

<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap-theme.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap-missing.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jquery-ui-1.10.3.custom.min.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/smoothness/jqueryui-themeroller.css">
<link rel="stylesheet" type="text/css" href="js/ui/css/app-list.css">


<div id="contentDiv" class="container"></div>

<script type="text/javascript">

function draw(response) {
var result = JSON.parse(response);
if(result.error) {
console.log(result.msg);
return;
}
var data = result.apps;
var contentDiv = document.getElementById('contentDiv');
for(var i =0; i < data.length ; i ++ ) {
var row = document.createElement("div");
row.setAttribute("class","row");
var columns = data[i].length;
for(var j=0 ; j < columns; j++) {
var appDetail = data[i][j];

var div1 = document.createElement("div");
div1.setAttribute("class","cloud-app-listing app-color-one col-xs-2 col-sm-2 col-md-1 col-lg-1");

var anchor = document.createElement("a");
anchor.setAttribute("href", appDetail["url"]);
anchor.setAttribute("target", "_blank");


var div2 = document.createElement("div");
div2.setAttribute("class","app-icon");

var img = document.createElement("img");
img.setAttribute("src","/portal/gadgets/sso-apps/js/ui/img/custom.png");
img.setAttribute("class","square-element");


var div3 = document.createElement("div");
div3.setAttribute("class","app-name");
div3.textContent = appDetail["appName"];


div2.appendChild(img);
anchor.appendChild(div2);

div1.appendChild(anchor);
div2.appendChild(div3);

row.appendChild(div1);

}
contentDiv.appendChild(row);
}
}


$(function WindowLoad(event) {
var userName = null;
var serverUrl = window.location.host + PROXY_CONTEXT_PATH;

url = 'wss://' + serverUrl + '/dashboard/session_manager.jag';
ws = new WebSocket(url);

ws.onopen = function () {
console.log("web Socket onopen. ");
ws.send("First Message open");
};

//event handler for the message event in the case of text frames
ws.onmessage = function (event) {
var obj = $.parseJSON(event.data);
username = obj.user;

var str = PROXY_CONTEXT_PATH + "/portal/gadgets/sso-apps/sso-apps.jag?username=" + username ;
$.ajax({
type: "GET",
url: str

})
.done(function (response) {
console.log("response " + response);
draw(response);
})
.fail(function () {
console.log('error');
})
.always(function () {
console.log('completed');
});

};
ws.onclose = function () {
console.log("web Socket onclose. ");
};
});

</script>
]]>

</Content>

</Module>

4. Create an API to get the list of service providers configured.

Add a jaggery file called sso-apps.jag.

<IS_HOME>/repository/deployment/server/jaggeryapps/portal/gadgets/sso-apps/sso-apps.jag

Implementation : Get the list of service providers configured by calling “getAllApplicationBasicInfo()” method of “ApplicationDAOImpl” class. Which will give the basic information (SP name and description) of the apps. Then extract the appname and access url defined in the description and return the app list for api calls.

When creating an SP there is no field to give the login url of the application.Which is needed to provide SSO when apps are listed in the gadget. So we can use the description field to provide the login url . Where Login url should be between two $ sings. Thus we can extract the login URL from the description field and create the app list in the api.

<%
var log = new Log("sso-apps.jag");
var multitenantUtils = Packages.org.wso2.carbon.utils.multitenancy.MultitenantUtils;
var username = request.getParameter("username");

//user not found
if(!username) {
var res = {"error": true, msg: "No user found" };
print(res);
}

var tenantDomain = multitenantUtils.getTenantDomain(username);

//Get the apps
var apps = getAppsInfo();
if(!apps){
var res = {"error": true, msg: "Error while fetching apps" };
print(res);
}

//Create the list of apps with app name and app access url
var appList = [];
if (apps && apps.length > 0) {
for (var i = 0; i < apps.length; i++) {
var appInfo = {};
var des = apps[i].getDescription();
if (des && des.length != 0) {
var url = getURl(des);
if (url && url.length != 0) {
appInfo.appName = apps[i].getApplicationName();
appInfo.url = url;
} else {
continue
}
}
appList.push(appInfo);
}
}

var res = {"error": false, apps: listToMatrix(appList, 6) };
print(res);


// Get the list of service providers configured (SP name, and description)
function getAppsInfo() {
var isTenantFlowStarted = false;
var appsInfo;
var PrivilegedCarbonContext = Packages.org.wso2.carbon.context.PrivilegedCarbonContext;
try {
if (tenantDomain != null && !"carbon.super".equals(tenantDomain))
{
log.info("Start tenant flow for tenant : " + tenantDomain);
isTenantFlowStarted = true;
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
}
var ApplicationDAOImpl = Packages.org.wso2.carbon.identity.application.mgt.dao.impl.ApplicationDAOImpl;
var applicationDAO = new ApplicationDAOImpl();
try {
appsInfo = applicationDAO.getAllApplicationBasicInfo();
} catch (e) {
log.error("Error while fetching application list");
log.error(e);
}

} catch (e) {
log.error("Error while fetching application list for tenant : " + tenantDomain);
log.erro(e);
} finally {
if (isTenantFlowStarted) {
log.info("End tenant flow for tenant : " + tenantDomain);
PrivilegedCarbonContext.endTenantFlow();
}
}
return appsInfo;
}

//Extract the url from description text. where url will be between tow $ signs
function getURl(des) {
var firstIndex = des.indexOf("$");
var lastIndex = des.lastIndexOf("$")
var url;
if (firstIndex > -1 && lastIndex > -1 && firstIndex!=lastIndex) {
url = des.substring(firstIndex + 1, lastIndex);
}
return url;
}

//To print 6 apps in a row.
function listToMatrix(list, elementsPerSubArray) {
var matrix = [], i, k;

for (i = 0, k = -1; i < list.length; i++) {
if (i % elementsPerSubArray === 0) {
k++;
matrix[k] = [];
}

matrix[k].push(list[i]);
}

return matrix;
}
%>

5. Providing SSO, Since Dashboard app is already configured to SSO, when a user login to dashboard app and clicks any app listed, user will be logged in to that app via SSO.

Download the POC from https://github.com/jenananthan/Blog/blob/master/sso-gadget.zip

--

--