#1 Implement a full authentication handler.
This commit is contained in:
parent
348ab7c943
commit
2fe2e0d841
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features.Authentication;
|
||||
|
||||
namespace Microsoft.AspNet.IISPlatformHandler
|
||||
{
|
||||
internal class AuthenticationHandler : IAuthenticationHandler
|
||||
{
|
||||
internal AuthenticationHandler(HttpContext httpContext, IISPlatformHandlerOptions options, ClaimsPrincipal user)
|
||||
{
|
||||
HttpContext = httpContext;
|
||||
User = user;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
internal HttpContext HttpContext { get; }
|
||||
|
||||
internal IISPlatformHandlerOptions Options { get; }
|
||||
|
||||
internal ClaimsPrincipal User { get; }
|
||||
|
||||
internal IAuthenticationHandler PriorHandler { get; set; }
|
||||
|
||||
public Task AuthenticateAsync(AuthenticateContext context)
|
||||
{
|
||||
if (ShouldHandleScheme(context.AuthenticationScheme))
|
||||
{
|
||||
if (User != null)
|
||||
{
|
||||
context.Authenticated(User, properties: null,
|
||||
description: Options.AuthenticationDescriptions.Where(descrip =>
|
||||
string.Equals(User.Identity.AuthenticationType, descrip.AuthenticationScheme, StringComparison.Ordinal)).FirstOrDefault()?.Items);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.NotAuthenticated();
|
||||
}
|
||||
}
|
||||
|
||||
if (PriorHandler != null)
|
||||
{
|
||||
return PriorHandler.AuthenticateAsync(context);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task ChallengeAsync(ChallengeContext context)
|
||||
{
|
||||
bool handled = false;
|
||||
if (ShouldHandleScheme(context.AuthenticationScheme))
|
||||
{
|
||||
switch (context.Behavior)
|
||||
{
|
||||
case ChallengeBehavior.Automatic:
|
||||
// If there is a principal already, invoke the forbidden code path
|
||||
if (User == null)
|
||||
{
|
||||
goto case ChallengeBehavior.Unauthorized;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto case ChallengeBehavior.Forbidden;
|
||||
}
|
||||
case ChallengeBehavior.Unauthorized:
|
||||
HttpContext.Response.StatusCode = 401;
|
||||
// We would normally set the www-authenticate header here, but IIS does that for us.
|
||||
break;
|
||||
case ChallengeBehavior.Forbidden:
|
||||
HttpContext.Response.StatusCode = 403;
|
||||
handled = true; // No other handlers need to consider this challenge.
|
||||
break;
|
||||
}
|
||||
context.Accept();
|
||||
}
|
||||
|
||||
if (!handled && PriorHandler != null)
|
||||
{
|
||||
return PriorHandler.ChallengeAsync(context);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void GetDescriptions(DescribeSchemesContext context)
|
||||
{
|
||||
foreach (var description in Options.AuthenticationDescriptions)
|
||||
{
|
||||
context.Accept(description.Items);
|
||||
}
|
||||
|
||||
if (PriorHandler != null)
|
||||
{
|
||||
PriorHandler.GetDescriptions(context);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SignInAsync(SignInContext context)
|
||||
{
|
||||
// Not supported, fall through
|
||||
if (PriorHandler != null)
|
||||
{
|
||||
return PriorHandler.SignInAsync(context);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SignOutAsync(SignOutContext context)
|
||||
{
|
||||
// Not supported, fall through
|
||||
if (PriorHandler != null)
|
||||
{
|
||||
return PriorHandler.SignOutAsync(context);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private bool ShouldHandleScheme(string authenticationScheme)
|
||||
{
|
||||
if (Options.AutomaticAuthentication && string.IsNullOrEmpty(authenticationScheme))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
foreach (var description in Options.AuthenticationDescriptions)
|
||||
{
|
||||
if (string.Equals(description.AuthenticationScheme, authenticationScheme, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.IISPlatformHandler
|
||||
{
|
||||
public class IISPlatformHandlerDefaults
|
||||
{
|
||||
public const string Negotiate = "Negotiate";
|
||||
public const string Ntlm = "NTLM";
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,18 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Http.Features.Authentication;
|
||||
using Microsoft.AspNet.Http.Features.Authentication.Internal;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNet.IISPlatformHandler
|
||||
{
|
||||
|
|
@ -22,13 +27,44 @@ namespace Microsoft.AspNet.IISPlatformHandler
|
|||
private const string XOriginalIPName = "X-Original-IP";
|
||||
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IISPlatformHandlerOptions _options;
|
||||
|
||||
public IISPlatformHandlerMiddleware(RequestDelegate next)
|
||||
public IISPlatformHandlerMiddleware(RequestDelegate next, IISPlatformHandlerOptions options)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(next));
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
_next = next;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public Task Invoke(HttpContext httpContext)
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
UpdateScheme(httpContext);
|
||||
|
||||
UpdateRemoteIp(httpContext);
|
||||
|
||||
var winPrincipal = UpdateUser(httpContext);
|
||||
|
||||
var handler = new AuthenticationHandler(httpContext, _options, winPrincipal);
|
||||
AttachAuthenticationHandler(handler);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(httpContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DetachAuthenticationhandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateScheme(HttpContext httpContext)
|
||||
{
|
||||
var xForwardProtoHeaderValue = httpContext.Request.Headers[XForwardedProtoHeaderName];
|
||||
if (!string.IsNullOrEmpty(xForwardProtoHeaderValue))
|
||||
|
|
@ -39,7 +75,10 @@ namespace Microsoft.AspNet.IISPlatformHandler
|
|||
}
|
||||
httpContext.Request.Scheme = xForwardProtoHeaderValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void UpdateRemoteIp(HttpContext httpContext)
|
||||
{
|
||||
var xForwardedForHeaderValue = httpContext.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName);
|
||||
if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0)
|
||||
{
|
||||
|
|
@ -54,32 +93,62 @@ namespace Microsoft.AspNet.IISPlatformHandler
|
|||
httpContext.Connection.RemoteIpAddress = ipFromHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WindowsPrincipal UpdateUser(HttpContext httpContext)
|
||||
{
|
||||
var xIISWindowsAuthToken = httpContext.Request.Headers[XIISWindowsAuthToken];
|
||||
int hexHandle;
|
||||
WindowsPrincipal winPrincipal = null;
|
||||
if (!StringValues.IsNullOrEmpty(xIISWindowsAuthToken)
|
||||
&& int.TryParse(xIISWindowsAuthToken, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hexHandle))
|
||||
{
|
||||
// Always create the identity if the handle exists, we need to dispose it so it does not leak.
|
||||
var handle = new IntPtr(hexHandle);
|
||||
var winIdentity = new WindowsIdentity(handle);
|
||||
|
||||
// WindowsIdentity just duplicated the handle so we need to close the original.
|
||||
NativeMethods.CloseHandle(handle);
|
||||
|
||||
httpContext.Response.RegisterForDispose(winIdentity);
|
||||
var winPrincipal = new WindowsPrincipal(winIdentity);
|
||||
winPrincipal = new WindowsPrincipal(winIdentity);
|
||||
|
||||
var existingPrincipal = httpContext.User;
|
||||
if (existingPrincipal != null)
|
||||
if (_options.AutomaticAuthentication)
|
||||
{
|
||||
httpContext.User = SecurityHelper.MergeUserPrincipal(existingPrincipal, winPrincipal);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpContext.User = winPrincipal;
|
||||
var existingPrincipal = httpContext.User;
|
||||
if (existingPrincipal != null)
|
||||
{
|
||||
httpContext.User = SecurityHelper.MergeUserPrincipal(existingPrincipal, winPrincipal);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpContext.User = winPrincipal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _next(httpContext);
|
||||
return winPrincipal;
|
||||
}
|
||||
|
||||
private void AttachAuthenticationHandler(AuthenticationHandler handler)
|
||||
{
|
||||
var auth = handler.HttpContext.Features.Get<IHttpAuthenticationFeature>();
|
||||
if (auth == null)
|
||||
{
|
||||
auth = new HttpAuthenticationFeature();
|
||||
handler.HttpContext.Features.Set(auth);
|
||||
}
|
||||
handler.PriorHandler = auth.Handler;
|
||||
auth.Handler = handler;
|
||||
}
|
||||
|
||||
private void DetachAuthenticationhandler(AuthenticationHandler handler)
|
||||
{
|
||||
var auth = handler.HttpContext.Features.Get<IHttpAuthenticationFeature>();
|
||||
if (auth != null)
|
||||
{
|
||||
auth.Handler = handler.PriorHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.IISPlatformHandler;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
|
|
@ -13,9 +14,56 @@ namespace Microsoft.AspNet.Builder
|
|||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseIISPlatformHandler(this IApplicationBuilder builder)
|
||||
public static IApplicationBuilder UseIISPlatformHandler(this IApplicationBuilder app)
|
||||
{
|
||||
return builder.UseMiddleware<IISPlatformHandlerMiddleware>();
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<IISPlatformHandlerMiddleware>(new IISPlatformHandlerOptions());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds middleware for interacting with the IIS HttpPlatformHandler reverse proxy module.
|
||||
/// This will handle forwarded Windows Authentication, request scheme, remote IPs, etc..
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseIISPlatformHandler(this IApplicationBuilder app, IISPlatformHandlerOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<IISPlatformHandlerMiddleware>(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds middleware for interacting with the IIS HttpPlatformHandler reverse proxy module.
|
||||
/// This will handle forwarded Windows Authentication, request scheme, remote IPs, etc..
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseIISPlatformHandler(this IApplicationBuilder app, Action<IISPlatformHandlerOptions> configureOptions)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
var options = new IISPlatformHandlerOptions();
|
||||
if (configureOptions != null)
|
||||
{
|
||||
configureOptions(options);
|
||||
}
|
||||
|
||||
return app.UseIISPlatformHandler(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
|
||||
namespace Microsoft.AspNet.IISPlatformHandler
|
||||
{
|
||||
public class IISPlatformHandlerOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// If true the authentication middleware alter the request user coming in and respond to generic challenges.
|
||||
/// If false the authentication middleware will only provide identity and respond to challenges when explicitly indicated
|
||||
/// by the AuthenticationScheme.
|
||||
/// </summary>
|
||||
public bool AutomaticAuthentication { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Additional information about the authentication type which is made available to the application.
|
||||
/// </summary>
|
||||
public IList<AuthenticationDescription> AuthenticationDescriptions { get; } = new List<AuthenticationDescription>()
|
||||
{
|
||||
new AuthenticationDescription()
|
||||
{
|
||||
AuthenticationScheme = IISPlatformHandlerDefaults.Negotiate,
|
||||
DisplayName = IISPlatformHandlerDefaults.Negotiate
|
||||
},
|
||||
new AuthenticationDescription()
|
||||
{
|
||||
AuthenticationScheme = IISPlatformHandlerDefaults.Ntlm,
|
||||
DisplayName = IISPlatformHandlerDefaults.Ntlm
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -4,17 +4,15 @@
|
|||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>abe53415-83ce-4af0-af67-e52160c7862b</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNet.PlatformHandler</RootNamespace>
|
||||
<RootNamespace>Microsoft.AspNet.IISPlatformHandler</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
"url": "git://github.com/aspnet/IISIntegration"
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Http": "1.0.0-*",
|
||||
"Microsoft.AspNet.Http.Extensions": "1.0.0-*",
|
||||
"Microsoft.Extensions.SecurityHelper.Sources": {
|
||||
"type": "build",
|
||||
|
|
|
|||
|
|
@ -1027,12 +1027,11 @@
|
|||
</system.webServer>
|
||||
</location>
|
||||
|
||||
<!-- Prabht -->
|
||||
<location path="NtlmAuthenticationTestSite">
|
||||
<system.webServer>
|
||||
<security>
|
||||
<authentication>
|
||||
<anonymousAuthentication enabled="false" />
|
||||
<anonymousAuthentication enabled="true" />
|
||||
<windowsAuthentication enabled="true" />
|
||||
</authentication>
|
||||
</security>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ namespace Microsoft.AspNet.IISPlatformHandler.FunctionalTests
|
|||
// Uses ports ranging 5050 - 5060.
|
||||
public class NtlmAuthenticationTests
|
||||
{
|
||||
// TODO: The middleware needs to implement auth handlers.
|
||||
[ConditionalTheory, Trait("ServerComparison.FunctionalTests", "ServerComparison.FunctionalTests")]
|
||||
[ConditionalTheory]
|
||||
[OSSkipCondition(OperatingSystems.Linux)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, "http://localhost:5050/")]
|
||||
|
|
@ -42,7 +41,7 @@ namespace Microsoft.AspNet.IISPlatformHandler.FunctionalTests
|
|||
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger))
|
||||
{
|
||||
var deploymentResult = deployer.Deploy();
|
||||
var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true };
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) };
|
||||
|
||||
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
|
||||
|
|
@ -54,54 +53,60 @@ namespace Microsoft.AspNet.IISPlatformHandler.FunctionalTests
|
|||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
try
|
||||
{
|
||||
// TODO: Currently we do not implement mixed auth.
|
||||
// https://github.com/aspnet/IISIntegration/issues/1
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
// Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString());
|
||||
// Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString());
|
||||
|
||||
/*
|
||||
Assert.Equal("Hello World", responseText);
|
||||
|
||||
responseText = await httpClient.GetStringAsync("/Anonymous");
|
||||
response = await httpClient.GetAsync("/Anonymous");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Anonymous?True", responseText);
|
||||
|
||||
response = await httpClient.GetAsync("/Restricted");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString());
|
||||
Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString());
|
||||
|
||||
response = await httpClient.GetAsync("/RestrictedNTLM");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString());
|
||||
// Note we can't restrict a challenge to a specific auth type, the native auth modules always add themselves.
|
||||
Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString());
|
||||
|
||||
response = await httpClient.GetAsync("/Forbidden");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
*/
|
||||
// httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true };
|
||||
// httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) };
|
||||
|
||||
responseText = await httpClient.GetStringAsync("/Anonymous");
|
||||
Assert.Equal("Anonymous?False", responseText);
|
||||
httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true };
|
||||
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) };
|
||||
|
||||
response = await httpClient.GetAsync("/Anonymous");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("Anonymous?True", responseText);
|
||||
|
||||
/*
|
||||
response = await httpClient.GetAsync("/AutoForbid");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
|
||||
responseText = await httpClient.GetStringAsync("/Restricted");
|
||||
Assert.Equal("Negotiate", responseText);
|
||||
response = await httpClient.GetAsync("/Restricted");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Kerberos", responseText);
|
||||
|
||||
responseText = await httpClient.GetStringAsync("/RestrictedNegotiate");
|
||||
Assert.Equal("Negotiate", responseText);
|
||||
|
||||
response = await httpClient.GetAsync("/RestrictedNTLM");
|
||||
// This isn't a Forbidden because we authenticate with Negotiate and challenge for NTLM.
|
||||
response = await httpClient.GetAsync("/RestrictedNegotiate");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
// This is Forbidden because we authenticate with Kerberos and challenge for Negotiate.
|
||||
// Note we can't restrict a challenge to a specific auth type, the native auth modules always add themselves,
|
||||
// so both Negotiate and NTLM get sent again.
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
*/
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
|
||||
response = await httpClient.GetAsync("/RestrictedNTLM");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
// This is Forbidden because we authenticate with Kerberos and challenge for NTLM.
|
||||
// Note we can't restrict a challenge to a specific auth type, the native auth modules always add themselves,
|
||||
// so both Negotiate and NTLM get sent again.
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
}
|
||||
catch (XunitException)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue