HttpSysServer => Auth 2.0
This commit is contained in:
parent
07ea0b0852
commit
bff13c7f43
|
|
@ -4,9 +4,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
|
@ -14,138 +14,67 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
internal class AuthenticationHandler : IAuthenticationHandler
|
||||
{
|
||||
private RequestContext _requestContext;
|
||||
private AuthenticationSchemes _authSchemes;
|
||||
private AuthenticationSchemes _customChallenges;
|
||||
private AuthenticationScheme _scheme;
|
||||
|
||||
internal AuthenticationHandler(RequestContext requestContext)
|
||||
{
|
||||
_requestContext = requestContext;
|
||||
_authSchemes = requestContext.Response.AuthenticationChallenges;
|
||||
_customChallenges = AuthenticationSchemes.None;
|
||||
}
|
||||
|
||||
public Task AuthenticateAsync(AuthenticateContext context)
|
||||
public Task<AuthenticateResult> AuthenticateAsync()
|
||||
{
|
||||
var identity = _requestContext.User?.Identity;
|
||||
|
||||
foreach (var authType in ListEnabledAuthSchemes())
|
||||
if (identity != null && identity.IsAuthenticated)
|
||||
{
|
||||
var authScheme = authType.ToString();
|
||||
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 Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(_requestContext.User, properties: null, authenticationScheme: _scheme.Name)));
|
||||
}
|
||||
return TaskCache.CompletedTask;
|
||||
return Task.FromResult(AuthenticateResult.None());
|
||||
}
|
||||
|
||||
public Task ChallengeAsync(ChallengeContext context)
|
||||
{
|
||||
var automaticChallenge = string.Equals("Automatic", context.AuthenticationScheme, StringComparison.Ordinal);
|
||||
foreach (var scheme in ListEnabledAuthSchemes())
|
||||
switch (context.Behavior)
|
||||
{
|
||||
var authScheme = scheme.ToString();
|
||||
// Not including any auth types means it's a blanket challenge for any auth type.
|
||||
if (automaticChallenge || string.Equals(context.AuthenticationScheme, authScheme, StringComparison.Ordinal))
|
||||
{
|
||||
switch (context.Behavior)
|
||||
case ChallengeBehavior.Forbidden:
|
||||
_requestContext.Response.StatusCode = 403;
|
||||
break;
|
||||
case ChallengeBehavior.Unauthorized:
|
||||
_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;
|
||||
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());
|
||||
_requestContext.Response.StatusCode = 403;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public void GetDescriptions(DescribeSchemesContext context)
|
||||
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
|
||||
{
|
||||
// TODO: Caching, this data doesn't change per request.
|
||||
foreach (var scheme in ListEnabledAuthSchemes())
|
||||
_scheme = scheme;
|
||||
_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)
|
||||
{
|
||||
// Not supported. AuthenticationManager will throw if !Accepted.
|
||||
return TaskCache.CompletedTask;
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Task SignOutAsync(SignOutContext context)
|
||||
{
|
||||
// Not supported. AuthenticationManager will throw if !Accepted.
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private string _traceIdentitfier;
|
||||
private X509Certificate2 _clientCert;
|
||||
private ClaimsPrincipal _user;
|
||||
private IAuthenticationHandler _authHandler;
|
||||
private CancellationToken _disconnectToken;
|
||||
private Stream _responseStream;
|
||||
private IHeaderDictionary _responseHeaders;
|
||||
|
|
@ -68,7 +67,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
_requestContext = requestContext;
|
||||
_features = new FeatureCollection(new StandardFeatureCollection(this));
|
||||
_authHandler = new AuthenticationHandler(requestContext);
|
||||
_enableResponseCaching = enableResponseCaching;
|
||||
|
||||
// Pre-initialize any fields that are not lazy at the lower level.
|
||||
|
|
@ -446,11 +444,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
set { _user = value; }
|
||||
}
|
||||
|
||||
IAuthenticationHandler IHttpAuthenticationFeature.Handler
|
||||
{
|
||||
get { return _authHandler; }
|
||||
set { _authHandler = value; }
|
||||
}
|
||||
IAuthenticationHandler IHttpAuthenticationFeature.Handler { get; set; }
|
||||
|
||||
string IHttpRequestIdentifierFeature.TraceIdentifier
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Diagnostics.Contracts;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
|
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
private readonly ServerAddressesFeature _serverAddresses;
|
||||
|
||||
public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactory)
|
||||
public MessagePump(IOptions<HttpSysOptions> options, ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
|
|
@ -40,10 +41,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_options = options.Value;
|
||||
Listener = new HttpSysListener(_options, loggerFactory);
|
||||
_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();
|
||||
_serverAddresses = new ServerAddressesFeature();
|
||||
Features.Set<IServerAddressesFeature>(_serverAddresses);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Core" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(AspNetCoreVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="$(AspNetCoreVersion)" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="$(AspNetCoreVersion)" />
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Hosting
|
|||
{
|
||||
return hostBuilder.ConfigureServices(services => {
|
||||
services.AddSingleton<IServer, MessagePump>();
|
||||
services.AddAuthenticationCore();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -26,8 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
|
|
@ -48,8 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Basic)]
|
||||
public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}))
|
||||
|
|
@ -67,8 +65,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Basic)]
|
||||
public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
|
|
@ -117,9 +114,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
|
|
@ -153,8 +149,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /* AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_RequireAuth_Success(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
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]
|
||||
[InlineData(AuthenticationSchemes.Negotiate)]
|
||||
[InlineData(AuthenticationSchemes.NTLM)]
|
||||
|
|
@ -230,18 +170,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
foreach (var scheme in authTypeList)
|
||||
{
|
||||
var authResults = await httpContext.Authentication.AuthenticateAsync(scheme);
|
||||
Assert.Null(authResults);
|
||||
}
|
||||
var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
Assert.False(authResults.Succeeded);
|
||||
Assert.True(authResults.Nothing);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
|
|
@ -258,23 +195,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, async httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, async httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
Assert.NotNull(httpContext.User.Identity);
|
||||
Assert.True(httpContext.User.Identity.IsAuthenticated);
|
||||
var count = 0;
|
||||
foreach (var scheme in authTypeList)
|
||||
{
|
||||
var authResults = await httpContext.Authentication.AuthenticateAsync(scheme);
|
||||
if (authResults != null)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
Assert.Equal(1, count);
|
||||
var authResults = await httpContext.AuthenticateAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
Assert.True(authResults.Succeeded);
|
||||
}))
|
||||
{
|
||||
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)]
|
||||
public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
return httpContext.Authentication.ChallengeAsync();
|
||||
return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
|
|
@ -314,17 +240,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
foreach (var scheme in authTypeList)
|
||||
{
|
||||
await httpContext.Authentication.ChallengeAsync(scheme);
|
||||
}
|
||||
await httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
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).")]
|
||||
[InlineData(AuthenticationSchemes.Negotiate)]
|
||||
[InlineData(AuthenticationSchemes.NTLM)]
|
||||
// [InlineData(AuthenticationSchemes.Digest)]
|
||||
[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 authTypes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM | /*AuthenticationSchemes.Digest |*/ AuthenticationSchemes.Basic;
|
||||
using (Utilities.CreateHttpAuthServer(authTypes, AllowAnoymous, out address, httpContext =>
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (var server = Utilities.CreateDynamicHost(authType, AllowAnoymous, out var address, httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
Assert.NotNull(httpContext.User.Identity);
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
return httpContext.Authentication.ChallengeAsync(authType.ToString());
|
||||
return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Equal(1, 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);
|
||||
Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -389,14 +306,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[InlineData(AuthenticationSchemes.Basic)]
|
||||
public async Task AuthTypes_Forbid_Forbidden(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
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.Identity);
|
||||
Assert.False(httpContext.User.Identity.IsAuthenticated);
|
||||
return httpContext.Authentication.ForbidAsync(authType.ToString());
|
||||
return httpContext.ForbidAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(address);
|
||||
|
|
@ -412,13 +328,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// [InlineData(AuthenticationSchemes.Basic)] // Can't log in with UseDefaultCredentials
|
||||
public async Task AuthTypes_ChallengeAuthenticatedAuthType_Forbidden(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
Assert.NotNull(httpContext.User.Identity);
|
||||
Assert.True(httpContext.User.Identity.IsAuthenticated);
|
||||
return httpContext.Authentication.ChallengeAsync(authType.ToString());
|
||||
return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
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
|
||||
public async Task AuthTypes_ChallengeAuthenticatedAuthTypeWithEmptyChallenge_Forbidden(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
Assert.NotNull(httpContext.User.Identity);
|
||||
Assert.True(httpContext.User.Identity.IsAuthenticated);
|
||||
return httpContext.Authentication.ChallengeAsync();
|
||||
return httpContext.ChallengeAsync(HttpSysDefaults.AuthenticationScheme);
|
||||
}))
|
||||
{
|
||||
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
|
||||
public async Task AuthTypes_UnathorizedAuthenticatedAuthType_Unauthorized(AuthenticationSchemes authType)
|
||||
{
|
||||
string address;
|
||||
using (Utilities.CreateHttpAuthServer(authType, DenyAnoymous, out address, httpContext =>
|
||||
using (var server = Utilities.CreateDynamicHost(authType, DenyAnoymous, out var address, httpContext =>
|
||||
{
|
||||
Assert.NotNull(httpContext.User);
|
||||
Assert.NotNull(httpContext.User.Identity);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var serverAddress = "http://localhost:11001/";
|
||||
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>();
|
||||
serverAddressesFeature.Addresses.Add(overrideAddress);
|
||||
|
|
@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
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>();
|
||||
serverAddressesFeature.Addresses.Add(overrideAddress);
|
||||
|
|
@ -58,7 +59,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
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>();
|
||||
serverAddressesFeature.PreferHostingUrls = true;
|
||||
|
|
@ -79,7 +80,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
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>();
|
||||
serverAddressesFeature.Addresses.Add(serverAddress);
|
||||
|
|
@ -96,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
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>();
|
||||
serverAddressesFeature.Addresses.Add(serverAddress);
|
||||
|
|
@ -108,12 +109,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[ConditionalFact]
|
||||
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();
|
||||
|
||||
Assert.Equal(Constants.DefaultServerAddress, server.Features.Get<IServerAddressesFeature>().Addresses.Single());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
using System;
|
||||
|
|
@ -9,6 +9,7 @@ using System.Net.Sockets;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
|
@ -306,7 +307,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app);
|
||||
dynamicServer.Dispose();
|
||||
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" })
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -289,7 +288,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
string address;
|
||||
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.RequestQueueLimit = 1001;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
|
||||
using System;
|
||||
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.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -38,6 +42,50 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
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)
|
||||
{
|
||||
lock (PortLock)
|
||||
|
|
@ -50,7 +98,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
root = prefix.Scheme + "://" + prefix.Host + ":" + prefix.Port;
|
||||
baseAddress = prefix.ToString();
|
||||
|
||||
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory());
|
||||
var server = CreatePump();
|
||||
server.Features.Get<IServerAddressesFeature>().Addresses.Add(baseAddress);
|
||||
server.Listener.Options.Authentication.Schemes = authType;
|
||||
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)
|
||||
{
|
||||
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.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
|
||||
return server;
|
||||
|
|
|
|||
Loading…
Reference in New Issue