public async Task Manual_CertificateSentMatchesCertificateReceived_Success( int numberOfRequests, bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage { if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler { _output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()"); return; } var options = new LoopbackServer.Options { UseSsl = true }; HttpClient CreateClient(X509Certificate2 cert) { HttpClientHandler handler = CreateHttpClientHandler(); handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates; handler.ClientCertificates.Add(cert); Assert.True(handler.ClientCertificates.Contains(cert)); return(CreateHttpClient(handler)); } async Task MakeAndValidateRequest(HttpClient client, LoopbackServer server, Uri url, X509Certificate2 cert) { await TestHelper.WhenAllCompletedOrAnyFailed( client.GetStringAsync(url), server.AcceptConnectionAsync(async connection => { SslStream sslStream = Assert.IsType <SslStream>(connection.Stream); // We can't do Assert.Equal(cert, sslStream.RemoteCertificate) because // on .NET Framework sslStream.RemoteCertificate is always an X509Certificate // object which is not equal to the X509Certificate2 object we use in the tests. // So, we'll just compare a few properties to make sure it's the right certificate. Assert.Equal(cert.Subject, sslStream.RemoteCertificate.Subject); Assert.Equal(cert.Issuer, sslStream.RemoteCertificate.Issuer); await connection.ReadRequestHeaderAndSendResponseAsync(additionalHeaders: "Connection: close\r\n"); })); }; await LoopbackServer.CreateServerAsync(async (server, url) => { using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate()) { if (reuseClient) { using (HttpClient client = CreateClient(cert)) { for (int i = 0; i < numberOfRequests; i++) { await MakeAndValidateRequest(client, server, url, cert); GC.Collect(); GC.WaitForPendingFinalizers(); } } } else { for (int i = 0; i < numberOfRequests; i++) { using (HttpClient client = CreateClient(cert)) { await MakeAndValidateRequest(client, server, url, cert); } GC.Collect(); GC.WaitForPendingFinalizers(); } } } }, options); }
public async Task Manual_CertificateSentMatchesCertificateReceived_Success( int numberOfRequests, bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage { if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler { _output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()"); return; } var options = new LoopbackServer.Options { UseSsl = true }; Func <X509Certificate2, HttpClient> createClient = (cert) => { HttpClientHandler handler = CreateHttpClientHandler(); handler.ServerCertificateCustomValidationCallback = delegate { return(true); }; handler.ClientCertificates.Add(cert); return(new HttpClient(handler)); }; Func <HttpClient, LoopbackServer, Uri, X509Certificate2, Task> makeAndValidateRequest = async(client, server, url, cert) => { await TestHelper.WhenAllCompletedOrAnyFailed( client.GetStringAsync(url), server.AcceptConnectionAsync(async connection => { SslStream sslStream = Assert.IsType <SslStream>(connection.Stream); Assert.Equal(cert, sslStream.RemoteCertificate); await connection.ReadRequestHeaderAndSendResponseAsync(); })); }; await LoopbackServer.CreateServerAsync(async (server, url) => { if (reuseClient) { using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate()) { using (HttpClient client = createClient(cert)) { for (int i = 0; i < numberOfRequests; i++) { await makeAndValidateRequest(client, server, url, cert); GC.Collect(); GC.WaitForPendingFinalizers(); } } } } else { for (int i = 0; i < numberOfRequests; i++) { using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate()) { using (HttpClient client = createClient(cert)) { await makeAndValidateRequest(client, server, url, cert); } } GC.Collect(); GC.WaitForPendingFinalizers(); } } }, options); }
public async Task Manual_CertificateSentMatchesCertificateReceived_Success( int numberOfRequests, bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage { var options = new LoopbackServer.Options { UseSsl = true }; using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate()) { Func <HttpClient> createClient = () => { var handler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = delegate { return(true); } }; handler.ClientCertificates.Add(cert); return(new HttpClient(handler)); }; Func <HttpClient, Socket, Uri, Task> makeAndValidateRequest = async(client, server, url) => { await TestHelper.WhenAllCompletedOrAnyFailed( client.GetStringAsync(url), LoopbackServer.AcceptSocketAsync(server, async(socket, stream, reader, writer) => { SslStream sslStream = Assert.IsType <SslStream>(stream); Assert.Equal(cert, sslStream.RemoteCertificate); await LoopbackServer.ReadWriteAcceptedAsync(socket, reader, writer); }, options)); }; await LoopbackServer.CreateServerAsync(async (server, url) => { if (reuseClient) { using (HttpClient client = createClient()) { for (int i = 0; i < numberOfRequests; i++) { await makeAndValidateRequest(client, server, url); GC.Collect(); GC.WaitForPendingFinalizers(); } } } else { for (int i = 0; i < numberOfRequests; i++) { using (HttpClient client = createClient()) { await makeAndValidateRequest(client, server, url); } GC.Collect(); GC.WaitForPendingFinalizers(); } } }, options); } }
public async Task ProxySetViaEnvironmentVariable_DefaultProxyCredentialsUsed(bool useProxy) { const string ExpectedUsername = "******"; const string ExpectedPassword = "******"; LoopbackServer.Options options = new LoopbackServer.Options { IsProxy = true, Username = ExpectedUsername, Password = ExpectedPassword }; await LoopbackServer.CreateClientAndServerAsync(uri => Task.Run(() => { var psi = new ProcessStartInfo(); psi.Environment.Add("http_proxy", $"http://{uri.Host}:{uri.Port}"); RemoteExecutor.Invoke(async(useProxyString, useVersionString, uriString) => { using (HttpClientHandler handler = CreateHttpClientHandler(useVersionString)) using (HttpClient client = CreateHttpClient(handler, useVersionString)) { var creds = new NetworkCredential(ExpectedUsername, ExpectedPassword); handler.DefaultProxyCredentials = creds; handler.UseProxy = bool.Parse(useProxyString); HttpResponseMessage response = await client.GetAsync(uriString); // Correctness of user and password is done in server part. Assert.True(response.StatusCode == HttpStatusCode.OK); }; }, useProxy.ToString(), UseVersion.ToString(), // If proxy is used , the url does not matter. We set it to be different to avoid confusion. useProxy ? Configuration.Http.RemoteEchoServer.ToString() : uri.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose(); }), server => server.AcceptConnectionAsync(async connection => { const string headerName = "Proxy-Authorization"; List <string> lines = await connection.ReadRequestHeaderAsync().ConfigureAwait(false); // First request should not have proxy credentials in either case. for (int i = 1; i < lines.Count; i++) { Assert.False(lines[i].StartsWith(headerName)); } if (useProxy) { // Reject request and wait for authenticated one. await connection.SendResponseAsync(HttpStatusCode.ProxyAuthenticationRequired, "Proxy-Authenticate: Basic realm=\"NetCore\"\r\n").ConfigureAwait(false); lines = await connection.ReadRequestHeaderAsync().ConfigureAwait(false); bool valid = false; for (int i = 1; i < lines.Count; i++) { if (lines[i].StartsWith(headerName)) { valid = LoopbackServer.IsBasicAuthTokenValid(lines[i], options); } } Assert.True(valid); } await connection.SendResponseAsync(HttpStatusCode.OK).ConfigureAwait(false); })); }