Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ public void CheckResponseForAuthentication(

state.LastStatusCode = statusCode;

// If we don't have any proxy credentials to try, then we end up with 407.
ICredentials proxyCreds = state.Proxy == null ?
state.DefaultProxyCredentials :
state.Proxy.Credentials;
if (proxyCreds == null)
{
break;
}

// Determine authorization scheme to use. We ignore the firstScheme
// parameter which is included in the supportedSchemes flags already.
// We pass the schemes to ChooseAuthScheme which will pick the scheme
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,10 @@ public async Task GetAsync_SupportedSSLVersion_Succeeds(string name, string url)
public void Proxy_BypassFalse_GetRequestGoesThroughCustomProxy(ICredentials creds)
{
int port;
Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(out port, requireAuth: creds != null && creds != CredentialCache.DefaultCredentials);
Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(
out port,
requireAuth: creds != null && creds != CredentialCache.DefaultCredentials,
expectCreds: true);
Uri proxyUrl = new Uri($"http://localhost:{port}");

using (var handler = new HttpClientHandler() { Proxy = new UseSpecifiedUriWebProxy(proxyUrl, creds) })
Expand Down Expand Up @@ -990,6 +993,26 @@ await response.Content.ReadAsStringAsync(),
}
}

[Fact]
public void Proxy_HaveNoCredsAndUseAuthenticatedCustomProxy_ProxyAuthenticationRequiredStatusCode()
{
int port;
Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(
out port,
requireAuth: true,
expectCreds: false);
Uri proxyUrl = new Uri($"http://localhost:{port}");

using (var handler = new HttpClientHandler() { Proxy = new UseSpecifiedUriWebProxy(proxyUrl, null) })
using (var client = new HttpClient(handler))
{
Task<HttpResponseMessage> responseTask = client.GetAsync(HttpTestServers.RemoteEchoServer);
Task.WaitAll(proxyTask, responseTask);

Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, responseTask.Result.StatusCode);
}
}

private sealed class UseSpecifiedUriWebProxy : IWebProxy
{
private readonly Uri _uri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ public struct ProxyResult
public string AuthenticationHeaderValue;
}

public static Task<ProxyResult> StartAsync(out int port, bool requireAuth)
public static Task<ProxyResult> StartAsync(out int port, bool requireAuth, bool expectCreds)
{
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
port = ((IPEndPoint)listener.LocalEndpoint).Port;
return StartAsync(listener, requireAuth);
return StartAsync(listener, requireAuth, expectCreds);
}

private static async Task<ProxyResult> StartAsync(TcpListener listener, bool requireAuth)
private static async Task<ProxyResult> StartAsync(TcpListener listener, bool requireAuth, bool expectCreds)
{
ProxyResult result = new ProxyResult();
var headers = new Dictionary<string, string>();
Expand Down Expand Up @@ -60,20 +60,26 @@ private static async Task<ProxyResult> StartAsync(TcpListener listener, bool req
await getAndReadRequest().ConfigureAwait(false);

// If we're expecting credentials, look for them, and if we didn't get them, send back
// a response and process a new request.
// a 407 response. Optionally, process a new request that would expect credentials.
if (requireAuth && !headers.ContainsKey("Proxy-Authorization"))
{
Task<Socket> secondListen = listener.AcceptSocketAsync();

// Send back a 407
await clientSocket.SendAsync(
new ArraySegment<byte>(Encoding.ASCII.GetBytes("HTTP/1.1 407 Proxy Auth Required\r\nProxy-Authenticate: Basic\r\n\r\n")),
SocketFlags.None).ConfigureAwait(false);
clientSocket.Shutdown(SocketShutdown.Send);
clientSocket.Dispose();

// Wait for a new connection that should have an auth header this time and parse it.
await getAndReadRequest().ConfigureAwait(false);
if (expectCreds)
{
// Wait for a new connection that should have an auth header this time and parse it.
await getAndReadRequest().ConfigureAwait(false);
}
else
{
// No credentials will be coming in a subsequent request.
return default(ProxyResult);
}
}

// Store any auth header we may have for later comparison.
Expand Down