From 80b7dc7c0cbae2e6a011014de2330799141108fd Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Sat, 18 Jul 2020 00:16:49 +0430 Subject: [PATCH 1/6] Load ClientCertificateMode from config --- .../Core/src/Internal/ConfigurationReader.cs | 14 ++++++++ .../Core/src/KestrelConfigurationLoader.cs | 2 ++ .../Kestrel/test/ConfigurationReaderTests.cs | 33 +++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs index 2843bb014c5e..e70e409820aa 100644 --- a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs +++ b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Authentication; +using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.Extensions.Configuration; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal @@ -18,12 +19,14 @@ internal class ConfigurationReader private const string EndpointDefaultsKey = "EndpointDefaults"; private const string EndpointsKey = "Endpoints"; private const string UrlKey = "Url"; + private const string ClientCertificateModeKey = "ClientCertificateMode"; private readonly IConfiguration _configuration; private IDictionary _certificates; private EndpointDefaults _endpointDefaults; private IEnumerable _endpoints; + private ClientCertificateMode? _clientCertificateMode; public ConfigurationReader(IConfiguration configuration) { @@ -33,6 +36,7 @@ public ConfigurationReader(IConfiguration configuration) public IDictionary Certificates => _certificates ??= ReadCertificates(); public EndpointDefaults EndpointDefaults => _endpointDefaults ??= ReadEndpointDefaults(); public IEnumerable Endpoints => _endpoints ??= ReadEndpoints(); + public ClientCertificateMode? ClientCertificateMode => _clientCertificateMode ??= ReadClientCertificateMode(); private IDictionary ReadCertificates() { @@ -100,6 +104,16 @@ private IEnumerable ReadEndpoints() return endpoints; } + private ClientCertificateMode? ReadClientCertificateMode() + { + if (Enum.TryParse(_configuration[ClientCertificateModeKey], ignoreCase: true, out var result)) + { + return result; + } + + return null; + } + private static HttpProtocols? ParseProtocols(string protocols) { if (Enum.TryParse(protocols, ignoreCase: true, out var result)) diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs index 04349031e2d1..fc54e75e4f15 100644 --- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs +++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs @@ -293,6 +293,8 @@ public void Load() httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) ?? httpsOptions.ServerCertificate; + httpsOptions.ClientCertificateMode = ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; + if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null) { // Fallback diff --git a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs index 06345cc46215..a47e5b644f93 100644 --- a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs +++ b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs @@ -7,6 +7,7 @@ using System.Security.Authentication; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.Extensions.Configuration; using Xunit; @@ -14,6 +15,38 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests { public class ConfigurationReaderTests { + [Fact] + public void ReadClientCertificateMode_ReturnsValue() + { + // Arrange + var config = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["ClientCertificateMode"] = "AllowCertificate" + }) + .Build(); + + // Act + var reader = new ConfigurationReader(config); + + // Assert + Assert.NotNull(reader.ClientCertificateMode); + Assert.Equal(ClientCertificateMode.AllowCertificate, reader.ClientCertificateMode); + } + + [Fact] + public void ReadClientCertificateModeWhenNoClientCertificateMode_ReturnsNull() + { + // Arrange + var config = new ConfigurationBuilder().AddInMemoryCollection().Build(); + + // Act + var reader = new ConfigurationReader(config); + + // Assert + Assert.Null(reader.ClientCertificateMode); + } + [Fact] public void ReadCertificatesWhenNoCertificatesSection_ReturnsEmptyCollection() { From 050632502e4813e4e70344f7d469d602cb12d2a7 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Tue, 21 Jul 2020 22:42:27 +0430 Subject: [PATCH 2/6] Move it, move it --- src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs index fc54e75e4f15..9d66a7489325 100644 --- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs +++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs @@ -289,11 +289,11 @@ public void Load() httpsOptions.SslProtocols = endpoint.SslProtocols.Value; } + httpsOptions.ClientCertificateMode = ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; + // Specified httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) - ?? httpsOptions.ServerCertificate; - - httpsOptions.ClientCertificateMode = ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; + ?? httpsOptions.ServerCertificate; if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null) { From 59619888b403a56398c582530b5bd4975a685928 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Wed, 22 Jul 2020 00:51:56 +0430 Subject: [PATCH 3/6] Config ClientCertificateMode per endpoint --- .../Kestrel/Core/src/Internal/ConfigurationReader.cs | 11 +++++++---- .../Kestrel/Core/src/KestrelConfigurationLoader.cs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs index e70e409820aa..9c3b6e4a70a2 100644 --- a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs +++ b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs @@ -36,7 +36,7 @@ public ConfigurationReader(IConfiguration configuration) public IDictionary Certificates => _certificates ??= ReadCertificates(); public EndpointDefaults EndpointDefaults => _endpointDefaults ??= ReadEndpointDefaults(); public IEnumerable Endpoints => _endpoints ??= ReadEndpoints(); - public ClientCertificateMode? ClientCertificateMode => _clientCertificateMode ??= ReadClientCertificateMode(); + public ClientCertificateMode? ClientCertificateMode => _clientCertificateMode ??= ReadClientCertificateMode(_configuration[ClientCertificateModeKey]); private IDictionary ReadCertificates() { @@ -95,7 +95,8 @@ private IEnumerable ReadEndpoints() Protocols = ParseProtocols(endpointConfig[ProtocolsKey]), ConfigSection = endpointConfig, Certificate = new CertificateConfig(endpointConfig.GetSection(CertificateKey)), - SslProtocols = ParseSslProcotols(endpointConfig.GetSection(SslProtocolsKey)) + SslProtocols = ParseSslProcotols(endpointConfig.GetSection(SslProtocolsKey)), + ClientCertificateMode = ReadClientCertificateMode(endpointConfig[ClientCertificateModeKey]) }; endpoints.Add(endpoint); @@ -104,9 +105,9 @@ private IEnumerable ReadEndpoints() return endpoints; } - private ClientCertificateMode? ReadClientCertificateMode() + private ClientCertificateMode? ReadClientCertificateMode(string clientCertificateMode) { - if (Enum.TryParse(_configuration[ClientCertificateModeKey], ignoreCase: true, out var result)) + if (Enum.TryParse(clientCertificateMode, ignoreCase: true, out var result)) { return result; } @@ -185,6 +186,8 @@ public IConfigurationSection ConfigSection } } + public ClientCertificateMode? ClientCertificateMode { get; internal set; } + public override bool Equals(object obj) => obj is EndpointConfig other && Name == other.Name && diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs index 9d66a7489325..6171b2de321f 100644 --- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs +++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs @@ -289,7 +289,7 @@ public void Load() httpsOptions.SslProtocols = endpoint.SslProtocols.Value; } - httpsOptions.ClientCertificateMode = ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; + httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode ?? ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; // Specified httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) From bd54413b45b1984b38a6dee1116d077234eaf5f7 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Wed, 22 Jul 2020 01:02:16 +0430 Subject: [PATCH 4/6] Test ClientCertificateMode in endpoint --- .../Kestrel/Core/src/KestrelConfigurationLoader.cs | 2 +- .../Kestrel/Kestrel/test/ConfigurationReaderTests.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs index 6171b2de321f..a506e53274cf 100644 --- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs +++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs @@ -293,7 +293,7 @@ public void Load() // Specified httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) - ?? httpsOptions.ServerCertificate; + ?? httpsOptions.ServerCertificate; if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null) { diff --git a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs index a47e5b644f93..1292bad0801d 100644 --- a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs +++ b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs @@ -125,7 +125,7 @@ public void ReadCertificatesSection_IsCaseInsensitive() [Fact] public void ReadCertificatesSection_ThrowsOnCaseInsensitiveDuplicate() { - var exception = Assert.Throws(() => + var exception = Assert.Throws(() => new ConfigurationBuilder().AddInMemoryCollection(new[] { new KeyValuePair("Certificates:filecert:Password", "certpassword"), @@ -187,10 +187,13 @@ public void ReadEndpointsSection_ReturnsCollection() { new KeyValuePair("Endpoints:End1:Url", "http://*:5001"), new KeyValuePair("Endpoints:End2:Url", "https://*:5002"), + new KeyValuePair("Endpoints:End2:ClientCertificateMode", "AllowCertificate"), new KeyValuePair("Endpoints:End3:Url", "https://*:5003"), + new KeyValuePair("Endpoints:End3:ClientCertificateMode", "RequireCertificate"), new KeyValuePair("Endpoints:End3:Certificate:Path", "/path/cert.pfx"), new KeyValuePair("Endpoints:End3:Certificate:Password", "certpassword"), new KeyValuePair("Endpoints:End4:Url", "https://*:5004"), + new KeyValuePair("Endpoints:End4:ClientCertificateMode", "NoCertificate"), new KeyValuePair("Endpoints:End4:Certificate:Subject", "certsubject"), new KeyValuePair("Endpoints:End4:Certificate:Store", "certstore"), new KeyValuePair("Endpoints:End4:Certificate:Location", "cetlocation"), @@ -204,6 +207,7 @@ public void ReadEndpointsSection_ReturnsCollection() var end1 = endpoints.First(); Assert.Equal("End1", end1.Name); Assert.Equal("http://*:5001", end1.Url); + Assert.Null(end1.ClientCertificateMode); Assert.NotNull(end1.ConfigSection); Assert.NotNull(end1.Certificate); Assert.False(end1.Certificate.ConfigSection.Exists()); @@ -211,6 +215,7 @@ public void ReadEndpointsSection_ReturnsCollection() var end2 = endpoints.Skip(1).First(); Assert.Equal("End2", end2.Name); Assert.Equal("https://*:5002", end2.Url); + Assert.Equal(ClientCertificateMode.AllowCertificate, end2.ClientCertificateMode); Assert.NotNull(end2.ConfigSection); Assert.NotNull(end2.Certificate); Assert.False(end2.Certificate.ConfigSection.Exists()); @@ -218,6 +223,7 @@ public void ReadEndpointsSection_ReturnsCollection() var end3 = endpoints.Skip(2).First(); Assert.Equal("End3", end3.Name); Assert.Equal("https://*:5003", end3.Url); + Assert.Equal(ClientCertificateMode.RequireCertificate, end3.ClientCertificateMode); Assert.NotNull(end3.ConfigSection); Assert.NotNull(end3.Certificate); Assert.True(end3.Certificate.ConfigSection.Exists()); @@ -230,6 +236,7 @@ public void ReadEndpointsSection_ReturnsCollection() var end4 = endpoints.Skip(3).First(); Assert.Equal("End4", end4.Name); Assert.Equal("https://*:5004", end4.Url); + Assert.Equal(ClientCertificateMode.NoCertificate, end4.ClientCertificateMode); Assert.NotNull(end4.ConfigSection); Assert.NotNull(end4.Certificate); Assert.True(end4.Certificate.ConfigSection.Exists()); @@ -268,7 +275,7 @@ public void ReadEndpointWithMultipleSslProtocolsSet_ReturnsCorrectValue() var reader = new ConfigurationReader(config); var endpoint = reader.Endpoints.First(); - Assert.Equal(SslProtocols.Tls11|SslProtocols.Tls12, endpoint.SslProtocols); + Assert.Equal(SslProtocols.Tls11 | SslProtocols.Tls12, endpoint.SslProtocols); } [Fact] From c6e894686f4e9fa975141916997f18a41dc45737 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Wed, 22 Jul 2020 02:02:34 +0430 Subject: [PATCH 5/6] Remove global config for ClientCertificateMode, add some tests --- .../Core/src/Internal/ConfigurationReader.cs | 20 +-- .../Core/src/KestrelConfigurationLoader.cs | 6 +- .../Kestrel/test/ConfigurationReaderTests.cs | 68 ++++----- .../test/KestrelConfigurationLoaderTests.cs | 130 ++++++++++++++++++ 4 files changed, 183 insertions(+), 41 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs index 9c3b6e4a70a2..a47c91c2abf0 100644 --- a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs +++ b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs @@ -26,7 +26,6 @@ internal class ConfigurationReader private IDictionary _certificates; private EndpointDefaults _endpointDefaults; private IEnumerable _endpoints; - private ClientCertificateMode? _clientCertificateMode; public ConfigurationReader(IConfiguration configuration) { @@ -36,7 +35,6 @@ public ConfigurationReader(IConfiguration configuration) public IDictionary Certificates => _certificates ??= ReadCertificates(); public EndpointDefaults EndpointDefaults => _endpointDefaults ??= ReadEndpointDefaults(); public IEnumerable Endpoints => _endpoints ??= ReadEndpoints(); - public ClientCertificateMode? ClientCertificateMode => _clientCertificateMode ??= ReadClientCertificateMode(_configuration[ClientCertificateModeKey]); private IDictionary ReadCertificates() { @@ -54,6 +52,7 @@ private IDictionary ReadCertificates() // "EndpointDefaults": { // "Protocols": "Http1AndHttp2", // "SslProtocols": [ "Tls11", "Tls12", "Tls13"], + // "ClientCertificateMode" : "NoCertificate" // } private EndpointDefaults ReadEndpointDefaults() { @@ -61,7 +60,8 @@ private EndpointDefaults ReadEndpointDefaults() return new EndpointDefaults { Protocols = ParseProtocols(configSection[ProtocolsKey]), - SslProtocols = ParseSslProcotols(configSection.GetSection(SslProtocolsKey)) + SslProtocols = ParseSslProcotols(configSection.GetSection(SslProtocolsKey)), + ClientCertificateMode = ParseClientCertificateMode(configSection[ClientCertificateModeKey]) }; } @@ -79,7 +79,8 @@ private IEnumerable ReadEndpoints() // "Certificate": { // "Path": "testCert.pfx", // "Password": "testPassword" - // } + // }, + // "ClientCertificateMode" : "NoCertificate" // } var url = endpointConfig[UrlKey]; @@ -96,7 +97,7 @@ private IEnumerable ReadEndpoints() ConfigSection = endpointConfig, Certificate = new CertificateConfig(endpointConfig.GetSection(CertificateKey)), SslProtocols = ParseSslProcotols(endpointConfig.GetSection(SslProtocolsKey)), - ClientCertificateMode = ReadClientCertificateMode(endpointConfig[ClientCertificateModeKey]) + ClientCertificateMode = ParseClientCertificateMode(endpointConfig[ClientCertificateModeKey]) }; endpoints.Add(endpoint); @@ -105,7 +106,7 @@ private IEnumerable ReadEndpoints() return endpoints; } - private ClientCertificateMode? ReadClientCertificateMode(string clientCertificateMode) + private ClientCertificateMode? ParseClientCertificateMode(string clientCertificateMode) { if (Enum.TryParse(clientCertificateMode, ignoreCase: true, out var result)) { @@ -144,11 +145,13 @@ private IEnumerable ReadEndpoints() // "EndpointDefaults": { // "Protocols": "Http1AndHttp2", // "SslProtocols": [ "Tls11", "Tls12", "Tls13"], + // "ClientCertificateMode" : "NoCertificate" // } internal class EndpointDefaults { public HttpProtocols? Protocols { get; set; } public SslProtocols? SslProtocols { get; set; } + public ClientCertificateMode? ClientCertificateMode { get; set; } } // "EndpointName": { @@ -158,7 +161,8 @@ internal class EndpointDefaults // "Certificate": { // "Path": "testCert.pfx", // "Password": "testPassword" - // } + // }, + // "ClientCertificateMode" : "NoCertificate" // } internal class EndpointConfig { @@ -170,6 +174,7 @@ internal class EndpointConfig public HttpProtocols? Protocols { get; set; } public SslProtocols? SslProtocols { get; set; } public CertificateConfig Certificate { get; set; } + public ClientCertificateMode? ClientCertificateMode { get; set; } // Compare config sections because it's accessible to app developers via an Action callback. // We cannot rely entirely on comparing config sections for equality, because KestrelConfigurationLoader.Reload() sets @@ -186,7 +191,6 @@ public IConfigurationSection ConfigSection } } - public ClientCertificateMode? ClientCertificateMode { get; internal set; } public override bool Equals(object obj) => obj is EndpointConfig other && diff --git a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs index a506e53274cf..86e63ddc6a73 100644 --- a/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs +++ b/src/Servers/Kestrel/Core/src/KestrelConfigurationLoader.cs @@ -280,6 +280,7 @@ public void Load() if (https) { httpsOptions.SslProtocols = ConfigurationReader.EndpointDefaults.SslProtocols ?? SslProtocols.None; + httpsOptions.ClientCertificateMode = ConfigurationReader.EndpointDefaults.ClientCertificateMode ?? ClientCertificateMode.NoCertificate; // Defaults Options.ApplyHttpsDefaults(httpsOptions); @@ -289,7 +290,10 @@ public void Load() httpsOptions.SslProtocols = endpoint.SslProtocols.Value; } - httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode ?? ConfigurationReader.ClientCertificateMode ?? httpsOptions.ClientCertificateMode; + if (endpoint.ClientCertificateMode.HasValue) + { + httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode.Value; + } // Specified httpsOptions.ServerCertificate = LoadCertificate(endpoint.Certificate, endpoint.Name) diff --git a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs index 1292bad0801d..6b24b86b62d2 100644 --- a/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs +++ b/src/Servers/Kestrel/Kestrel/test/ConfigurationReaderTests.cs @@ -15,38 +15,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests { public class ConfigurationReaderTests { - [Fact] - public void ReadClientCertificateMode_ReturnsValue() - { - // Arrange - var config = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary - { - ["ClientCertificateMode"] = "AllowCertificate" - }) - .Build(); - - // Act - var reader = new ConfigurationReader(config); - - // Assert - Assert.NotNull(reader.ClientCertificateMode); - Assert.Equal(ClientCertificateMode.AllowCertificate, reader.ClientCertificateMode); - } - - [Fact] - public void ReadClientCertificateModeWhenNoClientCertificateMode_ReturnsNull() - { - // Arrange - var config = new ConfigurationBuilder().AddInMemoryCollection().Build(); - - // Act - var reader = new ConfigurationReader(config); - - // Assert - Assert.Null(reader.ClientCertificateMode); - } - [Fact] public void ReadCertificatesWhenNoCertificatesSection_ReturnsEmptyCollection() { @@ -327,5 +295,41 @@ public void ReadEndpointDefaultsWithNoSslProtocolSettings_ReturnsCorrectValue() var endpoint = reader.EndpointDefaults; Assert.Null(endpoint.SslProtocols); } + + [Fact] + public void ReadEndpointWithNoClientCertificateModeSettings_ReturnsNull() + { + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("Endpoints:End1:Url", "http://*:5001"), + }).Build(); + var reader = new ConfigurationReader(config); + + var endpoint = reader.Endpoints.First(); + Assert.Null(endpoint.ClientCertificateMode); + } + + [Fact] + public void ReadEndpointDefaultsWithClientCertificateModeSet_ReturnsCorrectValue() + { + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("EndpointDefaults:ClientCertificateMode", "AllowCertificate"), + }).Build(); + var reader = new ConfigurationReader(config); + + var endpoint = reader.EndpointDefaults; + Assert.Equal(ClientCertificateMode.AllowCertificate, endpoint.ClientCertificateMode); + } + + [Fact] + public void ReadEndpointDefaultsWithNoAllowCertificateSettings_ReturnsCorrectValue() + { + var config = new ConfigurationBuilder().Build(); + var reader = new ConfigurationReader(config); + + var endpoint = reader.EndpointDefaults; + Assert.Null(endpoint.ClientCertificateMode); + } } } diff --git a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs index 5053b3cffb12..2e71cdb2239c 100644 --- a/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs +++ b/src/Servers/Kestrel/Kestrel/test/KestrelConfigurationLoaderTests.cs @@ -704,6 +704,136 @@ public void DefaultEndpointConfigureSection_ConfigureHttpsDefaultsCanOverrideSsl Assert.True(ran1); } + [Fact] + public void EndpointConfigureSection_CanSetClientCertificateMode() + { + var serverOptions = CreateServerOptions(); + var ranDefault = false; + + serverOptions.ConfigureHttpsDefaults(opt => + { + opt.ServerCertificate = TestResources.GetTestCertificate(); + + // Kestrel default + Assert.Equal(ClientCertificateMode.NoCertificate, opt.ClientCertificateMode); + ranDefault = true; + }); + + var ran1 = false; + var ran2 = false; + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("Endpoints:End1:ClientCertificateMode", "AllowCertificate"), + new KeyValuePair("Endpoints:End1:Url", "https://*:5001"), + }).Build(); + serverOptions.Configure(config) + .Endpoint("End1", opt => + { + Assert.Equal(ClientCertificateMode.AllowCertificate, opt.HttpsOptions.ClientCertificateMode); + ran1 = true; + }) + .Load(); + serverOptions.ListenAnyIP(0, opt => + { + opt.UseHttps(httpsOptions => + { + // Kestrel default. + Assert.Equal(ClientCertificateMode.NoCertificate, httpsOptions.ClientCertificateMode); + ran2 = true; + }); + }); + + Assert.True(ranDefault); + Assert.True(ran1); + Assert.True(ran2); + } + + [Fact] + public void EndpointConfigureSection_CanOverrideClientCertificateModeFromConfigureHttpsDefaults() + { + var serverOptions = CreateServerOptions(); + + serverOptions.ConfigureHttpsDefaults(opt => + { + opt.ServerCertificate = TestResources.GetTestCertificate(); + opt.ClientCertificateMode = ClientCertificateMode.RequireCertificate; + }); + + var ran1 = false; + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("Endpoints:End1:ClientCertificateMode", "AllowCertificate"), + new KeyValuePair("Endpoints:End1:Url", "https://*:5001"), + }).Build(); + serverOptions.Configure(config) + .Endpoint("End1", opt => + { + Assert.Equal(ClientCertificateMode.AllowCertificate, opt.HttpsOptions.ClientCertificateMode); + ran1 = true; + }) + .Load(); + + Assert.True(ran1); + } + + [Fact] + public void DefaultEndpointConfigureSection_CanSetClientCertificateMode() + { + var serverOptions = CreateServerOptions(); + + serverOptions.ConfigureHttpsDefaults(opt => + { + opt.ServerCertificate = TestResources.GetTestCertificate(); + }); + + var ran1 = false; + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("EndpointDefaults:ClientCertificateMode", "AllowCertificate"), + new KeyValuePair("Endpoints:End1:Url", "https://*:5001"), + }).Build(); + serverOptions.Configure(config) + .Endpoint("End1", opt => + { + Assert.Equal(ClientCertificateMode.AllowCertificate, opt.HttpsOptions.ClientCertificateMode); + ran1 = true; + }) + .Load(); + + Assert.True(ran1); + } + + + [Fact] + public void DefaultEndpointConfigureSection_ConfigureHttpsDefaultsCanOverrideClientCertificateMode() + { + var serverOptions = CreateServerOptions(); + + serverOptions.ConfigureHttpsDefaults(opt => + { + opt.ServerCertificate = TestResources.GetTestCertificate(); + + Assert.Equal(ClientCertificateMode.AllowCertificate, opt.ClientCertificateMode); + opt.ClientCertificateMode = ClientCertificateMode.RequireCertificate; + }); + + var ran1 = false; + var config = new ConfigurationBuilder().AddInMemoryCollection(new[] + { + new KeyValuePair("EndpointDefaults:ClientCertificateMode", "AllowCertificate"), + new KeyValuePair("Endpoints:End1:Url", "https://*:5001"), + }).Build(); + serverOptions.Configure(config) + .Endpoint("End1", opt => + { + Assert.Equal(ClientCertificateMode.RequireCertificate, opt.HttpsOptions.ClientCertificateMode); + ran1 = true; + }) + .Load(); + + Assert.True(ran1); + } + [Fact] public void Reload_IdentifiesEndpointsToStartAndStop() { From bfbd1c4a602e598624e8bb8d25d42a8e921a63ee Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Wed, 22 Jul 2020 02:08:42 +0430 Subject: [PATCH 6/6] Remove empty line --- src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs index a47c91c2abf0..894cd0fa01ed 100644 --- a/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs +++ b/src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs @@ -191,7 +191,6 @@ public IConfigurationSection ConfigSection } } - public override bool Equals(object obj) => obj is EndpointConfig other && Name == other.Name &&