A Light-weight CORS Wrapper for SharePoint REST

In this post I’m going to demonstrate a CORS Wrapper for postMessage operations, specifically in SharePoint, and intended to make CORS operations as simple as the Ajax operations we’re more familiar with. I’m going to develop the same simple pages I used in my last post, only using the CORS Wrapper this time. Then I’ll dump the CORS Wrapper on you. I’m not going to talk a great deal about the code, I’ve included a ridiculous number of comments in the code to explain what I’m doing.

Anyway, in my last post, I described the basics of using postMessage to do cross-origin web service calls in SharePoint. And I stressed that it is not that complicated. In just under 20 lines of JavaScript, I was able to expose the complete range of web services on a site collection to another site collection. And with another 10 lines of JavaScript I was able to consume one of these web services on another site collection.

And yet, in my experience, a lot of developers think this is too complicated and don’t want to deal with it. I think the reasons for this are twofold:

  1. SharePoint and it’s web services are already complicated. First, there’s a bunch of them, and they all take different parameters. And you need to set different headers depending on what you’re doing. And is it a GET, or POST, or MERGE. And they’re not very well documented, although that’s getting better. There are plenty of simple examples, but few complex ones (for instance, a lot is left to the imagination when it comes to filters or how lazy loading works).
  2. While postMessage does not add a ton of complexity, adding any complexity at all makes developers groan in agony (mostly because of reason 1).

Looks like an opportunity for some sort of CORS Wrapper or library. Deal with the complexity once, and forever more use the library to hide most if not all of the additional complexity.

The New CORS Wrapper Service Proxy Page

Below is the new Service Proxy page. Like before, it includes a button to test the web service calls locally, but is primarily intended to be loaded in a hidden iframe and called cross-origin. Don’t forget that you also need to include in the page a SharePoint:AllowFraming control or SharePoint won’t let you load the page in an iframe.

The CORS wrapper/library is in spcors.js in the same directory as the page. To implement the service proxy page, all you really need to do is instantiate an object like so:

This creates an event handler for post messages which takes in ajax options as a message, calls $.ajax, and sends a message back to the parent window.

Below is the complete JavaScript source code for the page. Like above, it initializes the origin to “*”, which isn’t ideal, but is your only option if you want to accept requests from multiple cross-origins.

But the ServiceProxy also has two additional parameters; originPatterns and urlPatterns. Both of these are arrays of RegExp instances. If either parameter is initialed with a non-zero-length array of patterns, it will validate that something matches at least one of the patterns. Not to surprisingly, the something that is compared is the origin against originPatterns and the ajax URL against urlPatterns.

These two options provide a great deal of flexibility to lock down who can call what and from where. Ideally you should always put some restrictions on both. As in don’t allow calls from anywhere. And don’t allow calls to anything. This is especially true if you have multiple origins that need access so you specified “*” as the expected origin.

Now if none of your data is important to anyone, go ahead in fire up the ServiceProxy with a single argument of “*” like above and have at it. But I’m a consultant and to date I’ve never had a client tell me that none of their data is important or sensitive.

And without further ado, here is the code for the proxy page:

Not bad. A few lines of code, a whole bunch of comments, and a few lines of test code, and we’ve exposed as much of the SharePoint REST API as we want to in a reasonably secure manner.

As before, this page is intended to be loaded in an iframe, but if you go to the page directly in the browser, and click the button, you can test calling the web service directly and make sure you’ve got that right before adding the complexity of trying to call the service cross-origin.

The New CORS Wrapper Proxy Client Page

And here is the proxy client page. I’ve been a bit naughty here and assigned my ProxyClient instance to a local variable called $. Not that anyone can really claim to have exclusive rights to $, but so many people are used to that being jQuery that it’s arguable not a good idea to use it for something else. Anyway, I did it to show that my call to $.ajax (highlighted below) is virtually identical to what you would expect calling the jQuery function with that name.

Also, keep in mind that to look at this as if one side is the server and the other the client is a dangerous falicy. Both frames have a message handler and recieve messages, so both sides are the server. And both sides send messages to other, so both are the client/consumer. So security needs to be implemented on the Proxy Client page too, thus the originPatterns array here too. The urlPatterns here don’t make any sense, since we’re recieving ajax responses, which don’t necessarily have a url.

The Post Message CORS Wrapper Library

Below is the implementation of the two JavaScript classes I’m using above. You now have a pretty good idea of how to use them, and there are ample comments explaining what they’re doing under the hood, so there really isn’t that much to say. Heck, if you strip out the comments you’ll see that it’s actually a pretty trivial amount of code.

Wrap-Up

You should now have enough information to be dangerous wrt Cross-Origin Resource Sharing (CORS). In order to make it work, you need to be able to place some code on both the source and the destination site collection, or coordinate with someone who has that access, which is why this is more secure than the old days of all SharePoint site collections existing in a single origin. And it does add a bit of complexity, but with a simple CORS wrapper like the one I’ve used here, you can make daily use of CORS no more complex than using REST directly (which as previously stated, is complex enough).

This CORS wrapper I’ve written is dependent on jQuery, mainly just so I can use $.ajax and promises without worrying too much about browser compatibility. If you’re already using jQuery for other things, then that makes sense. If not, it’s probably not worth including jQuery just for that. It wouldn’t be that hard to remove the jQuery dependency, and I could still use promises, if I switched to using something like fetch, which I’ll probably do in a follow up post at some point.

And keep in mind that I didn’t do anything with the response except popup a dialog so I didn’t need to do anything in particular to safeguard against a potentially malicious response. But if you’re going to put parts of the response directly in your HTML, you should escape it to remove the possibility of executing malicious code (like strip out script tags, and JavaScript in HTML attributes, etc.). And at a bare minimum, eval should be used sparingly in JavaScript if at all, but regardless of whether you agree with this statement or not, it should never be used on input that comes from a cross-origin resource. The point is that you can’t treat the response as coming from a fully trusted source.

The complete source code is in CORS_Wrapper_Source.zip.

References

Leave a Comment