private async Task RegisterDefaultServerAddresses_Success(IEnumerable <string> addresses, bool mockHttps = false) { var hostBuilder = TransportSelector.GetHostBuilder() .ConfigureWebHost(webHostBuilder => { webHostBuilder .UseKestrel(options => { if (mockHttps) { options.DefaultCertificate = TestResources.GetTestCertificate(); } }) .Configure(ConfigureEchoAddress); }) .ConfigureServices(AddTestLogging); using (var host = hostBuilder.Build()) { await host.StartAsync(); Assert.Equal(5000, host.GetPort()); if (mockHttps) { Assert.Contains(5001, host.GetPorts()); } Assert.Single(LogMessages, log => log.LogLevel == LogLevel.Debug && (string.Equals(CoreStrings.FormatBindingToDefaultAddresses(Constants.DefaultServerAddress, Constants.DefaultServerHttpsAddress), log.Message, StringComparison.Ordinal) || string.Equals(CoreStrings.FormatBindingToDefaultAddress(Constants.DefaultServerAddress), log.Message, StringComparison.Ordinal))); foreach (var address in addresses) { Assert.Equal(new Uri(address).ToString(), await HttpClientSlim.GetStringAsync(address, validateCertificate: false)); } await host.StopAsync(); } }
public async Task ClientCertificate_NoOrDelayed_Available_Ignored(ClientCertificateMode mode) { var builder = CreateHostBuilder(async context => { var hasCert = context.Connection.ClientCertificate != null; await context.Response.WriteAsync(hasCert.ToString()); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); httpsOptions.ClientCertificateMode = mode; httpsOptions.AllowAnyClientCertificate(); }); }); }); using var host = builder.Build(); using var client = HttpHelpers.CreateClient(includeClientCert: true); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; var response = await client.SendAsync(request, CancellationToken.None).DefaultTimeout(); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpVersion.Version30, response.Version); Assert.Equal("False", result); await host.StopAsync().DefaultTimeout(); }
public async Task ListenIPWithStaticPort_TransportsGetIPv6Any() { var options = new KestrelServerOptions(); options.ApplicationServices = new ServiceCollection() .AddLogging() .BuildServiceProvider(); options.ListenAnyIP(5000, options => { options.UseHttps(TestResources.GetTestCertificate()); options.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; }); var mockTransportFactory = new MockTransportFactory(); var mockMultiplexedTransportFactory = new MockMultiplexedTransportFactory(); using var server = new KestrelServerImpl( Options.Create(options), new List <IConnectionListenerFactory>() { mockTransportFactory }, new List <IMultiplexedConnectionListenerFactory>() { mockMultiplexedTransportFactory }, new LoggerFactory(new[] { new KestrelTestLoggerProvider() })); await server.StartAsync(new DummyApplication(context => Task.CompletedTask), CancellationToken.None); var transportEndPoint = Assert.Single(mockTransportFactory.BoundEndPoints); var multiplexedTransportEndPoint = Assert.Single(mockMultiplexedTransportFactory.BoundEndPoints); // Both transports should get the IPv6Any Assert.Equal(IPAddress.IPv6Any, ((IPEndPoint)transportEndPoint.OriginalEndPoint).Address); Assert.Equal(IPAddress.IPv6Any, ((IPEndPoint)multiplexedTransportEndPoint.OriginalEndPoint).Address); Assert.Equal(5000, ((IPEndPoint)transportEndPoint.OriginalEndPoint).Port); Assert.Equal(5000, ((IPEndPoint)multiplexedTransportEndPoint.OriginalEndPoint).Port); }
public void Equals_Different_Value_Returns_False() { var options1 = new ProxyHttpClientOptions { SslProtocols = SslProtocols.Tls11, DangerousAcceptAnyServerCertificate = false, ClientCertificate = TestResources.GetTestCertificate(), MaxConnectionsPerServer = 20 }; var options2 = new ProxyHttpClientOptions { SslProtocols = SslProtocols.Tls12, DangerousAcceptAnyServerCertificate = true, ClientCertificate = TestResources.GetTestCertificate(), MaxConnectionsPerServer = 20 }; var equals = ProxyHttpClientOptions.Equals(options1, options2); Assert.False(equals); }
public async Task LoggingConnectionAdapterCanBeAddedBeforeAndAfterHttpsAdapter() { using (var server = new TestServer(context => { context.Response.ContentLength = 12; return(context.Response.WriteAsync("Hello World!")); }, new TestServiceContext(LoggerFactory), listenOptions => { listenOptions.UseConnectionLogging(); listenOptions.UseHttps(TestResources.GetTestCertificate()); listenOptions.UseConnectionLogging(); })) { var response = await server.HttpClientSlim.GetStringAsync($"https://localhost:{server.Port}/", validateCertificate : false) .DefaultTimeout(); Assert.Equal("Hello World!", response); } }
public async Task ConnectionFilterDoesNotLeakBlock() { var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory) { ExpectedConnectionMiddlewareCount = 1 }, listenOptions => { listenOptions.UseHttps(TestResources.GetTestCertificate()); })) { using (var connection = server.CreateConnection()) { connection.Reset(); } } }
public async Task ListenWithCustomEndpoint_DoesNotThrow() { var options = new KestrelServerOptions(); options.ApplicationServices = new ServiceCollection() .AddLogging() .BuildServiceProvider(); var customEndpoint = new UriEndPoint(new("http://localhost:5000")); options.Listen(customEndpoint, options => { options.UseHttps(TestResources.GetTestCertificate()); options.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; }); var mockTransportFactory = new MockTransportFactory(); var mockMultiplexedTransportFactory = new MockMultiplexedTransportFactory(); using var server = new KestrelServerImpl( Options.Create(options), new List <IConnectionListenerFactory>() { mockTransportFactory }, new List <IMultiplexedConnectionListenerFactory>() { mockMultiplexedTransportFactory }, new LoggerFactory(new[] { new KestrelTestLoggerProvider() })); await server.StartAsync(new DummyApplication(context => Task.CompletedTask), CancellationToken.None); var transportEndPoint = Assert.Single(mockTransportFactory.BoundEndPoints); var multiplexedTransportEndPoint = Assert.Single(mockMultiplexedTransportFactory.BoundEndPoints); Assert.Same(customEndpoint, transportEndPoint.BoundEndPoint); Assert.Same(customEndpoint, multiplexedTransportEndPoint.BoundEndPoint); }
public async Task OverrideDirectConfigurationWithIServerAddressesFeature_Succeeds() { var useUrlsAddress = $"http://127.0.0.1:0"; var hostBuilder = TransportSelector.GetWebHostBuilder() .UseKestrel(options => { options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => { listenOptions.UseHttps(TestResources.GetTestCertificate()); }); }) .UseUrls(useUrlsAddress) .PreferHostingUrls(true) .ConfigureServices(AddTestLogging) .Configure(ConfigureEchoAddress); using (var host = hostBuilder.Build()) { await host.StartAsync(); var port = host.GetPort(); // If this isn't working properly, we'll get the HTTPS endpoint defined in UseKestrel // instead of the HTTP endpoint defined in UseUrls. var serverAddresses = host.ServerFeatures.Get <IServerAddressesFeature>().Addresses; Assert.Equal(1, serverAddresses.Count); var useUrlsAddressWithPort = $"http://127.0.0.1:{port}"; Assert.Equal(serverAddresses.First(), useUrlsAddressWithPort); Assert.Single(TestApplicationErrorLogger.Messages, log => log.LogLevel == LogLevel.Information && string.Equals(CoreStrings.FormatOverridingWithPreferHostingUrls(nameof(IServerAddressesFeature.PreferHostingUrls), useUrlsAddress), log.Message, StringComparison.Ordinal)); Assert.Equal(new Uri(useUrlsAddressWithPort).ToString(), await HttpClientSlim.GetStringAsync(useUrlsAddressWithPort)); await host.StopAsync(); } }
public async Task RegisterHttpAddress_UpgradedToHttpsByConfigureEndpointDefaults() { var hostBuilder = TransportSelector.GetHostBuilder() .ConfigureWebHost(webHostBuilder => { webHostBuilder .UseKestrel(serverOptions => { serverOptions.ConfigureEndpointDefaults(listenOptions => { listenOptions.UseHttps(TestResources.GetTestCertificate()); }); }) .UseUrls("http://127.0.0.1:0") .Configure(app => { var serverAddresses = app.ServerFeatures.Get <IServerAddressesFeature>(); app.Run(context => { Assert.Single(serverAddresses.Addresses); return(context.Response.WriteAsync(serverAddresses.Addresses.First())); }); }); }) .ConfigureServices(AddTestLogging); using (var host = hostBuilder.Build()) { host.Start(); var expectedUrl = $"https://127.0.0.1:{host.GetPort()}"; var response = await HttpClientSlim.GetStringAsync(expectedUrl, validateCertificate : false); Assert.Equal(expectedUrl, response); await host.StopAsync(); } }
public void Equals_Same_Value_Returns_True() { var options1 = new ProxyHttpClientOptions { SslProtocols = SslProtocols.Tls11, DangerousAcceptAnyServerCertificate = false, ClientCertificate = TestResources.GetTestCertificate(), MaxConnectionsPerServer = 20, WebProxy = new WebProxyOptions() { Address = new Uri("http://localhost:8080"), BypassOnLocal = true, UseDefaultCredentials = true }, #if NET RequestHeaderEncoding = Encoding.UTF8 #endif }; var options2 = new ProxyHttpClientOptions { SslProtocols = SslProtocols.Tls11, DangerousAcceptAnyServerCertificate = false, ClientCertificate = TestResources.GetTestCertificate(), MaxConnectionsPerServer = 20, WebProxy = new WebProxyOptions() { Address = new Uri("http://localhost:8080"), BypassOnLocal = true, UseDefaultCredentials = true }, #if NET RequestHeaderEncoding = Encoding.UTF8 #endif }; var equals = options1.Equals(options2); Assert.True(equals); Assert.True(options1 == options2); Assert.False(options1 != options2); }
public async Task OnAuthenticate_SeesOtherSettings() { var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); var testCert = TestResources.GetTestCertificate(); var onAuthenticateCalled = false; await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory) { ExpectedConnectionMiddlewareCount = 1 }, listenOptions => { listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = testCert; httpsOptions.OnAuthenticate = (connectionContext, authOptions) => { Assert.Same(testCert, authOptions.ServerCertificate); onAuthenticateCalled = true; }; }); })) { using (var connection = server.CreateConnection()) using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true)) { await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates : null, enabledSslProtocols : SslProtocols.Tls11 | SslProtocols.Tls12, checkCertificateRevocation : false); } } Assert.True(onAuthenticateCalled, "onAuthenticateCalled"); }
public async Task OnAuthenticate_CanSetSettings() { var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); var testCert = TestResources.GetTestCertificate(); var onAuthenticateCalled = false; await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory), listenOptions => { listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificateSelector = (_, __) => throw new NotImplementedException(); httpsOptions.OnAuthenticate = (connectionContext, authOptions) => { Assert.Null(authOptions.ServerCertificate); Assert.NotNull(authOptions.ServerCertificateSelectionCallback); authOptions.ServerCertificate = testCert; authOptions.ServerCertificateSelectionCallback = null; onAuthenticateCalled = true; }; }); })) { using (var connection = server.CreateConnection()) using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true)) { await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates : null, enabledSslProtocols : SslProtocols.Tls11 | SslProtocols.Tls12, checkCertificateRevocation : false); } } Assert.True(onAuthenticateCalled, "onAuthenticateCalled"); }
private async Task RegisterIPEndPoint_Success(IPEndPoint endPoint, string testUrl, int testPort = 0) { var hostBuilder = TransportSelector.GetHostBuilder() .ConfigureWebHost(webHostBuilder => { webHostBuilder .UseKestrel(options => { options.Listen(endPoint, listenOptions => { if (testUrl.StartsWith("https", StringComparison.Ordinal)) { listenOptions.UseHttps(TestResources.GetTestCertificate()); } }); }) .Configure(ConfigureEchoAddress); }) .ConfigureServices(AddTestLogging); using (var host = hostBuilder.Build()) { await host.StartAsync(); var testUrlWithPort = $"{testUrl}:{(testPort == 0 ? host.GetPort() : testPort)}"; var options = ((IOptions <KestrelServerOptions>)host.Services.GetService(typeof(IOptions <KestrelServerOptions>))).Value; Assert.Single(options.ListenOptions); var response = await HttpClientSlim.GetStringAsync(testUrlWithPort, validateCertificate : false); // Compare the response with Uri.ToString(), rather than testUrl directly. // Required to handle IPv6 addresses with zone index, like "fe80::3%1" Assert.Equal(new Uri(testUrlWithPort).ToString(), response); await host.StopAsync(); } }
public void ConfigureHttpsDefaultsNeverLoadsDefaultCert() { var serverOptions = CreateServerOptions(); var testCert = TestResources.GetTestCertificate(); serverOptions.ConfigureHttpsDefaults(options => { Assert.Null(options.ServerCertificate); options.ServerCertificate = testCert; options.ClientCertificateMode = ClientCertificateMode.RequireCertificate; }); serverOptions.ListenLocalhost(5000, options => { options.UseHttps(opt => { Assert.Equal(testCert, opt.ServerCertificate); Assert.Equal(ClientCertificateMode.RequireCertificate, opt.ClientCertificateMode); }); }); // Never lazy loaded Assert.False(serverOptions.IsDevCertLoaded); Assert.Null(serverOptions.DefaultCertificate); }
public async Task Http2(string requestSuffix, string expectedResponse) { InitializeArgs(); var hostBuilder = new WebHostBuilder() .UseKestrel(options => { options.Listen(IPAddress.Loopback, 0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; listenOptions.UseHttps(TestResources.GetTestCertificate()); }); }) .ConfigureServices(AddTestLogging) .Configure(app => app.Run(async context => { if (HttpMethods.IsPost(context.Request.Query["TestMethod"])) { await context.Response.WriteAsync(_postHtml); } else { await context.Response.WriteAsync($"Interop {context.Request.Protocol} {context.Request.Method}"); } })); using (var host = hostBuilder.Build()) { await host.StartAsync(); var chromeOutput = RunHeadlessChrome($"https://localhost:{host.GetPort()}/{requestSuffix}"); AssertExpectedResponseOrShowDebugInstructions(expectedResponse, chromeOutput); await host.StopAsync(); } }
public async Task Listen_Http3AndSocketsCoexistOnDifferentEndpoints_ClientSuccess(int http3Port, int http1Port) { // Arrange var builder = new HostBuilder() .ConfigureWebHost(webHostBuilder => { webHostBuilder .UseKestrel(o => { o.Listen(IPAddress.Parse("127.0.0.1"), http3Port, listenOptions => { listenOptions.Protocols = Core.HttpProtocols.Http3; listenOptions.UseHttps(TestResources.GetTestCertificate()); }); o.Listen(IPAddress.Parse("127.0.0.1"), http1Port, listenOptions => { listenOptions.Protocols = Core.HttpProtocols.Http1; listenOptions.UseHttps(TestResources.GetTestCertificate()); }); }) .Configure(app => { app.Run(async context => { await context.Response.WriteAsync("hello, world"); }); }); }) .ConfigureServices(AddTestLogging); using var host = builder.Build(); await host.StartAsync().DefaultTimeout(); await CallHttp3AndHttp1EndpointsAsync(http3Port, http1Port); await host.StopAsync().DefaultTimeout(); }
public async Task ClientCertificate_Allow_NotAvailable_Optional() { var builder = CreateHostBuilder(async context => { var hasCert = context.Connection.ClientCertificate != null; await context.Response.WriteAsync(hasCert.ToString()); }, configureKestrel: kestrelOptions => { kestrelOptions.ListenAnyIP(0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http3; listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); httpsOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate; httpsOptions.AllowAnyClientCertificate(); }); }); }); using var host = builder.Build(); using var client = Http3Helpers.CreateClient(includeClientCert: false); await host.StartAsync().DefaultTimeout(); var request = new HttpRequestMessage(HttpMethod.Get, $"https://127.0.0.1:{host.GetPort()}/"); request.Version = HttpVersion.Version30; request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; // https://github.com/dotnet/runtime/issues/57308, optional client certs aren't supported. var ex = await Assert.ThrowsAsync <HttpRequestException>(() => client.SendAsync(request, CancellationToken.None).DefaultTimeout()); Assert.StartsWith("Connection has been shutdown by transport. Error Code: 0x80410100", ex.Message); await host.StopAsync().DefaultTimeout(); }
public async Task RunIndividualTestCase(H2SpecTestCase testCase) { var hostBuilder = new WebHostBuilder() .UseKestrel(options => { options.Listen(IPAddress.Loopback, 0, listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; if (testCase.Https) { listenOptions.UseHttps(TestResources.GetTestCertificate()); } }); }) .ConfigureServices(AddTestLogging) .Configure(ConfigureHelloWorld); using (var host = hostBuilder.Build()) { await host.StartAsync(); H2SpecCommands.RunTest(testCase.Id, host.GetPort(), testCase.Https, Logger); } }
public async Task UsesExpectedFileName(bool fileExists) { // Arrange var certificate = TestResources.GetTestCertificate(TestResources.TrustedCARootCertificate); var sha256Thumbprint = certificate.ComputeSHA256Thumbprint().ToUpperInvariant(); var expectedFileName = GetExpectedFileName(sha256Thumbprint); var cancellationToken = CancellationToken.None; var storage = new Mock <IStorage>(MockBehavior.Strict); storage .Setup(m => m.ExistsAsync(expectedFileName, cancellationToken)) .ReturnsAsync(fileExists) .Verifiable(); var logger = new Mock <ILogger <CertificateStore> >(MockBehavior.Strict); var certificateStore = new CertificateStore(storage.Object, logger.Object); // Act var result = await certificateStore.ExistsAsync(sha256Thumbprint, cancellationToken); // Assert Assert.Equal(fileExists, result); storage.Verify(); }
public async Task DoesNotThrowObjectDisposedExceptionOnEmptyConnection() { var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory), listenOptions => { listenOptions.UseHttps(TestResources.GetTestCertificate()); })) { using (var connection = server.CreateConnection()) using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true)) { await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates : null, enabledSslProtocols : SslProtocols.Tls11 | SslProtocols.Tls12, checkCertificateRevocation : false); } } Assert.False(loggerProvider.ErrorLogger.ObjectDisposedExceptionLogged); }
private async Task RegisterAddresses_Success(string addressInput, string[] testUrls, int testPort = 0) { var hostBuilder = TransportSelector.GetWebHostBuilder() .UseKestrel(serverOptions => { serverOptions.ConfigureHttpsDefaults(httpsOptions => { httpsOptions.ServerCertificate = TestResources.GetTestCertificate(); }); }) .ConfigureServices(AddTestLogging) .UseUrls(addressInput) .Configure(ConfigureEchoAddress); using (var host = hostBuilder.Build()) { host.Start(); foreach (var testUrl in testUrls.Select(testUrl => $"{testUrl}:{(testPort == 0 ? host.GetPort() : testPort)}")) { var response = await HttpClientSlim.GetStringAsync(testUrl, validateCertificate : false); // Filter out the scope id for IPv6, that's not sent over the wire. "fe80::3%1" // See https://github.com/aspnet/Common/pull/369 var uri = new Uri(testUrl); if (uri.HostNameType == UriHostNameType.IPv6) { var builder = new UriBuilder(uri); var ip = IPAddress.Parse(builder.Host); builder.Host = new IPAddress(ip.GetAddressBytes()).ToString(); // Without the scope id. uri = builder.Uri; } Assert.Equal(uri.ToString(), response); } } }
public void UseHttpsDefaultsToDefaultCert() { var serverOptions = CreateServerOptions(); var defaultCert = TestResources.GetTestCertificate(); serverOptions.DefaultCertificate = defaultCert; serverOptions.ListenLocalhost(5000, options => { options.UseHttps(); }); Assert.False(serverOptions.IsDevCertLoaded); serverOptions.ListenLocalhost(5001, options => { options.UseHttps(opt => { // The default cert is applied after UseHttps. Assert.Null(opt.ServerCertificate); }); }); Assert.False(serverOptions.IsDevCertLoaded); }
public static FeatureCollection CreateBindAsyncFeatures(bool clientCertificateRequired = false) { var cert = TestResources.GetTestCertificate(); var sslServerAuthenticationOptions = new SslServerAuthenticationOptions(); sslServerAuthenticationOptions.ApplicationProtocols = new List <SslApplicationProtocol>() { SslApplicationProtocol.Http3 }; sslServerAuthenticationOptions.ServerCertificate = cert; sslServerAuthenticationOptions.RemoteCertificateValidationCallback = RemoteCertificateValidationCallback; sslServerAuthenticationOptions.ClientCertificateRequired = clientCertificateRequired; var features = new FeatureCollection(); features.Set(new TlsConnectionCallbackOptions { ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols, OnConnection = (context, cancellationToken) => ValueTask.FromResult(sslServerAuthenticationOptions) }); return(features); }
public async Task InitialLoadAsync_ProxyHttpClientOptionsSet_CreateAndSetHttpClient() { const string TestAddress = "https://localhost:123/"; var clientCertificate = TestResources.GetTestCertificate(); var cluster = new Cluster { Id = "cluster1", Destinations = new Dictionary <string, Destination>(StringComparer.OrdinalIgnoreCase) { { "d1", new Destination { Address = TestAddress } } }, HttpClient = new ProxyHttpClientOptions { SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12, MaxConnectionsPerServer = 10, ClientCertificate = clientCertificate, #if NET RequestHeaderEncoding = Encoding.UTF8 #endif } }; var route = new ProxyRoute { RouteId = "route1", ClusterId = "cluster1", Match = new RouteMatch { Path = "/" } }; var services = CreateServices(new List <ProxyRoute>() { route }, new List <Cluster>() { cluster }); var manager = services.GetRequiredService <ProxyConfigManager>(); var dataSource = await manager.InitialLoadAsync(); Assert.NotNull(dataSource); var endpoint = Assert.Single(dataSource.Endpoints); var routeConfig = endpoint.Metadata.GetMetadata <RouteConfig>(); var clusterInfo = routeConfig.Cluster; Assert.Equal("cluster1", clusterInfo.ClusterId); var clusterConfig = clusterInfo.Config; Assert.NotNull(clusterConfig.HttpClient); Assert.Equal(SslProtocols.Tls11 | SslProtocols.Tls12, clusterConfig.Options.HttpClient.SslProtocols); Assert.Equal(10, clusterConfig.Options.HttpClient.MaxConnectionsPerServer); Assert.Same(clientCertificate, clusterConfig.Options.HttpClient.ClientCertificate); #if NET Assert.Equal(Encoding.UTF8, clusterConfig.Options.HttpClient.RequestHeaderEncoding); #endif var handler = Proxy.Tests.ProxyHttpClientFactoryTests.GetHandler(clusterConfig.HttpClient); Assert.Equal(SslProtocols.Tls11 | SslProtocols.Tls12, handler.SslOptions.EnabledSslProtocols); Assert.Equal(10, handler.MaxConnectionsPerServer); Assert.Single(handler.SslOptions.ClientCertificates, clientCertificate); #if NET Assert.Equal(Encoding.UTF8, handler.RequestHeaderEncodingSelector(default, default));
public async Task HttpsConnectionClosedWhenResponseDoesNotSatisfyMinimumDataRate() { const int chunkSize = 1024; const int chunks = 256 * 1024; var chunkData = new byte[chunkSize]; var certificate = TestResources.GetTestCertificate(); var responseRateTimeoutMessageLogged = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var connectionStopMessageLogged = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var aborted = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var appFuncCompleted = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock <IKestrelTrace>(); mockKestrelTrace .Setup(trace => trace.ResponseMinimumDataRateNotSatisfied(It.IsAny <string>(), It.IsAny <string>())) .Callback(() => responseRateTimeoutMessageLogged.SetResult(null)); mockKestrelTrace .Setup(trace => trace.ConnectionStop(It.IsAny <string>())) .Callback(() => connectionStopMessageLogged.SetResult(null)); var testContext = new TestServiceContext(LoggerFactory, mockKestrelTrace.Object) { ServerOptions = { Limits = { MinResponseDataRate = new MinDataRate(bytesPerSecond: 1024 * 1024, gracePeriod: TimeSpan.FromSeconds(2)) } } }; testContext.InitializeHeartbeat(); void ConfigureListenOptions(ListenOptions listenOptions) { listenOptions.UseHttps(new HttpsConnectionAdapterOptions { ServerCertificate = certificate }); } using (var server = new TestServer(async context => { context.RequestAborted.Register(() => { aborted.SetResult(null); }); context.Response.ContentLength = chunks * chunkSize; try { for (var i = 0; i < chunks; i++) { await context.Response.BodyWriter.WriteAsync(new Memory <byte>(chunkData, 0, chunkData.Length), context.RequestAborted); } } catch (OperationCanceledException) { appFuncCompleted.SetResult(null); throw; } finally { await aborted.Task.DefaultTimeout(); } }, testContext, ConfigureListenOptions)) { using (var connection = server.CreateConnection()) { using (var sslStream = new SslStream(connection.Stream, false, (sender, cert, chain, errors) => true, null)) { await sslStream.AuthenticateAsClientAsync("localhost", new X509CertificateCollection(), SslProtocols.Tls12 | SslProtocols.Tls11, false); var request = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"); await sslStream.WriteAsync(request, 0, request.Length); await aborted.Task.DefaultTimeout(); await responseRateTimeoutMessageLogged.Task.DefaultTimeout(); await connectionStopMessageLogged.Task.DefaultTimeout(); await appFuncCompleted.Task.DefaultTimeout(); await AssertStreamAborted(connection.Stream, chunkSize *chunks); } } await server.StopAsync(); } }
public void CachedCertificateIsDisposed_RemoveItFromCache() { var config = new ConfigurationData() { Clusters = { { "cluster1", new ClusterData { Destinations ={ { "destinationA", new DestinationData { Address = "https://localhost:10001/destC" } } }, HttpClient = new ProxyHttpClientData{ ClientCertificate = new CertificateConfigData{ Path = "testCert.pfx" } } } } }, Routes = { new ProxyRouteData { RouteId = "routeA", ClusterId = "cluster1", Order = 1, Match ={ Hosts = new List <string> { "host-B" } } } } }; var configMonitor = new Mock <IOptionsMonitor <ConfigurationData> >(); Action <ConfigurationData, string> onChangeCallback = (a, s) => { Assert.False(true, "OnChange method was not called."); }; configMonitor.SetupGet(m => m.CurrentValue).Returns(config); configMonitor.Setup(m => m.OnChange(It.IsAny <Action <ConfigurationData, string> >())).Callback((Action <ConfigurationData, string> a) => { onChangeCallback = a; }); var provider = GetProvider(configMonitor.Object, "testCert.pfx", null, () => TestResources.GetTestCertificate(), null); // Get several certificates. var certificateConfig = new List <X509Certificate2>(); for (var i = 0; i < 5; i++) { certificateConfig.AddRange(provider.GetConfig().Clusters.Select(c => c.HttpClient.ClientCertificate)); if (i < 4) { onChangeCallback(config, null); } } // Verify cache contents match the configuration objects. var cachedCertificates = GetCachedCertificates(provider); Assert.Equal(certificateConfig.Count, cachedCertificates.Length); for (var i = 0; i < certificateConfig.Count; i++) { Assert.Same(certificateConfig[i], cachedCertificates[i]); } // Get several certificates. certificateConfig[1].Dispose(); certificateConfig[3].Dispose(); // Trigger cache compaction. onChangeCallback(config, null); // Verify disposed certificates were purged out. cachedCertificates = GetCachedCertificates(provider); Assert.Equal(4, cachedCertificates.Length); Assert.Same(certificateConfig[0], cachedCertificates[0]); Assert.Same(certificateConfig[2], cachedCertificates[1]); Assert.Same(certificateConfig[4], cachedCertificates[2]); }
public void GetConfig_ValidConfiguration_AllAbstractionsPropertiesAreSet() { var certificate = TestResources.GetTestCertificate(); var abstractionsNamespace = typeof(Abstractions.Cluster).Namespace; var provider = GetProvider(_validConfigurationData, "mycert.pfx", "myPassword1234", () => certificate); var abstractConfig = (ConfigurationSnapshot)provider.GetConfig(); //Removed incompletely filled out instances. abstractConfig.Clusters = abstractConfig.Clusters.Where(c => c.Id == "cluster1").ToList(); abstractConfig.Routes = abstractConfig.Routes.Where(r => r.RouteId == "routeA").ToList(); VerifyAllPropertiesAreSet(abstractConfig); void VerifyFullyInitialized(object obj, string name) { switch (obj) { case null: Assert.True(false, $"Property {name} is not initialized."); break; case Enum m: Assert.NotEqual(0, (int)(object)m); break; case string str: Assert.NotEmpty(str); break; case ValueType v: var equals = Equals(Activator.CreateInstance(v.GetType()), v); Assert.False(equals, $"Property {name} is not initialized."); if (v.GetType().Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(v); } break; case IDictionary d: Assert.NotEmpty(d); foreach (var value in d.Values) { VerifyFullyInitialized(value, name); } break; case IEnumerable e: Assert.NotEmpty(e); foreach (var item in e) { VerifyFullyInitialized(item, name); } var type = e.GetType(); if (!type.IsArray && type.Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(e); } break; case object o: if (o.GetType().Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(o); } break; } } void VerifyAllPropertiesAreSet(object obj) { var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Cast <PropertyInfo>(); foreach (var property in properties) { VerifyFullyInitialized(property.GetValue(obj), $"{property.DeclaringType.Name}.{property.Name}"); } } }
public async Task HttpsConnectionClosedWhenResponseDoesNotSatisfyMinimumDataRate() { const int chunkSize = 1024; const int chunks = 256 * 1024; var chunkData = new byte[chunkSize]; var certificate = TestResources.GetTestCertificate(); var responseRateTimeoutMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connectionStopMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var aborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); TestSink.MessageLogged += context => { if (context.EventId.Name == "ResponseMinimumDataRateNotSatisfied") { responseRateTimeoutMessageLogged.SetResult(); } if (context.EventId.Name == "ConnectionStop") { connectionStopMessageLogged.SetResult(); } }; var testContext = new TestServiceContext(LoggerFactory) { ServerOptions = { Limits = { MinResponseDataRate = new MinDataRate(bytesPerSecond: 1024 * 1024, gracePeriod: TimeSpan.FromSeconds(2)) } } }; testContext.InitializeHeartbeat(); void ConfigureListenOptions(ListenOptions listenOptions) { listenOptions.UseHttps(new HttpsConnectionAdapterOptions { ServerCertificate = certificate }); } await using (var server = new TestServer(async context => { context.RequestAborted.Register(() => { aborted.SetResult(); }); context.Response.ContentLength = chunks * chunkSize; try { for (var i = 0; i < chunks; i++) { await context.Response.BodyWriter.WriteAsync(new Memory <byte>(chunkData, 0, chunkData.Length), context.RequestAborted); } } catch (OperationCanceledException) { appFuncCompleted.SetResult(); throw; } finally { await aborted.Task.DefaultTimeout(); } }, testContext, ConfigureListenOptions)) { using (var connection = server.CreateConnection()) { using (var sslStream = new SslStream(connection.Stream, false, (sender, cert, chain, errors) => true, null)) { await sslStream.AuthenticateAsClientAsync("localhost", new X509CertificateCollection(), SslProtocols.None, false); var request = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"); await sslStream.WriteAsync(request, 0, request.Length); // Don't use the 5 second timeout for debug builds. This can actually take a while. await aborted.Task.DefaultTimeout(TimeSpan.FromSeconds(30)); await responseRateTimeoutMessageLogged.Task.DefaultTimeout(); await connectionStopMessageLogged.Task.DefaultTimeout(); await appFuncCompleted.Task.DefaultTimeout(); await AssertStreamAborted(connection.Stream, chunkSize *chunks); } } } }
public void GetConfig_ValidConfiguration_AllAbstractionsPropertiesAreSet() { var builder = new ConfigurationBuilder(); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(_validJsonConfig)); var proxyConfig = builder.AddJsonStream(stream).Build(); var certLoader = new Mock <ICertificateConfigLoader>(MockBehavior.Strict); using var certificate = TestResources.GetTestCertificate(); certLoader.Setup(l => l.LoadCertificate(It.Is <IConfigurationSection>(o => o["Path"] == "mycert.pfx" && o["Password"] == "myPassword1234"))).Returns(certificate); var logger = new Mock <ILogger <ConfigurationConfigProvider> >(); var provider = new ConfigurationConfigProvider(logger.Object, proxyConfig, certLoader.Object); var abstractConfig = (ConfigurationSnapshot)provider.GetConfig(); var abstractionsNamespace = typeof(Cluster).Namespace; // Removed incompletely filled out instances. abstractConfig.Clusters = abstractConfig.Clusters.Where(c => c.Id == "cluster1").ToList(); abstractConfig.Routes = abstractConfig.Routes.Where(r => r.RouteId == "routeA").ToList(); VerifyAllPropertiesAreSet(abstractConfig); void VerifyFullyInitialized(object obj, string name) { switch (obj) { case null: Assert.True(false, $"Property {name} is not initialized."); break; case Enum m: Assert.NotEqual(0, (int)(object)m); break; case string str: Assert.NotEmpty(str); break; case ValueType v: var equals = Equals(Activator.CreateInstance(v.GetType()), v); Assert.False(equals, $"Property {name} is not initialized."); if (v.GetType().Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(v); } break; case IDictionary d: Assert.NotEmpty(d); foreach (var value in d.Values) { VerifyFullyInitialized(value, name); } break; case IEnumerable e: Assert.NotEmpty(e); foreach (var item in e) { VerifyFullyInitialized(item, name); } var type = e.GetType(); if (!type.IsArray && type.Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(e); } break; case object o: if (o.GetType().Namespace == abstractionsNamespace) { VerifyAllPropertiesAreSet(o); } break; } } void VerifyAllPropertiesAreSet(object obj) { var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Cast <PropertyInfo>(); foreach (var property in properties) { VerifyFullyInitialized(property.GetValue(obj), $"{property.DeclaringType.Name}.{property.Name}"); } } }
public void CachedCertificateIsDisposed_RemoveItFromCache() { var builder = new ConfigurationBuilder(); var proxyConfig = builder.AddInMemoryCollection(new Dictionary <string, string> { ["Clusters:cluster1:Destinations:destinationA:Address"] = "https://localhost:10001/destC", ["Clusters:cluster1:HttpClient:ClientCertificate:Path"] = "testCert.pfx", ["Routes:0:RouteId"] = "routeA", ["Routes:0:ClusterId"] = "cluster1", ["Routes:0:Order"] = "1", ["Routes:0:Match:Hosts:0"] = "host-B", }).Build(); var certLoader = new Mock <ICertificateConfigLoader>(MockBehavior.Strict); using var certificate = TestResources.GetTestCertificate(); certLoader.Setup(l => l.LoadCertificate(It.IsAny <IConfigurationSection>())).Returns(() => TestResources.GetTestCertificate()); var logger = new Mock <ILogger <ConfigurationConfigProvider> >(); logger.Setup(l => l.IsEnabled(LogLevel.Error)).Returns(true); var provider = new ConfigurationConfigProvider(logger.Object, proxyConfig, certLoader.Object); // Get several certificates. var certificateConfig = new List <X509Certificate2>(); for (var i = 0; i < 5; i++) { certificateConfig.AddRange(provider.GetConfig().Clusters.Select(c => c.HttpClient.ClientCertificate)); if (i < 4) { TriggerOnChange(proxyConfig); } } // Verify cache contents match the configuration objects. var cachedCertificates = GetCachedCertificates(provider); Assert.Equal(certificateConfig.Count, cachedCertificates.Length); for (var i = 0; i < certificateConfig.Count; i++) { Assert.Same(certificateConfig[i], cachedCertificates[i]); } // Get several certificates. certificateConfig[1].Dispose(); certificateConfig[3].Dispose(); // Trigger cache compaction. TriggerOnChange(proxyConfig); // Verify disposed certificates were purged out. cachedCertificates = GetCachedCertificates(provider); Assert.Equal(4, cachedCertificates.Length); Assert.Same(certificateConfig[0], cachedCertificates[0]); Assert.Same(certificateConfig[2], cachedCertificates[1]); Assert.Same(certificateConfig[4], cachedCertificates[2]); }