Fix authenticated proxy for dotnet restore#123328
Conversation
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
|
@dotnet-policy-service agree |
|
@ptarjan could you please start with filing an issue to kick off a discussion? There are security implications of pro-actively sending credentials, especially with basic auth (equivalent of plain text) on non-secured connections. So this is not so straightforward and we cannot just accept a PR without any considerations. |
|
cc @wfurt |
|
This seems like something that could be driven by the existing |
This is problematic IMHO and we will have difficulty with security group IMHO as it especially with basic AUTH leaks the credentials. The "Many proxies" claim seems doubtful as it was generally ok for everyone and the 407 is described in RFC. I also do not understand the case 2 & 3. I'm not sure how for example environment configuration is related to lack of 407. having said that I would probably be OK with that if that has some opt-in method. Cutting the rounds can be viewed as general optimization. (as for example noted in #33964) |
Thanks for the detailed feedback. Let me address each point: On "many proxies" and RFC compliance: You're right that RFC 7235 specifies the 407 challenge-response flow. However, the real-world issue is that some proxies (particularly in containerized/cloud environments) don't follow the RFC:
The specific environment where this was reproduced (http://claude.ai/code) uses an egress proxy that returns On the opt-in approach: I don't really understand the credential leak, but I'm eager to learn. If the proxy would really like to see your credentials it could return an HTTP 407 and then you will happily send them along, right? Or is this less about an attacker and instead trying to limit logging? If so, then why is the user even using credentials in their proxy url. I agree an opt-in is more conservative but it does provide user friction. |
|
any concern here @dotnet/ncl ? Since this would be opt-in I feel it is ..... acceptable. And it would fix #100515 as well. For the 2 cases we have seen so far the AppContext seems sufficient e.g. adding new explicit API would be overkill and it would still depend on 3rd party tools to use it. |
|
Given that there are design decisions concerns, I would suggest to close this PR or switch it to Draft, until we have consensus. |
|
No need to change into draft, we will take this change. Me and @wfurt will review this. |
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ProactiveProxyAuth.cs
Show resolved
Hide resolved
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ProactiveProxyAuth.cs
Show resolved
Hide resolved
|
Regarding the scope question: the current implementation applies proactive proxy auth to all proxy requests (both plain proxy and CONNECT tunnels). Should this be restricted to only CONNECT tunnels, or is the general approach acceptable? Happy to narrow the scope if needed. |
Many proxies require the Proxy-Authorization header on the first request rather than sending a 407 Proxy Authentication Required response. This is especially common for: 1. Proxies that drop/ignore unauthenticated connections 2. HTTPS CONNECT tunnels where connection reuse isn't possible 3. Environment variable proxies (HTTP_PROXY/HTTPS_PROXY) with embedded credentials (http://user:password@proxy:port) This change modifies SendWithProxyAuthAsync to proactively send Basic authentication when credentials are available from the ICredentials provider, rather than waiting for a 407 challenge that may never come. The reactive authentication flow is still preserved for cases where the proxy does send a 407 response with different auth scheme requirements (Digest, NTLM, Negotiate).
Add functional tests to verify that Basic proxy authentication is sent proactively when credentials are provided, without waiting for a 407 challenge. This tests the fix for proxies that don't send 407 responses. Tests cover: - Proactive auth on first HTTP request - Proactive auth for HTTPS CONNECT tunnels - DefaultNetworkCredentials are NOT sent proactively (NTLM/Negotiate only)
Address PR feedback by making proactive proxy authentication opt-in rather than enabled by default. This preserves RFC 7235 compliant behavior (waiting for 407 challenge) as the default. Users can enable proactive auth via: - AppContext switch: System.Net.Http.EnableProactiveProxyAuth - Environment variable: DOTNET_SYSTEM_NET_HTTP_ENABLEPROACTIVEPROXYAUTH=1 This is useful for proxies that don't send 407 challenges but instead drop or reject unauthenticated connections (especially HTTPS CONNECT tunnel proxies). Updated tests to use RemoteExecutor with the environment variable to verify both opt-in and default behavior.
Changes based on reviewer feedback: - Move configuration to GlobalHttpSettings.SocketsHttpHandler using RuntimeSettingParser (per ManickaP and MihaZupan) - Rename switch to System.Net.Http.SocketsHttpHandler.ProxyPreAuthenticate with env var DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_PROXYPREAUTHENTICATE - Add test for credentials embedded in proxy URL (http://user:pass@proxy) - Add test for explicit WebProxy credentials - Keep tests for default behavior (no proactive auth) and DefaultNetworkCredentials exclusion
- Move proxy pre-auth logic into SendWithAuthAsync by handling the isProxyAuth case in the preAuthenticate block, instead of duplicating SetBasicAuthToken in SendWithProxyAuthAsync. Now SendWithProxyAuthAsync simply passes preAuthenticate: GlobalHttpSettings.SocketsHttpHandler.ProxyPreAuthenticate. - Guard the PreAuthCredentials cache logic with !isProxyAuth since proxy pre-auth doesn't use the per-pool credential cache. - Add parameterized test ProxyAuth_ProxyAndRequestProtocolCombinations_SentProactively covering 4 proxy/request protocol combinations: HTTP proxy + HTTP request, HTTP proxy + HTTPS request (CONNECT tunnel), HTTPS proxy + HTTP request, HTTPS proxy + HTTPS request (CONNECT tunnel). - Fix existing ProxyAuth_ExplicitWebProxyCredentials_SentProactively to stay within RemoteExecutor's 3-arg limit by encoding credentials in the proxy URI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
68eaab9 to
81d6701
Compare
Fixes: #123363
Many proxies require the Proxy-Authorization header on the first request rather than sending a 407 Proxy Authentication Required response. This is especially common for:
This change modifies SendWithProxyAuthAsync to proactively send Basic authentication when credentials are available from the ICredentials provider, rather than waiting for a 407 challenge that may never come.
The reactive authentication flow is still preserved for cases where the proxy does send a 407 response with different auth scheme requirements (Digest, NTLM, Negotiate).