From Esdin

Jump to: navigation, search

Example URL:


Challenges involved in implementing AJAX browser-based client for protected services

Our OpenLayers client is trying to make a request to a Shibboleth authenticated WMS server which is on a different, ie, foreign, domain to the one which OpenLayers is hosted on. Due to Cross-Site-Scripting(XSS) restrictions in browsers, it is not possible to request a resource from a foreign domain name, unless the server and client have the correct configuration.

The restriction only occurs when requesting non-image based resources, such as the initial GetCapabilities request for an XML file, or a GetFeatureInfo request. Images, including WMS GetMap requests, do not have this XSS restriction and are free to get data from any foreign domain.

For a request to work, the correct Shibboleth cookie must exist in the web browser for the domain that hosts the WMS resource. For the first request to that resource, ie the GetCapabilities request, this cookie is unlikely to exist. So, if this cookie does not exist then the browser is first forwarded from the SP to the WAYF to find out which IdP the user has authenticated to. The user has already authenticated so the WAYF cookie that indicates what IdP the user has selected already exists. The user is then forwarded to their IdP. Again, since they have already authenticated, the user is forwarded back to the original SP of the requested resource, but this time with the correct cookie in their browser.

Unfortunately the XMLHttpRequest object does not support all of these operations. In particular, it doesn't not support HTTP redirects and creating new cookies. This means that adding extra Shibboleth protected WMS servers to an OpenLayers client does not work without some extra configuration and JavaScript code changes.


The "image trick"

To get round this we use a trick which uses the main browser redirect/cookie handler code instead of the XMLHttpRequest object. This involves using a dummy image object to try and load the protected resource first. Because we're using an image object, this gets around the XSS site restriction and successfully follows redirects correctly and creates cookies for new domain names accessed. Obviously trying to load a non-image into an image object generates an error. When this error occurs, the same URL is loaded using the XMLHttpRequest instead. Since all the correct cookies are now in place the request succeeds.

To implement the trick:

Create a dummy image object and request the protected resource at 'foreignUrl':

   image = document.createElement("img");
   image.src = foreignUrl;
   image.setAttribute("onerror", "imgLoadError()");

This runs the 'imgLoadError()' function which then runs the normal XMLHttpRequest code for connecting to a resource. This is the same as any XMLHttpRequest code that you would use to access resources on your own domain except this property must also be set:

   xhrRequestObject.withCredentials = "true";

Apache configuration

Apache that serves the protected resources needs to be configured to allow access from foreign domains. This requires a header to be set in the HTTP response called "Access-Control-Allow-Origin". This header should contain a list of domain names that are allowed to make an XSS request for a resource. Normally you only have a fixed set of domains that you trust here for security reasons. Since we are assured that anyone requesting a resource is already authenticated with Shibboleth, we can just allow any domain to make a XSS request. Unfortunately, due to security restrictions, you cannot use a wild card in the response header, you must explicitly declare each domain that is allowed access. To get around this we can use the following Apache config to extract the domain name of the requesting site and insert that name back into the response. Functionally, this is identical to a wild card.

   SetEnvIf Origin (.+) ORIGIN=$1
   Header set Access-Control-Allow-Origin "%{ORIGIN}e" env=ORIGIN
   Header set Access-Control-Allow-Credentials "true" env=ORIGIN

The mod_headers module must be installed for this to work.

This technique works in the following browsers:

Firefox 3.5+ Google Chrome 5+ Safari 4+

We recommend using Firefox 3.5+ due to additional OpenLayers compatibility issues with some of their other JavaScript code.

The following browsers are not supported:

Internet Explorer Opera

Internet Explorer 8 will work with an additional fix. Instead of using the XMLHttpRequest object to make requests you must use the XDomainRequest object.

Download OpenLayers Patches


Attached is a patch for OpenLayers 2.9.1 which adds the modifications into OpenLayers.

To apply it, use the command:

   patch -p1 < esdin.patch

Before applying the patch, make sure the WMSControl.js plugin is installed into the base install of OpenLayers. This plugin is available from the OpenLayers site.

EDINA version of OpenLayers

To use openlayers as a WFS client then a second patch has to be applied to enable preflighted requests using the exact same trick. This is available together with the WMSManager patch in a fully prepatched release which is ready to use. The individual patches are still available under the directory patches/ after unzipping the file.

Personal tools