The 401 WWW-Negotiate challenge happens for each request.
Steps to reproduce the behavior:
options.Authentication.Schemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.Negotiate;The 401 WWW-Negotiate challenge happens only the first time.
It looks like when using IIS it is possible to configure authPersistNonNTLM=true to achieve this. See https://blogs.msdn.microsoft.com/dsnotes/2014/02/11/iis-how-to-reduce-multiple-authentication-or-multiple-401-while-using-kerberos-for-authentication/
Performing the 401 challenge means more requests, more traffic, less performance.
authPersistNonNTLM is effectively enabled by default for HttpSys. Are you sure each request is arriving on the same connection?
@Tratcher I've checked with Wireshark and each request is opening a new TCP connection (so a total of 10). I guess the culrpit could be the HttpClient:
var httpHandler = new HttpClientHandler
{
UseDefaultCredentials = true
};
var client = new HttpClient(httpHandler);
client.BaseAddress = new Uri("http://host:5000/");
for (int i = 0; i < 10; i++)
{
try
{
HttpResponseMessage response = client.GetAsync("api/user").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Result: " + result);
}
catch (System.Exception ex)
{
Console.WriteLine(ex);
}
}
is there a way to force HttpClient to reuse the same connection?
Can you share the wireshark trace? We want to see who's closing the prior connection.
Also, is the client app also .NET Core 2.2 or something else? HttpClient has several implementations.
Client is .NET 4.5.2. I will upload the Wireshark trace as soon as possible.
Ah, for .NET 4.x you need to replace HttpClientHandler with WebRequestHandler and set UnsafeAuthenticatedConnectionSharing.
So I tried with:
var httpHandler = new WebRequestHandler
{
UseDefaultCredentials = true,
UnsafeAuthenticatedConnectionSharing = true
};
and the result is the same but using a single connection (both from Fiddler using the proxy and from Wireshark).
Using the same connection saves you at least 50% of the costs 馃榾.
Are the client and server on the same or different machines?
Everything is controlled by this structure:
https://docs.microsoft.com/en-us/windows/win32/api/http/ns-http-http_server_authentication_info
On localhost it only uses NTLM which has caching enabled by default and we don't disable (DisableNTLMCredentialCaching). If they're on different machines it could end up using Kerberos which has caching disabled by default and we don't enable (HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING).
Different machines, same domain, same domain user running the server and the client.
You're saying it's a genuine bug?
Different machines, same domain, same domain user running the server and the client.
You're saying it's a genuine bug?
An un-exposed feature, yes.
There's a new alternative in 3.0 using Kestrel if that's an option for you. It does have the options available to enable/disable this kind of caching.
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio#kestrel
https://github.com/aspnet/AspNetCore/blob/e0ee04237af2fa58a525dbd63888894f62195f0a/src/Security/Authentication/Negotiate/src/NegotiateOptions.cs
moving to 3.0 + Kestrel is not an option for us, until it's released and finalized.
moving to 3.0 + Kestrel is not an option for us, until it's released and finalized.
3.0 releases this month and already has go-live supported previews. Now is the time to try it to confirm it satisfies your scenarios.
https://github.com/dotnet/core/blob/master/roadmap.md
That's much sooner than this issue will be addressed in HttpSys.
To come at this from a different angle, shouldn't the use of UseDefaultCredentials tell HttpClient to send the credentials on the first attempt, thus preventing the 401 in the first place? Or is it supposed to still wait for the 401 first?
(I was helping with this question on Stack Overflow)
No, UseDefaultCredentials means to use the current WindowsIdentity if challenged for 401 Negotiate/NTLM/Kerberos. It means you don't have to give it the username and password manually.
We would accept a PR for this issue, but given our other priorities we're backlogging this for now.
Most helpful comment
No, UseDefaultCredentials means to use the current WindowsIdentity if challenged for 401 Negotiate/NTLM/Kerberos. It means you don't have to give it the username and password manually.