SharePoint & IBM Connections better together?

Hi,

In my previous posts on IBM Connections vs SharePoint which you can find here, I tried to shed some light on the pros & cons of each platform regarding Social Business & Document Management.If you read those posts, you might think that I privilege SharePoint over IBM Connections, certainly as a SharePoint MVP. However, it was not the intention, I really tried to make an objective comparison but that kind of exercise is never easy.The purpose of those posts was to bring some clarity on both products out of a real world experience. I often read here and there *marketing* messages looking like a boxing match between IBM & Microsoft. I must say that IBM is often the first one to bite., maybe because they are in the skin of the challenger in this matter..:? SharePoint is a well known heavy weight for years now…

Anyway, in this post, I’ll rather focus on an integration scenario consisting in sharing SharePoint Documents with IBM Connections feed. I won’t oppose the two platforms but instead, I’ll make them cooperate. I’ll even advertise for a very nice feature of IBM Connections here, called Embedded Experience. This isn’t a specific IBM Connections feature but IBM was smart enough to reuse it. Before diving into the technical details, here are some screenshots showing the functionality of a component I recently developed:This is the kind of data you could get in your feed:

feed.png
and when clicking on the block, get an OpenSocial gadget embedded into an Embedded Experience:

ee.png

from there, you can start viewing & editing the document that’s stored in SharePoint.This business scenario is quite valid IMHO for large organizations where they decide to use IBM Connections for Social Related things and *light* document management and keep using SharePoint for more advanced Document Management including advanced workflows etc…At the end of a Document Lifecycle, one could consider *publishing* the document to IBM Connections or to a specific community in order to share the final result with the appropriate users.Okay, enough talking, in the upcoming paragraphs, I’ll explain you in details the required steps to accomplish that kind of integration, these are:

  • Develop the OpenSocial gadget that is shown in the Embedded Experience
  • Register that gadget in IBM Connections
  • Allow that gadget for use in IBM Connections
  • Post some JSON data using IBM Connection’s REST APIs
  • Handling authentication & cross-domain calls

Develop the OpenSocial gadget

The OpenSocial gadget is nothing else but an XML file, here is the code of the Office Web App gadget:

<?xml version="1.0" encoding="utf-8"?>
<Module>
	<ModulePrefs title="Office Web Apps Gadget" 		description="This Gadget shows Office documents in the browser within IBM Connections Feed">
		<Require feature="opensocial-0.9"/>
		<Require feature="embedded-experiences" />
		<Require feature="dynamic-height" />
	</ModulePrefs>

   <Content view="embedded,default" type="html">
   <![CDATA[
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <body>
<div id="SPDocument" style="display: none">
   <iframe width="300px" height="282px"  id="owaframe" src=""></iframe>
<div id="SPDocMetaInfo"></div>
</div>
<div id="PreviewError" style="display:none;"></div>
<script type="text/javascript">
		var gadgetContext;
		function loadContextData(context){
                     gadgetContext =  context;
        } 

		function initData() {
			opensocial.data.getDataContext()
				.registerListener('org.opensocial.ee.context', function(key){
				onLoad(opensocial.data.getDataContext().getDataSet(key));
			});
		}        

	function onLoad(context){
		loadContextData(context);
		var targetUrl=gadgetContext["TargetUrl"]
		if(targetUrl === undefined || targetUrl === '' || targetUrl === null){
			showError('Could not preview this document, no URL provided');
			return;
		}

		document.getElementById('owaframe').src=targetUrl;
		var createdBy =
			(gadgetContext["CreatedBy"] !== null && gadgetContext["CreatedBy"] !== undefined) ? gadgetContext["CreatedBy"] : '';
		var createdOn =
			(gadgetContext["CreatedOn"] !== null && gadgetContext["CreatedOn"] !== undefined) ? gadgetContext["CreatedOn"] : '';
		if(createdBy != '' && createdOn !=''){
			document.getElementById('SPDocMetaInfo').innerText = 'Created by '+createdBy+' on ' + createdOn;
		}

		document.getElementById('SPDocument').style.display='block';
	}

	function showError(err){
		document.getElementById('PreviewError').innerText=err;
		document.getElementById('PreviewError').style.display='block';
	}

	   gadgets.window.adjustHeight(400);
	   gadgets.util.registerOnLoadHandler(initData);
   </script>
   </body>
   </html>
   ]]>
   </Content>
</Module>
  • The ModulePrefs node is used to describe the gadgtet as well as to define the features that are required by it. This varies according to what the gadget is doing
  • The Content node contains the HTML/JavaScript/CSS code. For sake of simplicity, I’ve put all the code in the page but you can of course work with separate .js and .css files
  • Before the script tag, I’ve defined my DOM elements. Within the script tag, the context data is retrieved and used to set the src attribute of the iframe that ultimately points to wopiframe aka SharePoint’s office webapps utility page

You can save this piece of code in a file named officewa.xml. The file can be stored anywhere providing it’s a valid URL that’s accessible by end users.

Register the gadget

  • Start wsadmin, for more info, refer to IBM Documentation
  • execfile(“newsAdmin.py”)
  • NewsWidgetCatalogService.addWidget(title=”Office WebApps Gadget”, text=”Office WebApps Gadget”, url=”https://…/officewa.xml&#8221;,categoryName=WidgetCategories.NONE, isGadget=TRUE,appContexts=[WidgetContexts.EMBEDXP], policyFlags=[GadgetPolicyFlags.TRUSTED], prereqs= [])

In a nutshell, we tell the new service about the new gadget and we specify the path to our XML file.

Allow the usage of the gadget

  • Launch wsadmin
  • execfile(“connectionsConfig.py”)
  • LCConfigService.checkOutOpenSocialConfig(“d:\\temp\\social”, “yourcell”)
  • In opensocial-config.xml, set security whitelistEnabled to “false”.
  • LCConfigService.checkInOpensocialConfig()

In a nutshell, we allow the gadget to be used by disabling the whitelist mechanism. Note that this is OK in dev, in production, you should build a valid white list of gadgets. This process is a little similar to SharePoint’s SafeControls mechanism.

Post JSON data to Connection’s feed

{
 "actor": {
   "id": "@me"
 },
 "verb": "post",
 "title": "Dummy SharePoint Document",
 "content": "This shows how to share SharePoint Documents via Embedded Experiences
                    <img src='https://sphost/_layouts/15/WopiFrame.aspx?sourcedoc=%2FShared%20Documents%2Fdummy%2Edocx&action=imagepreview' />",
 "object": {
  "summary": "",
  "objectType": "note",
  "id": "put a guid here",
  "displayName": "SharePoint document"
  },
  "openSocial":{
   "embed": {
     "gadget": "http://gadgethost/homepage/gadgets/officewa.xml",
	 "context" : {
	  "TargetUrl" : "https://sphost/_layouts/15/WopiFrame.aspx?sourcedoc=%2FShared%20Documents%2Fdummy%2Edocx&action=interactivepreview&wdSmallView=1",
	  "CreatedBy" : "Stephane Eyskens",
	  "CreatedOn" : "20/08/2014"
	  }
    }
   }
}

Some explanations are required here:

  • sphost is SharePoint WFE
  • gadgethost is the web server on which the gadget definition is hosted, it can be on IBM Connections or anywhere else providing it can be accessed by user’s browsers
  • content is the actual content of the news, you can put some basic HTML in it
  • In the object section, it’s very important to specify a unique ID for the news, a GUID seems appropriate there
  • In the opensocial section, you must specify the gadget definition location. Note that alternatively, you can specify the url key instead of gadget and specify the URL of a page to be launched in the EE. The context property is a set of key/value pairs that you can transmit to the gadget

The SharePoint Ribbon is a nice place to emit this HTTP POST request to allow end users to select one or more documents they want to *socialize* using IBM Connections.

Handling authentication & cross-domain calls

Last but not least and usually, that’s where things start to get complicated….I made several blog posts about handling cross-domain calls and authentication, you can have a look at them here http://www.silver-it.com/taxonomy/term/59.
In my real world scenario, the authentication is performed via a device certificate that is trusted by both platforms. On SharePoint side, there is a custom membership provider that handles the certificate while there is a custom TAI module on IBM Connections side. From the gadget perspective, since in this case, all happens client side, the browser issues the requests to either Connections, either SharePoint and transmits the certificate along the request. It’s not equivalent to a web SSO but the authentication is transparent for the end user. At last, the only Cross-Domain call possibility is if you post the JSON data via JavaScript from a SharePoint page/Ribbon (remember my business scenario here). In this case, you’ll run under the same-origin policy since the SharePoint farm doesn’t live in the same domain as IBM Connections. Go read my other blog posts to get answers on how to handle this. If you issue the request server-side, you won’t fall under the same-origin pocliy anymore but you’ll need to have a way to authenticate the HTTP Request issued by the the SharePoint WFE (Claims-Based by default) to IBM Connections (LTPAToken by default). There are some possibilities to make them understand each other such as using SPNego, also a certificate or potentially setup a true SSO in place involving third parties but that’s beyond the scope of this blog post.

Happy Coding!

Advertisements

About Stephane Eyskens

Office 365, Azure PaaS and SharePoint platform expert
This entry was posted in IBM Connections, SharePoint and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s