HttpSysServer => Auth 2.0

This commit is contained in:
Hao Kung 2017-05-17 13:35:09 -07:00
parent 07ea0b0852
commit bff13c7f43
11 changed files with 174 additions and 267 deletions

View File

@ -4,9 +4,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Server.HttpSys namespace Microsoft.AspNetCore.Server.HttpSys
@ -14,138 +14,67 @@ namespace Microsoft.AspNetCore.Server.HttpSys
internal class AuthenticationHandler : IAuthenticationHandler internal class AuthenticationHandler : IAuthenticationHandler
{ {
private RequestContext _requestContext; private RequestContext _requestContext;
private AuthenticationSchemes _authSchemes; private AuthenticationScheme _scheme;
private AuthenticationSchemes _customChallenges;
internal AuthenticationHandler(RequestContext requestContext) public Task<AuthenticateResult> AuthenticateAsync()
{
_requestContext = requestContext;
_authSchemes = requestContext.Response.AuthenticationChallenges;
_customChallenges = AuthenticationSchemes.None;
}
public Task AuthenticateAsync(AuthenticateContext context)
{ {
var identity = _requestContext.User?.Identity; var identity = _requestContext.User?.Identity;
if (identity != null && identity.IsAuthenticated)
foreach (var authType in ListEnabledAuthSchemes())
{ {
var authScheme = authType.ToString(); return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(_requestContext.User, properties: null, authenticationScheme: _scheme.Name)));
if (string.Equals(authScheme, context.AuthenticationScheme, StringComparison.Ordinal))
{
if (identity != null && identity.IsAuthenticated
&& string.Equals(authScheme, identity.AuthenticationType, StringComparison.Ordinal))
{
context.Authenticated(_requestContext.User, properties: null, description: null);
}
else
{
context.NotAuthenticated();
}
}
} }
return TaskCache.CompletedTask; return Task.FromResult(AuthenticateResult.None());
} }
public Task ChallengeAsync(ChallengeContext context) public Task ChallengeAsync(ChallengeContext context)
{ {
var automaticChallenge = string.Equals("Automatic", context.AuthenticationScheme, StringComparison.Ordinal); switch (context.Behavior)
foreach (var scheme in ListEnabledAuthSchemes())
{ {
var authScheme = scheme.ToString(); case ChallengeBehavior.Forbidden:
// Not including any auth types means it's a blanket challenge for any auth type. _requestContext.Response.StatusCode = 403;
if (automaticChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal)) break;
{ case ChallengeBehavior.Unauthorized:
switch (context.Behavior) _requestContext.Response.StatusCode = 401;
break;
case ChallengeBehavior.Automatic:
var identity = (ClaimsIdentity)_requestContext.User?.Identity;
if (identity != null && identity.IsAuthenticated)
{ {
case ChallengeBehavior.Forbidden: _requestContext.Response.StatusCode = 403;
_requestContext.Response.StatusCode = 403;
context.Accept();
break;
case ChallengeBehavior.Unauthorized:
_requestContext.Response.StatusCode = 401;
_customChallenges |= scheme;
context.Accept();
break;
case ChallengeBehavior.Automatic:
var identity = (ClaimsIdentity)_requestContext.User?.Identity;
if (identity != null && identity.IsAuthenticated
&& (automaticChallenge || string.Equals(identity.AuthenticationType, context.AuthenticationScheme, StringComparison.Ordinal)))
{
_requestContext.Response.StatusCode = 403;
context.Accept();
}
else
{
_requestContext.Response.StatusCode = 401;
_customChallenges |= scheme;
context.Accept();
}
break;
default:
throw new NotSupportedException(context.Behavior.ToString());
} }
} else
{
_requestContext.Response.StatusCode = 401;
}
break;
default:
throw new NotSupportedException(context.Behavior.ToString());
} }
// A challenge was issued, it overrides any pre-set auth types.
_requestContext.Response.AuthenticationChallenges = _customChallenges;
return TaskCache.CompletedTask; return TaskCache.CompletedTask;
} }
public void GetDescriptions(DescribeSchemesContext context) public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{ {
// TODO: Caching, this data doesn't change per request. _scheme = scheme;
foreach (var scheme in ListEnabledAuthSchemes()) _requestContext = context.Features.Get<RequestContext>();
if (_requestContext == null)
{ {
context.Accept(GetDescription(scheme.ToString())); throw new InvalidOperationException("No RequestContext found.");
} }
return TaskCache.CompletedTask;
} }
public Task SignInAsync(SignInContext context) public Task SignInAsync(SignInContext context)
{ {
// Not supported. AuthenticationManager will throw if !Accepted. throw new NotSupportedException();
return TaskCache.CompletedTask;
} }
public Task SignOutAsync(SignOutContext context) public Task SignOutAsync(SignOutContext context)
{ {
// Not supported. AuthenticationManager will throw if !Accepted.
return TaskCache.CompletedTask; return TaskCache.CompletedTask;
} }
private IDictionary<string, object> GetDescription(string authenticationScheme)
{
return new Dictionary<string, object>()
{
{ "AuthenticationScheme", authenticationScheme },
};
}
private IEnumerable<AuthenticationSchemes> ListEnabledAuthSchemes()
{
// Order by strength.
if ((_authSchemes & AuthenticationSchemes.Kerberos) == AuthenticationSchemes.Kerberos)
{
yield return AuthenticationSchemes.Kerberos;
}
if ((_authSchemes & AuthenticationSchemes.Negotiate) == AuthenticationSchemes.Negotiate)
{
yield return AuthenticationSchemes.Negotiate;
}
if ((_authSchemes & AuthenticationSchemes.NTLM) == AuthenticationSchemes.NTLM)
{
yield return AuthenticationSchemes.NTLM;
}
/*if ((_authSchemes & AuthenticationSchemes.Digest) == AuthenticationSchemes.Digest)
{
// TODO:
throw new NotImplementedException("Digest challenge generation has not been implemented.");
yield return AuthenticationSchemes.Digest;
}*/
if ((_authSchemes & AuthenticationSchemes.Basic) == AuthenticationSchemes.Basic)
{
yield return AuthenticationSchemes.Basic;
}
}
} }
} }

View File

@ -52,7 +52,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
private string _traceIdentitfier; private string _traceIdentitfier;
private X509Certificate2 _clientCert; private X509Certificate2 _clientCert;
private ClaimsPrincipal _user; private ClaimsPrincipal _user;
private IAuthenticationHandler _authHandler;
private CancellationToken _disconnectToken; private CancellationToken _disconnectToken;
private Stream _responseStream; private Stream _responseStream;
private IHeaderDictionary _responseHeaders; private IHeaderDictionary _responseHeaders;
@ -68,7 +67,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
_requestContext = requestContext; _requestContext = requestContext;
_features = new FeatureCollection(new StandardFeatureCollection(this)); _features = new FeatureCollection(new StandardFeatureCollection(this));
_authHandler = new AuthenticationHandler(requestContext);
_enableResponseCaching = enableResponseCaching; _enableResponseCaching = enableResponseCaching;
// Pre-initialize any fields that are not lazy at the lower level. // Pre-initialize any fields that are not lazy at the lower level.
@ -446,11 +444,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
set { _user = value; } set { _user = value; }
} }
IAuthenticationHandler IHttpAuthenticationFeature.Handler IAuthenticationHandler IHttpAuthenticationFeature.Handler { get; set; }
{
get { return _authHandler; }
set { _authHandler = value; }
}
string IHttpRequestIdentifierFeature.TraceIdentifier string IHttpRequestIdentifierFeature.TraceIdentifier
{ {

View File

@ -0,0 +1,13 @@
// 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.HttpSys
{
public static class HttpSysDefaults
{
/// <summary>
/// The name of the authentication scheme used.
/// </summary>
public static readonly string AuthenticationScheme = "Windows";
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Diagnostics.Contracts; using System.Diagnostics.Contracts;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
private readonly ServerAddressesFeature _serverAddresses; private readonly ServerAddressesFeature _serverAddresses;
public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactory) public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication)
{ {
if (options == null) if (options == null)
{ {
@ -40,10 +41,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
throw new ArgumentNullException(nameof(loggerFactory)); throw new ArgumentNullException(nameof(loggerFactory));
} }
_options = options.Value; _options = options.Value;
Listener = new HttpSysListener(_options, loggerFactory); Listener = new HttpSysListener(_options, loggerFactory);
_logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump)); _logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump));
if (_options.Authentication.Schemes != AuthenticationSchemes.None)
{
authentication.AddScheme(new AuthenticationScheme(HttpSysDefaults.AuthenticationScheme, displayName: null, handlerType: typeof(AuthenticationHandler)));
}
Features = new FeatureCollection(); Features = new FeatureCollection();
_serverAddresses = new ServerAddressesFeature(); _serverAddresses = new ServerAddressesFeature();
Features.Set<IServerAddressesFeature>(_serverAddresses); Features.Set<IServerAddressesFeature>(_serverAddresses);

View File

@ -12,6 +12,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Core" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" /> <PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="$(AspNetCoreVersion)" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="$(AspNetCoreVersion)" />

View File

@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Hosting
{ {
return hostBuilder.ConfigureServices(services => { return hostBuilder.ConfigureServices(services => {
services.AddSingleton<IServer, MessagePump>(); services.AddSingleton<IServer, MessagePump>();
services.AddAuthenticationCore();
}); });
} }

View File

@ -6,7 +6,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
@ -26,8 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType) public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
@ -48,8 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Basic)]
public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType) public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
{ {
throw new NotImplementedException(); throw new NotImplementedException();
})) }))
@ -67,8 +65,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Basic)]
public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType) public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
@ -117,9 +114,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType) public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType)
{ {
string address;
int requestId = 0; int requestId = 0;
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
@ -153,8 +149,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType) public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
@ -167,61 +162,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
} }
} }
[ConditionalTheory]
[InlineData(AuthenticationSchemes.None)]
[InlineData(AuthenticationSchemes.Negotiate)]
[InlineData(AuthenticationSchemes.NTLM)]
// [InlineData(AuthenticationSchemes.Digest)]
[InlineData(AuthenticationSchemes.Basic)]
public async Task AuthTypes_GetSingleDescriptions(AuthenticationSchemes authType)
{
string address;
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext =>
{
var resultList = httpContext.Authentication.GetAuthenticationSchemes();
if (authType == AuthenticationSchemes.None)
{
Assert.Equal(0, resultList.Count());
}
else
{
Assert.Equal(1, resultList.Count());
var result = resultList.First();
Assert.Equal(authType.ToString(), result.AuthenticationScheme);
Assert.Null(result.DisplayName);
}
return Task.FromResult(0);
}))
{
var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
}
}
[ConditionalFact]
public async Task AuthTypes_GetMultipleDescriptions()
{
string address;
AuthenticationSchemes authType =
AuthenticationSchemes.Negotiate
| AuthenticationSchemes.NTLM
| /*AuthenticationSchemes.Digest
|*/ AuthenticationSchemes.Basic;
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext =>
{
var resultList = httpContext.Authentication.GetAuthenticationSchemes();
Assert.Equal(3, resultList.Count());
return Task.FromResult(0);
}))
{
var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
}
}
[ConditionalTheory] [ConditionalTheory]
[InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.Negotiate)]
[InlineData(AuthenticationSchemes.NTLM)] [InlineData(AuthenticationSchemes.NTLM)]
@ -230,18 +170,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType) public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType)
{ {
string address;
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, async httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated); Assert.False(httpContext.User.Identity.IsAuthenticated);
foreach (var scheme in authTypeList) var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme);
{ Assert.False(authResults.Succeeded);
var authResults = await httpContext.Authentication.AuthenticateAsync(scheme); Assert.True(authResults.Nothing);
Assert.Null(authResults);
}
})) }))
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
@ -258,23 +195,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType) public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, async httpContext =>
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, async httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.True(httpContext.User.Identity.IsAuthenticated); Assert.True(httpContext.User.Identity.IsAuthenticated);
var count = 0; var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme);
foreach (var scheme in authTypeList) Assert.True(authResults.Succeeded);
{
var authResults = await httpContext.Authentication.AuthenticateAsync(scheme);
if (authResults != null)
{
count++;
}
}
Assert.Equal(1, count);
})) }))
{ {
var response = await SendRequestAsync(address, useDefaultCredentials: true); var response = await SendRequestAsync(address, useDefaultCredentials: true);
@ -290,14 +217,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType) public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType)
{ {
string address;
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, httpContext => using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated); Assert.False(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ChallengeAsync(); return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
})) }))
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
@ -314,17 +240,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType) public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType)
{ {
string address;
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
using (Utilities.CreateHttpAuthServer(authType, AllowAnoymous, out address, async httpContext => using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, async httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated); Assert.False(httpContext.User.Identity.IsAuthenticated);
foreach (var scheme in authTypeList) await httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
{
await httpContext.Authentication.ChallengeAsync(scheme);
}
})) }))
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
@ -333,52 +255,47 @@ namespace Microsoft.AspNetCore.Server.HttpSys
} }
} }
[Fact(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")]
public async Task AuthTypes_OneChallengeSent()
{
var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic;
using (var server = Utilities.CreateDynamicHost(authTypes, AllowAnoymous, out var address, httpContext =>
{
Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated);
return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
}))
{
var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
Assert.Equal(3, response.Headers.WwwAuthenticate.Count);
}
}
[ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")] [ConditionalTheory(Skip = "HttpClientHandler issue (https://github.com/aspnet/ServerTests/issues/82).")]
[InlineData(AuthenticationSchemes.Negotiate)] [InlineData(AuthenticationSchemes.Negotiate)]
[InlineData(AuthenticationSchemes.NTLM)] [InlineData(AuthenticationSchemes.NTLM)]
// [InlineData(AuthenticationSchemes.Digest)] // [InlineData(AuthenticationSchemes.Digest)]
[InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Basic)]
public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationSchemes authType) [InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM)]
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.Basic)]
[InlineData(AuthenticationSchemes.NTLM | AuthenticationSchemes.Basic)]
public async Task AuthTypes_ChallengeWillAskForAllEnabledSchemes(AuthenticationSchemes authType)
{ {
string address; var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated); Assert.False(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ChallengeAsync(authType.ToString()); return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
})) }))
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
Assert.Equal(1, response.Headers.WwwAuthenticate.Count); Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count);
Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.First().Scheme);
}
}
[ConditionalTheory]
[InlineData(AuthenticationSchemes.Negotiate)]
[InlineData(AuthenticationSchemes.NTLM)]
// [InlineData(AuthenticationSchemes.Digest)]
[InlineData(AuthenticationSchemes.Basic)]
public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationSchemes authType)
{
string address;
var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic;
authTypes = authTypes & ~authType;
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext =>
{
Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated);
return Assert.ThrowsAsync<InvalidOperationException>(() => httpContext.Authentication.ChallengeAsync(authType.ToString()));
}))
{
var response = await SendRequestAsync(address);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
} }
} }
@ -389,14 +306,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[InlineData(AuthenticationSchemes.Basic)] [InlineData(AuthenticationSchemes.Basic)]
public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType) public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType)
{ {
string address;
var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic; var authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic;
using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext => using (var server = Utilities.CreateDynamicHost(authTypes, AllowAnoymous, out var address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.False(httpContext.User.Identity.IsAuthenticated); Assert.False(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ForbidAsync(authType.ToString()); return httpContext.ForbidAsync(HttpSysDefaults.AuthenticationScheme);
})) }))
{ {
var response = await SendRequestAsync(address); var response = await SendRequestAsync(address);
@ -412,13 +328,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
// [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials
public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType) public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.True(httpContext.User.Identity.IsAuthenticated); Assert.True(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ChallengeAsync(authType.ToString()); return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
})) }))
{ {
var response = await SendRequestAsync(address, useDefaultCredentials: true); var response = await SendRequestAsync(address, useDefaultCredentials: true);
@ -435,13 +350,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
// [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials
public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType) public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.True(httpContext.User.Identity.IsAuthenticated); Assert.True(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ChallengeAsync(); return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
})) }))
{ {
var response = await SendRequestAsync(address, useDefaultCredentials: true); var response = await SendRequestAsync(address, useDefaultCredentials: true);
@ -458,13 +372,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
// [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials // [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials
public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType) public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType)
{ {
string address; using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
{ {
Assert.NotNull(httpContext.User); Assert.NotNull(httpContext.User);
Assert.NotNull(httpContext.User.Identity); Assert.NotNull(httpContext.User.Identity);
Assert.True(httpContext.User.Identity.IsAuthenticated); Assert.True(httpContext.User.Identity.IsAuthenticated);
return httpContext.Authentication.ChallengeAsync(authType.ToString(), null, ChallengeBehavior.Unauthorized); return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme, null, ChallengeBehavior.Unauthorized);
})) }))
{ {
var response = await SendRequestAsync(address, useDefaultCredentials: true); var response = await SendRequestAsync(address, useDefaultCredentials: true);

View File

@ -3,6 +3,7 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
var serverAddress = "http://localhost:11001/"; var serverAddress = "http://localhost:11001/";
var overrideAddress = "http://localhost:11002/"; var overrideAddress = "http://localhost:11002/";
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>(); var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>();
serverAddressesFeature.Addresses.Add(overrideAddress); serverAddressesFeature.Addresses.Add(overrideAddress);
@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var serverAddress = "http://localhost:11002/"; var serverAddress = "http://localhost:11002/";
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>(); var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>();
serverAddressesFeature.Addresses.Add(overrideAddress); serverAddressesFeature.Addresses.Add(overrideAddress);
@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var serverAddress = "http://localhost:11002/"; var serverAddress = "http://localhost:11002/";
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>(); var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>();
serverAddressesFeature.PreferHostingUrls = true; serverAddressesFeature.PreferHostingUrls = true;
@ -79,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var overrideAddress = "http://localhost:11002/"; var overrideAddress = "http://localhost:11002/";
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>(); var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>();
serverAddressesFeature.Addresses.Add(serverAddress); serverAddressesFeature.Addresses.Add(serverAddress);
@ -96,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{ {
var serverAddress = "http://localhost:11001/"; var serverAddress = "http://localhost:11001/";
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>(); var serverAddressesFeature = server.Features.Get<IServerAddressesFeature>();
serverAddressesFeature.Addresses.Add(serverAddress); serverAddressesFeature.Addresses.Add(serverAddress);
@ -108,12 +109,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
[ConditionalFact] [ConditionalFact]
public void UseDefaultAddress_WhenNoServerAddressAndNoDirectConfiguration() public void UseDefaultAddress_WhenNoServerAddressAndNoDirectConfiguration()
{ {
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory())) using (var server = Utilities.CreatePump())
{ {
server.StartAsync(new DummyApplication(), CancellationToken.None).Wait(); server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(Constants.DefaultServerAddress, server.Features.Get<IServerAddressesFeature>().Addresses.Single()); Assert.Equal(Constants.DefaultServerAddress, server.Features.Get<IServerAddressesFeature>().Addresses.Single());
} }
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -9,6 +9,7 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
@ -306,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app); var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app);
dynamicServer.Dispose(); dynamicServer.Dispose();
var rootUri = new Uri(root); var rootUri = new Uri(root);
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); var server = Utilities.CreatePump();
foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" }) foreach (string path in new[] { "/", "/11", "/2/3", "/2", "/11/2" })
{ {

View File

@ -4,14 +4,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -289,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
string address; string address;
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { } using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); var server = Utilities.CreatePump();
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address)); server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(address));
server.Listener.Options.RequestQueueLimit = 1001; server.Listener.Options.RequestQueueLimit = 1001;

View File

@ -3,9 +3,13 @@
using System; using System;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -38,6 +42,50 @@ namespace Microsoft.AspNetCore.Server.HttpSys
return CreateDynamicHttpServer(string.Empty, authType, allowAnonymous, out root, out baseAddress, app); return CreateDynamicHttpServer(string.Empty, authType, allowAnonymous, out root, out baseAddress, app);
} }
internal static IWebHost CreateDynamicHost(AuthenticationSchemes authType, bool allowAnonymous, out string root, RequestDelegate app)
=> CreateDynamicHost(string.Empty, authType, allowAnonymous, out root, out var baseAddress, app);
internal static IWebHost CreateDynamicHost(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app)
{
lock (PortLock)
{
while (NextPort < MaxPort)
{
var port = NextPort++;
var prefix = UrlPrefix.Create("http", "localhost", port, basePath);
root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port;
baseAddress = prefix.ToString();
var builder = new WebHostBuilder()
.UseHttpSys(options =>
{
options.UrlPrefixes.Add(prefix);
options.Authentication.Schemes = authType;
options.Authentication.AllowAnonymous = allowAnonymous;
})
.Configure(appBuilder => appBuilder.Run(app));
var host = builder.Build();
try
{
host.Start();
return host;
}
catch (HttpSysException)
{
}
}
NextPort = BasePort;
}
throw new Exception("Failed to locate a free port.");
}
internal static MessagePump CreatePump()
=> new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory(), new AuthenticationSchemeProvider(Options.Create(new AuthenticationOptions())));
internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app) internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, bool allowAnonymous, out string root, out string baseAddress, RequestDelegate app)
{ {
lock (PortLock) lock (PortLock)
@ -50,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port; root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port;
baseAddress = prefix.ToString(); baseAddress = prefix.ToString();
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); var server = CreatePump();
server.Features.Get<IServerAddressesFeature>().Addresses.Add(baseAddress); server.Features.Get<IServerAddressesFeature>().Addresses.Add(baseAddress);
server.Listener.Options.Authentication.Schemes = authType; server.Listener.Options.Authentication.Schemes = authType;
server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous; server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous;
@ -75,7 +123,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app) internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app)
{ {
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()); var server = CreatePump();
server.Features.Get<IServerAddressesFeature>().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString()); server.Features.Get<IServerAddressesFeature>().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString());
server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait(); server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
return server; return server;