Skip to content

Initialize WebProxy credentials from URI UserInfo#125384

Open
Copilot wants to merge 5 commits intomainfrom
copilot/fix-webproxy-credentials-issue
Open

Initialize WebProxy credentials from URI UserInfo#125384
Copilot wants to merge 5 commits intomainfrom
copilot/fix-webproxy-credentials-issue

Conversation

Copy link
Contributor

Copilot AI commented Mar 10, 2026

Description

WebProxy ignores credentials embedded in proxy URIs (e.g., ******host:1080). The UserInfo component is never parsed, so Credentials stays null — causing SOCKS5 auth failures and forcing users to set credentials separately.

Changes:

  • Address property setter now extracts NetworkCredential from Uri.UserInfo when present, using Uri.UnescapeDataString for proper percent-decoding. Uses the C# field keyword to avoid an explicit backing field.
  • Constructor delegates credential extraction to the setter; explicit Credentials parameter still takes precedence
  • Added GetCredentialsFromUri helper (follows the same pattern as HttpEnvironmentProxy.GetCredentialsFromString)
  • Added System.Runtime.InteropServices project reference (required by SecureString used internally by NetworkCredential)
  • Added XML doc <remarks> on the Address property and all constructors that accept an address (both Uri? and string? overloads) documenting the automatic credential extraction behavior

Both paths now work equivalently:

// Credentials extracted from URI automatically
handler.Proxy = new WebProxy("******host:1080");

// Also works via the Address setter
var proxy = new WebProxy();
proxy.Address = new Uri("******host:1080");
// proxy.Credentials is now set

// Explicit credentials still take precedence
handler.Proxy = new WebProxy("******host:1080");
handler.Proxy.Credentials = new NetworkCredential("other", "creds"); // wins

23 new test cases covering constructor and setter paths, URL-encoded special characters, explicit credential precedence, and null/no-userinfo edge cases.

Original prompt

This section details on the original issue you should resolve

<issue_title>WebProxy doesn't initialize credentials from the Proxy URL UserInfo</issue_title>
<issue_description>### Description

In #123217, the original issue was that HttpClient did not support the socks5h proxy scheme, which was fixed via PR #123218. However, during the follow-up discussion, a new issue was discovered:

When proxy credentials are embedded directly in the WebProxy URL (e.g. socks5://username:password@ip:port), the SOCKS server returns error code 0x02 (connection not allowed). In contrast, setting credentials separately via handler.Proxy.Credentials = new NetworkCredential(...) works correctly.

Root issue: WebProxy does not appear to correctly extract and pass the credentials embedded in a socks5://username:password@ip:port URL to the SOCKS5 authentication flow, resulting in proxy authentication failure.

Reproduction Steps

Fails — credentials embedded in URL:

using var handler = new SocketsHttpHandler();
handler.Proxy = new WebProxy("socks5://username:password@ip:port");
using HttpClient client = new HttpClient(handler);
var response = await client.GetStringAsync("http://ifconfig.me/ip");

Works — credentials set via Credentials property:

using var handler = new SocketsHttpHandler();
handler.Proxy = new WebProxy("socks5://ip:port");
handler.Proxy.Credentials = new NetworkCredential("username", "password");
using HttpClient client = new HttpClient(handler);
var response = await client.GetStringAsync("http://ifconfig.me/ip");

Expected behavior

Both approaches should complete the request successfully. WebProxy should correctly parse the username and password embedded in the URL and use them for SOCKS5 proxy authentication.

Actual behavior

When credentials are embedded in the URL, an exception is thrown:

An error occurred while establishing a connection to the proxy tunnel.
SOCKS server failed to connect to the destination. Received error code 0x02.

Setting credentials via the Credentials property works as expected.

Regression?

No response

Known Workarounds

SOCKS5 error code 0x02 means "connection not allowed by ruleset", which typically indicates authentication failure or insufficient permissions. Given that setting credentials via the Credentials property works correctly, this confirms the issue lies in how WebProxy parses and passes credentials embedded in the URL.

Possible root causes:

  1. The WebProxy constructor does not extract username:password from socks5://username:password@ip:port into its Credentials property
  2. Or the SOCKS5 connection handler does not check the userinfo embedded in the WebProxy URL when retrieving proxy credentials

Configuration

No response

Other information

It is worth noting that in widely-used third-party libraries such as libcurl, when a connection is configured via a full proxy URI (e.g. socks5://user:pass@host:port), the library automatically parses the userinfo component from the URI and uses it for proxy authentication. This is standard practice across the industry. The .NET WebProxy does not follow this convention when handling SOCKS5 proxy URIs, which is inconsistent with developer expectations.</issue_description>

<agent_instructions>Initialize WebProxy credentials from the Uri if they were set. Ensure there's good test coverage</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix WebProxy not initializing credentials from Proxy URL Initialize WebProxy credentials from URI UserInfo Mar 10, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
@MihaZupan MihaZupan added this to the 11.0.0 milestone Mar 10, 2026
…dd ctor remarks

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
…opServices ref (needed for SecureString)

Co-authored-by: MihaZupan <25307628+MihaZupan@users.noreply.github.com>
@MihaZupan MihaZupan marked this pull request as ready for review March 10, 2026 18:18
Copilot AI review requested due to automatic review settings March 10, 2026 18:18
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates System.Net.WebProxy so that when a proxy Uri contains embedded credentials in its UserInfo (e.g., scheme://user:pass@host:port), WebProxy automatically initializes its Credentials from that information, improving parity with common proxy URI expectations (notably for SOCKS authentication).

Changes:

  • Updated WebProxy.Address setter (and thus constructors that set Address) to extract NetworkCredential from Uri.UserInfo with percent-decoding.
  • Ensured explicit Credentials passed to constructors still take precedence over URI-extracted credentials.
  • Added comprehensive unit tests covering constructor and setter behavior, encoding edge cases, and precedence rules.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs Extracts credentials from Address Uri.UserInfo and applies precedence rules when explicit credentials are provided.
src/libraries/System.Net.WebProxy/tests/WebProxyTest.cs Adds 23 test cases validating credential extraction, decoding, null/no-userinfo handling, and precedence behavior.
src/libraries/System.Net.WebProxy/src/System.Net.WebProxy.csproj Adds an explicit System.Runtime.InteropServices project reference to support NetworkCredential’s SecureString-related surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

WebProxy doesn't initialize credentials from the Proxy URL UserInfo

3 participants