SharePoint 2013 – Integration Challenges with remote applications – #2 Same Origin Policy & Authentication – Reverse Proxy

Hi,

I’m currently involved in integrating SharePoint with IBM Connections and I’m having a lot of fun trying to figure out all the possibilities. Since these integration considerations are not specific to SharePoint/IBM Connections, I’ll blog a series of posts which will be rather short or rather long according to the topic I’m focusing on.

In this post, I’m going to focus on very common problems when dealing with integration of external products.

Which API should I use?

Nowadays, and SharePoint makes no exception, a typical way to query a system is by consuming its REST endpoints. IBM Connections also exposes some REST endpoints and more particularly ATOM feeds.

So, it means that if I want to show data from IBM Connections within SharePoint, I can consume its ATOM feeds while if I want to do it the other way around, I’ll consume the SharePoint REST endpoints from IBM Connections.

Client-Side or Server-Side?

So far so good. The key question now is : how do I consume it? Client side with JavaScript or Server-side with HttpWebRequest?

The natural answer is client side of course, moreover, IBM Connections does not propose server-side components in its APIs. IBM Connections is based on Websphere so it is possible to deploy server-side components but it’s not really the philosophy. Basically, they rather suggest using client side Widgets (based on dojo) to enrich the pages.

Similary, SharePoint 2013 is pushing apps and for instance, SharePoint-Hosted Apps where you can only use client-side technologies. So, I’ll stick to the natural answer which is : I’ll consume those APIs client-side.

Same-origin policy

Although more and more people face the Same-origin policy restriction, it’s still sometimes challenging to work around it and to find good alternatives. The usual alternatives are JSONP, CORS (not so usual yet) and the HTML 5 PostMessage API. I’ll cover some of those in a later post. Now, I want to focus on another alternative that’s less known : using a reverse proxy.

What’s the idea with the reverse proxy?

To understand the idea, let’s remember what the Same-origin policy is all about. It prevents scripts in pages from calling pages/services living on another domain knowing that a domain is:
—————————[protocol]://[your site][:port]]/————————————-
If any of the above is different from one page to another, the Same-origin policy comes into play. So, even inside of SharePoint, if you have multiple web applications, pages from application A won’t be able to consume application B pages/services client-side since the host-header of those apps are different.

Now that the problem is clearly defined, let’s see how the Reserse Proxy can help fixing it. As a remider, a reverse proxy is a device that is between a browser and a web server.

—-User Browser—-Reverse Proxy—Web Server (SharePoint WFE for instance)

Most of the production environments make use of reverse proxies to ensure typical services such as security, load balancing, forbidding some URLs etc…but of course, one of the thing a reverse proxy can do is routing. So, we can leverage that in order to workaround the same-origin policy.

So, if for instance, I have a page in SharePoint (http://sharepointserver/mypage) that tries to consume an IBM Connection Feed available at http://ibmconnectionserver/myfeed, if I perform an AJAX query the following way:

$.ajax({
 url:"http://ibmconnectionserver/myfeed"
}).done(function(xml) {
    //ok
}).fail(function() {
    //failed
});

I’ll run under the same-origin policy and the browser will even not try to contact the server. If, however, I run the following query:

$.ajax({
 url:"http://sharepointserver/ibmconnection/myfeed"
}).done(function(xml) {
    //ok
}).fail(function() {
    //failed
});

The same-origin policy is not applicable since the host header is the SharePoint one. Of course, the feed doesn’t exist within SharePoint and that’s where the reverse proxy can help in translating (rerouting) http://sharepointserver/ibmconnection/myfeed to http://ibmconnectionserver/myfeed transparently making the browser believe that the target URL lives within the same domain as the current page.

What about authentication

Of course, that trick will allow you to transparently target resources that are not in the same domain but it will not authenticate you against that remote resource. So, what are the options?
In production environments, you can usually rely on tools such as SiteMinder/F5 which can deal with those things. They can transparently create an authentication token for the user “on the fly”.

Ok so in production, tools will be available but what about development? Let’s use Fiddler!

The tools I’ve just mentioned are often not available on development environments…Therefore, you are still blocked. Fortunately, Fiddler can come to the rescue.
Fiddler is a HTTP Debugging Proxy tool that’s available for free. The idea is to use its AutoResponder engine to mimic what the F5 and/or SiteMinder tools would do in other environments or at least, to have a workable solution in your development environment.

So, if you open Fiddler and go to Rules -> Customize Rules, you can easily perform the following steps:

Say that in this case, I want to reroute requests from SharePoint to connections:

I start by declaring a variable at the beginning of the file:

public static var IBMConnectionCookies: String = null;

Then, I add a rule

if(oSession.uriContains("ibmconnectionserver")){
  var cookies = oSession.oRequest.headers["Cookie"];
  if(cookies != null && cookies != '')
  {
    IBMConnectionCookies=cookies;
  }
}

where I’m taking all the cookies that were sent by the browser when connecting to IBM Connections. So, in order for that trick to work, you need to authenticate at least once with your browser.

then, I add another rule:

if (oSession.uriContains("/ibmconnections/")) {
   oSession.oRequest.headers.Add("Cookie",IBMConnectionCookies);

   oSession.fullUrl ="http://ibmconnectionserver/"+oSession.url.substring(oSession.url.indexOf('/ibmconnections/')+16);
}

which reroutes the request from sharepointserver/ibmconnection/….to http://ibmconnectionserver/…. and adds all the authentication cookies to it which in this case are the LtpaToken2 & JSESSIONID. Therefore, you’re not only able to perform an AJAX query to another domain but you’re also able to authenticate it…providing you’ve at least authenticated once before using your browser.

Advantages of using a Reverse Proxy to work around the same-origin policy

  • The solution is not a programmatic approach
  • The solution is not browser dependent since browsers “think” that they are requesting pages/services from the same domain
  • Other approaches such as JSONP, PostMessage, CORS have limitations or are not supported by all the browsers or not all the servers
  • From a security point of view, it’s more controllable at the enterprise level rather than letting developers define their own work arounds

Summary

So, in development, Fiddler can really help in mimicking the behavior of actual production devices such as F5/SiteMinder. While this technique isn’t SSO at all, it still allows you to bypass the same-origin policy and to authenticate the request along the way. Moreover, you’re not that far from the target solution.

Happy Coding

Advertisements

About Stephane Eyskens

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

One Response to SharePoint 2013 – Integration Challenges with remote applications – #2 Same Origin Policy & Authentication – Reverse Proxy

  1. Pingback: SharePoint 2013 – Integration Challenges – #3 Same Origin Policy & Authentication – Cross-Domain Library | Stéphane Eyskens, Office 365 and Azure PaaS Architect

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