diff --git a/IISIntegration.sln b/IISIntegration.sln index e282d6cf49..6548ea89c5 100644 --- a/IISIntegration.sln +++ b/IISIntegration.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 @@ -15,10 +14,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.IISPla EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{EF30B533-D715-421A-92B7-92FEF460AC9C}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.IISPlatformHandler.Tests", "test\Microsoft.AspNetCore.IISPlatformHandler.Tests\Microsoft.AspNetCore.IISPlatformHandler.Tests.xproj", "{FBBBE015-1CE3-454B-9647-23F8073FB7AB}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests", "test\Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests\Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests.xproj", "{A83A33D1-3D29-403C-9750-5811AC7B4025}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestSites", "test\TestSites\TestSites.xproj", "{E27453AD-9CA0-49A2-94FA-96337D77677D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9}" @@ -29,6 +24,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-publish-iis.Tests", EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-publish-iis", "src\dotnet-publish-iis\dotnet-publish-iis.xproj", "{E492AEF2-42C1-4399-B718-A6934EBB36AB}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.IISIntegration", "src\Microsoft.AspNetCore.Server.IISIntegration\Microsoft.AspNetCore.Server.IISIntegration.xproj", "{8B3446E8-E6A8-4591-AA63-A95837C6E97C}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests", "test\Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests\Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.xproj", "{7F2F50C7-610F-4B69-B945-CA283511A587}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Server.IISIntegration.Tests", "test\Microsoft.AspNetCore.Server.IISIntegration.Tests\Microsoft.AspNetCore.Server.IISIntegration.Tests.xproj", "{4106DB10-E09F-480E-9CE6-B39235512EE6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,14 +40,6 @@ Global {ABE53415-83CE-4AF0-AF67-E52160C7862B}.Debug|Any CPU.Build.0 = Debug|Any CPU {ABE53415-83CE-4AF0-AF67-E52160C7862B}.Release|Any CPU.ActiveCfg = Release|Any CPU {ABE53415-83CE-4AF0-AF67-E52160C7862B}.Release|Any CPU.Build.0 = Release|Any CPU - {FBBBE015-1CE3-454B-9647-23F8073FB7AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBBBE015-1CE3-454B-9647-23F8073FB7AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBBBE015-1CE3-454B-9647-23F8073FB7AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBBBE015-1CE3-454B-9647-23F8073FB7AB}.Release|Any CPU.Build.0 = Release|Any CPU - {A83A33D1-3D29-403C-9750-5811AC7B4025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A83A33D1-3D29-403C-9750-5811AC7B4025}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A83A33D1-3D29-403C-9750-5811AC7B4025}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A83A33D1-3D29-403C-9750-5811AC7B4025}.Release|Any CPU.Build.0 = Release|Any CPU {E27453AD-9CA0-49A2-94FA-96337D77677D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E27453AD-9CA0-49A2-94FA-96337D77677D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E27453AD-9CA0-49A2-94FA-96337D77677D}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -63,17 +56,30 @@ Global {E492AEF2-42C1-4399-B718-A6934EBB36AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E492AEF2-42C1-4399-B718-A6934EBB36AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {E492AEF2-42C1-4399-B718-A6934EBB36AB}.Release|Any CPU.Build.0 = Release|Any CPU + {8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B3446E8-E6A8-4591-AA63-A95837C6E97C}.Release|Any CPU.Build.0 = Release|Any CPU + {7F2F50C7-610F-4B69-B945-CA283511A587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F2F50C7-610F-4B69-B945-CA283511A587}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F2F50C7-610F-4B69-B945-CA283511A587}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F2F50C7-610F-4B69-B945-CA283511A587}.Release|Any CPU.Build.0 = Release|Any CPU + {4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4106DB10-E09F-480E-9CE6-B39235512EE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4106DB10-E09F-480E-9CE6-B39235512EE6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {ABE53415-83CE-4AF0-AF67-E52160C7862B} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} - {FBBBE015-1CE3-454B-9647-23F8073FB7AB} = {EF30B533-D715-421A-92B7-92FEF460AC9C} - {A83A33D1-3D29-403C-9750-5811AC7B4025} = {EF30B533-D715-421A-92B7-92FEF460AC9C} {E27453AD-9CA0-49A2-94FA-96337D77677D} = {EF30B533-D715-421A-92B7-92FEF460AC9C} {E4E2BDC4-A9C6-4AE9-B429-032EC83EDE64} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9} {CFB3AF72-0AF6-44CB-8815-6E4052C7B5A0} = {EF30B533-D715-421A-92B7-92FEF460AC9C} {E492AEF2-42C1-4399-B718-A6934EBB36AB} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} + {8B3446E8-E6A8-4591-AA63-A95837C6E97C} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} + {7F2F50C7-610F-4B69-B945-CA283511A587} = {EF30B533-D715-421A-92B7-92FEF460AC9C} + {4106DB10-E09F-480E-9CE6-B39235512EE6} = {EF30B533-D715-421A-92B7-92FEF460AC9C} EndGlobalSection EndGlobal diff --git a/samples/IISSample/Startup.cs b/samples/IISSample/Startup.cs index 0b6831ce40..9f6e1aa745 100644 --- a/samples/IISSample/Startup.cs +++ b/samples/IISSample/Startup.cs @@ -15,7 +15,7 @@ namespace IISSample var logger = loggerfactory.CreateLogger("Requests"); - app.UseIISPlatformHandler(); + app.UseIIS(); app.Run(async (context) => { @@ -49,7 +49,7 @@ namespace IISSample var host = new WebHostBuilder() .UseDefaultConfiguration(args) .UseServer("Microsoft.AspNetCore.Server.Kestrel") - .UseIISPlatformHandlerUrl() + .UseIISUrl() .UseStartup() .Build(); diff --git a/samples/IISSample/project.json b/samples/IISSample/project.json index 2d07f326ae..416c330ce0 100644 --- a/samples/IISSample/project.json +++ b/samples/IISSample/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.Extensions.Logging.Console": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*" diff --git a/samples/IISSample/wwwroot/web.config b/samples/IISSample/wwwroot/web.config index 8485f6719f..fc3b1ae0e9 100644 --- a/samples/IISSample/wwwroot/web.config +++ b/samples/IISSample/wwwroot/web.config @@ -2,8 +2,8 @@ - + - + - + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs new file mode 100644 index 0000000000..ff2196771a --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/AuthenticationHandler.cs @@ -0,0 +1,138 @@ +// 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; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.Http.Features.Authentication; + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + internal class AuthenticationHandler : IAuthenticationHandler + { + internal AuthenticationHandler(HttpContext httpContext, IISOptions options, ClaimsPrincipal user) + { + HttpContext = httpContext; + User = user; + Options = options; + } + + internal HttpContext HttpContext { get; } + + internal IISOptions Options { get; } + + internal ClaimsPrincipal User { get; } + + internal IAuthenticationHandler PriorHandler { get; set; } + + public Task AuthenticateAsync(AuthenticateContext context) + { + if (ShouldHandleScheme(context.AuthenticationScheme)) + { + if (User != null) + { + context.Authenticated(User, properties: null, + description: Options.AuthenticationDescriptions.FirstOrDefault(descrip => + string.Equals(User.Identity.AuthenticationType, descrip.AuthenticationScheme, StringComparison.Ordinal))?.Items); + } + else + { + context.NotAuthenticated(); + } + } + + if (PriorHandler != null) + { + return PriorHandler.AuthenticateAsync(context); + } + + return Task.FromResult(0); + } + + public Task ChallengeAsync(ChallengeContext context) + { + bool handled = false; + if (ShouldHandleScheme(context.AuthenticationScheme)) + { + switch (context.Behavior) + { + case ChallengeBehavior.Automatic: + // If there is a principal already, invoke the forbidden code path + if (User == null) + { + goto case ChallengeBehavior.Unauthorized; + } + else + { + goto case ChallengeBehavior.Forbidden; + } + case ChallengeBehavior.Unauthorized: + HttpContext.Response.StatusCode = 401; + // We would normally set the www-authenticate header here, but IIS does that for us. + break; + case ChallengeBehavior.Forbidden: + HttpContext.Response.StatusCode = 403; + handled = true; // No other handlers need to consider this challenge. + break; + } + context.Accept(); + } + + if (!handled && PriorHandler != null) + { + return PriorHandler.ChallengeAsync(context); + } + + return Task.FromResult(0); + } + + public void GetDescriptions(DescribeSchemesContext context) + { + foreach (var description in Options.AuthenticationDescriptions) + { + context.Accept(description.Items); + } + + if (PriorHandler != null) + { + PriorHandler.GetDescriptions(context); + } + } + + public Task SignInAsync(SignInContext context) + { + // Not supported, fall through + if (PriorHandler != null) + { + return PriorHandler.SignInAsync(context); + } + + return Task.FromResult(0); + } + + public Task SignOutAsync(SignOutContext context) + { + // Not supported, fall through + if (PriorHandler != null) + { + return PriorHandler.SignOutAsync(context); + } + + return Task.FromResult(0); + } + + private bool ShouldHandleScheme(string authenticationScheme) + { + if (Options.AutomaticAuthentication && string.Equals(AuthenticationManager.AutomaticScheme, authenticationScheme, StringComparison.Ordinal)) + { + return true; + } + + return Options.AuthenticationDescriptions.Any(description => string.Equals(description.AuthenticationScheme, authenticationScheme, StringComparison.Ordinal)); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs new file mode 100644 index 0000000000..c40ab415c7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/ForwardedTlsConnectionFeature.cs @@ -0,0 +1,56 @@ +// 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; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + internal class ForwardedTlsConnectionFeature : ITlsConnectionFeature + { + private StringValues _header; + private X509Certificate2 _certificate; + private ILogger _logger; + + public ForwardedTlsConnectionFeature(ILogger logger, StringValues header) + { + _logger = logger; + _header = header; + } + + public X509Certificate2 ClientCertificate + { + get + { + if (_certificate == null && _header != StringValues.Empty) + { + try + { + var bytes = Convert.FromBase64String(_header); + _certificate = new X509Certificate2(bytes); + } + catch (Exception ex) + { + _logger.LogWarning(0, ex, "Failed to read the client certificate."); + } + } + return _certificate; + } + set + { + _certificate = value; + _header = StringValues.Empty; + } + } + + public Task GetClientCertificateAsync(CancellationToken cancellationToken) + { + return Task.FromResult(ClientCertificate); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/IISAddressExtensions.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/IISAddressExtensions.cs new file mode 100644 index 0000000000..63602eb780 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/IISAddressExtensions.cs @@ -0,0 +1,38 @@ +// 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; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class IISAddressExtensions + { + // This is defined by IIS's AspNetCoreModule. + private static readonly string ServerPort = "ASPNETCORE_PORT"; + private static readonly string ServerPath = "ASPNETCORE_APPL_PATH"; + + /// + /// Configures the port and base path the server should listen on when running behind AspNetCoreModule. + /// + /// + /// + public static IWebHostBuilder UseIISUrl(this IWebHostBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + var port = Environment.GetEnvironmentVariable(ServerPort); + var path = Environment.GetEnvironmentVariable(ServerPath); + + if (!string.IsNullOrEmpty(port)) + { + var address = "http://localhost:" + port + path; + app.UseSetting(WebHostDefaults.ServerUrlsKey, address); + } + + return app; + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs new file mode 100644 index 0000000000..db7ea22732 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/IISDefaults.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + public class IISDefaults + { + public const string Negotiate = "Negotiate"; + public const string Ntlm = "NTLM"; + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs new file mode 100644 index 0000000000..d8b9d20bdb --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddleware.cs @@ -0,0 +1,155 @@ +// 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; +using System.Globalization; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Features.Authentication; +using Microsoft.AspNetCore.Http.Features.Authentication.Internal; +using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + public class IISMiddleware + { + private const string MSAspNetCoreWinAuthToken = "MS-ASPNETCORE-WINAUTHTOKEN"; + private const string MSAspNetCoreClientCert = "MS-ASPNETCORE-CLIENTCERT"; + private const string AspNetCoreToken = "ASPNETCORE_TOKEN"; + private const string MSAspNetCoreToken = "MS-ASPNETCORE-TOKEN"; + + private readonly RequestDelegate _next; + private readonly IISOptions _options; + private readonly ILogger _logger; + private readonly string _platformToken; + + public IISMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions options) + { + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _next = next; + _options = options.Value; + _logger = loggerFactory.CreateLogger(); + + _platformToken = Environment.GetEnvironmentVariable(AspNetCoreToken); + if (string.IsNullOrEmpty(_platformToken)) + { + _logger.LogInformation($"{AspNetCoreToken} not detected, {nameof(IISMiddleware)} will be skipped."); + } + } + + public async Task Invoke(HttpContext httpContext) + { + if (string.IsNullOrEmpty(_platformToken) + || !string.Equals(_platformToken, httpContext.Request.Headers[MSAspNetCoreToken], StringComparison.Ordinal)) + { + _logger.LogTrace($"{MSAspNetCoreToken} not detected, skipping {nameof(IISMiddleware)}."); + await _next(httpContext); + return; + } + + if (_options.ForwardClientCertificate) + { + var header = httpContext.Request.Headers[MSAspNetCoreClientCert]; + if (!StringValues.IsNullOrEmpty(header)) + { + httpContext.Features.Set(new ForwardedTlsConnectionFeature(_logger, header)); + } + } + + if (_options.ForwardWindowsAuthentication) + { + var winPrincipal = UpdateUser(httpContext); + var handler = new AuthenticationHandler(httpContext, _options, winPrincipal); + AttachAuthenticationHandler(handler); + try + { + await _next(httpContext); + } + finally + { + DetachAuthenticationhandler(handler); + } + } + else + { + await _next(httpContext); + } + } + + private WindowsPrincipal UpdateUser(HttpContext httpContext) + { + var tokenHeader = httpContext.Request.Headers[MSAspNetCoreWinAuthToken]; + + int hexHandle; + WindowsPrincipal winPrincipal = null; + if (!StringValues.IsNullOrEmpty(tokenHeader) + && int.TryParse(tokenHeader, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hexHandle)) + { + // Always create the identity if the handle exists, we need to dispose it so it does not leak. + var handle = new IntPtr(hexHandle); + var winIdentity = new WindowsIdentity(handle); + + // WindowsIdentity just duplicated the handle so we need to close the original. + NativeMethods.CloseHandle(handle); + + httpContext.Response.RegisterForDispose(winIdentity); + winPrincipal = new WindowsPrincipal(winIdentity); + + if (_options.AutomaticAuthentication) + { + // Don't get it from httpContext.User, that always returns a non-null anonymous user by default. + var existingPrincipal = httpContext.Features.Get()?.User; + if (existingPrincipal != null) + { + httpContext.User = SecurityHelper.MergeUserPrincipal(existingPrincipal, winPrincipal); + } + else + { + httpContext.User = winPrincipal; + } + } + } + + return winPrincipal; + } + + private void AttachAuthenticationHandler(AuthenticationHandler handler) + { + var auth = handler.HttpContext.Features.Get(); + if (auth == null) + { + auth = new HttpAuthenticationFeature(); + handler.HttpContext.Features.Set(auth); + } + handler.PriorHandler = auth.Handler; + auth.Handler = handler; + } + + private void DetachAuthenticationhandler(AuthenticationHandler handler) + { + var auth = handler.HttpContext.Features.Get(); + if (auth != null) + { + auth.Handler = handler.PriorHandler; + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddlewareExtensions.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddlewareExtensions.cs new file mode 100644 index 0000000000..0eb736cb2b --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/IISMiddlewareExtensions.cs @@ -0,0 +1,49 @@ +// 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; +using Microsoft.AspNetCore.Server.IISIntegration; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Builder +{ + public static class IISMiddlewareExtensions + { + /// + /// Adds middleware for interacting with the IIS AspNetCoreModule reverse proxy module. + /// This will handle forwarded Windows Authentication, client certificates, etc.. + /// + /// + /// + public static IApplicationBuilder UseIIS(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(); + } + + /// + /// Adds middleware for interacting with the IIS AspNetCoreModule reverse proxy module. + /// This will handle forwarded Windows Authentication, client certificates, etc.. + /// + /// + /// + /// + public static IApplicationBuilder UseIIS(this IApplicationBuilder app, IISOptions options) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + return app.UseMiddleware(Options.Create(options)); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs new file mode 100644 index 0000000000..9bceb66be4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/IISOptions.cs @@ -0,0 +1,45 @@ +// 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.Collections.Generic; +using Microsoft.AspNetCore.Http.Authentication; +using Microsoft.AspNetCore.Server.IISIntegration; + +namespace Microsoft.AspNetCore.Builder +{ + public class IISOptions + { + /// + /// If true the authentication middleware alter the request user coming in and respond to generic challenges. + /// If false the authentication middleware will only provide identity and respond to challenges when explicitly indicated + /// by the AuthenticationScheme. + /// + public bool AutomaticAuthentication { get; set; } = true; + + /// + /// If true authentication middleware will try to authenticate using platform handler windows authentication + /// If false authentication middleware won't be added + /// + public bool ForwardWindowsAuthentication { get; set; } = true; + + /// + /// Populates the ITLSConnectionFeature if the MS-ASPNETCORE-CLIENTCERT request header is present. + /// + public bool ForwardClientCertificate { get; set; } = true; + + /// + /// Additional information about the authentication type which is made available to the application. + /// + public IList AuthenticationDescriptions { get; } = new List() + { + new AuthenticationDescription() + { + AuthenticationScheme = IISDefaults.Negotiate + }, + new AuthenticationDescription() + { + AuthenticationScheme = IISDefaults.Ntlm + } + }; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.xproj b/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.xproj new file mode 100644 index 0000000000..b9dc5d5769 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.xproj @@ -0,0 +1,17 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 8b3446e8-e6a8-4591-aa63-a95837c6e97c + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\ + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs new file mode 100644 index 0000000000..8a49c2781c --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/NativeMethods.cs @@ -0,0 +1,24 @@ +// 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; +using System.Runtime.InteropServices; + +namespace Microsoft.AspNetCore.Server.IISIntegration +{ + internal class NativeMethods + { +#if DOTNET5_4 + private const string api_ms_win_core_handle_LIB = "api-ms-win-core-handle-l1-1-0.dll"; +#else + private const string KERNEL32 = "kernel32.dll"; +#endif + +#if DOTNET5_4 + [DllImport(api_ms_win_core_handle_LIB, ExactSpelling = true, SetLastError = true)] +#else + [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] +#endif + internal static extern bool CloseHandle(IntPtr handle); + } +} diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..76feceeff0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +// 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.Reflection; +using System.Resources; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] +[assembly: AssemblyCompany("Microsoft Corporation.")] +[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyProduct("Microsoft ASP.NET Core")] diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/project.json b/src/Microsoft.AspNetCore.Server.IISIntegration/project.json new file mode 100644 index 0000000000..a41ac368ac --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/project.json @@ -0,0 +1,34 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true + }, + "description": "ASP.NET Core components for working with the IIS AspNetCoreModule.", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/IISIntegration" + }, + "dependencies": { + "Microsoft.AspNetCore.Hosting.Abstractions": "1.0.0-*", + "Microsoft.AspNetCore.Http": "1.0.0-*", + "Microsoft.AspNetCore.Http.Extensions": "1.0.0-*", + "Microsoft.Extensions.Logging.Abstractions": "1.0.0-*", + "Microsoft.Extensions.Options": "1.0.0-*", + "Microsoft.Extensions.SecurityHelper.Sources": { + "type": "build", + "version": "1.0.0-*" + } + }, + "frameworks": { + "net451": { }, + "netstandard1.3": { + "dependencies": { + "System.Security.Principal.Windows": "4.0.0-*" + }, + "imports": [ "dotnet5.4" ] + } + } +} diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HelloWorldTest.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HelloWorldTest.cs similarity index 89% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HelloWorldTest.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HelloWorldTest.cs index 84d71a9003..a8413cd814 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HelloWorldTest.cs +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HelloWorldTest.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; using Xunit; using Xunit.Sdk; -namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { // Uses ports ranging 5061 - 5069. public class HelloWorldTests @@ -77,6 +77,14 @@ namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests try { Assert.Equal("Hello World", responseText); + + response = await httpClient.GetAsync("/Path%3F%3F?query"); + responseText = await response.Content.ReadAsStringAsync(); + Assert.Equal("/Path??", responseText); + + response = await httpClient.GetAsync("/Query%3FPath?query?"); + responseText = await response.Content.ReadAsStringAsync(); + Assert.Equal("?query?", responseText); } catch (XunitException) { diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Helpers.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Helpers.cs similarity index 84% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Helpers.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Helpers.cs index 4d2165e8c8..e8c923adcb 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Helpers.cs +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Helpers.cs @@ -3,7 +3,7 @@ using System.IO; -namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { public class Helpers { diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Http.config b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Http.config similarity index 99% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Http.config rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Http.config index b1b08c8b1d..5ef47a0ae4 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Http.config +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Http.config @@ -118,7 +118,7 @@
-
+
@@ -253,7 +253,7 @@ - + @@ -928,7 +928,7 @@ - + diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Https.config b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Https.config similarity index 99% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Https.config rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Https.config index 489c8d6891..f9907277f7 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Https.config +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Https.config @@ -118,7 +118,7 @@
-
+
@@ -253,7 +253,7 @@ - + @@ -928,7 +928,7 @@ - + diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HttpsTest.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HttpsTest.cs similarity index 99% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HttpsTest.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HttpsTest.cs index 8d8e18d986..5f422a9ef1 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/HttpsTest.cs +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/HttpsTest.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging; using Xunit; using Xunit.Sdk; -namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { // IisExpress preregisteres 44300-44399 ports. public class HttpsTest diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests.xproj b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.xproj similarity index 93% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests.xproj rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.xproj index 4a8963f8cc..5fd7da2bfa 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests.xproj +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests.xproj @@ -6,7 +6,7 @@ - a83a33d1-3d29-403c-9750-5811ac7b4025 + 7f2f50c7-610f-4b69-b945-ca283511a587 ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\ diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentation.config b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentation.config similarity index 99% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentation.config rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentation.config index 74e50ca34d..d2f3dee3c1 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentation.config +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentation.config @@ -118,7 +118,7 @@
-
+
@@ -253,7 +253,7 @@ - + @@ -928,7 +928,7 @@ - + diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentationTest.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentationTest.cs similarity index 99% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentationTest.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentationTest.cs index cf3c35810f..4f05f41d46 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/NtlmAuthentationTest.cs +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/NtlmAuthentationTest.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging; using Xunit; using Xunit.Sdk; -namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { // Uses ports ranging 5050 - 5060. public class NtlmAuthenticationTests diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Properties/AssemblyInfo.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Properties/AssemblyInfo.cs similarity index 100% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/Properties/AssemblyInfo.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/project.json similarity index 95% rename from test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/project.json rename to test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/project.json index 9053a9029a..1fecebc971 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests/project.json @@ -2,7 +2,7 @@ "content": [ "Http.config", "Https.config", - "NtlmAuthentation.config", + "NtlmAuthentation.config" ], "compilationOptions": { "warningsAsErrors": true diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs similarity index 50% rename from test/Microsoft.AspNetCore.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs rename to test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs index eef9c303b7..218dae0cab 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/HttpPlatformHandlerMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/IISMiddlewareTests.cs @@ -1,6 +1,7 @@ // 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; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -9,10 +10,33 @@ using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.TestHost; using Xunit; -namespace Microsoft.AspNetCore.IISPlatformHandler +namespace Microsoft.AspNetCore.Server.IISIntegration { - public class HttpPlatformHandlerMiddlewareTests + public class IISMiddlewareTests { + [Fact] + public async Task MiddlewareSkippedIfTokenIsMissing() + { + var assertsExecuted = false; + + var builder = new WebHostBuilder() + .Configure(app => + { + app.Run(context => + { + var auth = context.Features.Get(); + Assert.Null(auth); + assertsExecuted = true; + return Task.FromResult(0); + }); + }); + var server = new TestServer(builder); + + var req = new HttpRequestMessage(HttpMethod.Get, ""); + await server.CreateClient().SendAsync(req); + Assert.True(assertsExecuted); + } + [Fact] public async Task AddsAuthenticationHandlerByDefault() { @@ -21,12 +45,18 @@ namespace Microsoft.AspNetCore.IISPlatformHandler var builder = new WebHostBuilder() .Configure(app => { - app.UseIISPlatformHandler(); + Environment.SetEnvironmentVariable("ASPNETCORE_TOKEN", "TestToken"); + app.Use((context, next) => + { + context.Request.Headers["MS-ASPNETCORE-TOKEN"] = "TestToken"; + return next(); + }); + app.UseIIS(); app.Run(context => { - var auth = (IHttpAuthenticationFeature)context.Features[typeof(IHttpAuthenticationFeature)]; + var auth = context.Features.Get(); Assert.NotNull(auth); - Assert.Equal("Microsoft.AspNetCore.IISPlatformHandler.AuthenticationHandler", auth.Handler.GetType().FullName); + Assert.Equal("Microsoft.AspNetCore.Server.IISIntegration.AuthenticationHandler", auth.Handler.GetType().FullName); assertsExecuted = true; return Task.FromResult(0); }); @@ -47,13 +77,19 @@ namespace Microsoft.AspNetCore.IISPlatformHandler var builder = new WebHostBuilder() .Configure(app => { - app.UseIISPlatformHandler(new IISPlatformHandlerOptions + Environment.SetEnvironmentVariable("ASPNETCORE_TOKEN", "TestToken"); + app.Use((context, next) => + { + context.Request.Headers["MS-ASPNETCORE-TOKEN"] = "TestToken"; + return next(); + }); + app.UseIIS(new IISOptions { ForwardWindowsAuthentication = false }); app.Run(context => { - var auth = (IHttpAuthenticationFeature)context.Features[typeof(IHttpAuthenticationFeature)]; + var auth = context.Features.Get(); Assert.Null(auth); assertsExecuted = true; return Task.FromResult(0); diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/Microsoft.AspNetCore.IISPlatformHandler.Tests.xproj b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.xproj similarity index 93% rename from test/Microsoft.AspNetCore.IISPlatformHandler.Tests/Microsoft.AspNetCore.IISPlatformHandler.Tests.xproj rename to test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.xproj index ec688ba4cc..40a4f5de1d 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/Microsoft.AspNetCore.IISPlatformHandler.Tests.xproj +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/Microsoft.AspNetCore.Server.IISIntegration.Tests.xproj @@ -6,7 +6,7 @@ - fbbbe015-1ce3-454b-9647-23f8073fb7ab + 4106db10-e09f-480e-9ce6-b39235512ee6 ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin\ diff --git a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/project.json b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/project.json similarity index 87% rename from test/Microsoft.AspNetCore.IISPlatformHandler.Tests/project.json rename to test/Microsoft.AspNetCore.Server.IISIntegration.Tests/project.json index 0732e0b60a..da6782f459 100644 --- a/test/Microsoft.AspNetCore.IISPlatformHandler.Tests/project.json +++ b/test/Microsoft.AspNetCore.Server.IISIntegration.Tests/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-*", "Microsoft.AspNetCore.TestHost": "1.0.0-*", "Microsoft.NETCore.Platforms": "1.0.1-*", "xunit": "2.1.0" diff --git a/test/TestSites/Program.cs b/test/TestSites/Program.cs index 16d0c26e7a..4ea84843c2 100644 --- a/test/TestSites/Program.cs +++ b/test/TestSites/Program.cs @@ -11,7 +11,7 @@ namespace TestSites { var host = new WebHostBuilder() .UseDefaultConfiguration(args) - .UseIISPlatformHandlerUrl() + .UseIISUrl() .UseStartup("TestSites") .UseServer("Microsoft.AspNetCore.Server.Kestrel") .Build(); diff --git a/test/TestSites/StartupHelloWorld.cs b/test/TestSites/StartupHelloWorld.cs index b49729a343..34c22bf713 100644 --- a/test/TestSites/StartupHelloWorld.cs +++ b/test/TestSites/StartupHelloWorld.cs @@ -12,9 +12,18 @@ namespace TestSites public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); - app.UseIISPlatformHandler(); + app.UseIIS(); app.Run(ctx => { + if (ctx.Request.Path.Value.StartsWith("/Path")) + { + return ctx.Response.WriteAsync(ctx.Request.Path.Value); + } + if (ctx.Request.Path.Value.StartsWith("/Query")) + { + return ctx.Response.WriteAsync(ctx.Request.QueryString.Value); + } + return ctx.Response.WriteAsync("Hello World"); }); } diff --git a/test/TestSites/StartupHttpsHelloWorld.cs b/test/TestSites/StartupHttpsHelloWorld.cs index 22ba71998e..16e60f4682 100644 --- a/test/TestSites/StartupHttpsHelloWorld.cs +++ b/test/TestSites/StartupHttpsHelloWorld.cs @@ -12,7 +12,7 @@ namespace TestSites public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); - app.UseIISPlatformHandler(); + app.UseIIS(); app.Run(ctx => { if (ctx.Request.Path.Equals(new PathString("/checkclientcert"))) diff --git a/test/TestSites/StartupNtlmAuthentication.cs b/test/TestSites/StartupNtlmAuthentication.cs index 86f9b8623a..4c550ac4ea 100644 --- a/test/TestSites/StartupNtlmAuthentication.cs +++ b/test/TestSites/StartupNtlmAuthentication.cs @@ -37,7 +37,8 @@ namespace TestSites } }); - app.UseIISPlatformHandler(); + app.UseIIS(); + app.Use((context, next) => { if (context.Request.Path.Equals("/Anonymous")) diff --git a/test/TestSites/project.json b/test/TestSites/project.json index c3b35340a7..8cafbbc3cd 100644 --- a/test/TestSites/project.json +++ b/test/TestSites/project.json @@ -7,7 +7,7 @@ "wwwroot/**/*" ], "dependencies": { - "Microsoft.AspNetCore.IISPlatformHandler": "1.0.0-*", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-*", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*", "Microsoft.AspNetCore.WebUtilities": "1.0.0-*", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-*", diff --git a/test/TestSites/wwwroot/web.config b/test/TestSites/wwwroot/web.config index 95ee9cefdd..2680554657 100644 --- a/test/TestSites/wwwroot/web.config +++ b/test/TestSites/wwwroot/web.config @@ -2,9 +2,9 @@ - + - + \ No newline at end of file