public void GetCorsRequestContext_CachesTheContext()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://example.com/test");
            request.Headers.Add("Origin", "foo");
            request.Headers.Add("Host", "example.com");
            request.Headers.Add("Access-Control-Request-Method", "bar");

            CorsRequestContext result = request.GetCorsRequestContext();
            CorsRequestContext result2 = request.GetCorsRequestContext();

            Assert.Same(result, result2);
        }
        /// <summary>
        /// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation.
        /// </summary>
        /// <param name="request">The HTTP request message to send to the server.</param>
        /// <param name="cancellationToken">A cancellation token to cancel operation.</param>
        /// <returns>
        /// Returns <see cref="T:System.Threading.Tasks.Task`1" />. The task object representing the asynchronous operation.
        /// </returns>
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
            if (corsRequestContext != null)
            {
                try
                {
                    if (corsRequestContext.IsPreflight)
                    {
                        return await HandleCorsPreflightRequestAsync(request, corsRequestContext, cancellationToken);
                    }
                    else
                    {
                        return await HandleCorsRequestAsync(request, corsRequestContext, cancellationToken);
                    }
                }
                catch (Exception exception)
                {
                    return HandleException(request, exception);
                }
            }
            else
            {
                return await base.SendAsync(request, cancellationToken);
            }
        }
 public async Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
     var corsRequestContext = request.GetCorsRequestContext();
     var originRequested = corsRequestContext.Origin;
     if (await IsOriginApproved(originRequested))
     {
         // Grant CORS request
         var policy = new CorsPolicy();
         policy.Origins.Add(originRequested);
         policy.Methods.Add("GET");
         policy.Methods.Add("POST");
         policy.Methods.Add("PUT");
         policy.Methods.Add("DELETE");
         policy.Methods.Add("PATCH");
         policy.Methods.Add("OPTIONS");
         policy.Headers.Add("accept");
         policy.Headers.Add("content-type");
         policy.Headers.Add("X-Auth-Token");
         policy.Headers.Add("Origin");
         policy.ExposedHeaders.Add("DataServiceVersion");
         policy.ExposedHeaders.Add("MaxDataServiceVersion");
         policy.ExposedHeaders.Add("X-Auth-Token");
         policy.SupportsCredentials = true;
         return policy;
     }
     // Reject CORS request
     return null;
 }
        public void EvaluatePolicy_Trace_ContainsHttpRequest()
        {
            // Arrange
            HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Options, "http://example.com/test");
            httpRequest.Headers.Add("Origin", "foo");
            CorsRequestContext corsRequestContext = httpRequest.GetCorsRequestContext();

            Mock<ITraceWriter> traceWriterMock = new Mock<ITraceWriter>();
            traceWriterMock
                .Setup(t => t.Trace(httpRequest, It.IsAny<string>(), It.IsAny<TraceLevel>(), It.IsAny<Action<TraceRecord>>()))
                .Verifiable();

            Mock<ICorsEngine> corsEngineMock = new Mock<ICorsEngine>();
            corsEngineMock
                .Setup(engine => engine.EvaluatePolicy(corsRequestContext, It.IsAny<CorsPolicy>()))
                .Returns(new CorsResult());

            CorsEngineTracer tracer = new CorsEngineTracer(corsEngineMock.Object, traceWriterMock.Object);

            // Act
            tracer.EvaluatePolicy(corsRequestContext, new CorsPolicy());

            // Assert 
            traceWriterMock.Verify();
        }
 public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
 {
     return _traceWriter.TraceBeginEndAsync<CorsPolicy>(
         request,
         TraceCategories.CorsCategory,
         TraceLevel.Info,
         _innerPolicyProvider.GetType().Name,
         MethodName,
         beginTrace: (tr) =>
         {
             tr.Message = String.Format(CultureInfo.CurrentCulture, SRResources.TraceCorsRequestContext, request.GetCorsRequestContext());
         },
         execute: () => _innerPolicyProvider.GetCorsPolicyAsync(request),
         endTrace: (tr, policy) =>
         {
             if (policy != null)
             {
                 tr.Message = String.Format(CultureInfo.CurrentCulture, SRResources.TraceEndPolicyReturned, policy);
             }
             else
             {
                 tr.Message = SRResources.TraceEndNoPolicyReturned;
             }
         },
         errorTrace: null);
 }
        public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
        {
            ICorsPolicyProvider policyProvider = null;

            _traceWriter.TraceBeginEnd(
                request,
                TraceCategories.CorsCategory,
                TraceLevel.Info,
                _innerPolicyProviderFactory.GetType().Name,
                MethodName,
                beginTrace: (tr) =>
                {
                    tr.Message = String.Format(CultureInfo.CurrentCulture, SRResources.TraceCorsRequestContext, request.GetCorsRequestContext());
                },
                execute: () => { policyProvider = _innerPolicyProviderFactory.GetCorsPolicyProvider(request); },
                endTrace: (tr) =>
                {
                    if (policyProvider != null)
                    {
                        tr.Message = String.Format(CultureInfo.CurrentCulture, SRResources.TraceEndPolicyProviderReturned, policyProvider);
                    }
                    else
                    {
                        tr.Message = SRResources.TraceEndNoPolicyProviderReturned;
                    }
                },
                errorTrace: null);

            if (policyProvider != null)
            {
                return new CorsPolicyProviderTracer(policyProvider, _traceWriter);
            }

            return null;
        }
        public virtual ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
            HttpActionDescriptor actionDescriptor = null;
            if (corsRequestContext.IsPreflight)
            {
                HttpRequestMessage targetRequest = new HttpRequestMessage(new HttpMethod(corsRequestContext.AccessControlRequestMethod), request.RequestUri);

                request.RegisterForDispose(targetRequest);

                try
                {
                    foreach (var property in request.Properties)
                    {
                        // The RouteData and HttpContext from the preflight request properties contain information
                        // relevant to the preflight request and not the actual request, therefore we need to exclude them.
                        if (property.Key != HttpPropertyKeys.HttpRouteDataKey &&
                            property.Key != HttpContextBaseKey)
                        {
                            targetRequest.Properties.Add(property.Key, property.Value);
                        }
                    }

                    HttpConfiguration config = request.GetConfiguration();
                    if (config == null)
                    {
                        throw new InvalidOperationException(SRResources.NoConfiguration);
                    }

                    IHttpRouteData routeData = config.Routes.GetRouteData(request);
                    if (routeData == null)
                    {
                        // No route data found for selecting action with EnableCorsAttribute, thus no ICorsPolicyProvider is returned
                        // and let the CorsMessageHandler flow the request to the normal Web API pipeline.
                        return null;
                    }

                    actionDescriptor = SelectAction(targetRequest, routeData, config);
                }
                catch
                {
                    if (DefaultPolicyProvider != null)
                    {
                        return DefaultPolicyProvider;
                    }
                    throw;
                }
            }
            else
            {
                actionDescriptor = request.GetActionDescriptor();
            }

            return GetCorsPolicyProvider(actionDescriptor);
        }
        public void GetCorsRequestContext_ReturnsOrigin()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://example.com/test");
            request.Headers.Add("Origin", "foo");

            CorsRequestContext result = request.GetCorsRequestContext();

            Assert.Equal("foo", result.Origin);
        }
        public void GetCorsRequestContext_ReturnsRequestMethod()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://example.com/test");
            request.Headers.Add("Origin", "foo");
            request.Headers.Add("Access-Control-Request-Method", "bar");

            CorsRequestContext result = request.GetCorsRequestContext();

            Assert.Equal("bar", result.AccessControlRequestMethod);
        }
        public ICorsPolicyProvider GetCorsPolicyProvider(
          HttpRequestMessage request)
        {
            var route = request.GetRouteData();
            var controller = (string)route.Values["controller"];
            var corsRequestContext = request.GetCorsRequestContext();
            var originRequested = corsRequestContext.Origin;
            var policy = GetPolicyForControllerAndOrigin(
              controller, originRequested);

            return new CustomPolicyProvider(policy);
        }
        public virtual ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
            HttpActionDescriptor actionDescriptor = null;
            if (corsRequestContext.IsPreflight)
            {
                HttpRequestMessage targetRequest = new HttpRequestMessage(new HttpMethod(corsRequestContext.AccessControlRequestMethod), request.RequestUri);
                try
                {
                    foreach (var property in request.Properties)
                    {
                        // The RouteData and HttpContext from the preflight request properties contain information
                        // relevant to the preflight request and not the actual request, therefore we need to exclude them.
                        if (property.Key != HttpPropertyKeys.HttpRouteDataKey &&
                            property.Key != HttpContextBaseKey)
                        {
                            targetRequest.Properties.Add(property.Key, property.Value);
                        }
                    }
                    actionDescriptor = SelectAction(targetRequest);
                }
                catch
                {
                    if (DefaultPolicyProvider != null)
                    {
                        return DefaultPolicyProvider;
                    }
                    throw;
                }
                finally
                {
                    if (targetRequest != null)
                    {
                        request.RegisterForDispose(targetRequest);
                    }
                }
            }
            else
            {
                actionDescriptor = request.GetActionDescriptor();
            }

            return GetCorsPolicyProvider(actionDescriptor);
        }
        public void GetCorsPolicyProvider_Preflight_ReturnsExpectedPolicyProvider(string httpMethod, string path, Type expectedProviderType)
        {
            AttributeBasedPolicyProviderFactory providerFactory = new AttributeBasedPolicyProviderFactory();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/sample" + path);
            request.Headers.Add("Origin", "http://localhost");
            request.Headers.Add(CorsConstants.AccessControlRequestMethod, httpMethod);
            HttpConfiguration config = new HttpConfiguration();
            request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
            IHttpRoute route = config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
            request.Properties[HttpPropertyKeys.HttpRouteDataKey] = route.GetRouteData("/", request);

            ICorsPolicyProvider provider = providerFactory.GetCorsPolicyProvider(request);

            Assert.True(request.GetCorsRequestContext().IsPreflight);
            Assert.IsType(expectedProviderType, provider);
        }
        public async Task<CorsPolicy> GetCorsPolicyAsync( HttpRequestMessage request, CancellationToken cancellationToken )
        {
            var requestInfo = request.GetCorsRequestContext();
            var origin = requestInfo.Origin;

            // Check if request is from an authorized origin
            if ( await IsOriginValid(origin))
            {
                // Valid request
                var policy = new CorsPolicy { AllowAnyHeader = true, AllowAnyMethod = true };
                policy.Origins.Add( origin );
                return policy;
            }

            // Invalid Request
            return null;
        }
        public virtual ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
            HttpActionDescriptor actionDescriptor = null;
            if (corsRequestContext.IsPreflight)
            {
                HttpRequestMessage targetRequest = new HttpRequestMessage(new HttpMethod(corsRequestContext.AccessControlRequestMethod), request.RequestUri);
                try
                {
                    foreach (var property in request.Properties)
                    {
                        targetRequest.Properties.Add(property.Key, property.Value);
                    }
                    actionDescriptor = SelectAction(targetRequest);
                }
                catch
                {
                    if (DefaultPolicyProvider != null)
                    {
                        return DefaultPolicyProvider;
                    }
                    throw;
                }
                finally
                {
                    if (targetRequest != null)
                    {
                        request.RegisterForDispose(targetRequest);
                    }
                }
            }
            else
            {
                actionDescriptor = request.GetActionDescriptor();
            }

            return GetCorsPolicyProvider(actionDescriptor);
        }
        public void GetCorsPolicyProvider_Preflight_ReturnsDefaultPolicyProvider_WhenActionSelectionFails()
        {
            AttributeBasedPolicyProviderFactory providerFactory = new AttributeBasedPolicyProviderFactory();
            ICorsPolicyProvider mockProvider = new Mock<ICorsPolicyProvider>().Object;
            providerFactory.DefaultPolicyProvider = mockProvider;
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/sample");
            request.Headers.Add("Origin", "http://localhost");
            request.Headers.Add(CorsConstants.AccessControlRequestMethod, "RandomMethod");
            HttpConfiguration config = new HttpConfiguration();
            request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
            IHttpRoute route = config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
            request.Properties[HttpPropertyKeys.HttpRouteDataKey] = route.GetRouteData("/", request);

            ICorsPolicyProvider provider = providerFactory.GetCorsPolicyProvider(request);

            Assert.True(request.GetCorsRequestContext().IsPreflight);
            Assert.Same(mockProvider, provider);
        }
        public void GetCorsPolicyProvider_Preflight_ReturnsPolicyProviderUsingPerControllerConfiguration()
        {
            AttributeBasedPolicyProviderFactory providerFactory = new AttributeBasedPolicyProviderFactory();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/percontrollerconfig");
            request.Headers.Add("Origin", "http://localhost");
            request.Headers.Add(CorsConstants.AccessControlRequestMethod, "httpmethod");
            HttpConfiguration config = new HttpConfiguration();
            request.SetConfiguration(config);
            config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });

            ICorsPolicyProvider provider = providerFactory.GetCorsPolicyProvider(request);

            Assert.True(request.GetCorsRequestContext().IsPreflight);
            EnableCorsAttribute enableCorsAttribute = Assert.IsType<EnableCorsAttribute>(provider);
            Assert.Equal(1, enableCorsAttribute.Origins.Count());
            Assert.Equal("http://example.com", enableCorsAttribute.Origins.First());
        }
 public void GetCorsRequestContext_NotOrigin_ReturnsNull()
 {
     HttpRequestMessage request = new HttpRequestMessage();
     CorsRequestContext result = request.GetCorsRequestContext();
     Assert.Null(result);
 }
        public void GetCorsPolicyProvider_Preflight_Throws_WhenNoDefaultPolicyProviderAndActionSelectionFails()
        {
            AttributeBasedPolicyProviderFactory providerFactory = new AttributeBasedPolicyProviderFactory();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/sample");
            request.Headers.Add("Origin", "http://localhost");
            request.Headers.Add(CorsConstants.AccessControlRequestMethod, "RandomMethod");
            HttpConfiguration config = new HttpConfiguration();
            request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
            IHttpRoute route = config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
            request.Properties[HttpPropertyKeys.HttpRouteDataKey] = route.GetRouteData("/", request);

            Assert.True(request.GetCorsRequestContext().IsPreflight);
            Assert.Throws<HttpResponseException>(() =>
                providerFactory.GetCorsPolicyProvider(request));
        }
        public void GetCorsRequestContext_RetunsEmptyRequestHeaders()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://example.com/test");
            request.Headers.Add("Origin", "foo");

            CorsRequestContext result = request.GetCorsRequestContext();

            Assert.Empty(result.AccessControlRequestHeaders);
        }
        public void GetCorsRequestContext_RetunsRequestHeaders()
        {
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "http://example.com/test");
            request.Headers.Add("Origin", "foo");
            request.Headers.Add("Access-Control-Request-Headers", "foo, bar");

            CorsRequestContext result = request.GetCorsRequestContext();

            Assert.Equal(2, result.AccessControlRequestHeaders.Count);
            Assert.Contains("foo", result.AccessControlRequestHeaders);
            Assert.Contains("bar", result.AccessControlRequestHeaders);
        }
        public void GetCorsRequestContext_ReturnsHttpRequestInThePropertiesCollection()
        {
            // Arrange
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://example.com/test");
            request.Headers.Add("Origin", "foo");

            // Act 
            CorsRequestContext result = request.GetCorsRequestContext();

            // Assert
            object actualRequest;
            result.Properties.TryGetValue(typeof(HttpRequestMessage).FullName, out actualRequest);
            Assert.Equal(request, actualRequest);
        }
        public void GetCorsPolicyProvider_Preflight_DoesNotUseRouteDataOnTheRequest()
        {
            AttributeBasedPolicyProviderFactory providerFactory = new AttributeBasedPolicyProviderFactory();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Options, "http://localhost/sample");
            request.Headers.Add("Origin", "http://localhost");
            request.Headers.Add(CorsConstants.AccessControlRequestMethod, "Put");
            HttpConfiguration config = new HttpConfiguration();
            request.SetConfiguration(config);
            var route = config.Routes.MapHttpRoute("default", "{controller}/{id}", new { id = RouteParameter.Optional });
            request.SetRouteData(new HttpRouteData(route, new HttpRouteValueDictionary(new { action = "Options", controller = "sample", id = 2 })));

            ICorsPolicyProvider provider = providerFactory.GetCorsPolicyProvider(request);

            Assert.True(request.GetCorsRequestContext().IsPreflight);
            EnableCorsAttribute enableCorsAttribute = Assert.IsType<EnableCorsAttribute>(provider);
            Assert.Equal(2, enableCorsAttribute.Origins.Count());
            Assert.Equal("http://example.com", enableCorsAttribute.Origins[0]);
            Assert.Equal("http://localhost", enableCorsAttribute.Origins[1]);
        }