CORS Domain Wildcarding for SharePoint 2013 Apps

Scot Hillier

by Scot Hillier on 4/13/2014

Share this:
Print

Article Details

Date Revised:
12/2/2015

Applies to:
Article, Content Type, EDITORIAL USE ONLY


Originally published 4/14/2014 and reproduced here for reference 

I have been speaking for a while about the need for the SharePoint development community to move from simply consuming RESTful services to creating their own. If you buy into the argument that the future of programming involves client-side code over HTTP, then you can’t deny the need to create your own services. At SharePoint Conference 2014, I presented the basics for creating these services and you can watch the session on Channel 9. The remainder of the article will assume you have familiarity with the content in the session recording.

One challenge when creating your own RESTful services is that they will likely live in a different domain than the SharePoint apps that need to consume them. This situation is compounded when you want multiple SharePoint apps to consume the same resource because all SharePoint apps are deployed in their own domain. By default, browsers are not allowed to access resources in a different domain due to the same-origin policy.

There are a couple of ways to get around same-origin policy, such as JSONP, which uses the “script tag hack” to “download” the data from the cross-domain service. It’s also common to request the server perform the call using a web proxy. All of these solutions, however, are really workarounds to the issue of establishing trust between the browser and the cross-domain service. Modern browsers have a better answer for this problem known as Cross-Origin Resource Sharing (CORS).

CORS allows a browser and cross-domain service to exchange headers that establish trust. In a simple scenario, the service maintains a white list of authorized domains, which it can use to check the incoming request. If the incoming request is on the list, then the call succeeds. When you create RESTful services in WebAPI, you can easily support CORS by following these steps:

1.       In your WebAPI solution, install the NuGet package “Microsoft ASP.NET Web API 2 CORS”

2.       In the WebAPIConfig class, enable CORS support using the code config.EnableCors()

3.       For each controller you want to support CORS, decorate it with the [EnableCors] attribute

The [EnableCors] attribute allows you to specify a white list of domains, but here is where things become interesting. If you intend for SharePoint apps to consume your service, this list cannot be well-known because the domain for each app instance is created dynamically. So, what you need is a mechanism to allow some kind of wildcarding or pattern matching so that you can recognize the domains that are part of your SharePoint environment.

Fortunately, some nice work has been done by Matt Mazzola (Twitter: @mdmb54) solving this problem. He has created a custom attribute that can be applied to Web API controllers, which allows for the specification of a RegEx to pattern match your SharePoint app domain to the service white list. Because Matt doesn’t blog, I’ll show you how this works, but the full code is available from GitHub.

The basic approach to the problem is to create a custom CORS Policy attribute that will be used in lieu of the standard [EnableCors] attribute. The following code is Matt’s basic code modified for my dev environment.

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]

    public class SharePointAppDomainCorsPolicy : Attribute, ICorsPolicyProvider

    {

        private static List<string> AcceptableDomainPatterns = new List<string>()

        {

            @"app([-\w]+)\.apps\.wingtip\.com"

        };

 

 

        public async Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken token)

        {

            var corsRequestContext = request.GetCorsRequestContext();

            var originRequested = corsRequestContext.Origin;

 

            if (await IsOriginAcceptable(originRequested))

            {

                // Grant CORS request

                var policy = new CorsPolicy

                {

                    AllowAnyHeader = true,

                    AllowAnyMethod = true,

                };

                policy.Origins.Add(originRequested);

                return policy;

            }

            else

            {

                return null;

            }

        }

 

        private async Task<Boolean> IsOriginAcceptable(string origin)

        {

            var isOriginAcceptable = false;

 

            foreach (var pattern in AcceptableDomainPatterns)

            {

                var regex = new Regex(pattern, RegexOptions.IgnoreCase);

                if (regex.IsMatch(origin))

                {

                    isOriginAcceptable = true;

                    break;

                }

            }

            return isOriginAcceptable;

        }

    }

Notice that the new attribute inherits from ICorsPolicyProvider. It uses a RegEx to set up a pattern that matches my SharePoint 2013 app domain and return a Boolean indicating if the app domain pattern puts it on the white list. In my dev environment, the pattern for these domains looks like this:

https://app-{GUID}.apps.wingtip.com

In order to use the new attribute, I must modify the code in the WebAPIConfig class to reference the new policy. This code will apply the policy globally and eliminate the need to decorate each controller individually.

config.EnableCors(new SharePointAppDomainCorsPolicy());

It’s that simple! Now all my SharePoint apps can access the service. Thanks again to Matt Mazzola for providing the code.

 


Topic: Article

Sign in with

Or register