From 77ceb77665fffe98f3610f4ab31fcab18fd87909 Mon Sep 17 00:00:00 2001 From: Anouar Hassine Date: Thu, 6 Dec 2018 18:01:16 +0100 Subject: [PATCH 1/2] Adding SSL support for RabbitMq --- .../Configuration/BusDetails.cs | 42 +++++++++++++-- .../Configuration/ConfigurationOverrides.cs | 15 +++++- ReactiveXComponent/Configuration/XCApiTags.cs | 8 +++ .../Parser/XCApiConfigParser.cs | 51 +++++++++++++++---- .../RabbitMq/RabbitMqConnection.cs | 30 +++++++++++ .../RabbitMq/RabbitMqSession.cs | 34 +++++++++++++ .../Configuration/ConfigurationTests.cs | 9 +++- ReactiveXComponentTest/RabbitMqTestApi.xcApi | 2 +- 8 files changed, 176 insertions(+), 15 deletions(-) diff --git a/ReactiveXComponent/Configuration/BusDetails.cs b/ReactiveXComponent/Configuration/BusDetails.cs index a4c5ca4..44211c4 100644 --- a/ReactiveXComponent/Configuration/BusDetails.cs +++ b/ReactiveXComponent/Configuration/BusDetails.cs @@ -1,4 +1,6 @@ +using System.Security.Authentication; + namespace ReactiveXComponent.Configuration { public class BusDetails @@ -8,14 +10,30 @@ public BusDetails() } - public BusDetails(string username, string password, string host, string virtualHost, int port) + public BusDetails( + string username, + string password, + string host, + string virtualHost, + int port, + bool sslEnabled = false, + string sslServerName = "", + string sslCertPath = "", + string sslCertPassphrase = "", + SslProtocols sslProtocol = SslProtocols.Default, + bool sslAllowUntrustedServerCertificate = false) { Username = username; Password = password; Host = host; VirtualHost = virtualHost; Port = port; - + SslEnabled = sslEnabled; + SslServerName = sslServerName; + SslCertPath = sslCertPath; + SslCertPassphrase = sslCertPassphrase; + SslProtocol = sslProtocol; + SslAllowUntrustedServerCertificate = sslAllowUntrustedServerCertificate; } public string Username { get; set; } @@ -28,6 +46,18 @@ public BusDetails(string username, string password, string host, string virtualH public int Port { get; set; } + public bool SslEnabled { get; set; } + + public string SslServerName { get; set; } + + public string SslCertPath { get; set; } + + public string SslCertPassphrase { get; set; } + + public SslProtocols SslProtocol { get; set; } + + public bool SslAllowUntrustedServerCertificate { get; set; } + public BusDetails Clone() { return new BusDetails( @@ -35,7 +65,13 @@ public BusDetails Clone() Password, Host, VirtualHost, - Port); + Port, + SslEnabled, + SslServerName, + SslCertPath, + SslCertPassphrase, + SslProtocol, + SslAllowUntrustedServerCertificate); } } } diff --git a/ReactiveXComponent/Configuration/ConfigurationOverrides.cs b/ReactiveXComponent/Configuration/ConfigurationOverrides.cs index 33782ab..92d217d 100644 --- a/ReactiveXComponent/Configuration/ConfigurationOverrides.cs +++ b/ReactiveXComponent/Configuration/ConfigurationOverrides.cs @@ -1,4 +1,5 @@ -using ReactiveXComponent.Common; +using System.Security.Authentication; +using ReactiveXComponent.Common; namespace ReactiveXComponent.Configuration { @@ -15,5 +16,17 @@ public class ConfigurationOverrides public string Password { get; set; } public WebSocketType? WebSocketType { get; set; } + + public bool? SslEnabled { get; set; } + + public string SslServerName { get; set; } + + public string SslCertPath { get; set; } + + public string SslCertPassphrase { get; set; } + + public SslProtocols? SslProtocol { get; set; } + + public bool? SslAllowUntrustedServerCertificate { get; set; } } } diff --git a/ReactiveXComponent/Configuration/XCApiTags.cs b/ReactiveXComponent/Configuration/XCApiTags.cs index de89362..e979857 100644 --- a/ReactiveXComponent/Configuration/XCApiTags.cs +++ b/ReactiveXComponent/Configuration/XCApiTags.cs @@ -29,5 +29,13 @@ public static class XCApiTags public const string Json = "Json"; public const string Bson = "Bson"; public const string GzipJson = "GzipJson"; + public const string WebsocketType = "type"; + public const string VirtualHost = "virtualHost"; + public const string BusSslEnabled = "sslEnabled"; + public const string BusSslServerName = "sslServerName"; + public const string BusSslCertPath = "sslCertPath"; + public const string BusSslCertPassphrase = "sslCertPassphrase"; + public const string BusSslProtocol = "sslProtocol"; + public const string BusSslAllowUntrustedServerCertificate = "sslAllowUntrustedServerCertificate"; } } diff --git a/ReactiveXComponent/Parser/XCApiConfigParser.cs b/ReactiveXComponent/Parser/XCApiConfigParser.cs index 2059f76..ad85718 100644 --- a/ReactiveXComponent/Parser/XCApiConfigParser.cs +++ b/ReactiveXComponent/Parser/XCApiConfigParser.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security.Authentication; using System.Xml; using System.Xml.Linq; using ReactiveXComponent.Common; @@ -182,12 +183,44 @@ public string GetSerializationType() public BusDetails GetBusDetails() { XElement busInfos = _xcApiDescription.GetBusNode()?.FirstOrDefault(); + + var sslEnabledString = busInfos?.Attribute(XCApiTags.BusSslEnabled)?.Value; + var sslEnabled = false; + if (!string.IsNullOrEmpty(sslEnabledString)) + { + bool.TryParse(sslEnabledString, out sslEnabled); + } + + var sslServerName = busInfos?.Attribute(XCApiTags.BusSslServerName)?.Value; + var sslCertPath = busInfos?.Attribute(XCApiTags.BusSslCertPath)?.Value; + var sslCertPassphrase = busInfos?.Attribute(XCApiTags.BusSslCertPassphrase)?.Value; + + var sslProtocolString = busInfos?.Attribute(XCApiTags.BusSslProtocol)?.Value; + SslProtocols sslProtocol = SslProtocols.Default; + if (!string.IsNullOrEmpty(sslProtocolString)) + { + Enum.TryParse(sslProtocolString, out sslProtocol); + } + + var sslAllowUntrustedServerCertificateString = busInfos?.Attribute(XCApiTags.BusSslAllowUntrustedServerCertificate)?.Value; + var sslAllowUntrustedServerCertificate = false; + if (!string.IsNullOrEmpty(sslAllowUntrustedServerCertificateString)) + { + bool.TryParse(sslAllowUntrustedServerCertificateString, out sslAllowUntrustedServerCertificate); + } + var busDetails = new BusDetails( - busInfos?.Attribute("user")?.Value, - busInfos?.Attribute("password")?.Value, - busInfos?.Attribute("host")?.Value, - busInfos?.Attribute("virtualHost")?.Value, - Convert.ToInt32(busInfos?.Attribute("port")?.Value)); + busInfos?.Attribute(XCApiTags.User)?.Value, + busInfos?.Attribute(XCApiTags.Password)?.Value, + busInfos?.Attribute(XCApiTags.Host)?.Value, + busInfos?.Attribute(XCApiTags.VirtualHost)?.Value, + Convert.ToInt32(busInfos?.Attribute(XCApiTags.Port)?.Value), + sslEnabled, + sslServerName, + sslCertPath, + sslCertPassphrase, + sslProtocol, + sslAllowUntrustedServerCertificate); return busDetails; } @@ -197,16 +230,16 @@ public WebSocketEndpoint GetWebSocketEndpoint() XElement websocketInfos = _xcApiDescription.GetWebSocketNode()?.FirstOrDefault(); WebSocketType webSocketType; - var webSocketTypeString = websocketInfos?.Attribute("type")?.Value; + var webSocketTypeString = websocketInfos?.Attribute(XCApiTags.WebsocketType)?.Value; if (!Enum.TryParse(webSocketTypeString, out webSocketType)) { throw new ReactiveXComponentException($"Could not parse communication type: {webSocketTypeString}"); } var webSocketEndpoint = new WebSocketEndpoint( - websocketInfos?.Attribute("name")?.Value, - websocketInfos?.Attribute("host")?.Value, - websocketInfos?.Attribute("port")?.Value, + websocketInfos?.Attribute(XCApiTags.Name)?.Value, + websocketInfos?.Attribute(XCApiTags.Host)?.Value, + websocketInfos?.Attribute(XCApiTags.Port)?.Value, webSocketType); return webSocketEndpoint; diff --git a/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs b/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs index a3db190..628db38 100644 --- a/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs +++ b/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs @@ -50,6 +50,36 @@ public IXCSession CreateSession(ConfigurationOverrides configurationOverrides = busDetails.Password = configurationOverrides.Password; } + if (configurationOverrides.SslEnabled != null) + { + busDetails.SslEnabled = configurationOverrides.SslEnabled.Value; + } + + if (configurationOverrides.SslServerName != null) + { + busDetails.SslServerName = configurationOverrides.SslServerName; + } + + if (configurationOverrides.SslCertPath != null) + { + busDetails.SslCertPath = configurationOverrides.SslCertPath; + } + + if (configurationOverrides.SslCertPassphrase != null) + { + busDetails.SslCertPassphrase = configurationOverrides.SslCertPassphrase; + } + + if (configurationOverrides.SslProtocol != null) + { + busDetails.SslProtocol = configurationOverrides.SslProtocol.Value; + } + + if (configurationOverrides.SslAllowUntrustedServerCertificate != null) + { + busDetails.SslAllowUntrustedServerCertificate = configurationOverrides.SslAllowUntrustedServerCertificate.Value; + } + return new RabbitMqSession(_xcConfiguration, busDetails, _privateCommunicationIdentifier); } } diff --git a/ReactiveXComponent/RabbitMq/RabbitMqSession.cs b/ReactiveXComponent/RabbitMq/RabbitMqSession.cs index 7805ead..f976a6f 100644 --- a/ReactiveXComponent/RabbitMq/RabbitMqSession.cs +++ b/ReactiveXComponent/RabbitMq/RabbitMqSession.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net.Security; using RabbitMQ.Client; using RabbitMQ.Client.Exceptions; using ReactiveXComponent.Common; @@ -39,6 +40,39 @@ private void InitConnection(BusDetails busDetails) Protocol = Protocols.DefaultProtocol }; + if (busDetails.SslEnabled) + { + _factory.Ssl.Enabled = true; + + _factory.Ssl.ServerName = busDetails.SslServerName; + + if (!string.IsNullOrEmpty(busDetails.SslCertPath)) + { + _factory.Ssl.CertPath = busDetails.SslCertPath; + } + + if (!string.IsNullOrEmpty(busDetails.SslCertPassphrase)) + { + _factory.Ssl.CertPassphrase = busDetails.SslCertPassphrase; + } + + _factory.Ssl.Version = busDetails.SslProtocol; + + if (busDetails.SslAllowUntrustedServerCertificate) + { + _factory.Ssl.CertificateValidationCallback += (sender, certificate, chain, errors) => + { + if ((errors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch || + (errors & SslPolicyErrors.RemoteCertificateNotAvailable) == SslPolicyErrors.RemoteCertificateNotAvailable) + { + return false; + } + + return true; + }; + } + } + _connection = _factory?.CreateConnection(); _connection.ConnectionShutdown += ConnectionOnConnectionShutdown; diff --git a/ReactiveXComponentTest/Configuration/ConfigurationTests.cs b/ReactiveXComponentTest/Configuration/ConfigurationTests.cs index 1ce9830..ca7af30 100644 --- a/ReactiveXComponentTest/Configuration/ConfigurationTests.cs +++ b/ReactiveXComponentTest/Configuration/ConfigurationTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Security.Authentication; using NFluent; using NUnit.Framework; using ReactiveXComponent.Common; @@ -77,7 +78,13 @@ public void GetBusDetailsTest() Check.That(busDetails.VirtualHost).IsEqualTo("myVirtualHost"); Check.That(busDetails.Username).IsEqualTo("guest"); Check.That(busDetails.Password).IsEqualTo("guest"); - Check.That(busDetails.Port).IsEqualTo(5672); + Check.That(busDetails.Port).IsEqualTo(5671); + Check.That(busDetails.SslEnabled).IsTrue(); + Check.That(busDetails.SslServerName).IsEqualTo("XComponent RMq"); + Check.That(busDetails.SslCertPath).IsEqualTo("some_cert_path"); + Check.That(busDetails.SslCertPassphrase).IsEqualTo("some_cert_pass"); + Check.That(busDetails.SslProtocol).IsEqualTo(SslProtocols.Default); + Check.That(busDetails.SslAllowUntrustedServerCertificate).IsTrue(); } [Test] diff --git a/ReactiveXComponentTest/RabbitMqTestApi.xcApi b/ReactiveXComponentTest/RabbitMqTestApi.xcApi index c95c6d9..cf273da 100644 --- a/ReactiveXComponentTest/RabbitMqTestApi.xcApi +++ b/ReactiveXComponentTest/RabbitMqTestApi.xcApi @@ -3,7 +3,7 @@ Binary - + From cadc84ffc71a701fb978480f7ea3d9abcfe3809d Mon Sep 17 00:00:00 2001 From: Anouar Hassine Date: Fri, 7 Dec 2018 10:14:32 +0100 Subject: [PATCH 2/2] Refactoring some variables names and adding summary for some fields. --- .../Configuration/BusDetails.cs | 49 ++++++++++++++++--- .../Configuration/ConfigurationOverrides.cs | 4 +- ReactiveXComponent/Configuration/XCApiTags.cs | 4 +- .../Parser/XCApiConfigParser.cs | 8 +-- .../RabbitMq/RabbitMqConnection.cs | 8 +-- .../RabbitMq/RabbitMqSession.cs | 8 +-- .../Configuration/ConfigurationTests.cs | 4 +- 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/ReactiveXComponent/Configuration/BusDetails.cs b/ReactiveXComponent/Configuration/BusDetails.cs index 44211c4..6613c37 100644 --- a/ReactiveXComponent/Configuration/BusDetails.cs +++ b/ReactiveXComponent/Configuration/BusDetails.cs @@ -18,8 +18,8 @@ public BusDetails( int port, bool sslEnabled = false, string sslServerName = "", - string sslCertPath = "", - string sslCertPassphrase = "", + string sslCertificatePath = "", + string sslCertificatePassphrase = "", SslProtocols sslProtocol = SslProtocols.Default, bool sslAllowUntrustedServerCertificate = false) { @@ -30,32 +30,65 @@ public BusDetails( Port = port; SslEnabled = sslEnabled; SslServerName = sslServerName; - SslCertPath = sslCertPath; - SslCertPassphrase = sslCertPassphrase; + SslCertificatePath = sslCertificatePath; + SslCertificatePassphrase = sslCertificatePassphrase; SslProtocol = sslProtocol; SslAllowUntrustedServerCertificate = sslAllowUntrustedServerCertificate; } + /// + /// Rabbit Mq user. + /// public string Username { get; set; } + /// + /// Rabbit Mq password for user. + /// public string Password { get; set; } + /// + /// Rabbit Mq server's address. + /// public string Host { get; set; } + /// + /// Rabbit Mq virtual host to connect to. + /// public string VirtualHost { get; set; } + /// + /// Rabbit Mq server's port. + /// public int Port { get; set; } + /// + /// To enable SSL. + /// public bool SslEnabled { get; set; } + /// + /// Server's Common Name. It's indicated in the CN field of the server's certificate. + /// public string SslServerName { get; set; } - public string SslCertPath { get; set; } + /// + /// Path to the client's certificate. + /// + public string SslCertificatePath { get; set; } - public string SslCertPassphrase { get; set; } + /// + /// Passphrase for the client's certificate if it has one. + /// + public string SslCertificatePassphrase { get; set; } + /// + /// SSL protocol to use. + /// public SslProtocols SslProtocol { get; set; } + /// + /// To accept untrusted (e.g self-signed) server certificates. Only use this in Dev environment. + /// public bool SslAllowUntrustedServerCertificate { get; set; } public BusDetails Clone() @@ -68,8 +101,8 @@ public BusDetails Clone() Port, SslEnabled, SslServerName, - SslCertPath, - SslCertPassphrase, + SslCertificatePath, + SslCertificatePassphrase, SslProtocol, SslAllowUntrustedServerCertificate); } diff --git a/ReactiveXComponent/Configuration/ConfigurationOverrides.cs b/ReactiveXComponent/Configuration/ConfigurationOverrides.cs index 92d217d..490449e 100644 --- a/ReactiveXComponent/Configuration/ConfigurationOverrides.cs +++ b/ReactiveXComponent/Configuration/ConfigurationOverrides.cs @@ -21,9 +21,9 @@ public class ConfigurationOverrides public string SslServerName { get; set; } - public string SslCertPath { get; set; } + public string SslCertificatePath { get; set; } - public string SslCertPassphrase { get; set; } + public string SslCertificatePassphrase { get; set; } public SslProtocols? SslProtocol { get; set; } diff --git a/ReactiveXComponent/Configuration/XCApiTags.cs b/ReactiveXComponent/Configuration/XCApiTags.cs index e979857..6732682 100644 --- a/ReactiveXComponent/Configuration/XCApiTags.cs +++ b/ReactiveXComponent/Configuration/XCApiTags.cs @@ -33,8 +33,8 @@ public static class XCApiTags public const string VirtualHost = "virtualHost"; public const string BusSslEnabled = "sslEnabled"; public const string BusSslServerName = "sslServerName"; - public const string BusSslCertPath = "sslCertPath"; - public const string BusSslCertPassphrase = "sslCertPassphrase"; + public const string BusSslCertificatePath = "sslCertPath"; + public const string BusSslCertificatePassphrase = "sslCertPassphrase"; public const string BusSslProtocol = "sslProtocol"; public const string BusSslAllowUntrustedServerCertificate = "sslAllowUntrustedServerCertificate"; } diff --git a/ReactiveXComponent/Parser/XCApiConfigParser.cs b/ReactiveXComponent/Parser/XCApiConfigParser.cs index ad85718..fb53d3f 100644 --- a/ReactiveXComponent/Parser/XCApiConfigParser.cs +++ b/ReactiveXComponent/Parser/XCApiConfigParser.cs @@ -192,8 +192,8 @@ public BusDetails GetBusDetails() } var sslServerName = busInfos?.Attribute(XCApiTags.BusSslServerName)?.Value; - var sslCertPath = busInfos?.Attribute(XCApiTags.BusSslCertPath)?.Value; - var sslCertPassphrase = busInfos?.Attribute(XCApiTags.BusSslCertPassphrase)?.Value; + var sslCertificatePath = busInfos?.Attribute(XCApiTags.BusSslCertificatePath)?.Value; + var sslCertificatePassphrase = busInfos?.Attribute(XCApiTags.BusSslCertificatePassphrase)?.Value; var sslProtocolString = busInfos?.Attribute(XCApiTags.BusSslProtocol)?.Value; SslProtocols sslProtocol = SslProtocols.Default; @@ -217,8 +217,8 @@ public BusDetails GetBusDetails() Convert.ToInt32(busInfos?.Attribute(XCApiTags.Port)?.Value), sslEnabled, sslServerName, - sslCertPath, - sslCertPassphrase, + sslCertificatePath, + sslCertificatePassphrase, sslProtocol, sslAllowUntrustedServerCertificate); diff --git a/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs b/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs index 628db38..b6ba99a 100644 --- a/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs +++ b/ReactiveXComponent/RabbitMq/RabbitMqConnection.cs @@ -60,14 +60,14 @@ public IXCSession CreateSession(ConfigurationOverrides configurationOverrides = busDetails.SslServerName = configurationOverrides.SslServerName; } - if (configurationOverrides.SslCertPath != null) + if (configurationOverrides.SslCertificatePath != null) { - busDetails.SslCertPath = configurationOverrides.SslCertPath; + busDetails.SslCertificatePath = configurationOverrides.SslCertificatePath; } - if (configurationOverrides.SslCertPassphrase != null) + if (configurationOverrides.SslCertificatePassphrase != null) { - busDetails.SslCertPassphrase = configurationOverrides.SslCertPassphrase; + busDetails.SslCertificatePassphrase = configurationOverrides.SslCertificatePassphrase; } if (configurationOverrides.SslProtocol != null) diff --git a/ReactiveXComponent/RabbitMq/RabbitMqSession.cs b/ReactiveXComponent/RabbitMq/RabbitMqSession.cs index f976a6f..e8dce11 100644 --- a/ReactiveXComponent/RabbitMq/RabbitMqSession.cs +++ b/ReactiveXComponent/RabbitMq/RabbitMqSession.cs @@ -46,14 +46,14 @@ private void InitConnection(BusDetails busDetails) _factory.Ssl.ServerName = busDetails.SslServerName; - if (!string.IsNullOrEmpty(busDetails.SslCertPath)) + if (!string.IsNullOrEmpty(busDetails.SslCertificatePath)) { - _factory.Ssl.CertPath = busDetails.SslCertPath; + _factory.Ssl.CertPath = busDetails.SslCertificatePath; } - if (!string.IsNullOrEmpty(busDetails.SslCertPassphrase)) + if (!string.IsNullOrEmpty(busDetails.SslCertificatePassphrase)) { - _factory.Ssl.CertPassphrase = busDetails.SslCertPassphrase; + _factory.Ssl.CertPassphrase = busDetails.SslCertificatePassphrase; } _factory.Ssl.Version = busDetails.SslProtocol; diff --git a/ReactiveXComponentTest/Configuration/ConfigurationTests.cs b/ReactiveXComponentTest/Configuration/ConfigurationTests.cs index ca7af30..7f10ad4 100644 --- a/ReactiveXComponentTest/Configuration/ConfigurationTests.cs +++ b/ReactiveXComponentTest/Configuration/ConfigurationTests.cs @@ -81,8 +81,8 @@ public void GetBusDetailsTest() Check.That(busDetails.Port).IsEqualTo(5671); Check.That(busDetails.SslEnabled).IsTrue(); Check.That(busDetails.SslServerName).IsEqualTo("XComponent RMq"); - Check.That(busDetails.SslCertPath).IsEqualTo("some_cert_path"); - Check.That(busDetails.SslCertPassphrase).IsEqualTo("some_cert_pass"); + Check.That(busDetails.SslCertificatePath).IsEqualTo("some_cert_path"); + Check.That(busDetails.SslCertificatePassphrase).IsEqualTo("some_cert_pass"); Check.That(busDetails.SslProtocol).IsEqualTo(SslProtocols.Default); Check.That(busDetails.SslAllowUntrustedServerCertificate).IsTrue(); }