private async Task InvokeCore(HttpContext context) { var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName); if (corsPolicy == null) { Logger?.NoCorsPolicyFound(); await _next(context); return; } var corsResult = CorsService.EvaluatePolicy(context, corsPolicy); if (corsResult.IsPreflightRequest) { CorsService.ApplyResult(corsResult, context.Response); // Since there is a policy which was identified, // always respond to preflight requests. context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else { context.Response.OnStarting(OnResponseStartingDelegate, Tuple.Create(this, context, corsResult)); await _next(context); } }
public void EvaluatePolicy_PreflightRequest_HeadersRequested_NotAllHeaderMatches_ReturnsInvalidResult() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext( method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT", accessControlRequestHeaders: new[] { "match", "noMatch" }); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("*"); policy.Headers.Add("match"); policy.Headers.Add("foo"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Empty(result.AllowedHeaders); Assert.Empty(result.AllowedMethods); Assert.Empty(result.AllowedExposedHeaders); Assert.Null(result.AllowedOrigin); }
private Task EvaluateAndApplyPolicy(HttpContext context, CorsPolicy corsPolicy) { if (corsPolicy == null) { Logger.NoCorsPolicyFound(); return(_next(context)); } var corsResult = CorsService.EvaluatePolicy(context, corsPolicy); if (corsResult.IsPreflightRequest) { CorsService.ApplyResult(corsResult, context.Response); // Since there is a policy which was identified, // always respond to preflight requests. context.Response.StatusCode = StatusCodes.Status204NoContent; return(Task.CompletedTask); } else { context.Response.OnStarting(OnResponseStartingDelegate, Tuple.Create(this, context, corsResult)); return(_next(context)); } }
public void EvaluatePolicy_NoOrigin_ReturnsInvalidResult() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext("GET", origin: null); // Act var result = corsService.EvaluatePolicy(requestContext, new CorsPolicy()); // Assert Assert.Null(result.AllowedOrigin); Assert.False(result.VaryByOrigin); }
public void EvaluatePolicy_EmptyOriginsPolicy_ReturnsInvalidResult() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy(); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Null(result.AllowedOrigin); Assert.False(result.VaryByOrigin); }
public void EvaluatePolicy_NoExposedHeaders_NoAllowExposedHeaders() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Empty(result.AllowedExposedHeaders); }
public void EvaluatePolicy_PreflightRequest_MethodNotAllowed_ReturnsInvalidResult() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("GET"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Empty(result.AllowedMethods); }
public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader_PolicySucceeded() { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(origin: "http://allowed.example.com"); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); Assert.Equal("The request has an origin header: 'http://allowed.example.com'.", sink.Writes[0].State.ToString()); Assert.Equal("Policy execution successful.", sink.Writes[1].State.ToString()); }
public void EvaluatePolicy_MultiOriginsPolicy_ReturnsVaryByOriginHeader() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy(); policy.Origins.Add("http://example.com"); policy.Origins.Add("http://example-two.com"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.NotNull(result.AllowedOrigin); Assert.True(result.VaryByOrigin); }
public void EvaluatePolicy_OneExposedHeaders_HeadersAllowed() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.ExposedHeaders.Add("foo"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal(1, result.AllowedExposedHeaders.Count); Assert.Contains("foo", result.AllowedExposedHeaders); }
public void EvaluatePolicy_LoggingForPreflightRequests_DoesNotHaveOriginHeader() { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(method: "OPTIONS", origin: null, accessControlRequestMethod: "PUT"); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); policy.Methods.Add("PUT"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); Assert.Equal("The request is a preflight request.", sink.Writes[0].State.ToString()); Assert.Equal("The request does not have an origin header.", sink.Writes[1].State.ToString()); }
public void EvaluatePolicy_LoggingForNonPreflightRequests_DoesNotHaveOriginHeader() { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(origin: null); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); var logMessage = Assert.Single(sink.Writes); Assert.Equal("The request does not have an origin header.", logMessage.State.ToString()); }
public void EvaluatePolicy_SupportsCredentials_AllowCredentialsReturnsTrue() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy { SupportsCredentials = true }; policy.Origins.Add(CorsConstants.AnyOrigin); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.True(result.SupportsCredentials); }
public void EvaluatePolicy_PreflightRequest_ListedMethod_ReturnsSubsetOfListedMethods() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("PUT"); policy.Methods.Add("DELETE"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal(1, result.AllowedMethods.Count); Assert.Contains("PUT", result.AllowedMethods); }
public void EvaluatePolicy_PreflightRequest_SupportsCredentials_AllowCredentialsReturnsTrue() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy { SupportsCredentials = true }; policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("*"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.True(result.SupportsCredentials); }
public void EvaluatePolicy_DoesCaseSensitiveComparison() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var policy = new CorsPolicy(); policy.Methods.Add("POST"); var httpContext = GetHttpContext(origin: null, accessControlRequestMethod: "post"); // Act var result = corsService.EvaluatePolicy(httpContext, policy); // Assert Assert.Empty(result.AllowedHeaders); Assert.Empty(result.AllowedMethods); Assert.Empty(result.AllowedExposedHeaders); Assert.Null(result.AllowedOrigin); }
public void TryValidateOrigin_DoesCaseSensitiveComparison() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var policy = new CorsPolicy(); policy.Origins.Add("http://Example.com"); var httpContext = GetHttpContext(origin: "http://example.com"); // Act var result = corsService.EvaluatePolicy(httpContext, policy); // Assert Assert.Empty(result.AllowedHeaders); Assert.Empty(result.AllowedMethods); Assert.Empty(result.AllowedExposedHeaders); Assert.Null(result.AllowedOrigin); }
public void EvaluatePolicy_AllowAnyOrigin_DoesNotSupportCredentials_EmitsWildcardForOrigin() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy { SupportsCredentials = false }; policy.Origins.Add(CorsConstants.AnyOrigin); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal("*", result.AllowedOrigin); }
public void EvaluatePolicy_AllowAnyOrigin_SupportsCredentials_AddsSpecificOrigin() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy { SupportsCredentials = true }; policy.Origins.Add(CorsConstants.AnyOrigin); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal("http://example.com", result.AllowedOrigin); Assert.True(result.VaryByOrigin); }
public void EvaluatePolicy_PreflightRequest_PreflightMaxAge_PreflightMaxAgeSet() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy { PreflightMaxAge = TimeSpan.FromSeconds(10) }; policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("*"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal(TimeSpan.FromSeconds(10), result.PreflightMaxAge); }
public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader_PolicyFailed() { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(origin: "http://example.com"); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); var writeList = sink.Writes.ToList(); Assert.Equal("The request has an origin header: 'http://example.com'.", writeList[0].State.ToString()); Assert.Equal("CORS policy execution failed.", writeList[1].State.ToString()); Assert.Equal("Request origin http://example.com does not have permission to access the resource.", writeList[2].State.ToString()); }
public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader_PolicyFailed(LogData logData) { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(method: "OPTIONS", origin: logData.Origin, accessControlRequestMethod: logData.Method, accessControlRequestHeaders: logData.Headers); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); policy.Methods.Add("PUT"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); Assert.Equal("The request is a preflight request.", sink.Writes[0].State.ToString()); Assert.Equal(logData.OriginLogMessage, sink.Writes[1].State.ToString()); Assert.Equal(logData.PolicyLogMessage, sink.Writes[2].State.ToString()); Assert.Equal(logData.FailureReason, sink.Writes[3].State.ToString()); }
public void EvaluatePolicy_CaseInsensitivePreflightRequest_OriginAllowed_ReturnsOrigin(string preflightMethod) { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext( method: preflightMethod, origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Origins.Add("http://example.com"); policy.Methods.Add("*"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal("http://example.com", result.AllowedOrigin); }
public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader_PolicySucceeded() { var sink = new TestSink(); var loggerFactory = new TestLoggerFactory(sink, enabled: true); var corsService = new CorsService(new TestCorsOptions(), loggerFactory); var requestContext = GetHttpContext(method: "OPTIONS", origin: "http://allowed.example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy(); policy.Origins.Add("http://allowed.example.com"); policy.Methods.Add("PUT"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); var writeList = sink.Writes.ToList(); Assert.Equal("The request is a preflight request.", writeList[0].State.ToString()); Assert.Equal("The request has an origin header: 'http://allowed.example.com'.", writeList[1].State.ToString()); Assert.Equal("CORS policy execution successful.", writeList[2].State.ToString()); }
public void EvaluatePolicy_PreflightRequest_IsOriginAllowedReturnsTrue_ReturnsOrigin() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext( method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT"); var policy = new CorsPolicy { IsOriginAllowed = origin => true }; policy.Methods.Add("*"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal("http://example.com", result.AllowedOrigin); }
public void EvaluatePolicy_PreflightRequest_HeadersRequested_AllowAllHeaders_ReturnsRequestedHeaders() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext( method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT", accessControlRequestHeaders: new[] { "foo", "bar" }); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("*"); policy.Headers.Add("*"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal(2, result.AllowedHeaders.Count); Assert.Contains("foo", result.AllowedHeaders); Assert.Contains("bar", result.AllowedHeaders); }
public void EvaluatePolicy_PreflightRequest_HeadersRequested_AllowSomeHeaders_ReturnsSubsetOfListedHeaders() { // Arrange var corsService = new CorsService(new TestCorsOptions()); var requestContext = GetHttpContext( method: "OPTIONS", origin: "http://example.com", accessControlRequestMethod: "PUT", accessControlRequestHeaders: new[] { "content-type", "accept" }); var policy = new CorsPolicy(); policy.Origins.Add(CorsConstants.AnyOrigin); policy.Methods.Add("*"); policy.Headers.Add("foo"); policy.Headers.Add("bar"); policy.Headers.Add("Content-Type"); // Act var result = corsService.EvaluatePolicy(requestContext, policy); // Assert Assert.Equal(2, result.AllowedHeaders.Count); Assert.Contains("Content-Type", result.AllowedHeaders, StringComparer.OrdinalIgnoreCase); }
private async Task InvokeCore(HttpContext context, ICorsPolicyProvider corsPolicyProvider) { // CORS policy resolution rules: // // 1. If there is an endpoint with IDisableCorsAttribute then CORS is not run // 2. If there is an endpoint with ICorsPolicyMetadata then use its policy or if // there is an endpoint with IEnableCorsAttribute that has a policy name then // fetch policy by name, prioritizing it above policy on middleware // 3. If there is no policy on middleware then use name on middleware var endpoint = context.GetEndpoint(); // Get the most significant CORS metadata for the endpoint // For backwards compatibility reasons this is then downcast to Enable/Disable metadata var corsMetadata = endpoint?.Metadata.GetMetadata <ICorsMetadata>(); if (corsMetadata is IDisableCorsAttribute) { var isOptionsRequest = string.Equals( context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase); var isCorsPreflightRequest = isOptionsRequest && context.Request.Headers.ContainsKey(CorsConstants.AccessControlRequestMethod); if (isCorsPreflightRequest) { // If this is a preflight request, and we disallow CORS, complete the request context.Response.StatusCode = StatusCodes.Status204NoContent; return; } await _next(context); return; } var corsPolicy = _policy; var policyName = _corsPolicyName; if (corsMetadata is ICorsPolicyMetadata corsPolicyMetadata) { policyName = null; corsPolicy = corsPolicyMetadata.Policy; } else if (corsMetadata is IEnableCorsAttribute enableCorsAttribute && enableCorsAttribute.PolicyName != null) { // If a policy name has been provided on the endpoint metadata then prioritizing it above the static middleware policy policyName = enableCorsAttribute.PolicyName; corsPolicy = null; } if (corsPolicy == null) { // Resolve policy by name if the local policy is not being used corsPolicy = await corsPolicyProvider.GetPolicyAsync(context, policyName); } if (corsPolicy == null) { Logger?.NoCorsPolicyFound(); await _next(context); return; } var corsResult = CorsService.EvaluatePolicy(context, corsPolicy); if (corsResult.IsPreflightRequest) { CorsService.ApplyResult(corsResult, context.Response); // Since there is a policy which was identified, // always respond to preflight requests. context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else { context.Response.OnStarting(OnResponseStartingDelegate, Tuple.Create(this, context, corsResult)); await _next(context); } }
private async Task InvokeCore(HttpContext context, ICorsPolicyProvider corsPolicyProvider) { // CORS policy resolution rules: // // 1. If there is an endpoint with IDisableCorsAttribute then CORS is not run // 2. If there is an endpoint with ICorsPolicyMetadata then use its policy or if // there is an endpoint with IEnableCorsAttribute that has a policy name then // fetch policy by name, prioritizing it above policy on middleware // 3. If there is no policy on middleware then use name on middleware // Flag to indicate to other systems, e.g. MVC, that CORS middleware was run for this request context.Items[CorsMiddlewareInvokedKey] = CorsMiddlewareInvokedValue; var endpoint = context.GetEndpoint(); // Get the most significant CORS metadata for the endpoint // For backwards compatibility reasons this is then downcast to Enable/Disable metadata var corsMetadata = endpoint?.Metadata.GetMetadata <ICorsMetadata>(); if (corsMetadata is IDisableCorsAttribute) { await _next(context); return; } var corsPolicy = _policy; var policyName = _corsPolicyName; if (corsMetadata is ICorsPolicyMetadata corsPolicyMetadata) { policyName = null; corsPolicy = corsPolicyMetadata.Policy; } else if (corsMetadata is IEnableCorsAttribute enableCorsAttribute && enableCorsAttribute.PolicyName != null) { // If a policy name has been provided on the endpoint metadata then prioritizing it above the static middleware policy policyName = enableCorsAttribute.PolicyName; corsPolicy = null; } if (corsPolicy == null) { // Resolve policy by name if the local policy is not being used corsPolicy = await corsPolicyProvider.GetPolicyAsync(context, policyName); } if (corsPolicy == null) { Logger?.NoCorsPolicyFound(); await _next(context); return; } var corsResult = CorsService.EvaluatePolicy(context, corsPolicy); if (corsResult.IsPreflightRequest) { CorsService.ApplyResult(corsResult, context.Response); // Since there is a policy which was identified, // always respond to preflight requests. context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else { context.Response.OnStarting(OnResponseStartingDelegate, Tuple.Create(this, context, corsResult)); await _next(context); } }