From 9227daea61d82c584e0fc8fbe0c0d2b26b4a087d Mon Sep 17 00:00:00 2001 From: TheAlain <43777839+asaintsever@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:18:30 +0100 Subject: [PATCH] Allow to provide SslClientAuthenticationOptions when leveraging SslStream (#213) --- .gitignore | 1 + .../IMemcachedClientConfiguration.cs | 3 +++ .../MemcachedClientConfiguration.cs | 3 +++ .../Configuration/MemcachedClientOptions.cs | 3 +++ .../Memcached/DefaultServerPool.cs | 2 +- src/Enyim.Caching/Memcached/MemcachedNode.cs | 9 ++++++--- src/Enyim.Caching/Memcached/PooledSocket.cs | 20 ++++++++++++++----- .../Memcached/Protocol/Binary/BinaryNode.cs | 6 ++++-- .../Memcached/Protocol/Binary/BinaryPool.cs | 2 +- 9 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index b2753ce0..35a07388 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ **/bin/* **/obj/* +.DS_Store* TestResults/* *.suo *.user diff --git a/src/Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs b/src/Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs index 9349167c..8d50c1c3 100755 --- a/src/Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs +++ b/src/Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Net.Security; using Enyim.Caching.Memcached; namespace Enyim.Caching.Configuration @@ -47,6 +48,8 @@ public interface IMemcachedClientConfiguration bool UseIPv6 { get; } bool SuppressException { get; } + + SslClientAuthenticationOptions SslClientAuth { get; } } } diff --git a/src/Enyim.Caching/Configuration/MemcachedClientConfiguration.cs b/src/Enyim.Caching/Configuration/MemcachedClientConfiguration.cs index 578b9afc..86a3abc8 100644 --- a/src/Enyim.Caching/Configuration/MemcachedClientConfiguration.cs +++ b/src/Enyim.Caching/Configuration/MemcachedClientConfiguration.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Configuration; using System.Linq; +using System.Net.Security; using System.Net.Sockets; using AEPLCore.Monitoring; using Enyim.Caching.Memcached.Transcoders; @@ -128,6 +129,7 @@ public MemcachedClientConfiguration( { UseSslStream = options.UseSslStream; } + SslClientAuth = options.SslClientAuth; UseIPv6 = options.UseIPv6; if (!string.IsNullOrEmpty(options.KeyTransformer)) @@ -355,6 +357,7 @@ IServerPool IMemcachedClientConfiguration.CreatePool() public bool UseSslStream { get; private set; } public bool UseIPv6 { get; private set; } + public SslClientAuthenticationOptions SslClientAuth { get; private set; } #endregion } diff --git a/src/Enyim.Caching/Configuration/MemcachedClientOptions.cs b/src/Enyim.Caching/Configuration/MemcachedClientOptions.cs index 34f7a257..7485a879 100644 --- a/src/Enyim.Caching/Configuration/MemcachedClientOptions.cs +++ b/src/Enyim.Caching/Configuration/MemcachedClientOptions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Security; using System.Threading.Tasks; namespace Enyim.Caching.Configuration @@ -27,6 +28,8 @@ public class MemcachedClientOptions : IOptions public bool SuppressException { get; set; } = true; + public SslClientAuthenticationOptions SslClientAuth { get; set; } + public IProviderFactory NodeLocatorFactory { get; set; } public MemcachedClientOptions Value => this; diff --git a/src/Enyim.Caching/Memcached/DefaultServerPool.cs b/src/Enyim.Caching/Memcached/DefaultServerPool.cs index 65cea9b9..b2fb220e 100644 --- a/src/Enyim.Caching/Memcached/DefaultServerPool.cs +++ b/src/Enyim.Caching/Memcached/DefaultServerPool.cs @@ -54,7 +54,7 @@ public DefaultServerPool( protected virtual IMemcachedNode CreateNode(EndPoint endpoint) { - return new MemcachedNode(endpoint, _configuration.SocketPool, _logger, _metricFunctions, _configuration.UseSslStream, _configuration.UseIPv6); + return new MemcachedNode(endpoint, _configuration.SocketPool, _logger, _metricFunctions, _configuration.UseSslStream, _configuration.UseIPv6, _configuration.SslClientAuth); } private void rezCallback(object state) diff --git a/src/Enyim.Caching/Memcached/MemcachedNode.cs b/src/Enyim.Caching/Memcached/MemcachedNode.cs index 19debe9d..912c4d79 100644 --- a/src/Enyim.Caching/Memcached/MemcachedNode.cs +++ b/src/Enyim.Caching/Memcached/MemcachedNode.cs @@ -13,6 +13,7 @@ using System.Diagnostics; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Runtime.Serialization; using System.Security; @@ -39,15 +40,17 @@ public class MemcachedNode : IMemcachedNode private readonly TimeSpan _initPoolTimeout; private bool _useSslStream; private bool _useIPv6; + private readonly SslClientAuthenticationOptions _sslClientAuthOptions; public MemcachedNode( EndPoint endpoint, ISocketPoolConfiguration socketPoolConfig, ILogger logger, IMetricFunctions metricFunctions, bool useSslStream, - bool useIPv6) + bool useIPv6, SslClientAuthenticationOptions sslClientAuthOptions) { _endPoint = endpoint; _useSslStream = useSslStream; + _sslClientAuthOptions = sslClientAuthOptions; EndPointString = endpoint?.ToString().Replace("Unspecified/", string.Empty); _config = socketPoolConfig; @@ -979,7 +982,7 @@ protected internal virtual PooledSocket CreateSocket() { try { - var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream, _useIPv6); + var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream, _useIPv6, _sslClientAuthOptions); ps.Connect(); return ps; } @@ -995,7 +998,7 @@ protected internal virtual async Task CreateSocketAsync() { try { - var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream, _useIPv6); + var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger, _useSslStream, _useIPv6, _sslClientAuthOptions); await ps.ConnectAsync(); return ps; } diff --git a/src/Enyim.Caching/Memcached/PooledSocket.cs b/src/Enyim.Caching/Memcached/PooledSocket.cs index f935e7ea..ff15cb90 100644 --- a/src/Enyim.Caching/Memcached/PooledSocket.cs +++ b/src/Enyim.Caching/Memcached/PooledSocket.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics; @@ -6,10 +7,8 @@ using System.Net; using System.Net.Security; using System.Net.Sockets; -using System.Text; using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; namespace Enyim.Caching.Memcached { @@ -28,13 +27,24 @@ public partial class PooledSocket : IDisposable private NetworkStream _inputStream; public DateTime LastConnectionTimestamp { get; set; } private SslStream _sslStream; + private readonly SslClientAuthenticationOptions _sslClientAuthOptions; - public PooledSocket(EndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, ILogger logger, bool useSslStream, bool useIPv6) + public PooledSocket(EndPoint endpoint, TimeSpan connectionTimeout, TimeSpan receiveTimeout, ILogger logger, bool useSslStream, bool useIPv6, SslClientAuthenticationOptions sslClientAuthOptions) { _logger = logger; _isAlive = true; _useSslStream = useSslStream; _useIPv6 = useIPv6; + _sslClientAuthOptions = sslClientAuthOptions; + + if (_useSslStream && _sslClientAuthOptions == null) + { + // When not provided, create a default instance with target host set to the endpoint's host + _sslClientAuthOptions = new SslClientAuthenticationOptions + { + TargetHost = ((DnsEndPoint)_endpoint).Host, + }; + } var socket = new Socket(useIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); @@ -101,7 +111,7 @@ void Cancel() if (_useSslStream) { _sslStream = new SslStream(new NetworkStream(_socket)); - _sslStream.AuthenticateAsClient(((DnsEndPoint)_endpoint).Host); + _sslStream.AuthenticateAsClient(_sslClientAuthOptions); } else { @@ -161,7 +171,7 @@ public async Task ConnectAsync() if (_useSslStream) { _sslStream = new SslStream(new NetworkStream(_socket)); - await _sslStream.AuthenticateAsClientAsync(((DnsEndPoint)_endpoint).Host); + await _sslStream.AuthenticateAsClientAsync(_sslClientAuthOptions); } else { diff --git a/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryNode.cs b/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryNode.cs index 12cb962e..70383aff 100644 --- a/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryNode.cs +++ b/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryNode.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net; +using System.Net.Security; using System.Threading; using Enyim.Caching.Configuration; using Enyim.Collections; @@ -27,8 +28,9 @@ public BinaryNode( ISaslAuthenticationProvider authenticationProvider, ILogger logger, IMetricFunctions metricFunctions, bool useSslStream, - bool useIPv6) - : base(endpoint, config, logger, metricFunctions, useSslStream, useIPv6) + bool useIPv6, + SslClientAuthenticationOptions sslClientAuthOptions) + : base(endpoint, config, logger, metricFunctions, useSslStream, useIPv6, sslClientAuthOptions) { _authenticationProvider = authenticationProvider; _logger = logger; diff --git a/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryPool.cs b/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryPool.cs index 2f1fb8ac..5b3a6620 100644 --- a/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryPool.cs +++ b/src/Enyim.Caching/Memcached/Protocol/Binary/BinaryPool.cs @@ -32,7 +32,7 @@ public BinaryPool(IMemcachedClientConfiguration configuration, ILogger logger, I protected override IMemcachedNode CreateNode(EndPoint endpoint) { - return new BinaryNode(endpoint, _configuration.SocketPool, _authenticationProvider, _logger,_metricFunctions, _configuration.UseSslStream, _configuration.UseIPv6); + return new BinaryNode(endpoint, _configuration.SocketPool, _authenticationProvider, _logger,_metricFunctions, _configuration.UseSslStream, _configuration.UseIPv6, _configuration.SslClientAuth); } private static ISaslAuthenticationProvider GetProvider(IMemcachedClientConfiguration configuration)