public async Task ProxyTunnelRequest_OriginServerSendsProxyAuthChallenge_NoProxyAuthPerformed() { if (IsWinHttpHandler) { return; } using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create()) { HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); handler.Proxy = new WebProxy(proxyServer.Uri) { Credentials = ConstructCredentials(new NetworkCredential("username", "password"), proxyServer.Uri, BasicAuth, true) }; using (HttpClient client = CreateHttpClient(handler)) { var options = new LoopbackServer.Options { UseSsl = true }; await LoopbackServer.CreateServerAsync(async (server, uri) => { Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri)); Task <HttpResponseMessage> clientTask = client.GetAsync(uri); await server.AcceptConnectionSendResponseAndCloseAsync(statusCode: HttpStatusCode.ProxyAuthenticationRequired, additionalHeaders: "Proxy-Authenticate: Basic").WaitAsync(TestHelper.PassingTestTimeout); using (var response = await clientTask.WaitAsync(TestHelper.PassingTestTimeout)) { Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, response.StatusCode); } }, options).WaitAsync(TestHelper.PassingTestTimeout); } Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine); } }
public async Task ProxyTunnelRequest_GetAsync_Success() { if (IsWinHttpHandler) { return; } const string Content = "Hello world"; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create()) { HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); handler.Proxy = new WebProxy(proxyServer.Uri); using (HttpClient client = CreateHttpClient(handler)) { var options = new LoopbackServer.Options { UseSsl = true }; await LoopbackServer.CreateServerAsync(async (server, uri) => { Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri)); Task <HttpResponseMessage> clientTask = client.GetAsync(uri); await server.AcceptConnectionSendResponseAndCloseAsync(content: Content); using (var response = await clientTask) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(Content, await response.Content.ReadAsStringAsync()); } }, options); } Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine); } }
public async Task AuthenticatedProxiedRequest_GetAsyncWithCreds_Success(NetworkCredential cred, bool wrapCredsInCache, bool connectionCloseAfter407) { var options = new LoopbackProxyServer.Options { AuthenticationSchemes = cred != null ? AuthenticationSchemes.Basic : AuthenticationSchemes.None, ConnectionCloseAfter407 = connectionCloseAfter407 }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) using (HttpClientHandler handler = CreateHttpClientHandler()) using (HttpClient client = CreateHttpClient(handler)) { handler.Proxy = new WebProxy(proxyServer.Uri) { Credentials = ConstructCredentials(cred, proxyServer.Uri, BasicAuth, wrapCredsInCache) }; using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.RemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentMD5, false, null); ValidateProxyBasicAuthentication(proxyServer, cred); } } }
public async Task UseCallback_HaveNoCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_ProxyAuthenticationRequiredStatusCode() { if (!BackendSupportsCustomCertificateHandling) { return; } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Basic, ConnectionCloseAfter407 = true }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; using (HttpClient client = CreateHttpClient(handler)) using (HttpResponseMessage response = await client.PostAsync( Configuration.Http.SecureRemoteEchoServer, new StringContent("This is a test"))) { Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, response.StatusCode); } } }
public async Task AuthenticatedProxyTunnelRequest_PostAsyncWithNoCreds_Throws() { if (IsWinHttpHandler) { return; } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Basic, }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; using (HttpClient client = CreateHttpClient(handler)) { HttpRequestException e = await Assert.ThrowsAnyAsync <HttpRequestException>(async() => await client.PostAsync("https://nosuchhost.invalid", new StringContent(content))); Assert.Contains("407", e.Message); } } }
public async Task ProxyTunnelRequest_MaxConnectionsSetButDoesNotApplyToProxyConnect_Success() { if (IsWinHttpHandler) { return; } const string Content = "Hello world"; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create()) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; handler.MaxConnectionsPerServer = 1; using (HttpClient client = CreateHttpClient(handler)) { var options = new LoopbackServer.Options { UseSsl = true }; await LoopbackServer.CreateServerAsync(async (server1, uri1) => { await LoopbackServer.CreateServerAsync(async(server2, uri2) => { Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri1)); Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri2)); Task <HttpResponseMessage> clientTask1 = client.GetAsync(uri1); Task <HttpResponseMessage> clientTask2 = client.GetAsync(uri2); await server1.AcceptConnectionAsync(async connection1 => { await server2.AcceptConnectionAsync(async connection2 => { await connection1.HandleRequestAsync(content: Content); await connection2.HandleRequestAsync(content: Content); }); }); using (var response1 = await clientTask1) { Assert.Equal(HttpStatusCode.OK, response1.StatusCode); Assert.Equal(Content, await response1.Content.ReadAsStringAsync()); } using (var response2 = await clientTask2) { Assert.Equal(HttpStatusCode.OK, response2.StatusCode); Assert.Equal(Content, await response2.Content.ReadAsStringAsync()); } }, options); }, options); } Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine); Assert.Contains("CONNECT", proxyServer.Requests[1].RequestLine); } }
public async Task Proxy_BypassFalse_GetRequestGoesThroughCustomProxy(ICredentials creds, bool wrapCredsInCache) { var options = new LoopbackProxyServer.Options { AuthenticationSchemes = creds != null ? AuthenticationSchemes.Basic : AuthenticationSchemes.None }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { const string BasicAuth = "Basic"; if (wrapCredsInCache) { Assert.IsAssignableFrom <NetworkCredential>(creds); var cache = new CredentialCache(); cache.Add(proxyServer.Uri, BasicAuth, (NetworkCredential)creds); creds = cache; } using (HttpClientHandler handler = CreateHttpClientHandler()) using (var client = new HttpClient(handler)) { handler.Proxy = new WebProxy(proxyServer.Uri) { Credentials = creds }; using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.RemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentMD5, false, null); if (options.AuthenticationSchemes != AuthenticationSchemes.None) { NetworkCredential nc = creds?.GetCredential(proxyServer.Uri, BasicAuth); Assert.NotNull(nc); string expectedAuth = string.IsNullOrEmpty(nc.Domain) ? $"{nc.UserName}:{nc.Password}" : $"{nc.Domain}\\{nc.UserName}:{nc.Password}"; _output.WriteLine($"expectedAuth={expectedAuth}"); string expectedAuthHash = Convert.ToBase64String(Encoding.UTF8.GetBytes(expectedAuth)); // Check last request to proxy server. CurlHandler will use pre-auth for Basic proxy auth, // so there might only be 1 request received by the proxy server. Other handlers won't use // pre-auth for proxy so there would be 2 requests. int requestCount = proxyServer.Requests.Count; _output.WriteLine($"proxyServer.Requests.Count={requestCount}"); Assert.Equal(BasicAuth, proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueScheme); Assert.Equal(expectedAuthHash, proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueToken); } } } } }
public static LoopbackProxyServer Create(Options options = null) { options = options ?? new Options(); var server = new LoopbackProxyServer(options); server.Start(); return(server); }
public async Task Proxy_SendSecureRequestThruProxy_ConnectTunnelUsed() { using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create()) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); using (HttpClient client = CreateHttpClient(handler)) using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.SecureRemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); _output.WriteLine($"Proxy request line: {proxyServer.Requests[0].RequestLine}"); Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine); } } }
public async Task AuthProxy__ValidCreds_ProxySendsRequestToServer( AuthenticationSchemes proxyAuthScheme, bool secureServer, bool proxyClosesConnectionAfterFirst407Response) { if (PlatformDetection.IsWindowsNanoServer && IsWinHttpHandler && proxyAuthScheme == AuthenticationSchemes.Digest) { // WinHTTP doesn't support Digest very well and is disabled on Nano. return; } if (!PlatformDetection.IsWindows && (proxyAuthScheme == AuthenticationSchemes.Negotiate || proxyAuthScheme == AuthenticationSchemes.Ntlm)) { // CI machines don't have GSSAPI module installed and will fail with error from // System.Net.Security.NegotiateStreamPal.AcquireCredentialsHandle(): // "GSSAPI operation failed with error - An invalid status code was supplied // Configuration file does not specify default realm)." return; } Uri serverUri = secureServer ? Configuration.Http.SecureRemoteEchoServer : Configuration.Http.RemoteEchoServer; var options = new LoopbackProxyServer.Options { AuthenticationSchemes = proxyAuthScheme, ConnectionCloseAfter407 = proxyClosesConnectionAfterFirst407Response }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { using (HttpClientHandler handler = CreateHttpClientHandler()) using (HttpClient client = CreateHttpClient(handler)) { handler.Proxy = new WebProxy(proxyServer.Uri); handler.Proxy.Credentials = new NetworkCredential("username", "password"); using (HttpResponseMessage response = await client.GetAsync(serverUri)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentMD5, false, null); } } } }
public async Task UseCallback_HaveCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_Success() { if (!BackendSupportsCustomCertificateHandling) { return; } if (IsWinHttpHandler && PlatformDetection.IsWindows7) { // Issue #27612 return; } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Basic, ConnectionCloseAfter407 = true }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { HttpClientHandler handler = CreateHttpClientHandler(); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; handler.Proxy = new WebProxy(proxyServer.Uri) { Credentials = new NetworkCredential("rightusername", "rightpassword") }; const string content = "This is a test"; using (HttpClient client = CreateHttpClient(handler)) using (HttpResponseMessage response = await client.PostAsync( Configuration.Http.SecureRemoteEchoServer, new StringContent(content))) { string responseContent = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, content); } } }
public async Task Proxy_HaveNoCredsAndUseAuthenticatedCustomProxy_ProxyAuthenticationRequiredStatusCode() { var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Basic }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); using (var client = new HttpClient(handler)) using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.RemoteEchoServer)) { Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, response.StatusCode); } } }
public async Task Proxy_DomainJoinedProxyServerUsesKerberos_Success(Uri server) { // We skip the test unless it is running on a Windows client machine. That is because only Windows // automatically registers an SPN for HTTP/<hostname> of the machine. This will enable Kerberos to properly // work with the loopback proxy server. if (!PlatformDetection.IsWindows || !PlatformDetection.IsNotWindowsNanoServer) { throw new SkipTestException("Test can only run on domain joined Windows client machine"); } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Negotiate }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { using (HttpClientHandler handler = CreateHttpClientHandler()) using (HttpClient client = CreateHttpClient(handler)) { // Use 'localhost' DNS name for loopback proxy server (instead of IP address) so that the SPN will // get calculated properly to use Kerberos. _output.WriteLine(proxyServer.Uri.AbsoluteUri.ToString()); handler.Proxy = new WebProxy("localhost", proxyServer.Uri.Port) { Credentials = DomainCredential }; using (HttpResponseMessage response = await client.GetAsync(server)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); int requestCount = proxyServer.Requests.Count; // We expect 2 requests to the proxy server. One without the 'Proxy-Authorization' header and // one with the header. Assert.Equal(2, requestCount); Assert.Equal("Negotiate", proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueScheme); // Base64 tokens that use SPNEGO protocol start with 'Y'. NTLM tokens start with 'T'. Assert.Equal('Y', proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueToken[0]); } } } }
private void ValidateProxyBasicAuthentication(LoopbackProxyServer proxyServer, NetworkCredential cred) { if (cred != null) { string expectedAuth = string.IsNullOrEmpty(cred.Domain) ? $"{cred.UserName}:{cred.Password}" : $"{cred.Domain}\\{cred.UserName}:{cred.Password}"; _output.WriteLine($"expectedAuth={expectedAuth}"); string expectedAuthHash = Convert.ToBase64String(Encoding.UTF8.GetBytes(expectedAuth)); // Check last request to proxy server. Handlers that don't use // pre-auth for proxy will make 2 requests. int requestCount = proxyServer.Requests.Count; _output.WriteLine($"proxyServer.Requests.Count={requestCount}"); Assert.Equal(BasicAuth, proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueScheme); Assert.Equal(expectedAuthHash, proxyServer.Requests[requestCount - 1].AuthorizationHeaderValueToken); } }
public void Proxy_UseEnvironmentVariableToSetSystemProxy_RequestGoesThruProxy() { RemoteExecutor.Invoke(async(useVersionString) => { var options = new LoopbackProxyServer.Options { AddViaRequestHeader = true }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { Environment.SetEnvironmentVariable("http_proxy", proxyServer.Uri.AbsoluteUri.ToString()); using (HttpClient client = CreateHttpClient(useVersionString)) using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.RemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string body = await response.Content.ReadAsStringAsync(); Assert.Contains(proxyServer.ViaHeader, body); } } }, UseVersion.ToString()).Dispose(); }
public async Task Proxy_SendSecureRequestThruProxy_ConnectTunnelUsed() { if (PlatformDetection.IsFedora && IsCurlHandler) { // CurlHandler seems unstable on Fedora26 and returns error // "System.Net.Http.CurlException : Failure when receiving data from the peer". return; } using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create()) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); using (var client = new HttpClient(handler)) using (HttpResponseMessage response = await client.GetAsync(Configuration.Http.SecureRemoteEchoServer)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); _output.WriteLine($"Proxy request line: {proxyServer.Requests[0].RequestLine}"); Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine); } } }
public async Task AuthenticatedProxyTunnelRequest_PostAsyncWithCreds_Success(NetworkCredential cred, bool wrapCredsInCache, bool connectionCloseAfter407) { if (IsWinHttpHandler) { return; } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = cred != null ? AuthenticationSchemes.Basic : AuthenticationSchemes.None, ConnectionCloseAfter407 = connectionCloseAfter407 }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) using (HttpClientHandler handler = CreateHttpClientHandler()) using (HttpClient client = CreateHttpClient(handler)) { handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; handler.Proxy = new WebProxy(proxyServer.Uri) { Credentials = ConstructCredentials(cred, proxyServer.Uri, BasicAuth, wrapCredsInCache) }; using (HttpResponseMessage response = await client.PostAsync(Configuration.Http.SecureRemoteEchoServer, new StringContent(content))) { string responseContent = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, content); ValidateProxyBasicAuthentication(proxyServer, cred); } } }
public async Task AuthenticatedProxyTunnelRequest_PostAsyncWithNoCreds_ProxyAuthenticationRequiredStatusCode() { if (IsWinHttpHandler) { return; } var options = new LoopbackProxyServer.Options { AuthenticationSchemes = AuthenticationSchemes.Basic, }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Proxy = new WebProxy(proxyServer.Uri); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; using (HttpClient client = CreateHttpClient(handler)) using (HttpResponseMessage response = await client.PostAsync(Configuration.Http.SecureRemoteEchoServer, new StringContent(content))) { Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, response.StatusCode); } } }
public async Task MultiProxy_PAC_Failover_Succeeds() { if (IsWinHttpHandler) { // PAC-based failover is only supported on Windows/SocketsHttpHandler return; } // Create our failing proxy server. // Bind a port to reserve it, but don't start listening yet. The first Connect() should fail and cause a fail-over. using Socket failingProxyServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); failingProxyServer.Bind(new IPEndPoint(IPAddress.Loopback, 0)); var failingEndPoint = (IPEndPoint)failingProxyServer.LocalEndPoint; using LoopbackProxyServer succeedingProxyServer = LoopbackProxyServer.Create(); string proxyConfigString = $"{failingEndPoint.Address}:{failingEndPoint.Port} {succeedingProxyServer.Uri.Host}:{succeedingProxyServer.Uri.Port}"; // Create a WinInetProxyHelper and override its values with our own. object winInetProxyHelper = Activator.CreateInstance(typeof(HttpClient).Assembly.GetType("System.Net.Http.WinInetProxyHelper", true), true); winInetProxyHelper.GetType().GetField("_autoConfigUrl", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(winInetProxyHelper, null); winInetProxyHelper.GetType().GetField("_autoDetect", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(winInetProxyHelper, false); winInetProxyHelper.GetType().GetField("_proxy", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(winInetProxyHelper, proxyConfigString); winInetProxyHelper.GetType().GetField("_proxyBypass", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(winInetProxyHelper, null); // Create a HttpWindowsProxy with our custom WinInetProxyHelper. IWebProxy httpWindowsProxy = (IWebProxy)Activator.CreateInstance(typeof(HttpClient).Assembly.GetType("System.Net.Http.HttpWindowsProxy", true), Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Instance, null, new[] { winInetProxyHelper, null }, null); Task <bool> nextFailedConnection = null; // Run a request with that proxy. Task requestTask = LoopbackServerFactory.CreateClientAndServerAsync( async uri => { using HttpClientHandler handler = CreateHttpClientHandler(); using HttpClient client = CreateHttpClient(handler); handler.Proxy = httpWindowsProxy; // First request is expected to hit the failing proxy server, then failover to the succeeding proxy server. Assert.Equal("foo", await client.GetStringAsync(uri)); // Second request should start directly at the succeeding proxy server. // So, start listening on our failing proxy server to catch if it tries to connect. failingProxyServer.Listen(1); nextFailedConnection = WaitForNextFailedConnection(); Assert.Equal("bar", await client.GetStringAsync(uri)); }, async server => { await server.HandleRequestAsync(statusCode: HttpStatusCode.OK, content: "foo"); await server.HandleRequestAsync(statusCode: HttpStatusCode.OK, content: "bar"); }); // Wait for request to finish. await requestTask; // Triggers WaitForNextFailedConnection to stop, and then check // to ensure we haven't got any further requests against it. failingProxyServer.Dispose(); Assert.False(await nextFailedConnection); Assert.Equal(2, succeedingProxyServer.Requests.Count); async Task <bool> WaitForNextFailedConnection() { try { (await failingProxyServer.AcceptAsync()).Dispose(); return(true); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted) { // Dispose() of the loopback server will cause AcceptAsync() in EstablishConnectionAsync() to abort. return(false); } } }
public async Task AuthProxy__ValidCreds_ProxySendsRequestToServer( AuthenticationSchemes proxyAuthScheme, bool secureServer, bool proxyClosesConnectionAfterFirst407Response) { if (PlatformDetection.IsFedora && IsCurlHandler) { // CurlHandler seems unstable on Fedora26 and returns error // "System.Net.Http.CurlException : Failure when receiving data from the peer". return; } if (PlatformDetection.IsWindowsNanoServer && IsWinHttpHandler && proxyAuthScheme == AuthenticationSchemes.Digest) { // WinHTTP doesn't support Digest very well and is disabled on Nano. return; } if (PlatformDetection.IsFullFramework && (proxyAuthScheme == AuthenticationSchemes.Negotiate || proxyAuthScheme == AuthenticationSchemes.Ntlm)) { // Skip due to bug in .NET Framework with Windows auth and proxy tunneling. return; } if (!PlatformDetection.IsWindows && (proxyAuthScheme == AuthenticationSchemes.Negotiate || proxyAuthScheme == AuthenticationSchemes.Ntlm)) { // CI machines don't have GSSAPI module installed and will fail with error from // System.Net.Security.NegotiateStreamPal.AcquireCredentialsHandle(): // "GSSAPI operation failed with error - An invalid status code was supplied // Configuration file does not specify default realm)." return; } if (IsCurlHandler && proxyAuthScheme != AuthenticationSchemes.Basic) { // Issue #27870 curl HttpHandler can only do basic auth to proxy. return; } Uri serverUri = secureServer ? Configuration.Http.SecureRemoteEchoServer : Configuration.Http.RemoteEchoServer; var options = new LoopbackProxyServer.Options { AuthenticationSchemes = proxyAuthScheme, ConnectionCloseAfter407 = proxyClosesConnectionAfterFirst407Response }; using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create(options)) { using (StandardSocketsHttpHandler handler = CreateSocketsHttpHandler()) using (var client = new HttpClient(handler)) { handler.Proxy = new WebProxy(proxyServer.Uri); handler.Proxy.Credentials = new NetworkCredential("username", "password"); using (HttpResponseMessage response = await client.GetAsync(serverUri)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); TestHelper.VerifyResponseBody( await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentMD5, false, null); } } } }