Enable custom auth challenges. Integrate IAuthenticationHandler.
This commit is contained in:
parent
0e197a59ed
commit
e15fe540a8
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc.
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
|
||||
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
||||
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
||||
// NON-INFRINGEMENT.
|
||||
// See the Apache 2 License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="AuthenticationManager.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.HttpFeature.Security;
|
||||
using Microsoft.Net.Server;
|
||||
|
||||
namespace Microsoft.AspNet.Server.WebListener
|
||||
{
|
||||
internal class AuthenticationHandler : IAuthenticationHandler
|
||||
{
|
||||
private RequestContext _requestContext;
|
||||
private AuthenticationTypes _authTypes;
|
||||
private AuthenticationTypes _customChallenges;
|
||||
|
||||
internal AuthenticationHandler(RequestContext requestContext)
|
||||
{
|
||||
_requestContext = requestContext;
|
||||
_authTypes = requestContext.AuthenticationChallenges;
|
||||
_customChallenges = AuthenticationTypes.None;
|
||||
}
|
||||
|
||||
public void Authenticate(IAuthenticateContext context)
|
||||
{
|
||||
var user = _requestContext.User;
|
||||
var identity = user == null ? null : (ClaimsIdentity)user.Identity;
|
||||
|
||||
foreach (var authType in ListEnabledAuthTypes())
|
||||
{
|
||||
string authString = authType.ToString();
|
||||
if (context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal))
|
||||
{
|
||||
if (identity != null && identity.IsAuthenticated
|
||||
&& string.Equals(authString, identity.AuthenticationType, StringComparison.Ordinal))
|
||||
{
|
||||
context.Authenticated((ClaimsIdentity)user.Identity, properties: null, description: GetDescription(user.Identity.AuthenticationType));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.NotAuthenticated(authString, properties: null, description: GetDescription(user.Identity.AuthenticationType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task AuthenticateAsync(IAuthenticateContext context)
|
||||
{
|
||||
Authenticate(context);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Challenge(IChallengeContext context)
|
||||
{
|
||||
foreach (var authType in ListEnabledAuthTypes())
|
||||
{
|
||||
var authString = authType.ToString();
|
||||
// Not including any auth types means it's a blanket challenge for any auth type.
|
||||
if (context.AuthenticationTypes == null || context.AuthenticationTypes.Count == 0
|
||||
|| context.AuthenticationTypes.Contains(authString, StringComparer.Ordinal))
|
||||
{
|
||||
_customChallenges |= authType;
|
||||
context.Accept(authString, GetDescription(authType.ToString()));
|
||||
}
|
||||
}
|
||||
// A challenge was issued, it overrides any pre-set auth types.
|
||||
_requestContext.AuthenticationChallenges = _customChallenges;
|
||||
}
|
||||
|
||||
public void GetDescriptions(IAuthTypeContext context)
|
||||
{
|
||||
// TODO: Caching, this data doesn't change per request.
|
||||
foreach (var authType in ListEnabledAuthTypes())
|
||||
{
|
||||
context.Accept(GetDescription(authType.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
public void SignIn(ISignInContext context)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
public void SignOut(ISignOutContext context)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
private IDictionary<string, object> GetDescription(string authenticationType)
|
||||
{
|
||||
return new Dictionary<string, object>()
|
||||
{
|
||||
{ "AuthenticationType", authenticationType },
|
||||
{ "Caption", "Windows:" + authenticationType },
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<AuthenticationTypes> ListEnabledAuthTypes()
|
||||
{
|
||||
// Order by strength.
|
||||
if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos)
|
||||
{
|
||||
yield return AuthenticationTypes.Kerberos;
|
||||
}
|
||||
if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate)
|
||||
{
|
||||
yield return AuthenticationTypes.Negotiate;
|
||||
}
|
||||
if ((_authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM)
|
||||
{
|
||||
yield return AuthenticationTypes.NTLM;
|
||||
}
|
||||
/*if ((_authTypes & AuthenticationTypes.Digest) == AuthenticationTypes.Digest)
|
||||
{
|
||||
// TODO:
|
||||
throw new NotImplementedException("Digest challenge generation has not been implemented.");
|
||||
yield return AuthenticationTypes.Digest;
|
||||
}*/
|
||||
if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic)
|
||||
{
|
||||
yield return AuthenticationTypes.Basic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,6 +70,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
{
|
||||
_requestContext = requestContext;
|
||||
_features = new FeatureCollection();
|
||||
_authHandler = new AuthenticationHandler(requestContext);
|
||||
PopulateFeatures();
|
||||
}
|
||||
|
||||
|
|
@ -109,14 +110,11 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
_features.Add(typeof(IHttpWebSocketFeature), this);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// _environment.CallCancelled = _cts.Token;
|
||||
// _environment.User = _request.User;
|
||||
// Channel binding
|
||||
|
||||
// TODO:
|
||||
/*
|
||||
// Server
|
||||
Server
|
||||
_environment.Listener = _server;
|
||||
Channel binding
|
||||
_environment.ConnectionId = _request.ConnectionId;
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyNeutralAttribute.cs" />
|
||||
<Compile Include="AuthenticationHandler.cs" />
|
||||
<Compile Include="FeatureContext.cs" />
|
||||
<Compile Include="Helpers.cs" />
|
||||
<Compile Include="LogHelper.cs" />
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ namespace Microsoft.Net.Server
|
|||
}
|
||||
set
|
||||
{
|
||||
if (_authTypes == AuthenticationTypes.None)
|
||||
{
|
||||
throw new ArgumentException("value", "'None' is not a valid authentication type. Use 'AllowAnonymous' instead.");
|
||||
}
|
||||
_authTypes = value;
|
||||
SetServerSecurity();
|
||||
}
|
||||
|
|
@ -106,22 +110,25 @@ namespace Microsoft.Net.Server
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: If we're not going to support Digest then this whole list can be pre-computed and cached.
|
||||
// consider even pre-serialzing and caching the bytes for the !AllowAnonymous scenario.
|
||||
internal IList<string> GenerateChallenges()
|
||||
internal static IList<string> GenerateChallenges(AuthenticationTypes authTypes)
|
||||
{
|
||||
IList<string> challenges = new List<string>();
|
||||
|
||||
if (authTypes == AuthenticationTypes.None)
|
||||
{
|
||||
return challenges;
|
||||
}
|
||||
|
||||
// Order by strength.
|
||||
if ((_authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos)
|
||||
if ((authTypes & AuthenticationTypes.Kerberos) == AuthenticationTypes.Kerberos)
|
||||
{
|
||||
challenges.Add("Kerberos");
|
||||
}
|
||||
if ((_authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate)
|
||||
if ((authTypes & AuthenticationTypes.Negotiate) == AuthenticationTypes.Negotiate)
|
||||
{
|
||||
challenges.Add("Negotiate");
|
||||
}
|
||||
if ((_authTypes & AuthenticationTypes.Ntlm) == AuthenticationTypes.Ntlm)
|
||||
if ((authTypes & AuthenticationTypes.NTLM) == AuthenticationTypes.NTLM)
|
||||
{
|
||||
challenges.Add("NTLM");
|
||||
}
|
||||
|
|
@ -131,7 +138,7 @@ namespace Microsoft.Net.Server
|
|||
throw new NotImplementedException("Digest challenge generation has not been implemented.");
|
||||
// challenges.Add("Digest");
|
||||
}*/
|
||||
if ((_authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic)
|
||||
if ((authTypes & AuthenticationTypes.Basic) == AuthenticationTypes.Basic)
|
||||
{
|
||||
// TODO: Realm
|
||||
challenges.Add("Basic");
|
||||
|
|
@ -139,9 +146,9 @@ namespace Microsoft.Net.Server
|
|||
return challenges;
|
||||
}
|
||||
|
||||
internal void SetAuthenticationChallenge(Response response)
|
||||
internal void SetAuthenticationChallenge(RequestContext context)
|
||||
{
|
||||
IList<string> challenges = GenerateChallenges();
|
||||
IList<string> challenges = GenerateChallenges(context.AuthenticationChallenges);
|
||||
|
||||
if (challenges.Count > 0)
|
||||
{
|
||||
|
|
@ -149,7 +156,7 @@ namespace Microsoft.Net.Server
|
|||
// Append to the existing header, if any. Some clients (IE, Chrome) require each challenges to be sent on their own line/header.
|
||||
string[] oldValues;
|
||||
string[] newValues;
|
||||
if (response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues))
|
||||
if (context.Response.Headers.TryGetValue(HttpKnownHeaderNames.WWWAuthenticate, out oldValues))
|
||||
{
|
||||
newValues = new string[oldValues.Length + challenges.Count];
|
||||
Array.Copy(oldValues, newValues, oldValues.Length);
|
||||
|
|
@ -160,7 +167,7 @@ namespace Microsoft.Net.Server
|
|||
newValues = new string[challenges.Count];
|
||||
challenges.CopyTo(newValues, 0);
|
||||
}
|
||||
response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues;
|
||||
context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate] = newValues;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,10 +191,30 @@ namespace Microsoft.Net.Server
|
|||
&& requestInfo->pInfo->AuthStatus == UnsafeNclNativeMethods.HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
|
||||
{
|
||||
#if NET45
|
||||
return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken));
|
||||
return new WindowsPrincipal(new WindowsIdentity(requestInfo->pInfo->AccessToken,
|
||||
GetAuthTypeFromRequest(requestInfo->pInfo->AuthType).ToString()));
|
||||
#endif
|
||||
}
|
||||
return new ClaimsPrincipal(new ClaimsIdentity(string.Empty)); // Anonymous / !IsAuthenticated
|
||||
return new ClaimsPrincipal(new ClaimsIdentity()); // Anonymous / !IsAuthenticated
|
||||
}
|
||||
|
||||
private static AuthenticationTypes GetAuthTypeFromRequest(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE input)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic:
|
||||
return AuthenticationTypes.Basic;
|
||||
// case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest:
|
||||
// return AuthenticationTypes.Digest;
|
||||
case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM:
|
||||
return AuthenticationTypes.NTLM;
|
||||
case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate:
|
||||
return AuthenticationTypes.Negotiate;
|
||||
case UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos:
|
||||
return AuthenticationTypes.Kerberos;
|
||||
default:
|
||||
throw new NotImplementedException(input.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ namespace Microsoft.Net.Server
|
|||
[Flags]
|
||||
public enum AuthenticationTypes
|
||||
{
|
||||
// None = 0x0, // None is invalid, use AllowAnonymous (which must have a non-zero value).
|
||||
None = 0x0,
|
||||
Basic = 0x1,
|
||||
// Digest = 0x2, // TODO: Verify this is no longer supported by Http.Sys
|
||||
Ntlm = 0x4,
|
||||
NTLM = 0x4,
|
||||
Negotiate = 0x8,
|
||||
Kerberos = 0x10,
|
||||
AllowAnonymous = 0x1000
|
||||
|
|
|
|||
|
|
@ -45,14 +45,15 @@ namespace Microsoft.Net.Server
|
|||
private CancellationTokenSource _requestAbortSource;
|
||||
private CancellationToken? _disconnectToken;
|
||||
|
||||
internal RequestContext(WebListener httpListener, NativeRequestContext memoryBlob)
|
||||
internal RequestContext(WebListener server, NativeRequestContext memoryBlob)
|
||||
{
|
||||
// TODO: Verbose log
|
||||
_server = httpListener;
|
||||
_server = server;
|
||||
_memoryBlob = memoryBlob;
|
||||
_request = new Request(this, _memoryBlob);
|
||||
_response = new Response(this);
|
||||
_request.ReleasePins();
|
||||
AuthenticationChallenges = server.AuthenticationManager.AuthenticationTypes & ~AuthenticationTypes.AllowAnonymous;
|
||||
}
|
||||
|
||||
public Request Request
|
||||
|
|
@ -129,6 +130,12 @@ namespace Microsoft.Net.Server
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication challengest that will be added to the response if the status code is 401.
|
||||
/// This must be a subset of the AuthenticationTypes enabled on the server.
|
||||
/// </summary>
|
||||
public AuthenticationTypes AuthenticationChallenges { get; set; }
|
||||
|
||||
public bool IsUpgradableRequest
|
||||
{
|
||||
get { return _request.IsUpgradable; }
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ namespace Microsoft.Net.Server
|
|||
// 401
|
||||
if (StatusCode == (ushort)HttpStatusCode.Unauthorized)
|
||||
{
|
||||
RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(this);
|
||||
RequestContext.Server.AuthenticationManager.SetAuthenticationChallenge(RequestContext);
|
||||
}
|
||||
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE;
|
||||
|
|
|
|||
|
|
@ -661,7 +661,8 @@ namespace Microsoft.Net.Server
|
|||
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob;
|
||||
if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo))
|
||||
{
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized, AuthenticationManager.GenerateChallenges());
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized,
|
||||
AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationTypes));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -31,12 +32,13 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
private const string Address = "http://localhost:8080/";
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.AllowAnonymous)]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType)
|
||||
{
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
|
|
@ -56,7 +58,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType)
|
||||
|
|
@ -75,7 +77,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType)
|
||||
|
|
@ -101,7 +103,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
using (Utilities.CreateAuthServer(
|
||||
AuthenticationTypes.Kerberos
|
||||
| AuthenticationTypes.Negotiate
|
||||
| AuthenticationTypes.Ntlm
|
||||
| AuthenticationTypes.NTLM
|
||||
/* | AuthenticationTypes.Digest TODO: Not implemented */
|
||||
| AuthenticationTypes.Basic
|
||||
| AuthenticationTypes.AllowAnonymous,
|
||||
|
|
@ -123,10 +125,10 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
// [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType)
|
||||
{
|
||||
int requestId = 0;
|
||||
|
|
@ -159,10 +161,10 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
// [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /* AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType)
|
||||
{
|
||||
using (Utilities.CreateAuthServer(authType, env =>
|
||||
|
|
@ -178,6 +180,216 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.AllowAnonymous)]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
// [InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_GetSingleDescriptions(AuthenticationTypes authType)
|
||||
{
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
var resultList = context.GetAuthenticationTypes();
|
||||
if (authType == AuthenticationTypes.AllowAnonymous)
|
||||
{
|
||||
Assert.Equal(0, resultList.Count());
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(1, resultList.Count());
|
||||
var result = resultList.First();
|
||||
Assert.Equal(authType.ToString(), result.AuthenticationType);
|
||||
Assert.Equal("Windows:" + authType.ToString(), result.Caption);
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AuthTypes_GetMultipleDescriptions()
|
||||
{
|
||||
AuthenticationTypes authType =
|
||||
AuthenticationTypes.Kerberos
|
||||
| AuthenticationTypes.Negotiate
|
||||
| AuthenticationTypes.NTLM
|
||||
| /*AuthenticationTypes.Digest
|
||||
|*/ AuthenticationTypes.Basic;
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
var resultList = context.GetAuthenticationTypes();
|
||||
Assert.Equal(4, resultList.Count());
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AuthenticateWithNoUser_NoResults(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
var authResults = context.Authenticate(authTypeList);
|
||||
Assert.False(authResults.Any());
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
// [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AuthenticateWithUser_OneResult(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateAuthServer(authType, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
var authResults = context.Authenticate(authTypeList);
|
||||
Assert.Equal(1, authResults.Count());
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address, useDefaultCredentials: true);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_ChallengeWithoutAuthTypes_AllChallengesSent(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
context.Response.Challenge();
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_ChallengeWithAllAuthTypes_AllChallengesSent(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
context.Response.Challenge(authTypeList);
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Equal(authTypeList.Count(), response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_ChallengeOneAuthType_OneChallengeSent(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic;
|
||||
using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
context.Response.Challenge(authType.ToString());
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_ChallengeDisabledAuthType_Error(AuthenticationTypes authType)
|
||||
{
|
||||
var authTypes = AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic;
|
||||
authTypes = authTypes & ~authType;
|
||||
var authTypeList = authType.ToString().Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
using (Utilities.CreateAuthServer(authTypes | AuthenticationTypes.AllowAnonymous, env =>
|
||||
{
|
||||
var context = new DefaultHttpContext((IFeatureCollection)env);
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.Challenge(authType.ToString()));
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
var response = await SendRequestAsync(Address);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Equal(0, response.Headers.WwwAuthenticate.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool useDefaultCredentials = false)
|
||||
{
|
||||
HttpClientHandler handler = new HttpClientHandler();
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ namespace Microsoft.Net.Server
|
|||
[InlineData(AuthenticationTypes.AllowAnonymous)]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)]
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationTypes.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymous_NoChallenge(AuthenticationTypes authType)
|
||||
{
|
||||
using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous))
|
||||
|
|
@ -29,6 +29,14 @@ namespace Microsoft.Net.Server
|
|||
var context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
if (authType == AuthenticationTypes.AllowAnonymous)
|
||||
{
|
||||
Assert.Equal(AuthenticationTypes.None, context.AuthenticationChallenges);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
}
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -40,7 +48,7 @@ namespace Microsoft.Net.Server
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationType.Digest)] // TODO: Not implemented
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthType_RequireAuth_ChallengesAdded(AuthenticationTypes authType)
|
||||
|
|
@ -60,7 +68,7 @@ namespace Microsoft.Net.Server
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
[InlineData(AuthenticationTypes.Basic)]
|
||||
public async Task AuthType_AllowAnonymousButSpecify401_ChallengesAdded(AuthenticationTypes authType)
|
||||
|
|
@ -72,6 +80,7 @@ namespace Microsoft.Net.Server
|
|||
var context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -84,19 +93,20 @@ namespace Microsoft.Net.Server
|
|||
[Fact]
|
||||
public async Task MultipleAuthTypes_AllowAnonymousButSpecify401_ChallengesAdded()
|
||||
{
|
||||
using (var server = Utilities.CreateAuthServer(
|
||||
AuthenticationTypes authType =
|
||||
AuthenticationTypes.Kerberos
|
||||
| AuthenticationTypes.Negotiate
|
||||
| AuthenticationTypes.Ntlm
|
||||
| AuthenticationTypes.NTLM
|
||||
/* | AuthenticationTypes.Digest TODO: Not implemented */
|
||||
| AuthenticationTypes.Basic
|
||||
| AuthenticationTypes.AllowAnonymous))
|
||||
| AuthenticationTypes.Basic;
|
||||
using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(Address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -109,10 +119,10 @@ namespace Microsoft.Net.Server
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
// [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_AllowAnonymousButSpecify401_Success(AuthenticationTypes authType)
|
||||
{
|
||||
using (var server = Utilities.CreateAuthServer(authType | AuthenticationTypes.AllowAnonymous))
|
||||
|
|
@ -122,12 +132,14 @@ namespace Microsoft.Net.Server
|
|||
var context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -138,10 +150,10 @@ namespace Microsoft.Net.Server
|
|||
[Theory]
|
||||
[InlineData(AuthenticationTypes.Kerberos)]
|
||||
[InlineData(AuthenticationTypes.Negotiate)]
|
||||
[InlineData(AuthenticationTypes.Ntlm)]
|
||||
[InlineData(AuthenticationTypes.NTLM)]
|
||||
// [InlineData(AuthenticationTypes.Digest)] // TODO: Not implemented
|
||||
// [InlineData(AuthenticationTypes.Basic)] // Doesn't work with default creds
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.Ntlm | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)]
|
||||
[InlineData(AuthenticationTypes.Kerberos | AuthenticationTypes.Negotiate | AuthenticationTypes.NTLM | /*AuthenticationType.Digest |*/ AuthenticationTypes.Basic)]
|
||||
public async Task AuthTypes_RequireAuth_Success(AuthenticationTypes authType)
|
||||
{
|
||||
using (var server = Utilities.CreateAuthServer(authType))
|
||||
|
|
@ -151,6 +163,7 @@ namespace Microsoft.Net.Server
|
|||
var context = await server.GetContextAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
|
|||
Loading…
Reference in New Issue