Skip to content

Commit

Permalink
Ssl mutual authentication implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
asimarslan committed Dec 7, 2018
1 parent f08fef1 commit d14e269
Show file tree
Hide file tree
Showing 32 changed files with 1,097 additions and 1,156 deletions.
4 changes: 2 additions & 2 deletions .nuget/packages.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit.ConsoleRunner" version="3.8.0" />
<package id="NUnit.ConsoleRunner" version="3.9.0" />
<package id="NUnit.Extension.NUnitV2ResultWriter" version="3.6.0" />
<package id="JetBrains.dotCover.CommandLineTools" version="2018.2.0" />
<package id="JetBrains.dotCover.CommandLineTools" version="2018.2.3" />
</packages>
37 changes: 33 additions & 4 deletions Hazelcast.Net/Hazelcast.Client.Connection/ClientConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -111,14 +113,41 @@ public ClientConnection(ClientConnectionManager clientConnectionManager,
_builder = new ClientMessageBuilder(invocationService.HandleClientMessage);

var networkStream = new NetworkStream(_clientSocket, false);
if (clientNetworkConfig.GetSSLConfig().IsEnabled())
var sslConfig = clientNetworkConfig.GetSSLConfig();
if (sslConfig.IsEnabled())
{
var sslStream = new SslStream(networkStream, false,
(sender, certificate, chain, sslPolicyErrors) =>
RemoteCertificateValidationCallback(sender, certificate, chain, sslPolicyErrors,
clientNetworkConfig), null);
var certificateName = clientNetworkConfig.GetSSLConfig().GetCertificateName() ?? "";
sslStream.AuthenticateAsClient(certificateName);
var certificateName = sslConfig.GetCertificateName() ?? "";
var cerPath = sslConfig.GetCertificateFilePath();
if (cerPath != null)
{
var clientCertificates= new X509Certificate2Collection();
try
{
clientCertificates.Import(cerPath, sslConfig.GetCertificatePassword(), X509KeyStorageFlags.DefaultKeySet);
}
catch (Exception)
{
Logger.Finest(string.Format("Cannot load client certificate:{0}.", cerPath));
throw;
}

var enabledSslProtocols = sslConfig.GetSslProtocol();
var checkCertificateRevocation = sslConfig.IsCheckCertificateRevocation();
sslStream.AuthenticateAsClient(certificateName, clientCertificates, enabledSslProtocols, checkCertificateRevocation);
}
else
{
sslStream.AuthenticateAsClient(certificateName);
}

Logger.Info(string.Format(
"Client connection ready. Encrypted:{0}, MutualAuthenticated:{1} using ssl protocol:{2}",
sslStream.IsEncrypted, sslStream.IsMutuallyAuthenticated, sslStream.SslProtocol));

_stream = sslStream;
}
else
Expand All @@ -135,7 +164,7 @@ public ClientConnection(ClientConnectionManager clientConnectionManager,
{
_stream.Close();
}
throw new IOException("Cannot connect! Socket error:" + e.Message);
throw new IOException("Cannot init connection.", e);
}
}

Expand Down
73 changes: 69 additions & 4 deletions Hazelcast.Net/Hazelcast.Config/SSLConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Text;

namespace Hazelcast.Config
Expand All @@ -23,10 +26,30 @@ namespace Hazelcast.Config
public class SSLConfig
{
/// <summary>
/// Certifate Name; CN part of the Certificate Subject.
/// Certificate Name to be validated against SAN field of the remote certificate, if not present then the CN part of the Certificate Subject.
/// </summary>
public const string CertificateName = "CertificateServerName";

/// <summary>
/// Certificate File path.
/// </summary>
public const string CertificateFilePath = "CertificateFilePath";

/// <summary>
/// Password need to import the certificates.
/// </summary>
public const string CertificatePassword = "CertificatePassword";

/// <summary>
/// SSL/TLS protocol. string value of enum type <see cref="System.Security.Authentication.SslProtocols"/>
/// </summary>
public const string SslProtocol = "SslProtocol";

/// <summary>
/// specifies whether the certificate revocation list is checked during authentication.
/// </summary>
public const string CheckCertificateRevocation = "CheckCertificateRevocation";

/// <summary>
/// The property is used to configure ssl to enable certificate chain validation.
/// </summary>
Expand All @@ -41,6 +64,11 @@ public class SSLConfig

private Dictionary<string, string> _properties = new Dictionary<string, string>();

public SSLConfig()
{
SetProperty(ValidateCertificateChain, true.ToString());
}

public bool IsEnabled()
{
return _enabled;
Expand All @@ -57,9 +85,9 @@ public virtual Dictionary<string, string> GetProperties()
return _properties;
}

public SSLConfig SetProperties(Dictionary<string, string> properites)
public SSLConfig SetProperties(Dictionary<string, string> properties)
{
_properties = properites;
_properties = properties;
return this;
}

Expand All @@ -72,7 +100,7 @@ public virtual string GetProperty(string name)

public virtual SSLConfig SetProperty(string name, string value)
{
_properties.Add(name, value);
_properties[name] = value;
return this;
}

Expand All @@ -93,6 +121,43 @@ internal string GetCertificateName()
return GetProperty(CertificateName);
}

internal string GetCertificateFilePath()
{
return GetProperty(CertificateFilePath);
}

internal string GetCertificatePassword()
{
return GetProperty(CertificatePassword);
}

internal SslProtocols GetSslProtocol()
{
var sslProtocol = GetProperty(SslProtocol);
if (sslProtocol == null)
{
#if NET40
return SslProtocols.Tls;
#else
return SslProtocols.None;
#endif
}
SslProtocols result;
if (Enum.TryParse(sslProtocol, true, out result))
{
return result;
}
throw new ArgumentException(
"Invalid ssl configuration: SslProtocol. You should use one of SslProtocol enum values: " +
string.Join(", ", Enum.GetNames(typeof(SslProtocols))));
}

internal bool IsCheckCertificateRevocation()
{
var prop = GetProperty(CheckCertificateRevocation);
return AbstractXmlConfigHelper.CheckTrue(prop);
}

/// <inheritdoc />
public override string ToString()
{
Expand Down
1 change: 1 addition & 0 deletions Hazelcast.Net/Hazelcast.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<RootNamespace>
</RootNamespace>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Hazelcast.Net.xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Label="sign">
<!--Condition=" '$(OS)' != 'Windows_NT' "-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public virtual void TestXmlParserWithConfigFile()
[Test]
public virtual void TestXmlParserWithReader()
{
var clientConfig = XmlClientConfigBuilder.Build(new StringReader(Hazelcast.Test.Resources.hazelcast_config_full));
var clientConfig = XmlClientConfigBuilder.Build(new StringReader(Resources.hazelcast_config_full));
Assert.NotNull(clientConfig);
}
}
Expand Down
105 changes: 0 additions & 105 deletions Hazelcast.Test/Hazelcast.Client.Test/ClientSSLTest.cs

This file was deleted.

Loading

0 comments on commit d14e269

Please sign in to comment.