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.Linq;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using MQTTnet.Serializer;
namespace MQTTnet.Client
@@ -76,6 +79,29 @@ namespace MQTTnet.Client
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)
{
_webSocketOptions = new MqttClientWebSocketOptions
@@ -86,11 +112,54 @@ namespace MQTTnet.Client
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(
bool allowUntrustedCertificates = false,
bool allowUntrustedCertificates,
bool ignoreCertificateChainErrors = 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
{
@@ -98,21 +167,14 @@ namespace MQTTnet.Client
AllowUntrustedCertificates = allowUntrustedCertificates,
IgnoreCertificateChainErrors = ignoreCertificateChainErrors,
IgnoreCertificateRevocationErrors = ignoreCertificateRevocationErrors,
Certificates = certificates?.ToList()
Certificates = certificates?.ToList(),
SslProtocol = sslProtocol,
CertificateValidationCallback = certificateValidationCallback
};
return this;
}
public MqttClientOptionsBuilder WithTls()
{
_tlsOptions = new MqttClientTlsOptions
{
UseTls = true
};
return this;
}
public IMqttClientOptions Build()
{
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Authentication;
namespace MQTTnet.Client
{
@@ -17,6 +18,8 @@ namespace MQTTnet.Client
public List<byte[]> Certificates { get; set; }
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
public Func<X509Certificate, X509Chain, SslPolicyErrors, IMqttClientOptions, bool> CertificateValidationCallback { get; set; }
}
}
@@ -13,6 +13,10 @@ namespace MQTTnet.Client
public CookieContainer CookieContainer { get; set; }
#if NET452 || NET461
public MqttClientWebSocketProxyOptions MqttClientWebSocketProxy { get; set; } = new MqttClientWebSocketProxyOptions();
#endif
public MqttClientTlsOptions TlsOptions { get; set; } = new MqttClientTlsOptions();
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)
{
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);
@@ -6,6 +6,10 @@ using System.Threading.Tasks;
using MQTTnet.Channel;
using MQTTnet.Client;
#if NET452 || NET461
using System.Net;
#endif
namespace MQTTnet.Implementations
{
public class MqttWebSocketChannel : IMqttChannel
@@ -14,7 +18,7 @@ namespace MQTTnet.Implementations
private readonly MqttClientWebSocketOptions _options;
private WebSocket _webSocket;
public MqttWebSocketChannel(MqttClientWebSocketOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
@@ -45,6 +49,26 @@ namespace MQTTnet.Implementations
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)
{
foreach (var requestHeader in _options.RequestHeaders)