public void SettingNegativePreflightMaxAge_Throws() { // Arrange var result = new CorsResult(); // Act var exception = Assert.Throws <ArgumentOutOfRangeException>(() => { result.PreflightMaxAge = TimeSpan.FromSeconds(-1); }); // Assert Assert.Equal( $"PreflightMaxAge must be greater than or equal to 0.{Environment.NewLine}Parameter name: value", exception.Message); }
public void ApplyResult_PreflightMaxAge_MaxAgeHeaderAdded() { // Arrange var result = new CorsResult { PreflightMaxAge = TimeSpan.FromSeconds(30) }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("30", httpContext.Response.Headers["Access-Control-Max-Age"]); }
public void ApplyResult_OneAllowHeaders_AllowHeadersHeaderAdded() { // Arrange var result = new CorsResult(); result.AllowedHeaders.Add("foo"); var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("foo", httpContext.Response.Headers["Access-Control-Allow-Headers"]); }
public void ApplyResult_NoPreflightMaxAge_MaxAgeHeaderNotAdded() { // Arrange var result = new CorsResult { PreflightMaxAge = null }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Max-Age", httpContext.Response.Headers.Keys); }
public void ApplyResult_AllowOrigin_AllowOriginHeaderAdded() { // Arrange var result = new CorsResult { AllowedOrigin = "http://example.com" }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("http://example.com", httpContext.Response.Headers["Access-Control-Allow-Origin"]); }
public void ApplyResult_NoAllowOrigin_AllowOriginHeaderNotAdded() { // Arrange var result = new CorsResult { AllowedOrigin = null }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Allow-Origin", httpContext.Response.Headers.Keys); }
public void ApplyResult_AddVaryHeader_VaryHeaderAdded() { // Arrange var result = new CorsResult { VaryByOrigin = true }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("Origin", httpContext.Response.Headers["Vary"]); }
public void ApplyResult_NoAllowCredentials_AllowCredentialsHeaderNotAdded() { // Arrange var result = new CorsResult { SupportsCredentials = false }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Allow-Credentials", httpContext.Response.Headers.Keys); }
public void ApplyResult_NoAllowExposedHeaders_ExposedHeadersHeaderNotAdded() { // Arrange var result = new CorsResult { // AllowExposedHeaders is empty by default }; var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Expose-Headers", httpContext.Response.Headers.Keys); }
/// <inheritdoc /> public CorsResult EvaluatePolicy(HttpContext context, CorsPolicy policy) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (policy == null) { throw new ArgumentNullException(nameof(policy)); } if (policy.AllowAnyOrigin && policy.SupportsCredentials) { throw new ArgumentException("The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the CORS policy by listing individual origins if credentials needs to be supported.", nameof(policy)); } var requestHeaders = context.Request.Headers; var origin = requestHeaders[CorsConstants.Origin]; var isOptionsRequest = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase); var isPreflightRequest = isOptionsRequest && requestHeaders.ContainsKey(CorsConstants.AccessControlRequestMethod); if (isOptionsRequest && !isPreflightRequest) { _logger.IsNotPreflightRequest(); } var corsResult = new CorsResult { IsPreflightRequest = isPreflightRequest, IsOriginAllowed = IsOriginAllowed(policy, origin), }; if (isPreflightRequest) { EvaluatePreflightRequest(context, policy, corsResult); } else { EvaluateRequest(context, policy, corsResult); } return(corsResult); }
/// <inheritdoc /> public CorsResult EvaluatePolicy(HttpContext context, CorsPolicy policy) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (policy == null) { throw new ArgumentNullException(nameof(policy)); } if (policy.AllowAnyOrigin && policy.SupportsCredentials) { throw new ArgumentException(Resources.InsecureConfiguration, nameof(policy)); } var origin = context.Request.Headers[CorsConstants.Origin]; var requestHeaders = context.Request.Headers; var isOptionsRequest = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase); var isPreflightRequest = isOptionsRequest && requestHeaders.ContainsKey(CorsConstants.AccessControlRequestMethod); if (isOptionsRequest && !isPreflightRequest) { _logger.IsNotPreflightRequest(); } var corsResult = new CorsResult { IsPreflightRequest = isPreflightRequest, IsOriginAllowed = IsOriginAllowed(policy, origin), }; if (isPreflightRequest) { EvaluatePreflightRequest(context, policy, corsResult); } else { EvaluateRequest(context, policy, corsResult); } return(corsResult); }
public void ApplyResult_OneAllowExposedHeaders_ExposedHeadersHeaderAdded() { // Arrange var result = new CorsResult { IsOriginAllowed = true, AllowedExposedHeaders = { "foo" }, }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("foo", httpContext.Response.Headers["Access-Control-Expose-Headers"]); }
public void ApplyResult_NoAllowHeaders_AllowHeadersHeaderNotAdded() { // Arrange var result = new CorsResult { // AllowHeaders is empty by default IsOriginAllowed = true, }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys); }
public void ApplyResult_SimpleAllowMethods_AllowMethodsHeaderNotAdded() { // Arrange var result = new CorsResult(); result.AllowedMethods.Add("GET"); result.AllowedMethods.Add("HEAD"); result.AllowedMethods.Add("POST"); var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Allow-Methods", httpContext.Response.Headers.Keys); }
public void ApplyResult_PreflightMaxAge_MaxAgeHeaderAdded() { // Arrange var result = new CorsResult { IsOriginAllowed = true, IsPreflightRequest = true, PreflightMaxAge = TimeSpan.FromSeconds(30), }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("30", httpContext.Response.Headers["Access-Control-Max-Age"]); }
public void ApplyResult_SimpleAllowHeaders_AllowHeadersHeaderNotAdded() { // Arrange var result = new CorsResult(); result.AllowedHeaders.Add("Accept"); result.AllowedHeaders.Add("Accept-Language"); result.AllowedHeaders.Add("Content-Language"); var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys); }
public void ApplyResult_AllowCredentials_AllowCredentialsHeaderAdded() { // Arrange var result = new CorsResult { SupportsCredentials = true }; var service = new CorsService(new TestCorsOptions()); // Act var httpContext = new DefaultHttpContext(); service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("true", httpContext.Response.Headers["Access-Control-Allow-Credentials"]); }
private void AddOriginToResult(string origin, CorsPolicy policy, CorsResult result) { if (policy.AllowAnyOrigin) { if (policy.SupportsCredentials) { result.AllowedOrigin = origin; result.VaryByOrigin = true; } else { result.AllowedOrigin = CorsConstants.AnyOrigin; } } else if (policy.Origins.Contains(origin)) { result.AllowedOrigin = origin; } }
public void ApplyResult_OneAllowMethods_AllowMethodsHeaderAdded() { // Arrange var result = new CorsResult { IsOriginAllowed = true, IsPreflightRequest = true, AllowedMethods = { "PUT" } }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("PUT", httpContext.Response.Headers["Access-Control-Allow-Methods"]); }
public void ApplyResult_PreflightRequest_ExposesHeadersNotAdded() { // Arrange var result = new CorsResult { IsOriginAllowed = true, IsPreflightRequest = true, AllowedExposedHeaders = { "foo", "bar" }, }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.DoesNotContain("Access-Control-Expose-Headers", httpContext.Response.Headers.Keys); }
public void ApplyResult_NoPreflightRequest_ExposesHeadersAdded() { // Arrange var result = new CorsResult { IsOriginAllowed = true, IsPreflightRequest = false, AllowedExposedHeaders = { "foo", "bar" }, }; var httpContext = new DefaultHttpContext(); var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("foo,bar", httpContext.Response.Headers[CorsConstants.AccessControlExposeHeaders]); }
public void ApplyResult_AppendsVaryHeader() { // Arrange var result = new CorsResult { IsOriginAllowed = true, VaryByOrigin = true }; var httpContext = new DefaultHttpContext(); httpContext.Response.Headers["Vary"] = "Cookie"; var service = GetCorsService(); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Equal("Cookie,Origin", httpContext.Response.Headers["Vary"]); }
public void ApplyResult_SomeSimpleAllowHeaders_AllowHeadersHeaderAddedForNonSimpleHeaders() { // Arrange var result = new CorsResult(); result.AllowedHeaders.Add("Content-Language"); result.AllowedHeaders.Add("foo"); result.AllowedHeaders.Add("bar"); result.AllowedHeaders.Add("Accept"); var httpContext = new DefaultHttpContext(); var service = new CorsService(new TestCorsOptions()); // Act service.ApplyResult(result, httpContext.Response); // Assert Assert.Contains("Access-Control-Allow-Headers", httpContext.Response.Headers.Keys); string[] headerValues = httpContext.Response.Headers.GetCommaSeparatedValues("Access-Control-Allow-Headers"); Assert.Equal(2, headerValues.Length); Assert.Contains("foo", headerValues); Assert.Contains("bar", headerValues); }
public void ToString_ReturnsThePropertyValues() { // Arrange var corsResult = new CorsResult { SupportsCredentials = true, PreflightMaxAge = TimeSpan.FromSeconds(30), AllowedOrigin = "*" }; corsResult.AllowedExposedHeaders.Add("foo"); corsResult.AllowedHeaders.Add("bar"); corsResult.AllowedHeaders.Add("baz"); corsResult.AllowedMethods.Add("GET"); // Act var result = corsResult.ToString(); // Assert Assert.Equal( @"AllowCredentials: True, PreflightMaxAge: 30, AllowOrigin: *," + " AllowExposedHeaders: {foo}, AllowHeaders: {bar,baz}, AllowMethods: {GET}", result); }
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result) { var origin = context.Request.Headers[CorsConstants.Origin]; if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin)) { return; } var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod]; if (StringValues.IsNullOrEmpty(accessControlRequestMethod)) { return; } var requestHeaders = context.Request.Headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders); if (!policy.AllowAnyMethod && !policy.Methods.Contains(accessControlRequestMethod)) { return; } if (!policy.AllowAnyHeader && requestHeaders != null && !requestHeaders.All(header => CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase) || policy.Headers.Contains(header, StringComparer.OrdinalIgnoreCase))) { return; } AddOriginToResult(origin, policy, result); result.SupportsCredentials = policy.SupportsCredentials; result.PreflightMaxAge = policy.PreflightMaxAge; result.AllowedMethods.Add(accessControlRequestMethod); AddHeaderValues(result.AllowedHeaders, requestHeaders); }
/// <inheritdoc /> public virtual void ApplyResult(CorsResult result, HttpResponse response) { if (result == null) { throw new ArgumentNullException(nameof(result)); } if (response == null) { throw new ArgumentNullException(nameof(response)); } var headers = response.Headers; if (result.AllowedOrigin != null) { headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin; } if (result.VaryByOrigin) { headers["Vary"] = "Origin"; } if (result.SupportsCredentials) { headers[CorsConstants.AccessControlAllowCredentials] = "true"; } if (result.AllowedMethods.Count > 0) { // Filter out simple methods var nonSimpleAllowMethods = result.AllowedMethods .Where(m => !CorsConstants.SimpleMethods.Contains(m, StringComparer.OrdinalIgnoreCase)) .ToArray(); if (nonSimpleAllowMethods.Length > 0) { headers.SetCommaSeparatedValues( CorsConstants.AccessControlAllowMethods, nonSimpleAllowMethods); } } if (result.AllowedHeaders.Count > 0) { // Filter out simple request headers var nonSimpleAllowRequestHeaders = result.AllowedHeaders .Where(header => !CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase)) .ToArray(); if (nonSimpleAllowRequestHeaders.Length > 0) { headers.SetCommaSeparatedValues( CorsConstants.AccessControlAllowHeaders, nonSimpleAllowRequestHeaders); } } if (result.AllowedExposedHeaders.Count > 0) { // Filter out simple response headers var nonSimpleAllowResponseHeaders = result.AllowedExposedHeaders .Where(header => !CorsConstants.SimpleResponseHeaders.Contains(header, StringComparer.OrdinalIgnoreCase)) .ToArray(); if (nonSimpleAllowResponseHeaders.Length > 0) { headers.SetCommaSeparatedValues( CorsConstants.AccessControlExposeHeaders, nonSimpleAllowResponseHeaders); } } if (result.PreflightMaxAge.HasValue) { headers[CorsConstants.AccessControlMaxAge] = result.PreflightMaxAge.Value.TotalSeconds.ToString(CultureInfo.InvariantCulture); } }
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result) { var origin = context.Request.Headers[CorsConstants.Origin]; if (!IsOriginAllowed(policy, origin)) { return; } var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod]; if (StringValues.IsNullOrEmpty(accessControlRequestMethod)) { return; } var requestHeaders = context.Request.Headers.GetCommaSeparatedValues(CorsConstants.AccessControlRequestHeaders); if (!policy.AllowAnyMethod) { var found = false; for (var i = 0; i < policy.Methods.Count; i++) { var method = policy.Methods[i]; if (string.Equals(method, accessControlRequestMethod, StringComparison.OrdinalIgnoreCase)) { found = true; break; } } if (!found) { _logger?.PolicyFailure(); _logger?.AccessControlMethodNotAllowed(accessControlRequestMethod); return; } } if (!policy.AllowAnyHeader && requestHeaders != null) { foreach (var requestHeader in requestHeaders) { if (!CorsConstants.SimpleRequestHeaders.Contains(requestHeader, StringComparer.OrdinalIgnoreCase) && !policy.Headers.Contains(requestHeader, StringComparer.OrdinalIgnoreCase)) { _logger?.PolicyFailure(); _logger?.RequestHeaderNotAllowed(requestHeader); return; } } } AddOriginToResult(origin, policy, result); result.SupportsCredentials = policy.SupportsCredentials; result.PreflightMaxAge = policy.PreflightMaxAge; result.AllowedMethods.Add(accessControlRequestMethod); AddHeaderValues(result.AllowedHeaders, requestHeaders); _logger?.PolicySuccess(); }
/// <inheritdoc /> public virtual void ApplyResult(CorsResult result, HttpResponse response) { if (result == null) { throw new ArgumentNullException(nameof(result)); } if (response == null) { throw new ArgumentNullException(nameof(response)); } if (!result.IsOriginAllowed) { // In case a server does not wish to participate in the CORS protocol, its HTTP response to the // CORS or CORS-preflight request must not include any of the above headers. return; } var headers = response.Headers; headers[CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin; if (result.SupportsCredentials) { headers[CorsConstants.AccessControlAllowCredentials] = "true"; } if (result.IsPreflightRequest) { _logger.IsPreflightRequest(); // An HTTP response to a CORS-preflight request can include the following headers: // `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, `Access-Control-Max-Age` if (result.AllowedHeaders.Count > 0) { headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowHeaders, result.AllowedHeaders.ToArray()); } if (result.AllowedMethods.Count > 0) { headers.SetCommaSeparatedValues(CorsConstants.AccessControlAllowMethods, result.AllowedMethods.ToArray()); } if (result.PreflightMaxAge.HasValue) { headers[CorsConstants.AccessControlMaxAge] = result.PreflightMaxAge.Value.TotalSeconds.ToString(CultureInfo.InvariantCulture); } } else { // An HTTP response to a CORS request that is not a CORS-preflight request can also include the following header: // `Access-Control-Expose-Headers` if (result.AllowedExposedHeaders.Count > 0) { headers.SetCommaSeparatedValues(CorsConstants.AccessControlExposeHeaders, result.AllowedExposedHeaders.ToArray()); } } if (result.VaryByOrigin) { headers.Append("Vary", "Origin"); } }
public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result) { PopulateResult(context, policy, result); }