#95 Switch the middleware from HttpPlatfromHandler to AspNetCoreModule.

This commit is contained in:
Chris R 2016-03-09 12:19:18 -08:00
parent 3e7efd04da
commit 126ed6c4de
34 changed files with 690 additions and 52 deletions

View File

@ -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

View File

@ -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<Startup>()
.Build();

View File

@ -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-*"

View File

@ -2,8 +2,8 @@
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600"/>
<aspNetCore processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600" />
</system.webServer>
</configuration>
</configuration>

View File

@ -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));
}
}
}

View File

@ -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<X509Certificate2> GetClientCertificateAsync(CancellationToken cancellationToken)
{
return Task.FromResult(ClientCertificate);
}
}
}

View File

@ -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";
/// <summary>
/// Configures the port and base path the server should listen on when running behind AspNetCoreModule.
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
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;
}
}
}

View File

@ -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";
}
}

View File

@ -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<IISOptions> 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<IISMiddleware>();
_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<ITlsConnectionFeature>(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<IHttpAuthenticationFeature>()?.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<IHttpAuthenticationFeature>();
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<IHttpAuthenticationFeature>();
if (auth != null)
{
auth.Handler = handler.PriorHandler;
}
}
}
}

View File

@ -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
{
/// <summary>
/// Adds middleware for interacting with the IIS AspNetCoreModule reverse proxy module.
/// This will handle forwarded Windows Authentication, client certificates, etc..
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseIIS(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<IISMiddleware>();
}
/// <summary>
/// Adds middleware for interacting with the IIS AspNetCoreModule reverse proxy module.
/// This will handle forwarded Windows Authentication, client certificates, etc..
/// </summary>
/// <param name="app"></param>
/// <param name="options"></param>
/// <returns></returns>
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<IISMiddleware>(Options.Create(options));
}
}
}

View File

@ -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
{
/// <summary>
/// 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.
/// </summary>
public bool AutomaticAuthentication { get; set; } = true;
/// <summary>
/// If true authentication middleware will try to authenticate using platform handler windows authentication
/// If false authentication middleware won't be added
/// </summary>
public bool ForwardWindowsAuthentication { get; set; } = true;
/// <summary>
/// Populates the ITLSConnectionFeature if the MS-ASPNETCORE-CLIENTCERT request header is present.
/// </summary>
public bool ForwardClientCertificate { get; set; } = true;
/// <summary>
/// Additional information about the authentication type which is made available to the application.
/// </summary>
public IList<AuthenticationDescription> AuthenticationDescriptions { get; } = new List<AuthenticationDescription>()
{
new AuthenticationDescription()
{
AuthenticationScheme = IISDefaults.Negotiate
},
new AuthenticationDescription()
{
AuthenticationScheme = IISDefaults.Ntlm
}
};
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>8b3446e8-e6a8-4591-aa63-a95837c6e97c</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -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);
}
}

View File

@ -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")]

View File

@ -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" ]
}
}
}

View File

@ -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)
{

View File

@ -3,7 +3,7 @@
using System.IO;
namespace Microsoft.AspNetCore.IISPlatformHandler.FunctionalTests
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
public class Helpers
{

View File

@ -118,7 +118,7 @@
</sectionGroup>
<section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
<section name="webSocket" overrideModeDefault="Deny" />
<section name="httpPlatform" overrideModeDefault="Allow" />
<section name="aspNetCore" overrideModeDefault="Allow" />
</sectionGroup>
</configSections>
@ -253,7 +253,7 @@
<add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
<add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
<add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
<add name="httpPlatformHandler" image="%SystemRoot%\System32\inetsrv\httpPlatformHandler.dll" />
<add name="AspNetCoreModule" image="%SystemRoot%\System32\inetsrv\aspnetcore.dll" />
</globalModules>
<httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
@ -928,7 +928,7 @@
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
<add name="httpPlatformHandler" />
<add name="AspNetCoreModule" />
</modules>
<handlers accessPolicy="Read, Script">
<!-- <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->

View File

@ -118,7 +118,7 @@
</sectionGroup>
<section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
<section name="webSocket" overrideModeDefault="Deny" />
<section name="httpPlatform" overrideModeDefault="Allow" />
<section name="aspNetCore" overrideModeDefault="Allow" />
</sectionGroup>
</configSections>
@ -253,7 +253,7 @@
<add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
<add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
<add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
<add name="httpPlatformHandler" image="%SystemRoot%\system32\inetsrv\httpPlatformHandler.dll" />
<add name="AspNetCoreModule" image="%SystemRoot%\system32\inetsrv\aspnetcore.dll" />
</globalModules>
<httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
@ -928,7 +928,7 @@
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
<add name="httpPlatformHandler" />
<add name="AspNetCoreModule" />
</modules>
<handlers accessPolicy="Read, Script">
<!-- <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->

View File

@ -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

View File

@ -6,7 +6,7 @@
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a83a33d1-3d29-403c-9750-5811ac7b4025</ProjectGuid>
<ProjectGuid>7f2f50c7-610f-4b69-b945-ca283511a587</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\</OutputPath>
</PropertyGroup>

View File

@ -118,7 +118,7 @@
</sectionGroup>
<section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
<section name="webSocket" overrideModeDefault="Deny" />
<section name="httpPlatform" overrideModeDefault="Allow" />
<section name="aspNetCore" overrideModeDefault="Allow" />
</sectionGroup>
</configSections>
@ -253,7 +253,7 @@
<add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
<add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
<add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
<add name="httpPlatformHandler" image="%SystemRoot%\System32\inetsrv\httpPlatformHandler.dll" />
<add name="AspNetCoreModule" image="%SystemRoot%\System32\inetsrv\aspnetcore.dll" />
</globalModules>
<httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
@ -928,7 +928,7 @@
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
<add name="httpPlatformHandler" />
<add name="AspNetCoreModule" />
</modules>
<handlers accessPolicy="Read, Script">
<!-- <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->

View File

@ -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

View File

@ -2,7 +2,7 @@
"content": [
"Http.config",
"Https.config",
"NtlmAuthentation.config",
"NtlmAuthentation.config"
],
"compilationOptions": {
"warningsAsErrors": true

View File

@ -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<IHttpAuthenticationFeature>();
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<IHttpAuthenticationFeature>();
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<IHttpAuthenticationFeature>();
Assert.Null(auth);
assertsExecuted = true;
return Task.FromResult(0);

View File

@ -6,7 +6,7 @@
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>fbbbe015-1ce3-454b-9647-23f8073fb7ab</ProjectGuid>
<ProjectGuid>4106db10-e09f-480e-9ce6-b39235512ee6</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\</OutputPath>
</PropertyGroup>

View File

@ -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"

View File

@ -11,7 +11,7 @@ namespace TestSites
{
var host = new WebHostBuilder()
.UseDefaultConfiguration(args)
.UseIISPlatformHandlerUrl()
.UseIISUrl()
.UseStartup("TestSites")
.UseServer("Microsoft.AspNetCore.Server.Kestrel")
.Build();

View File

@ -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");
});
}

View File

@ -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")))

View File

@ -37,7 +37,8 @@ namespace TestSites
}
});
app.UseIISPlatformHandler();
app.UseIIS();
app.Use((context, next) =>
{
if (context.Request.Path.Equals("/Anonymous"))

View File

@ -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-*",

View File

@ -2,9 +2,9 @@
<system.webServer>
<!-- This repository cannot use the iis publish tool because there's a bug in the installer if the tool package is a package reference -->
<!-- See https://github.com/dotnet/cli/issues/1215 -->
<httpPlatform forwardWindowsAuthToken="true" processPath="..\TestSites.exe" stdoutLogEnabled="false" stdoutLogFile="..\logs\stdout.log" startupTimeLimit="3600" />
<aspNetCore forwardWindowsAuthToken="true" processPath="..\TestSites.exe" stdoutLogEnabled="false" stdoutLogFile="..\logs\stdout.log" startupTimeLimit="3600" />
<handlers>
<add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>