New optional MvcOptions.SslPort. If not defined the redirection uses an empty port (default), otherwise the custom port is used.
This commit is contained in:
parent
5b805bb12d
commit
c259f82615
|
|
@ -127,5 +127,11 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// Gets a list of <see cref="IValueProviderFactory"/> used by this application.
|
/// Gets a list of <see cref="IValueProviderFactory"/> used by this application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<IValueProviderFactory> ValueProviderFactories { get; }
|
public IList<IValueProviderFactory> ValueProviderFactories { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SSL port that is used by this application when <see cref="RequireHttpsAttribute"/>
|
||||||
|
/// is used. If not set the port won't be specified in the secured URL e.g. https://localhost/path.
|
||||||
|
/// </summary>
|
||||||
|
public int? SslPort { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -35,10 +37,25 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var optionsAccessor = filterContext.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
|
||||||
|
|
||||||
var request = filterContext.HttpContext.Request;
|
var request = filterContext.HttpContext.Request;
|
||||||
|
|
||||||
|
var host = request.Host;
|
||||||
|
if (optionsAccessor.Value.SslPort.HasValue && optionsAccessor.Value.SslPort > 0)
|
||||||
|
{
|
||||||
|
// a specific SSL port is specified
|
||||||
|
host = new HostString(host.Host, optionsAccessor.Value.SslPort.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// clear the port
|
||||||
|
host = new HostString(host.Host);
|
||||||
|
}
|
||||||
|
|
||||||
var newUrl = string.Concat(
|
var newUrl = string.Concat(
|
||||||
"https://",
|
"https://",
|
||||||
request.Host.ToUriComponent(),
|
host.ToUriComponent(),
|
||||||
request.PathBase.ToUriComponent(),
|
request.PathBase.ToUriComponent(),
|
||||||
request.Path.ToUriComponent(),
|
request.Path.ToUriComponent(),
|
||||||
request.QueryString.ToUriComponent());
|
request.QueryString.ToUriComponent());
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Internal;
|
using Microsoft.AspNetCore.Http.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
|
|
@ -37,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
return new TheoryData<string, string, string, string, string>
|
return new TheoryData<string, string, string, string, string>
|
||||||
{
|
{
|
||||||
{ "localhost", null, null, null, "https://localhost" },
|
{ "localhost", null, null, null, "https://localhost" },
|
||||||
{ "localhost:5000", null, null, null, "https://localhost:5000" },
|
{ "localhost:5000", null, null, null, "https://localhost" },
|
||||||
{ "localhost", "/pathbase", null, null, "https://localhost/pathbase" },
|
{ "localhost", "/pathbase", null, null, "https://localhost/pathbase" },
|
||||||
{ "localhost", "/pathbase", "/path", null, "https://localhost/pathbase/path" },
|
{ "localhost", "/pathbase", "/path", null, "https://localhost/pathbase/path" },
|
||||||
{ "localhost", "/pathbase", "/path", "?foo=bar", "https://localhost/pathbase/path?foo=bar" },
|
{ "localhost", "/pathbase", "/path", "?foo=bar", "https://localhost/pathbase/path?foo=bar" },
|
||||||
|
|
@ -67,6 +70,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requestContext = new DefaultHttpContext();
|
var requestContext = new DefaultHttpContext();
|
||||||
|
requestContext.RequestServices = CreateServices();
|
||||||
requestContext.Request.Scheme = "http";
|
requestContext.Request.Scheme = "http";
|
||||||
requestContext.Request.Method = "GET";
|
requestContext.Request.Method = "GET";
|
||||||
requestContext.Request.Host = HostString.FromUriComponent(host);
|
requestContext.Request.Host = HostString.FromUriComponent(host);
|
||||||
|
|
@ -109,6 +113,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requestContext = new DefaultHttpContext();
|
var requestContext = new DefaultHttpContext();
|
||||||
|
requestContext.RequestServices = CreateServices();
|
||||||
requestContext.Request.Scheme = "http";
|
requestContext.Request.Scheme = "http";
|
||||||
requestContext.Request.Method = method;
|
requestContext.Request.Method = method;
|
||||||
var authContext = CreateAuthorizationContext(requestContext);
|
var authContext = CreateAuthorizationContext(requestContext);
|
||||||
|
|
@ -128,6 +133,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requestContext = new DefaultHttpContext();
|
var requestContext = new DefaultHttpContext();
|
||||||
|
requestContext.RequestServices = CreateServices();
|
||||||
requestContext.Request.Scheme = "http";
|
requestContext.Request.Scheme = "http";
|
||||||
|
|
||||||
var authContext = CreateAuthorizationContext(requestContext);
|
var authContext = CreateAuthorizationContext(requestContext);
|
||||||
|
|
@ -141,6 +147,51 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode);
|
Assert.Equal(StatusCodes.Status404NotFound, result.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("http://localhost", null, "https://localhost/")]
|
||||||
|
[InlineData("http://localhost:5000", null, "https://localhost/")]
|
||||||
|
[InlineData("http://[2001:db8:a0b:12f0::1]", null, "https://[2001:db8:a0b:12f0::1]/")]
|
||||||
|
[InlineData("http://[2001:db8:a0b:12f0::1]:5000", null, "https://[2001:db8:a0b:12f0::1]/")]
|
||||||
|
[InlineData("http://localhost:5000/path", null, "https://localhost/path")]
|
||||||
|
[InlineData("http://localhost:5000/path?foo=bar", null, "https://localhost/path?foo=bar")]
|
||||||
|
[InlineData("http://本地主機:5000", null, "https://xn--tiq21tzznx7c/")]
|
||||||
|
[InlineData("http://localhost", 44380, "https://localhost:44380/")]
|
||||||
|
[InlineData("http://localhost:5000", 44380, "https://localhost:44380/")]
|
||||||
|
[InlineData("http://[2001:db8:a0b:12f0::1]", 44380, "https://[2001:db8:a0b:12f0::1]:44380/")]
|
||||||
|
[InlineData("http://[2001:db8:a0b:12f0::1]:5000", 44380, "https://[2001:db8:a0b:12f0::1]:44380/")]
|
||||||
|
[InlineData("http://localhost:5000/path", 44380, "https://localhost:44380/path")]
|
||||||
|
[InlineData("http://localhost:5000/path?foo=bar", 44380, "https://localhost:44380/path?foo=bar")]
|
||||||
|
[InlineData("http://本地主機:5000", 44380, "https://xn--tiq21tzznx7c:44380/")]
|
||||||
|
public void OnAuthorization_RedirectsToHttpsEndpoint_ForCustomSslPort(
|
||||||
|
string url,
|
||||||
|
int? sslPort,
|
||||||
|
string expectedUrl)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var options = new TestOptionsManager<MvcOptions>();
|
||||||
|
var uri = new Uri(url);
|
||||||
|
|
||||||
|
var requestContext = new DefaultHttpContext();
|
||||||
|
requestContext.RequestServices = CreateServices(sslPort);
|
||||||
|
requestContext.Request.Scheme = "http";
|
||||||
|
requestContext.Request.Method = "GET";
|
||||||
|
requestContext.Request.Host = HostString.FromUriComponent(uri);
|
||||||
|
requestContext.Request.Path = PathString.FromUriComponent(uri);
|
||||||
|
requestContext.Request.QueryString = QueryString.FromUriComponent(uri);
|
||||||
|
|
||||||
|
var authContext = CreateAuthorizationContext(requestContext);
|
||||||
|
var attr = new RequireHttpsAttribute();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
attr.OnAuthorization(authContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(authContext.Result);
|
||||||
|
var result = Assert.IsType<RedirectResult>(authContext.Result);
|
||||||
|
|
||||||
|
Assert.Equal(expectedUrl, result.Url);
|
||||||
|
}
|
||||||
|
|
||||||
private class CustomRequireHttpsAttribute : RequireHttpsAttribute
|
private class CustomRequireHttpsAttribute : RequireHttpsAttribute
|
||||||
{
|
{
|
||||||
protected override void HandleNonHttpsRequest(AuthorizationFilterContext filterContext)
|
protected override void HandleNonHttpsRequest(AuthorizationFilterContext filterContext)
|
||||||
|
|
@ -154,5 +205,16 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
var actionContext = new ActionContext(ctx, new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(ctx, new RouteData(), new ActionDescriptor());
|
||||||
return new AuthorizationFilterContext(actionContext, new IFilterMetadata[0]);
|
return new AuthorizationFilterContext(actionContext, new IFilterMetadata[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IServiceProvider CreateServices(int? sslPort = null)
|
||||||
|
{
|
||||||
|
var options = new TestOptionsManager<MvcOptions>();
|
||||||
|
options.Value.SslPort = sslPort;
|
||||||
|
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddSingleton<IOptions<MvcOptions>>(options);
|
||||||
|
|
||||||
|
return services.BuildServiceProvider();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue