diff --git a/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs b/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs
index b52e000fa8..72e17d5365 100644
--- a/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs
+++ b/src/Microsoft.AspNetCore.Cors/Infrastructure/CorsService.cs
@@ -97,26 +97,40 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result)
{
var origin = context.Request.Headers[CorsConstants.Origin];
- if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
+ if (StringValues.IsNullOrEmpty(origin))
{
return;
}
+ if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
+ {
+ _logger?.RequestHasOriginHeader();
+ _logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
+ return;
+ }
+
_logger?.RequestHasOriginHeader();
AddOriginToResult(origin, policy, result);
result.SupportsCredentials = policy.SupportsCredentials;
- _logger?.PolicySuccess();
AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
+ _logger?.PolicySuccess();
}
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))
+ if (StringValues.IsNullOrEmpty(origin))
{
return;
}
+ if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
+ {
+ _logger?.RequestHasOriginHeader();
+ _logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
+ return;
+ }
+
_logger?.RequestHasOriginHeader();
var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod];
if (StringValues.IsNullOrEmpty(accessControlRequestMethod))
@@ -160,8 +174,8 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
result.SupportsCredentials = policy.SupportsCredentials;
result.PreflightMaxAge = policy.PreflightMaxAge;
result.AllowedMethods.Add(accessControlRequestMethod);
+ AddHeaderValues(result.AllowedHeaders, requestHeaders);
_logger?.PolicySuccess();
- AddHeaderValues(result.AllowedHeaders, requestHeaders);
}
///
diff --git a/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs b/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs
index b3a92a8d68..617155ea43 100644
--- a/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs
+++ b/test/Microsoft.AspNetCore.Cors.Test/CorsServiceTests.cs
@@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore.Http;
using Xunit;
+using Microsoft.Extensions.Logging.Testing;
namespace Microsoft.AspNetCore.Cors.Infrastructure
{
@@ -227,6 +228,81 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
Assert.Contains("PUT", result.AllowedMethods);
}
+ public static TheoryData LoggingData
+ {
+ get
+ {
+ return new TheoryData
+ {
+ {
+ "http://example.com",
+ "PUT",
+ null,
+ "Policy execution failed. Request origin http://example.com does not have permission to access the resource."
+ },
+ {
+ "http://allowedexample.com",
+ "DELETE",
+ null,
+ "Policy execution failed. Request method DELETE not allowed in CORS policy."
+ },
+ {
+ "http://allowedexample.com",
+ "PUT",
+ new[] { "test" },
+ "Policy execution failed. One or more request header(s) not allowed in CORS policy."
+ },
+ {
+ "http://allowedexample.com",
+ "PUT",
+ null,
+ "Policy execution successful."
+ },
+ };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(LoggingData))]
+ public void EvaluatePolicy_LoggingForPreflightRequests(string origin, string method, string[] headers, string logMessage)
+ {
+ var sink = new TestSink();
+ var loggerFactory = new TestLoggerFactory(sink, enabled: true);
+
+ var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
+ var requestContext = GetHttpContext(method: "OPTIONS", origin: origin, accessControlRequestMethod: method, accessControlRequestHeaders: headers);
+ var policy = new CorsPolicy();
+ policy.Origins.Add("http://allowedexample.com");
+ policy.Methods.Add("PUT");
+
+ // Act
+ var result = corsService.EvaluatePolicy(requestContext, policy);
+
+ Assert.Equal("The request is preflight.", sink.Writes[0].State.ToString());
+ Assert.Equal("The request has an origin header.", sink.Writes[1].State.ToString());
+ Assert.Equal(logMessage, sink.Writes[2].State.ToString());
+ }
+
+ [Theory]
+ [InlineData("http://allowedexample.com", "Policy execution successful.")]
+ [InlineData("http://example.com", "Policy execution failed. Request origin http://example.com does not have permission to access the resource.")]
+ public void EvaluatePolicy_LoggingForRequests(string origin, string logMessage)
+ {
+ var sink = new TestSink();
+ var loggerFactory = new TestLoggerFactory(sink, enabled: true);
+
+ var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
+ var requestContext = GetHttpContext(origin: origin);
+ var policy = new CorsPolicy();
+ policy.Origins.Add("http://allowedexample.com");
+
+ // Act
+ var result = corsService.EvaluatePolicy(requestContext, policy);
+
+ Assert.Equal("The request has an origin header.", sink.Writes[0].State.ToString());
+ Assert.Equal(logMessage, sink.Writes[1].State.ToString());
+ }
+
[Theory]
[InlineData("OpTions")]
[InlineData("OPTIONS")]