Nov 14 2012

Beating CRM2011 Anti-XSS with a Web Resource Shim

Published by at 11:57 pm under Microsoft CRM

Background

In Microsoft Dynamics CRM we’ve got several places that documents relating to an account can be uploaded to SharePoint.  Some are custom solutions developed whilst we were using CRM4 and others are using the built-in CRM2011 SharePoint integration.

To keep things simple for users, I have created a SharePoint web part that allows them to see a consolidated view of documents relating to each account.  This web part has a menu against each document that allows users to open the record that the document was uploaded against.

The Problem

Previously, I was just opening the CRM record in an Internet Explorer (IE) window and everything was fine.  However, now CRM has got a nifty Xrm.Utility.openEntityForm() JavaScript function that will open entity forms in either an IE or Outlook window, depending on which client the user is using to access CRM.

If you are using a CRM Web Page WebResource, you’ve got the option of either including ClientGlobalContext.js.aspx or using parent.Xrm to access the Microsoft Xrm JavaScript object model.  Unfortunately, Crm is on one website address and SharePoint is another website address.  Therefore, although SharePoint is being displayed in CRM using an iFrame, Anti-XSS (Cross Site Scripting) prevents the use of parent.Xrm in the SharePoint page.

The Solution

Given that the Xrm JavaScript object model needs to be used from a page in CRM the solution I came up with is to use a WebResource html page that will act as a shim for SharePoint:

!DOCTYPE html>
<html>
<head>
    <title>Xrm Shim</title>
    <base>
    <script type="text/javascript" src="../ClientGlobalContext.js.aspx"></script>
    <script type="text/javascript" src="../c5_javascript/lib/jquery.min.js"></script>
    <script type="text/javascript">
        $(function () {
            var data = Xrm.Page.context.getQueryStringParameters();
            Xrm.Utility.openEntityForm(data.typename, data.id);
        });
    </script>
    <meta charset="utf-8">
</head>
<body>
</body>
</html>

I then updated my SharePoint web part to run the following script when the user clicks the CRM Record menu item:

crmRecordMenuItem.ClientOnClickScript =
    string.Format(@"ifrm = document.createElement('IFRAME');
        ifrm.setAttribute('src', '{0}/{1}/WebResources/xrmshim.htm?typename=%DocTypeName%&amp;id=%CRMDocID%');
        ifrm.style.width = 1+'px';
        ifrm.style.height = 1+'px';
        document.body.appendChild(ifrm);", crmUrl, crmOrgName);

This creates an iFrame that loads from html shim from CRM which in turn calls Xrm.Utility.openEntityForm using the typename and id passed from SharePoint in the query string parameters.

The shim is simple enough that it can be used on any page that is hosted on any site other that CRM.  It could be extended to call any Xrm object model methods provided by ClientGlobalContext.js.aspx.

No responses yet