diff --git a/samples/IISSample/Properties/launchSettings.json b/samples/IISSample/Properties/launchSettings.json new file mode 100644 index 0000000000..081be10c09 --- /dev/null +++ b/samples/IISSample/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:25334/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + }, + "weblistener": { + "commandName": "weblistener", + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + }, + "web": { + "commandName": "web", + "environmentVariables": { + "ASPNET_ENVIRONMENT": "Development" + } + } + } + } \ No newline at end of file diff --git a/samples/IISSample/project.json b/samples/IISSample/project.json index 0a6ff38be0..d5cc2e3da9 100644 --- a/samples/IISSample/project.json +++ b/samples/IISSample/project.json @@ -1,24 +1,19 @@ { - "webroot": "wwwroot", "version": "1.0.0-*", - "dependencies": { "Microsoft.AspNet.IISPlatformHandler": "1.0.0-*", "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*" }, - "commands": { - "weblistener": "Microsoft.AspNet.Server.WebListener", - "web": "Microsoft.AspNet.Server.Kestrel" + "web": "Microsoft.AspNet.Server.Kestrel", + "weblistener": "Microsoft.AspNet.Server.WebListener" }, - "frameworks": { "dnx451": { }, "dnxcore50": { } }, - "publishExclude": [ "node_modules", "bower_components", diff --git a/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddleware.cs b/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddleware.cs index 5a5a3b565e..19b530983d 100644 --- a/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddleware.cs +++ b/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddleware.cs @@ -3,29 +3,20 @@ using System; using System.Globalization; -using System.Linq; -using System.Net; using System.Security.Principal; using System.Threading.Tasks; -using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.AspNet.Http.Features.Authentication.Internal; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Primitives; -using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.IISPlatformHandler { public class IISPlatformHandlerMiddleware { - private const string XForwardedForHeaderName = "X-Forwarded-For"; - private const string XForwardedProtoHeaderName = "X-Forwarded-Proto"; private const string XIISWindowsAuthToken = "X-IIS-WindowsAuthToken"; - private const string XOriginalPortName = "X-Original-Port"; - private const string XOriginalProtoName = "X-Original-Proto"; - private const string XOriginalIPName = "X-Original-IP"; private readonly RequestDelegate _next; private readonly IISPlatformHandlerOptions _options; @@ -46,9 +37,6 @@ namespace Microsoft.AspNet.IISPlatformHandler public async Task Invoke(HttpContext httpContext) { - UpdateScheme(httpContext); - - UpdateRemoteIp(httpContext); if (_options.FlowWindowsAuthentication) { var winPrincipal = UpdateUser(httpContext); @@ -69,47 +57,6 @@ namespace Microsoft.AspNet.IISPlatformHandler } } - private static void UpdateScheme(HttpContext httpContext) - { - var xForwardProtoHeaderValue = httpContext.Request.Headers[XForwardedProtoHeaderName]; - if (!string.IsNullOrEmpty(xForwardProtoHeaderValue)) - { - if (!string.IsNullOrEmpty(httpContext.Request.Scheme)) - { - httpContext.Request.Headers[XOriginalProtoName] = httpContext.Request.Scheme; - } - httpContext.Request.Scheme = xForwardProtoHeaderValue; - } - } - - private static void UpdateRemoteIp(HttpContext httpContext) - { - var xForwardedForHeaderValue = httpContext.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); - if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0) - { - IPAddress ipFromHeader; - int? port; - if (IPAddressWithPortParser.TryParse(xForwardedForHeaderValue[0], out ipFromHeader, out port)) - { - var connection = httpContext.Connection; - var remoteIPString = connection.RemoteIpAddress?.ToString(); - if (!string.IsNullOrEmpty(remoteIPString)) - { - httpContext.Request.Headers[XOriginalIPName] = remoteIPString; - } - if (port.HasValue) - { - if (connection.RemotePort != 0) - { - httpContext.Request.Headers[XOriginalPortName] = connection.RemotePort.ToString(CultureInfo.InvariantCulture); - } - connection.RemotePort = port.Value; - } - connection.RemoteIpAddress = ipFromHeader; - } - } - } - private WindowsPrincipal UpdateUser(HttpContext httpContext) { var xIISWindowsAuthToken = httpContext.Request.Headers[XIISWindowsAuthToken]; diff --git a/src/Microsoft.AspNet.IISPlatformHandler/IPAddressWithPortParser.cs b/src/Microsoft.AspNet.IISPlatformHandler/IPAddressWithPortParser.cs deleted file mode 100644 index 0c1ceeb400..0000000000 --- a/src/Microsoft.AspNet.IISPlatformHandler/IPAddressWithPortParser.cs +++ /dev/null @@ -1,73 +0,0 @@ -// 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.Net; - -namespace Microsoft.AspNet.IISPlatformHandler -{ - public static class IPAddressWithPortParser - { - public static bool TryParse(string addressWithPort, out IPAddress address, out int? port) - { - port = null; - - string addressPart = null; - string portPart = null; - - var lastColonIndex = addressWithPort.LastIndexOf(':'); - if (lastColonIndex > 0) - { - // IPv4 with port or IPv6 - var closingIndex = addressWithPort.LastIndexOf(']'); - if (closingIndex > 0) - { - // IPv6 with brackets - addressPart = addressWithPort.Substring(1, closingIndex - 1); - if (closingIndex < lastColonIndex) - { - // IPv6 with port [::1]:80 - portPart = addressWithPort.Substring(lastColonIndex + 1); - } - } - else - { - // IPv6 without port or IPv4 - var firstColonIndex = addressWithPort.IndexOf(':'); - if (firstColonIndex != lastColonIndex) - { - // IPv6 ::1 - addressPart = addressWithPort; - } - else - { - // IPv4 with port 127.0.0.1:123 - addressPart = addressWithPort.Substring(0, firstColonIndex); - portPart = addressWithPort.Substring(firstColonIndex + 1); - } - } - } - else - { - // IPv4 without port - addressPart = addressWithPort; - } - - var success = IPAddress.TryParse(addressPart, out address); - if (success && portPart != null) - { - int portValue; - success &= int.TryParse(portPart, out portValue); - if (success) - { - port = portValue; - } - else - { - // we cannot parse port, reset address - address = null; - } - } - return success; - } - } -} diff --git a/test/Microsoft.AspNet.IISPlatformHandler.FunctionalTests/HttpsTest.cs b/test/Microsoft.AspNet.IISPlatformHandler.FunctionalTests/HttpsTest.cs index bc40025641..6d2d7e0895 100644 --- a/test/Microsoft.AspNet.IISPlatformHandler.FunctionalTests/HttpsTest.cs +++ b/test/Microsoft.AspNet.IISPlatformHandler.FunctionalTests/HttpsTest.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNet.IISPlatformHandler.FunctionalTests var responseText = await response.Content.ReadAsStringAsync(); try { - Assert.Equal("https Hello World", responseText); + Assert.Equal("Scheme:http; Forwarded:https", responseText); } catch (XunitException) { @@ -138,11 +138,11 @@ namespace Microsoft.AspNet.IISPlatformHandler.FunctionalTests { if (sendClientCert) { - Assert.Equal("https Hello World, has cert? True", responseText); + Assert.Equal("Scheme:http; Forwarded:https; has cert? True", responseText); } else { - Assert.Equal("https Hello World, has cert? False", responseText); + Assert.Equal("Scheme:http; Forwarded:https; has cert? False", responseText); } } catch (XunitException) diff --git a/test/Microsoft.AspNet.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs b/test/Microsoft.AspNet.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs index f43d7e6482..c63f66552a 100644 --- a/test/Microsoft.AspNet.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs +++ b/test/Microsoft.AspNet.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs @@ -1,13 +1,10 @@ // 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.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http.Features.Authentication; -using Microsoft.AspNet.Http.Internal; -using Microsoft.AspNet.IISPlatformHandler; using Microsoft.AspNet.TestHost; using Xunit; @@ -15,103 +12,6 @@ namespace Microsoft.AspNet.IISPlatformHandler { public class HttpPlatformHandlerMiddlewareTests { - [Fact] - public async Task XForwardedForOverrideChangesRemoteIpAndPort() - { - var assertsExecuted = false; - - var server = TestServer.Create(app => - { - app.UseIISPlatformHandler(); - app.Run(context => - { - Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString()); - Assert.Equal(123, context.Connection.RemotePort); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11:123"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedForStoresOriginalIpAndPort() - { - var assertsExecuted = false; - - var server = TestServer.Create(app => - { - app.Use((context, next) => - { - context.Connection.RemoteIpAddress = IPAddress.Loopback; - context.Connection.RemotePort = 1; - return next(); - }); - app.UseIISPlatformHandler(); - app.Run(context => - { - Assert.Equal("127.0.0.1", context.Request.Headers["X-Original-IP"]); - Assert.Equal("1", context.Request.Headers["X-Original-Port"]); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "11.111.111.11:123"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedForOverrideBadIpDoesntChangeRemoteIp() - { - var assertsExecuted = false; - - var server = TestServer.Create(app => - { - app.UseIISPlatformHandler(); - app.Run(context => - { - Assert.Null(context.Connection.RemoteIpAddress); - Assert.Equal(0, context.Connection.RemotePort); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-For", "BAD-IP"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - - [Fact] - public async Task XForwardedProtoOverrideChangesRequestProtocol() - { - var assertsExecuted = false; - - var server = TestServer.Create(app => - { - app.UseIISPlatformHandler(); - app.Run(context => - { - Assert.Equal("TestProtocol", context.Request.Scheme); - assertsExecuted = true; - return Task.FromResult(0); - }); - }); - - var req = new HttpRequestMessage(HttpMethod.Get, ""); - req.Headers.Add("X-Forwarded-Proto", "TestProtocol"); - await server.CreateClient().SendAsync(req); - Assert.True(assertsExecuted); - } - [Fact] public async Task AddsAuthenticationHandlerByDefault() { diff --git a/test/Microsoft.AspNet.IISPlatformHandler.Tests/IPAddressWithPortParserTests.cs b/test/Microsoft.AspNet.IISPlatformHandler.Tests/IPAddressWithPortParserTests.cs deleted file mode 100644 index 83ca511911..0000000000 --- a/test/Microsoft.AspNet.IISPlatformHandler.Tests/IPAddressWithPortParserTests.cs +++ /dev/null @@ -1,49 +0,0 @@ -// 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.Net; -using Microsoft.AspNet.IISPlatformHandler; -using Xunit; - -namespace Microsoft.AspNet.PipelineHandler.Tests -{ - public class IPAddressWithPortParserTests - { - [Theory] - [InlineData("127.0.0.1", "127.0.0.1", null)] - [InlineData("127.0.0.1:1", "127.0.0.1", 1)] - [InlineData("1", "0.0.0.1", null)] - [InlineData("1:1", "0.0.0.1", 1)] - [InlineData("::1", "::1", null)] - [InlineData("[::1]", "::1", null)] - [InlineData("[::1]:1", "::1", 1)] - public void ParsesCorrectly(string input, string expectedAddress, int? expectedPort) - { - IPAddress address; - int? port; - var success = IPAddressWithPortParser.TryParse(input, out address, out port); - Assert.True(success); - Assert.Equal(expectedAddress, address?.ToString()); - Assert.Equal(expectedPort, port); - } - - [InlineData("[::1]:")] - [InlineData("[::1:")] - [InlineData("::1:")] - [InlineData("127:")] - [InlineData("127.0.0.1:")] - [InlineData("")] - [InlineData("[]")] - [InlineData("]")] - [InlineData("]:1")] - public void ShouldNotParse(string input) - { - IPAddress address; - int? port; - var success = IPAddressWithPortParser.TryParse(input, out address, out port); - Assert.False(success); - Assert.Equal(null, address); - Assert.Equal(null, port); - } - } -} diff --git a/test/TestSites/Properties/launchSettings.json b/test/TestSites/Properties/launchSettings.json index b111483280..ef0298b09e 100644 --- a/test/TestSites/Properties/launchSettings.json +++ b/test/TestSites/Properties/launchSettings.json @@ -1,4 +1,12 @@ { + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:25334/", + "sslPort": 0 + } + }, "profiles": { "IIS Express": { "commandName": "IISExpress", @@ -6,6 +14,12 @@ "environmentVariables": { "ASPNET_ENV": "HelloWorld" } + }, + "web": { + "commandName": "web", + "environmentVariables": { + "Hosting:Environment": "Development" + } } } } \ No newline at end of file diff --git a/test/TestSites/StartupHttpsHelloWorld.cs b/test/TestSites/StartupHttpsHelloWorld.cs index 46d7f0e4b5..b15975e2aa 100644 --- a/test/TestSites/StartupHttpsHelloWorld.cs +++ b/test/TestSites/StartupHttpsHelloWorld.cs @@ -17,9 +17,10 @@ namespace TestSites { if (ctx.Request.Path.Equals(new PathString("/checkclientcert"))) { - return ctx.Response.WriteAsync(ctx.Request.Scheme + " Hello World, has cert? " + (ctx.Connection.ClientCertificate != null)); + return ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Forwarded:" + ctx.Request.Headers["x-forwarded-proto"] + + "; has cert? " + (ctx.Connection.ClientCertificate != null)); } - return ctx.Response.WriteAsync(ctx.Request.Scheme + " Hello World"); + return ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Forwarded:" + ctx.Request.Headers["x-forwarded-proto"]); }); } } diff --git a/test/TestSites/StartupNtlmAuthentication.cs b/test/TestSites/StartupNtlmAuthentication.cs index bdda8c9dcd..f007cd9c00 100644 --- a/test/TestSites/StartupNtlmAuthentication.cs +++ b/test/TestSites/StartupNtlmAuthentication.cs @@ -15,6 +15,7 @@ namespace TestSites { loggerFactory.AddConsole(); + // Simple error page without depending on Diagnostics. app.Use(async (context, next) => { try @@ -66,7 +67,7 @@ namespace TestSites if (context.Request.Path.Equals("/RestrictedNegotiate")) { - if (string.Equals("Negotiate", context.User.Identity.AuthenticationType, System.StringComparison.Ordinal)) + if (string.Equals("Negotiate", context.User.Identity.AuthenticationType, StringComparison.Ordinal)) { return context.Response.WriteAsync("Negotiate"); } @@ -78,7 +79,7 @@ namespace TestSites if (context.Request.Path.Equals("/RestrictedNTLM")) { - if (string.Equals("NTLM", context.User.Identity.AuthenticationType, System.StringComparison.Ordinal)) + if (string.Equals("NTLM", context.User.Identity.AuthenticationType, StringComparison.Ordinal)) { return context.Response.WriteAsync("NTLM"); }