PR comments incorporated

This commit is contained in:
Jass Bagga 2016-11-17 17:36:18 -08:00
parent 517dc3c860
commit 5dcf47ef12
20 changed files with 199 additions and 166 deletions

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace SampleDestination
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(policy => policy.WithOrigins("http://origin.sample.com:8080").WithMethods("GET"));
app.UseMiddleware<StatusMiddleware>();
}
}
}

View File

@ -1,35 +0,0 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SampleDestination
{
public class StatusMiddleware
{
/// <summary>
/// Instantiates a new <see cref="StatusMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the pipeline.</param>
public StatusMiddleware(RequestDelegate next)
{
}
/// <summary>
/// Writes the status of the request sent in response. Does not invoke later middleware in the pipeline.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> of the current request.</param>
/// <returns>A <see cref="Task"/> that completes when writing to the response is done.</returns>
public Task Invoke(HttpContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return context.Response.WriteAsync(context.Response.StatusCode.ToString());
}
}
}

View File

@ -1,3 +0,0 @@
{
"server.urls": "http://destination.sample.com:80"
}

View File

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.IO;
namespace SampleOrigin
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
}
}
}

View File

@ -1,3 +0,0 @@
{
"server.urls": "http://origin.sample.com:8080"
}

28
samples/README.md Normal file
View File

@ -0,0 +1,28 @@
CORS Sample
===
This sample consists of a request origin (SampleOrigin) and a request destination (SampleDestination).
Both have different domain names, to simulate a CORS request.
Modify Hosts File
Windows:
Run a text editor (e.g. Notepad) as an Administrator. Open the hosts file on the path: "C:\Windows\System32\drivers\etc\hosts".
Linux:
On a Terminal window, type "sudo nano /etc/hosts" and enter your admin password when prompted.
In the hosts file, add the following to the bottom of the file:
127.0.0.1 destination.example.com
127.0.0.1 origin.example.com
Save the file and close it. Then clear your browser history.
Run the sample
*In a command prompt window, open the directory where you cloned the repository, and open the SampleDestination directory. Run the command: dotnet run
*Repeat the above step in the SampleOrigin directory.
*Open a browser window and go to http://origin.example.com
*Click the button to see CORS in action.
If using Visual Studio to launch the request origin:
Open Visual Studio and in the launchSettings.json file for the SampleOrigin project, change the launchUrl under SampleOrigin to
http://origin.example.com:8080. Using the dropdown near the Start button, choose SampleOrigin before pressing Start to ensure that it uses Kestrel
and not IIS Express.

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
namespace SampleDestination
{
@ -12,14 +10,9 @@ namespace SampleDestination
{
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseUrls("http://*:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace SampleDestination
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.UseCors(policy => policy.WithOrigins("http://origin.example.com:8080"));
app.Run(async context =>
{
await context.Response.WriteAsync("Status code of your request: " + context.Response.StatusCode.ToString());
});
}
}
}

View File

@ -4,13 +4,10 @@
"version": "1.1.0-*",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.2.0-*",
"Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*",
"Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*",
"Microsoft.Extensions.Logging.Console": "1.2.0-*",
"Microsoft.AspNetCore.StaticFiles": "1.2.0-*",
"Microsoft.Extensions.Configuration.FileExtensions": "1.2.0-*",
"Microsoft.Extensions.Configuration.Json": "1.2.0-*"
"Microsoft.AspNetCore.Cors": "1.2.0-*"
},
"tools": {

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
namespace SampleOrigin
{
@ -12,14 +10,9 @@ namespace SampleOrigin
{
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseUrls("http://*:8080")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()

View File

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace SampleOrigin
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.Run( context =>
{
var fileInfoProvider = env.WebRootFileProvider;
var fileInfo = fileInfoProvider.GetFileInfo("/Index.html");
context.Response.Headers.Add("Content-Type", "text/html; charset=utf-8");
return context.Response.SendFileAsync(fileInfo);
});
app.Run(async context =>
{
await context.Response.WriteAsync("Status code of your request: " + context.Response.StatusCode.ToString());
});
}
}
}

View File

@ -4,13 +4,9 @@
"version": "1.1.0-*",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.2.0-*",
"Microsoft.AspNetCore.Server.IISIntegration": "1.2.0-*",
"Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*",
"Microsoft.Extensions.Logging.Console": "1.2.0-*",
"Microsoft.AspNetCore.Cors": "1.2.0-*",
"Microsoft.Extensions.Configuration.FileExtensions": "1.2.0-*",
"Microsoft.Extensions.Configuration.Json": "1.2.0-preview1-*"
"Microsoft.Extensions.Logging.Console": "1.2.0-*"
},
"tools": {

View File

@ -14,7 +14,7 @@
function makeCORSRequest(method) {
// Destination server with CORS enabled.
var url = 'http://destination.sample.com/api';
var url = 'http://destination.example.com:5000/api';
var request = createCORSRequest(method , url);
if (!request) {

View File

@ -99,13 +99,14 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
var origin = context.Request.Headers[CorsConstants.Origin];
if (StringValues.IsNullOrEmpty(origin))
{
_logger?.RequestDoesNotHaveOriginHeader();
return;
}
if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
{
_logger?.RequestHasOriginHeader();
_logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
_logger?.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
return;
}
@ -121,13 +122,14 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
var origin = context.Request.Headers[CorsConstants.Origin];
if (StringValues.IsNullOrEmpty(origin))
{
_logger?.RequestDoesNotHaveOriginHeader();
return;
}
if (!policy.AllowAnyOrigin && !policy.Origins.Contains(origin))
{
_logger?.RequestHasOriginHeader();
_logger.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
_logger?.PolicyFailure($"Request origin {origin} does not have permission to access the resource.");
return;
}

View File

@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Cors.Internal
{
private static readonly Action<ILogger, Exception> _isPreflightRequest;
private static readonly Action<ILogger, Exception> _requestHasOriginHeader;
private static readonly Action<ILogger, Exception> _requestDoesNotHaveOriginHeader;
private static readonly Action<ILogger, Exception> _policySuccess;
private static readonly Action<ILogger, string, Exception> _policyFailure;
@ -18,21 +19,26 @@ namespace Microsoft.AspNetCore.Cors.Internal
_isPreflightRequest = LoggerMessage.Define(
LogLevel.Debug,
1,
"The request is preflight.");
"This is a preflight request.");
_requestHasOriginHeader = LoggerMessage.Define(
LogLevel.Debug,
2,
"The request has an origin header.");
_requestDoesNotHaveOriginHeader = LoggerMessage.Define(
LogLevel.Debug,
3,
"The request does not have an origin header.");
_policySuccess = LoggerMessage.Define(
LogLevel.Information,
3,
4,
"Policy execution successful.");
_policyFailure = LoggerMessage.Define<string>(
LogLevel.Information,
3,
5,
"Policy execution failed. {FailureReason}");
}
@ -46,6 +52,11 @@ namespace Microsoft.AspNetCore.Cors.Internal
_requestHasOriginHeader(logger, null);
}
public static void RequestDoesNotHaveOriginHeader(this ILogger logger)
{
_requestDoesNotHaveOriginHeader(logger, null);
}
public static void PolicySuccess(this ILogger logger)
{
_policySuccess(logger, null);

View File

@ -228,34 +228,38 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
Assert.Contains("PUT", result.AllowedMethods);
}
public static TheoryData<string, string, string[], string> LoggingData
public static TheoryData<string, string, string[], string, string> PreflightRequests_LoggingData
{
get
{
return new TheoryData<string, string, string[], string>
return new TheoryData<string, string, string[], string, string>
{
{
"http://example.com",
"PUT",
null,
"The request has an origin header.",
"Policy execution failed. Request origin http://example.com does not have permission to access the resource."
},
{
"http://allowedexample.com",
"http://allowed.example.com",
"DELETE",
null,
"The request has an origin header.",
"Policy execution failed. Request method DELETE not allowed in CORS policy."
},
{
"http://allowedexample.com",
"http://allowed.example.com",
"PUT",
new[] { "test" },
"The request has an origin header.",
"Policy execution failed. One or more request header(s) not allowed in CORS policy."
},
{
"http://allowedexample.com",
"http://allowed.example.com",
"PUT",
null,
"The request has an origin header.",
"Policy execution successful."
},
};
@ -263,8 +267,8 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
}
[Theory]
[MemberData(nameof(LoggingData))]
public void EvaluatePolicy_LoggingForPreflightRequests(string origin, string method, string[] headers, string logMessage)
[MemberData(nameof(PreflightRequests_LoggingData))]
public void EvaluatePolicy_LoggingForPreflightRequests_HasOriginHeader(string origin, string method, string[] headers, string originLogMessage, string policyLogMessage)
{
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
@ -272,21 +276,59 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
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.Origins.Add("http://allowed.example.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());
Assert.Equal("This is a preflight request.", sink.Writes[0].State.ToString());
Assert.Equal(originLogMessage, sink.Writes[1].State.ToString());
Assert.Equal(policyLogMessage, sink.Writes[2].State.ToString());
}
[Fact]
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("This 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 static TheoryData<string, string, string> NonPreflightRequests_LoggingData
{
get
{
return new TheoryData<string, string, string>
{
{
"http://example.com",
"The request has an origin header.",
"Policy execution failed. Request origin http://example.com does not have permission to access the resource."
},
{
"http://allowed.example.com",
"The request has an origin header.",
"Policy execution successful."
}
};
}
}
[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)
[MemberData(nameof(NonPreflightRequests_LoggingData))]
public void EvaluatePolicy_LoggingForNonPreflightRequests_HasOriginHeader(string origin, string originlogMessage, string policyLogMessage)
{
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
@ -294,13 +336,31 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure
var corsService = new CorsService(new TestCorsOptions(), loggerFactory);
var requestContext = GetHttpContext(origin: origin);
var policy = new CorsPolicy();
policy.Origins.Add("http://allowedexample.com");
policy.Origins.Add("http://allowed.example.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());
Assert.Equal(originlogMessage, sink.Writes[0].State.ToString());
Assert.Equal(policyLogMessage, sink.Writes[1].State.ToString());
}
[Fact]
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());
}
[Theory]