Merge pull request #364 from PitySOFT/webproxy

Add proxy settings for WebSocket connections for .NET 451 and 461 and add option to specify the SSLProtocol and CertificateValidationCallback  in TLS options, SSLProtocol default is TLS1.2
This commit is contained in:
Christian
2018-07-26 10:04:52 +02:00
committed by GitHub
6 changed files with 128 additions and 14 deletions
@@ -1,5 +1,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using MQTTnet.Serializer; using MQTTnet.Serializer;
namespace MQTTnet.Client namespace MQTTnet.Client
@@ -76,6 +79,29 @@ namespace MQTTnet.Client
return this; return this;
} }
#if NET452 || NET461
public MqttClientOptionsBuilder WithProxy(string address, string username = null, string password = null, string domain = null, bool bypassOnLocal = false, string[] bypassList = null)
{
if (_webSocketOptions == null)
{
throw new InvalidOperationException("A WebSocket channel must be set if MqttClientWebSocketProxy is configured.");
}
_webSocketOptions.MqttClientWebSocketProxy = new MqttClientWebSocketProxyOptions
{
Address = address,
Username = username,
Password = password,
Domain = domain,
BypassOnLocal = bypassOnLocal,
BypassList = bypassList
};
return this;
}
#endif
public MqttClientOptionsBuilder WithWebSocketServer(string uri) public MqttClientOptionsBuilder WithWebSocketServer(string uri)
{ {
_webSocketOptions = new MqttClientWebSocketOptions _webSocketOptions = new MqttClientWebSocketOptions
@@ -86,11 +112,54 @@ namespace MQTTnet.Client
return this; return this;
} }
public MqttClientOptionsBuilder WithTls()
{
return WithTls(null);
}
public MqttClientOptionsBuilder WithTls(Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback)
{
return WithTls(SslProtocols.None, certificateValidationCallback);
}
public MqttClientOptionsBuilder WithTls(SslProtocols sslProtocol,
Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback = null)
{
return WithTls(new byte[][] { }, sslProtocol, certificateValidationCallback);
}
public MqttClientOptionsBuilder WithTls(byte[][] certificates,
SslProtocols sslProtocol = SslProtocols.Tls12,
Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback = null)
{
return WithTls(false, certificates, sslProtocol, certificateValidationCallback);
}
public MqttClientOptionsBuilder WithTls(bool ignoreCertificateRevocationErrors,
byte[][] certificates = null,
SslProtocols sslProtocol = SslProtocols.Tls12,
Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback = null)
{
return WithTls(false, ignoreCertificateRevocationErrors, certificates, sslProtocol, certificateValidationCallback);
}
public MqttClientOptionsBuilder WithTls(bool ignoreCertificateChainErrors,
bool ignoreCertificateRevocationErrors = false,
byte[][] certificates = null,
SslProtocols sslProtocol = SslProtocols.Tls12,
Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback = null)
{
return WithTls(false, ignoreCertificateChainErrors, ignoreCertificateRevocationErrors, certificates, sslProtocol, certificateValidationCallback);
}
public MqttClientOptionsBuilder WithTls( public MqttClientOptionsBuilder WithTls(
bool allowUntrustedCertificates = false, bool allowUntrustedCertificates,
bool ignoreCertificateChainErrors = false, bool ignoreCertificateChainErrors = false,
bool ignoreCertificateRevocationErrors = false, bool ignoreCertificateRevocationErrors = false,
params byte[][] certificates) byte[][] certificates = null,
SslProtocols sslProtocol = SslProtocols.Tls12,
Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> certificateValidationCallback = null)
{ {
_tlsOptions = new MqttClientTlsOptions _tlsOptions = new MqttClientTlsOptions
{ {
@@ -98,21 +167,14 @@ namespace MQTTnet.Client
AllowUntrustedCertificates = allowUntrustedCertificates, AllowUntrustedCertificates = allowUntrustedCertificates,
IgnoreCertificateChainErrors = ignoreCertificateChainErrors, IgnoreCertificateChainErrors = ignoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors, IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors,
Certificates = certificates?.ToList() Certificates = certificates?.ToList(),
SslProtocol = sslProtocol,
CertificateValidationCallback = certificateValidationCallback
}; };
return this; return this;
} }
public MqttClientOptionsBuilder WithTls()
{
_tlsOptions = new MqttClientTlsOptions
{
UseTls = true
};
return this;
}
public IMqttClientOptions Build() public IMqttClientOptions Build()
{ {
@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Security; using System.Net.Security;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Security.Authentication;
namespace MQTTnet.Client namespace MQTTnet.Client
{ {
@@ -17,6 +18,8 @@ namespace MQTTnet.Client
public List<byte[]> Certificates { get; set; } public List<byte[]> Certificates { get; set; }
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; } public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; }
} }
} }
@@ -13,6 +13,10 @@ namespace MQTTnet.Client
public CookieContainer CookieContainer { get; set; } public CookieContainer CookieContainer { get; set; }
#if NET452 || NET461
public MqttClientWebSocketProxyOptions MqttClientWebSocketProxy { get; set; } = new MqttClientWebSocketProxyOptions();
#endif
public MqttClientTlsOptions TlsOptions { get; set; } = new MqttClientTlsOptions(); public MqttClientTlsOptions TlsOptions { get; set; } = new MqttClientTlsOptions();
public override string ToString() public override string ToString()
@@ -0,0 +1,21 @@
#if NET452 || NET461
namespace MQTTnet.Client
{
public class MqttClientWebSocketProxyOptions
{
public string Address { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Domain { get; set; }
public bool BypassOnLocal { get; set; } = true;
public string[] BypassList { get; set; }
}
}
#endif
@@ -63,7 +63,7 @@ namespace MQTTnet.Implementations
if (_options.TlsOptions.UseTls) if (_options.TlsOptions.UseTls)
{ {
sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback); sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback);
await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
} }
CreateStream(sslStream); CreateStream(sslStream);
@@ -6,6 +6,10 @@ using System.Threading.Tasks;
using MQTTnet.Channel; using MQTTnet.Channel;
using MQTTnet.Client; using MQTTnet.Client;
#if NET452 || NET461
using System.Net;
#endif
namespace MQTTnet.Implementations namespace MQTTnet.Implementations
{ {
public class MqttWebSocketChannel : IMqttChannel public class MqttWebSocketChannel : IMqttChannel
@@ -14,7 +18,7 @@ namespace MQTTnet.Implementations
private readonly MqttClientWebSocketOptions _options; private readonly MqttClientWebSocketOptions _options;
private WebSocket _webSocket; private WebSocket _webSocket;
public MqttWebSocketChannel(MqttClientWebSocketOptions options) public MqttWebSocketChannel(MqttClientWebSocketOptions options)
{ {
_options = options ?? throw new ArgumentNullException(nameof(options)); _options = options ?? throw new ArgumentNullException(nameof(options));
@@ -45,6 +49,26 @@ namespace MQTTnet.Implementations
var clientWebSocket = new ClientWebSocket(); var clientWebSocket = new ClientWebSocket();
#if NET452 || NET461
// use proxy if we have an address
if (string.IsNullOrEmpty(_options.MqttClientWebSocketProxy.Address) == false)
{
var proxyUri = new Uri(_options.MqttClientWebSocketProxy.Address);
// use proxy credentials if we have them
if (string.IsNullOrEmpty(_options.MqttClientWebSocketProxy.Username) == false && string.IsNullOrEmpty(_options.MqttClientWebSocketProxy.Password) == false)
{
var credentials = new NetworkCredential(_options.MqttClientWebSocketProxy.Username, _options.MqttClientWebSocketProxy.Password, _options.MqttClientWebSocketProxy.Domain);
clientWebSocket.Options.Proxy = new WebProxy(proxyUri, _options.MqttClientWebSocketProxy.BypassOnLocal, _options.MqttClientWebSocketProxy.BypassList, credentials);
}
else
{
// use proxy without credentials
clientWebSocket.Options.Proxy = new WebProxy(proxyUri, _options.MqttClientWebSocketProxy.BypassOnLocal, _options.MqttClientWebSocketProxy.BypassList);
}
}
#endif
if (_options.RequestHeaders != null) if (_options.RequestHeaders != null)
{ {
foreach (var requestHeader in _options.RequestHeaders) foreach (var requestHeader in _options.RequestHeaders)