diff --git a/ReactiveXComponent/Configuration/BusDetails.cs b/ReactiveXComponent/Configuration/BusDetails.cs index a4c5ca4..6613c37 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,26 +10,87 @@ 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 sslCertificatePath = "", + string sslCertificatePassphrase = "", + SslProtocols sslProtocol = SslProtocols.Default, + bool sslAllowUntrustedServerCertificate = false) { Username = username; Password = password; Host = host; VirtualHost = virtualHost; Port = port; - + SslEnabled = sslEnabled; + SslServerName = sslServerName; + 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; } + + /// + /// Path to the client's certificate. + /// + public string SslCertificatePath { 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() { return new BusDetails( @@ -35,7 +98,13 @@ public BusDetails Clone() Password, Host, VirtualHost, - Port); + Port, + SslEnabled, + SslServerName, + SslCertificatePath, + SslCertificatePassphrase, + SslProtocol, + SslAllowUntrustedServerCertificate); } } } diff --git a/ReactiveXComponent/Configuration/ConfigurationOverrides.cs b/ReactiveXComponent/Configuration/ConfigurationOverrides.cs index 33782ab..490449e 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 SslCertificatePath { get; set; } + + public string SslCertificatePassphrase { 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..6732682 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 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 2059f76..fb53d3f 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 sslCertificatePath = busInfos?.Attribute(XCApiTags.BusSslCertificatePath)?.Value; + var sslCertificatePassphrase = busInfos?.Attribute(XCApiTags.BusSslCertificatePassphrase)?.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, + sslCertificatePath, + sslCertificatePassphrase, + 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..b6ba99a 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.SslCertificatePath != null) + { + busDetails.SslCertificatePath = configurationOverrides.SslCertificatePath; + } + + if (configurationOverrides.SslCertificatePassphrase != null) + { + busDetails.SslCertificatePassphrase = configurationOverrides.SslCertificatePassphrase; + } + + 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..e8dce11 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.SslCertificatePath)) + { + _factory.Ssl.CertPath = busDetails.SslCertificatePath; + } + + if (!string.IsNullOrEmpty(busDetails.SslCertificatePassphrase)) + { + _factory.Ssl.CertPassphrase = busDetails.SslCertificatePassphrase; + } + + _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..7f10ad4 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.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(); } [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 - +