-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
.NET Core 2.1 SocketsHttpHandler proxy authentication using Windows auth is broken #26397
Comments
I ran: using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static void Main()
{
var handler = new HttpClientHandler();
handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
var client = new HttpClient(handler);
var response = client.GetAsync("https://www.mocky.io/v2/5185415ba171ea3a00704eed").GetAwaiter().GetResult();
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine(content);
}
} on both 2.0 and 2.1 on Windows, and on both I get:
What am I supposed to get instead? What OS are you on? You're using the released version of 2.1 or a preview? |
Ah, I'm not behind a proxy so my test wasn't valid... |
What platform and authentication scheme @dotconsulting ? |
Windows world. The proxy requests Windows authentication. I don't know exactly which scheme is used. But for example, with some tools we have to define proxy settings like this : http://{domain\user}:{password}@{proxy}:{port}. I don't know if it helps. |
Would it help to get Fiddler/Wireshark traces? To see if we have any proxy info available at all. |
Yeah, I think Fiddler or Wireshark traces would be really useful here. |
Putting the username and password in the URL is not supported. It is considered insecure. Our HTTP stacks in general don't support that way for both .NET Framework and .NET Core.
The code above here assumes two things. First, that the proxy settings are found via the "default system proxy" settings. On Windows machines, that typically means IE (Internet Explorer) settings. Second, using .DefaultCredentials only works when the proxy supports Windows authentication schemes such as Negotiate or NTLM. If the proxy only asks for Basic or Digest, then .DefaultCredentials doesn't work. You would have to use an explicit NetworkCredential object. |
@davidsh: |
In the short term, you might want to opt-out of the new SocketsHttpHandler HTTP stack in .NET Core 2.1. See the release notes for instructions on switching back to the HTTP stack (WinHttpHandler for Windows) that was used in .NET Core 2.0: https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1.0.md Adding a line of code like this to your app will switch you back to the .NET Core 2.0 HTTP stack:
|
I'll try that workaround. I'll keep out posted. Thanks! |
This isn't a case I considered when writing the default proxy string parser, so if WinHttp supports providing credentials that way there is a regression here. |
@rmkerr: |
Can you try an experiment? Instead of using Just want to see if the problem is .DefaultCredentials or a generalized problem with Windows Authentication for proxy handling in SocketsHttpHandler? Thx. |
@davidsh |
Thanks for trying. This looks like there is a bug with Windows Authentication for proxy credentials in SocketsHttpHandler. To speed up our investigation, is it possible for you to take WireShark traces? I'd like to see if there is actual network traffic attempting Windows authentication (but failing) or just not attempting it at all. Please remove any confidential information from the traces. Thx. |
@davidsh |
There is nothing specific w/ .NET Core regarding WireShark. Once you set it up on your client machine, you can start the trace, run your app long enough to produce the failure and then stop tracing. Then you can process the trace and remove unneeded TCP sessions, etc. from it to reduce it down. If you haven't used WireShark before, then you can go here to get more info: |
I've reproduced the bug. SocketsHttpHandler isn't even beginning the Windows authentication exchange to the proxy. I set up a repro using a test proxy server that uses Negotiate (it actually isn't a fully working implementation of Negotiate..but it's enough to see there is a problem with SocketsHttpHandler). On .NET Core 2.1 using SocketsHttpHandler. I see this exchange thru the proxy:
So, you can see that SocketsHttpHandler didn't even try to send Windows credentials to the proxy. I.e., it never sent an initial "Proxy-Authorization: Negotiate Base64blob" to the proxy. It appeared to stop the HTTP exchange right away the proxy sent back "Proxy-Authenticate: Negotiate". On .NET Core 2.1, using the AppContextSwitch to switch back to WinHttpHandler, I see this (note: I edited the Negotiate strings to remove confidential info).
|
It seems that SocketsHttpHandler is requiring the proxy to send back a 'Proxy-Support' header in order to do any Windows authentication to either the proxy or a destination server:
This header normally describes how a proxy supports connection persistence to a destination server. That persistence is required in order to do Windows auth schemes such as Negotiate/NTLM to a destination server (i.e. 401). However, this header doesn't necessarily describe client HTTP stack requirements when doing Windows auth to the proxy server itself (i.e. 407). When I modified my test proxy server to send back the "Proxy-Support: Session-Based-Authentication" response header, I got a different behavior from SocketsHttpHandler. It threw an exception:
So, there is probably a few different things to fix in SocketsHttpHandler for this scenario.
This exception that SocketsHttpHandler is throwing isn't valid in this scenario. Many servers including proxy servers will close the connection the first time they send back a 401 or 407. The exception shouldn't be thrown in those cases. SocketsHttpHandler should just use a new connection. Only in cases during the multi-leg back-and-forth of the Windows auth and the connection being closed should result in an error. And it's not clear that error should be an exception but rather just let the 401/407 be the final thing. |
I tried to use
But then I got an exception coming from WinHttpAuthHelper class:
Here is the code (line 21 is the client.GetAsync): class Program
{
static void Main(string[] args)
{
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
var handler = new HttpClientHandler();
handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
var client = new HttpClient(handler);
var response = client.GetAsync("https://www.mocky.io/v2/5185415ba171ea3a00704eed").GetAwaiter().GetResult();
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
} |
I've experienced the same issue with proxy authentication in Windows 10 with a proxy autoconfigured via a pac file. In 2.0 this code works. var handler = new HttpClientHandler();
handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials; It doesn't work in 2.1, regardless of whether 'System.Net.Http.UseSocketsHttpHandler' is true or false, although an exception is thrown if it is false. I've tried a few combination of settings to get proxy authentication to work in 2.1. The code below was the only thing that appeared to work. Not ideal as the proxy settings had to be specified explicitly. AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
var httpClient = new HttpClient(
new HttpClientHandler()
{
Proxy = new WebProxy("http://proxy:8080") { UseDefaultCredentials = true }
}); |
NuGet affected too (dotnet restore) |
This is suprising. When the AppContext switch is used to switch off SocketsHttpHandler, proxy detection and use is done by the original WinHttpHandler HTTP stack. I haven't seen any problems with that. Can you show a repro and the callstack / exception you're getting? Thx. |
Can you describe in more detail how the proxy is configured in your scenario? What are the IE settings? Is it auto-discovery...i.e. looking for a PAC file on the network? What kind of proxy server is it? Etc. Thx. |
@davidsh |
What about the kind of proxy server? Is it using Negotiate or NTLM (or both)? Can you do some WireShark traces of this? We'd like to understand the error you're getting when using WinHttpHandler. There are probably 2 different bugs here: one with SocketsHttpHandler that we understand already, second with WinHttpHandler that we can't repro yet. |
I was able to reproduce this exception in WinHttpHandler when I use a PAC file. I used explicit PAC file settings instead of "automatic discovery" since it was easier to repro it that way. where the contents of the PAC file are a simple function to a localhost test proxy server that requires authentication. function FindProxyForURL(url, host) { return "PROXY [::1]:3128"; } But I got the same NullReferenceException. |
We will probably split this bug into separate bugs since the root causes are different between WinHttpHandler vs. SocketsHttpHandler. |
This causes PowerShell Core 6.1 to fail with SPNego as well, so it's not just with Proxies but seems to be an issue with Negotiate auth in general. i.e.: SocketsHttpHandler not using Negotiate / SPNego This PowerShell issue has some more details as well. TestingAs per testing this, IIS can be configured to only support Negotiate:Kerberos as the windows auth provider. i.e.: disable NTLM. So maybe you can do a quicker / easier / cheaper setup with IIS to make sure that SocketsHttpHandler works with negotiate. @PatrickLang has a work in progress for how to setup containers with gMSA's SPN's, etc for a Kerberos setup MicrosoftDocs/Virtualization-Documentation#592 |
@csharmath I am not 100% sure how is your comment related to this issue.
|
i think the biggest issue is that now in Corporation don’t ever try to use env var like for example my current client have 3 proxy url and use a i would expect some code to check the current Platform and use respective standard in each one of them to actually get that last piece of code working every single third part on nuget using HttpClieny is broken right now if they did not designed the API so you can pass the proxy url (wich is bad for PAC scenario) the easiest example today is the result is that dotnet restore is fully broken |
@tebeco good points (esp. on the As I mentioned earlier in https://github.com/dotnet/corefx/issues/30166#issuecomment-396725994, the proxy support came in late. We had the option to not support proxies at all in 2.1, or to make an honest attempt with potential tail of bugs. While it is not ideal, it went quite ok IMO - we had a few bugs reported, couple of dozens customers impacted, but it was not super-massive + there is always opt-out to the old way. |
you lost me here, 2.1.5 runtime (hence the TBR ?) ?
you mean the env var to disable not sure what i missed |
AFAIK all known proxy related bugs are fixed in 2.1.5 (to be released).
Yes, that is what I meant. Maybe dotnet/nuget are doing something special and use |
i’m not sure moving to the CLI is a good idea for example when using it could break CosmosDb api (i did not check if it does not allows to feed an httpClient) same question for EfCore |
i just noticed that you saw this one i could try 2.1.5 but honestly the main issue is the loss of windows specific code the httpclient is instanciated using reflection to check if it’s running using fullfx or netcore to call a |
@karelz thanks for pointing out that I am mixing a different topic to this proxy only issue, adding a new issue about SPNego. |
@karelz so yesterday we tried to use CosmosDb with DocumentDb client api if you look for “DocumentDb” you’ll find answers telling you to do : <system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy usesystemdefault="True" />
</defaultProxy>
</system.net> this is why this issue probably need to be dealt in coreFx and not over every single repo
so i wonder as there was on Opt_out from SocketHandler
again ... we cannot control third part that were released and was never designed to take care of proxy properly |
@tebeco it seems that we have duplicate conversation here and in #23811. It is also confusing to see several scenarios thrown into the same pile and mixed. The main problem seems to be that proxy on Windows does not use default credentials unless you explicitly ask for it via Current workaround: Disable SocketsHttpHandler in the app via env. settings. Is that good summary? Did I miss other problems / bugs / suggestions in your replies? |
I did not have time yesterday to disable On thursday we had a contractor for Microsoft that was introduced to this issue. side note : the process that run on premise are hosting in windows services lets forget that part |
@tebeco I don't quite understand what you meant in your last post. Can you please rephrase /explain in details what you meant?
Currently we use IE settings. Why do you think we don't?
No idea what you meant here. I would suggest to stick to facts - what works vs. what does not. Let's avoid any speculations what MS is trying to convince developers to do.
Can you please double check? If it never worked even in .NET Core 2.0 (same as disabled SocketsHttpHandler), that would be good to know.
What should work where without app.config? On .NET Framework I assume app.config is necessary. |
@karelz done, sry about that |
This also includes the Azure WebJobs SDK. I was never able to get it running behind our evil company proxy ( |
In case anyone else runs in to this, using HttpClient to call out to WEBAPIs inside of IIS was causing the error:
When troubleshooting with Fiddler, the error would go away and everything would work fine. Solution was to add the following to startup.cs: |
I am still seeing this issue, and my company does not have a proxy. Any update on the status of this bug? |
This issue is closed. It was fixed in .NET Core 3.0 which is available in Preview right now. |
Same issue here. Trying to connect from Azure function emulator to Azure blob storage. TCP Viewer shows the calls are attempted directly to Azure ip without any knowledge of Proxy settings. Net version woks as expected. Setting AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false) resolved the issue, but we had to spend hours to understand the root cause. Has it ever been tested from behind the firewalls ? |
Azure Functions SDK still uses .Net Core 2.* |
This issue was only fixed in .NET Core 3.0. It was not fixed in .NET Core 2.*. That's why you still see the problem. When Azure Functions SDK is upgraded to .NET Core 3.x, then the problem should be resolved for you. |
When being behind a proxy requesting authentication, .net core 2.1 HttpClientHandler fails to properly authenticate against the proxy. The following code is working in .net core 2.0 but doesn't work anymore with .net core 2.1:
The text was updated successfully, but these errors were encountered: