From 0c100d408c43e4ad5010e0c2e0095f1821e0bdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?As=C4=B1m=20Arslan?= Date: Tue, 4 Dec 2018 16:35:50 +0300 Subject: [PATCH] Ssl mutual authentication implementation --- .nuget/packages.config | 4 +- .../ClientConnection.cs | 37 +- Hazelcast.Net/Hazelcast.Config/SSLConfig.cs | 73 ++- Hazelcast.Net/Hazelcast.Net.csproj | 1 + .../ClientXmlTest.cs | 2 +- .../Hazelcast.Client.Test/ClientSSLTest.cs | 105 ---- .../ClientSslBaseTest.cs | 110 ++++ .../ClientSslMutualAuthenticationTest.cs | 137 +++++ .../Hazelcast.Client.Test/ClientSslTest.cs | 150 +++++ Hazelcast.Test/Hazelcast.Test.csproj | 24 +- .../Properties/Resources.Designer.cs | 97 --- Hazelcast.Test/Properties/Resources.cs | 50 ++ Hazelcast.Test/Properties/Resources.resx | 561 ------------------ Hazelcast.Test/Resources/client1.pfx | Bin 0 -> 2550 bytes Hazelcast.Test/Resources/client2.pfx | Bin 0 -> 2550 bytes .../Resources/hazelcast-client-full.xml | 8 +- Hazelcast.Test/Resources/hazelcast-delay.xml | 76 +-- Hazelcast.Test/Resources/hazelcast-hb.xml | 43 ++ Hazelcast.Test/Resources/hazelcast-ipv6.xml | 29 + .../Resources/hazelcast-ma-optional.xml | 46 ++ .../Resources/hazelcast-ma-required.xml | 46 ++ .../Resources/hazelcast-nearcache.xml | 44 ++ .../Resources/hazelcast-ssl-signed.xml | 41 ++ Hazelcast.Test/Resources/hazelcast-ssl.xml | 90 ++- Hazelcast.Test/Resources/hazelcast-stat.xml | 57 ++ Hazelcast.Test/Resources/hazelcast.xml | 106 ++-- build.bat | 133 +---- build.ps1 | 13 +- build.sh | 28 +- start-rc.bat | 63 +- start-rc.ps1 | 64 ++ start-rc.sh | 15 +- 32 files changed, 1097 insertions(+), 1156 deletions(-) delete mode 100644 Hazelcast.Test/Hazelcast.Client.Test/ClientSSLTest.cs create mode 100644 Hazelcast.Test/Hazelcast.Client.Test/ClientSslBaseTest.cs create mode 100644 Hazelcast.Test/Hazelcast.Client.Test/ClientSslMutualAuthenticationTest.cs create mode 100644 Hazelcast.Test/Hazelcast.Client.Test/ClientSslTest.cs delete mode 100644 Hazelcast.Test/Properties/Resources.Designer.cs create mode 100644 Hazelcast.Test/Properties/Resources.cs delete mode 100644 Hazelcast.Test/Properties/Resources.resx create mode 100644 Hazelcast.Test/Resources/client1.pfx create mode 100644 Hazelcast.Test/Resources/client2.pfx create mode 100644 Hazelcast.Test/Resources/hazelcast-hb.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-ipv6.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-ma-optional.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-ma-required.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-nearcache.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-ssl-signed.xml create mode 100644 Hazelcast.Test/Resources/hazelcast-stat.xml create mode 100644 start-rc.ps1 diff --git a/.nuget/packages.config b/.nuget/packages.config index 2ce6123e1c..da7ace8042 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@  - + - + \ No newline at end of file diff --git a/Hazelcast.Net/Hazelcast.Client.Connection/ClientConnection.cs b/Hazelcast.Net/Hazelcast.Client.Connection/ClientConnection.cs index 266a534915..3c568c4dda 100644 --- a/Hazelcast.Net/Hazelcast.Client.Connection/ClientConnection.cs +++ b/Hazelcast.Net/Hazelcast.Client.Connection/ClientConnection.cs @@ -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; @@ -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 @@ -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); } } diff --git a/Hazelcast.Net/Hazelcast.Config/SSLConfig.cs b/Hazelcast.Net/Hazelcast.Config/SSLConfig.cs index 25db9c32eb..a7795ccfc7 100644 --- a/Hazelcast.Net/Hazelcast.Config/SSLConfig.cs +++ b/Hazelcast.Net/Hazelcast.Config/SSLConfig.cs @@ -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 @@ -23,10 +26,30 @@ namespace Hazelcast.Config public class SSLConfig { /// - /// 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. /// public const string CertificateName = "CertificateServerName"; + /// + /// Certificate File path. + /// + public const string CertificateFilePath = "CertificateFilePath"; + + /// + /// Password need to import the certificates. + /// + public const string CertificatePassword = "CertificatePassword"; + + /// + /// SSL/TLS protocol. string value of enum type + /// + public const string SslProtocol = "SslProtocol"; + + /// + /// specifies whether the certificate revocation list is checked during authentication. + /// + public const string CheckCertificateRevocation = "CheckCertificateRevocation"; + /// /// The property is used to configure ssl to enable certificate chain validation. /// @@ -41,6 +64,11 @@ public class SSLConfig private Dictionary _properties = new Dictionary(); + public SSLConfig() + { + SetProperty(ValidateCertificateChain, true.ToString()); + } + public bool IsEnabled() { return _enabled; @@ -57,9 +85,9 @@ public virtual Dictionary GetProperties() return _properties; } - public SSLConfig SetProperties(Dictionary properites) + public SSLConfig SetProperties(Dictionary properties) { - _properties = properites; + _properties = properties; return this; } @@ -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; } @@ -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); + } + /// public override string ToString() { diff --git a/Hazelcast.Net/Hazelcast.Net.csproj b/Hazelcast.Net/Hazelcast.Net.csproj index 08948cd393..6ad93adcc9 100644 --- a/Hazelcast.Net/Hazelcast.Net.csproj +++ b/Hazelcast.Net/Hazelcast.Net.csproj @@ -12,6 +12,7 @@ bin\$(Configuration)\$(TargetFramework)\Hazelcast.Net.xml + 1701;1702;1591 diff --git a/Hazelcast.Test/Hazelcast.Client.Test.Config/ClientXmlTest.cs b/Hazelcast.Test/Hazelcast.Client.Test.Config/ClientXmlTest.cs index 873416187a..587cdd54fb 100644 --- a/Hazelcast.Test/Hazelcast.Client.Test.Config/ClientXmlTest.cs +++ b/Hazelcast.Test/Hazelcast.Client.Test.Config/ClientXmlTest.cs @@ -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); } } diff --git a/Hazelcast.Test/Hazelcast.Client.Test/ClientSSLTest.cs b/Hazelcast.Test/Hazelcast.Client.Test/ClientSSLTest.cs deleted file mode 100644 index ef09ba183b..0000000000 --- a/Hazelcast.Test/Hazelcast.Client.Test/ClientSSLTest.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// 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.Text; -using Hazelcast.Config; -using Hazelcast.Core; -using Hazelcast.Remote; -using Hazelcast.Test; -using NUnit.Framework; - -namespace Hazelcast.Client.Test -{ - [TestFixture] - [Category("enterprise")] - public class ClientSSLTest : HazelcastTestSupport - { - private const string ValidCertName = "foo.bar.com"; - - private IHazelcastInstance Client { get; set; } - private RemoteController.Client RemoteController { get; set; } - - private ClientConfig ConfigureClient(bool ssl, bool validateCertificateChain, bool validateCertificateName, string certificateName) - { - var clientConfig = new ClientConfig(); - clientConfig.GetNetworkConfig().AddAddress("localhost:5701"); - clientConfig.GetNetworkConfig().GetSSLConfig().SetEnabled(ssl) - .SetProperty(SSLConfig.CertificateName, certificateName) - .SetProperty(SSLConfig.ValidateCertificateChain, validateCertificateChain.ToString()) - .SetProperty(SSLConfig.ValidateCertificateName, validateCertificateName.ToString()); - return clientConfig; - } - - private void Setup(bool ssl, bool validateCertificateChain, bool validateCertificateName, string certificateName) - { - RemoteController = CreateRemoteController(); - var cluster = CreateCluster(RemoteController, ssl?Resources.hazelcast_ssl:Resources.hazelcast); - RemoteController.startMember(cluster.Id); - var clientConfig = ConfigureClient(ssl, validateCertificateChain, validateCertificateName, certificateName); - clientConfig.GetGroupConfig().SetName(cluster.Id).SetPassword(cluster.Id); - Client = HazelcastClient.NewHazelcastClient(clientConfig); - } - - [TearDown] - public void ShutdownRemoteController() - { - HazelcastClient.ShutdownAll(); - StopRemoteController(RemoteController); - } - - [Test] - public void TestMapSSLEnabled_validateName_validName() - { - Setup(true, false, true, ValidCertName); - Assert.True(Client.GetLifecycleService().IsRunning()); - } - - - [Test] - public void TestMapSSLEnabled_validateName_invalideName() - { - Assert.Throws(() => - { - Setup(true, false, true, "Invalid Cert Name"); - }); - } - - [Test] - public void TestMapSSLEnabled_validateChain_DoNotValidateName_invalideName() - { - Assert.Throws(() => - { - Setup(true, true, false, "Invalid Cert Name"); - }); - } - - [Test] - public void TestMapSSLEnabled_DoNotValidateName() - { - Setup(true, false, false, "Invalid Cert Name"); - Assert.True(Client.GetLifecycleService().IsRunning()); - } - - [Test] - public void TestMapSSLDisabled() - { - Setup(false, false, false, "IGNORE"); - Assert.True(Client.GetLifecycleService().IsRunning()); - } - - } -} diff --git a/Hazelcast.Test/Hazelcast.Client.Test/ClientSslBaseTest.cs b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslBaseTest.cs new file mode 100644 index 0000000000..0659b30137 --- /dev/null +++ b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslBaseTest.cs @@ -0,0 +1,110 @@ +// Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Resources; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Hazelcast.Config; +using Hazelcast.Core; +using Hazelcast.Remote; +using Hazelcast.Test; +using NUnit.Framework; + + +namespace Hazelcast.Client.Test +{ + public abstract class ClientSSLBaseTest : HazelcastTestSupport + { + protected const string ValidCertNameSigned = "member1.hazelcast-test.download"; + protected const string Password = "password"; + + protected IHazelcastInstance Client { get; set; } + protected RemoteController.Client RemoteController { get; set; } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + var di = new DirectoryInfo(Path.GetTempPath()); + foreach (var fileInfo in di.GetFiles()) + { + try + { + fileInfo.Delete(); + } + catch (Exception) {} + } + } + + [TearDown] + public void ShutdownRemoteController() + { + HazelcastClient.ShutdownAll(); + StopRemoteController(RemoteController); + } + + protected void Setup(string serverXml, bool isSslEnabled, bool? validateCertificateChain, + bool? validateCertificateName, bool? checkCertificateRevocation, string certSubjectName, byte[] clientCertificate, + string certPassword) + { + RemoteController = CreateRemoteController(); + var cluster = CreateCluster(RemoteController, serverXml); + RemoteController.startMember(cluster.Id); + var clientConfig = new ClientConfig(); + clientConfig.GetNetworkConfig().AddAddress("localhost:5701"); + clientConfig.GetNetworkConfig().SetSSLConfig(CreateSslConfig(isSslEnabled, validateCertificateChain, + validateCertificateName, checkCertificateRevocation, certSubjectName, clientCertificate, certPassword)); + clientConfig.GetGroupConfig().SetName(cluster.Id).SetPassword(cluster.Id); + Client = HazelcastClient.NewHazelcastClient(clientConfig); + } + + private static SSLConfig CreateSslConfig(bool isSslEnabled, bool? validateCertificateChain, bool? validateCertificateName, + bool? checkCertificateRevocation, string certSubjectName, byte[] clientCertificate, string certPassword) + { + var sslConfig = new SSLConfig(); + sslConfig.SetEnabled(isSslEnabled); + if (clientCertificate != null) + { + var certFilePath = CreateTmpFile(clientCertificate); + sslConfig.SetProperty(SSLConfig.CertificateFilePath, certFilePath); + if (certPassword != null) + sslConfig.SetProperty(SSLConfig.CertificatePassword, certPassword); + } + if (validateCertificateChain != null) + sslConfig.SetProperty(SSLConfig.ValidateCertificateChain, validateCertificateChain.ToString()); + if (validateCertificateName != null) + sslConfig.SetProperty(SSLConfig.ValidateCertificateName, validateCertificateName.ToString()); + if (certSubjectName != null) + sslConfig.SetProperty(SSLConfig.CertificateName, certSubjectName); + if (checkCertificateRevocation != null) + sslConfig.SetProperty(SSLConfig.CheckCertificateRevocation, checkCertificateRevocation.ToString()); + return sslConfig; + } + + private static string CreateTmpFile(byte[] cert) + { + var tmpFileName = Path.GetTempFileName(); + var fs = File.Open(tmpFileName, FileMode.Append); + var bw = new BinaryWriter(fs); + bw.Write(cert); + bw.Close(); + fs.Close(); + return tmpFileName; + } + } +} \ No newline at end of file diff --git a/Hazelcast.Test/Hazelcast.Client.Test/ClientSslMutualAuthenticationTest.cs b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslMutualAuthenticationTest.cs new file mode 100644 index 0000000000..ebb3a884ac --- /dev/null +++ b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslMutualAuthenticationTest.cs @@ -0,0 +1,137 @@ +// Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using Hazelcast.Test; +using NUnit.Framework; + +namespace Hazelcast.Client.Test +{ + [TestFixture] + [Category("enterprise")] + [Category("3.8")] + public class ClientSslMutualAuthenticationTest : ClientSSLBaseTest + { + + [Test] + public void TestSSLEnabled_mutualAuthRequired_Server1KnowsClient1() + { + Setup(serverXml:Resources.hazelcast_ma_required, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:Resources.client1, + certPassword:Password); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_mutualAuthRequired_Server1KnowsClient1_clientDoesNotProvideCerts() + { + Assert.Throws(() => + { + Setup(serverXml:Resources.hazelcast_ma_required, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + }); + } + + [Test] + public void TestSSLEnabled_mutualAuthRequired_Server1NotKnowsClient2() + { + Assert.Throws(() => + { + Setup(serverXml:Resources.hazelcast_ma_required, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:Resources.client2, + certPassword:Password); + Assert.True(Client.GetLifecycleService().IsRunning()); + }); + } + + [Test] + public void TestSSLEnabled_mutualAuthOptional_Server1KnowsClient1() + { + Setup(serverXml:Resources.hazelcast_ma_optional, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:Resources.client1, + certPassword:Password); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_mutualAuthOptional_Server1KnowsClient1_clientDoesNotProvideCerts() + { + Setup(serverXml:Resources.hazelcast_ma_optional, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_mutualAuthOptional_Server1NotKnowsClient2() + { + Assert.Throws(() => + { + Setup(serverXml:Resources.hazelcast_ma_optional, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:Resources.client2, + certPassword:Password); + Assert.True(Client.GetLifecycleService().IsRunning()); + }); + } + + [Test] + public void TestSSLEnabled_mutualAuthDisabled_Client1() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:Resources.client1, + certPassword:Password); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + } +} \ No newline at end of file diff --git a/Hazelcast.Test/Hazelcast.Client.Test/ClientSslTest.cs b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslTest.cs new file mode 100644 index 0000000000..99969231f9 --- /dev/null +++ b/Hazelcast.Test/Hazelcast.Client.Test/ClientSslTest.cs @@ -0,0 +1,150 @@ +// Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Authentication; +using System.Text; +using Hazelcast.Config; +using Hazelcast.Core; +using Hazelcast.Remote; +using Hazelcast.Test; +using NUnit.Framework; + +namespace Hazelcast.Client.Test +{ + [TestFixture] + [Category("enterprise")] + public class ClientSSLTest : ClientSSLBaseTest + { + + [Test] + public void TestSSLEnabled_validateName_validName() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:true, + checkCertificateRevocation:null, + certSubjectName:ValidCertNameSigned, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_validateName_invalidName() + { + Assert.Throws(() => + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:true, + checkCertificateRevocation:null, + certSubjectName:"Invalid Cert Name", + clientCertificate:null, + certPassword:null); + }); + } + + [Test] + public void TestSSLEnabled_validateChain_DoNotValidateName_invalidName() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:true, + validateCertificateName:false, + checkCertificateRevocation:null, + certSubjectName:"Invalid Cert Name", + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_DoNotValidateChain_DoNotValidateName_invalidName() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:false, + validateCertificateName:false, + checkCertificateRevocation:null, + certSubjectName:"Invalid Cert Name", + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLDisabled() + { + Setup(serverXml:Resources.hazelcast, + isSslEnabled:false, + validateCertificateChain:null, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_self_signed_remote_cert() + { + Assert.Throws(() => + { + Setup(serverXml:Resources.hazelcast_ssl, + isSslEnabled:true, + validateCertificateChain:null, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:null, + certPassword:null); + }); + } + + [Test] + public void TestSSLEnabled_signed_remote_cert() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:null, + validateCertificateName:null, + checkCertificateRevocation:null, + certSubjectName:null, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + + [Test] + public void TestSSLEnabled_validateChain_validateName_validName() + { + Setup(serverXml:Resources.hazelcast_ssl_signed, + isSslEnabled:true, + validateCertificateChain:null, + validateCertificateName:true, + checkCertificateRevocation:null, + certSubjectName:ValidCertNameSigned, + clientCertificate:null, + certPassword:null); + Assert.True(Client.GetLifecycleService().IsRunning()); + } + } +} \ No newline at end of file diff --git a/Hazelcast.Test/Hazelcast.Test.csproj b/Hazelcast.Test/Hazelcast.Test.csproj index ad32c0db25..37afe2657d 100644 --- a/Hazelcast.Test/Hazelcast.Test.csproj +++ b/Hazelcast.Test/Hazelcast.Test.csproj @@ -16,33 +16,17 @@ ..\public.snk - - - - - - - + + ..\packages\ApacheThrift.0.9.3\lib\Thrift.dll - + - - True - True - Resources.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Hazelcast.Test - + \ No newline at end of file diff --git a/Hazelcast.Test/Properties/Resources.Designer.cs b/Hazelcast.Test/Properties/Resources.Designer.cs deleted file mode 100644 index 899c150194..0000000000 --- a/Hazelcast.Test/Properties/Resources.Designer.cs +++ /dev/null @@ -1,97 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Hazelcast.Test { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string hazelcast { - get { - return ResourceManager.GetString("hazelcast", resourceCulture); - } - } - - internal static string hazelcast_hb { - get { - return ResourceManager.GetString("hazelcast_hb", resourceCulture); - } - } - - internal static string hazelcast_config_full { - get { - return ResourceManager.GetString("hazelcast_config_full", resourceCulture); - } - } - - internal static string hazelcast_delay { - get { - return ResourceManager.GetString("hazelcast_delay", resourceCulture); - } - } - - internal static string hazelcast_ipv6 { - get { - return ResourceManager.GetString("hazelcast_ipv6", resourceCulture); - } - } - - internal static string hazelcast_nearcache { - get { - return ResourceManager.GetString("hazelcast_nearcache", resourceCulture); - } - } - - internal static string hazelcast_ssl { - get { - return ResourceManager.GetString("hazelcast_ssl", resourceCulture); - } - } - - internal static string hazelcast_stat { - get { - return ResourceManager.GetString("hazelcast_stat", resourceCulture); - } - } - } -} diff --git a/Hazelcast.Test/Properties/Resources.cs b/Hazelcast.Test/Properties/Resources.cs new file mode 100644 index 0000000000..104b742b2b --- /dev/null +++ b/Hazelcast.Test/Properties/Resources.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Text; + +namespace Hazelcast.Test +{ + internal static class Resources + { + //Binary files + public static byte[] client1 {get { return GetBytes("Resources.client1.pfx"); }} + public static byte[] client2 {get { return GetBytes("Resources.client2.pfx"); }} + + //Text files + public static string hazelcast_config_full {get { return GetXmlResourceContent("hazelcast-client-full"); }} + public static string hazelcast {get { return GetXmlResourceContent("hazelcast"); }} + public static string hazelcast_delay {get { return GetXmlResourceContent("hazelcast-delay"); }} + public static string hazelcast_hb {get { return GetXmlResourceContent("hazelcast-hb"); }} + public static string hazelcast_ipv6 {get { return GetXmlResourceContent("hazelcast-ipv6"); }} + public static string hazelcast_ma_required {get { return GetXmlResourceContent("hazelcast-ma-required"); }} + public static string hazelcast_ma_optional {get { return GetXmlResourceContent("hazelcast-ma-optional"); }} + public static string hazelcast_nearcache {get { return GetXmlResourceContent("hazelcast-nearcache"); }} + public static string hazelcast_ssl_signed {get { return GetXmlResourceContent("hazelcast-ssl-signed"); }} + public static string hazelcast_ssl {get { return GetXmlResourceContent("hazelcast-ssl"); }} + public static string hazelcast_stat {get { return GetXmlResourceContent("hazelcast-stat"); }} + + private static byte[] GetBytes(string name) + { + var assembly = typeof(Resources).Assembly; + using (var stream = assembly.GetManifestResourceStream(name)) + { + if (stream == null) + { + return null; + } + using (var ms = new MemoryStream()) + { + stream.CopyTo(ms); + return ms.ToArray(); + } + } + } + + private static string GetXmlResourceContent(string name) + { + var fullName = "Resources." + name + ".xml"; + var bytes = GetBytes(fullName); + return Encoding.UTF8.GetString(bytes); + } + } +} \ No newline at end of file diff --git a/Hazelcast.Test/Properties/Resources.resx b/Hazelcast.Test/Properties/Resources.resx deleted file mode 100644 index 902910ea9c..0000000000 --- a/Hazelcast.Test/Properties/Resources.resx +++ /dev/null @@ -1,561 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <properties> - <property name="hazelcast.map.invalidation.batch.enabled">false</property> - <property name="hazelcast.cache.invalidation.batch.size">10</property> - <property name="hazelcast.partition.count">271</property> - </properties> - - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - <ssl enabled="false"/> - <socket-interceptor enabled="false"/> - </network> - <serialization> - <data-serializable-factories> - <data-serializable-factory factory-id="66">com.hazelcast.client.test.IdentifiedFactory - </data-serializable-factory> - </data-serializable-factories> - </serialization> - - <queue name="ClientQueueTest*"> - <!-- - Maximum size of the queue. When a JVM's local queue size reaches the maximum, - all put/offer operations will get blocked until the queue size - of the JVM goes down below the maximum. - Any integer between 0 and Integer.MAX_VALUE. 0 means - Integer.MAX_VALUE. Default is 0. - --> - <max-size>6</max-size> - </queue> - <ringbuffer name="ClientRingbufferTest*"> - <capacity>10</capacity> - </ringbuffer> - <ringbuffer name="ClientRingbufferTestWithTTL*"> - <capacity>10</capacity> - <time-to-live-seconds>180</time-to-live-seconds> - </ringbuffer> - -</hazelcast> - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <properties> - <property name="hazelcast.client.max.no.heartbeat.seconds">8</property> - </properties> - - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - <ssl enabled="false"/> - <socket-interceptor enabled="false"/> - </network> - <serialization> - <data-serializable-factories> - <data-serializable-factory factory-id="66">com.hazelcast.client.test.IdentifiedFactory - </data-serializable-factory> - </data-serializable-factories> - </serialization> -</hazelcast> - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast-client xsi:schemaLocation="http://www.hazelcast.com/schema/client-config hazelcast-client-config-3.11.xsd" - xmlns="http://www.hazelcast.com/schema/client-config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - - <network> - <cluster-members> - <address>127.0.0.1</address> - <address>127.0.0.2</address> - </cluster-members> - <smart-routing>true</smart-routing> - <redo-operation>true</redo-operation> - <connection-timeout>60000</connection-timeout> - <connection-attempt-period>3000</connection-attempt-period> - <connection-attempt-limit>2</connection-attempt-limit> - <socket-interceptor enabled="true"> - <class-name>com.hazelcast.examples.MySocketInterceptor</class-name> - <properties> - <property name="foo">bar</property> - </properties> - </socket-interceptor> - <socket-options> - <tcp-no-delay>false</tcp-no-delay> - <keep-alive>true</keep-alive> - <reuse-address>true</reuse-address> - <linger-seconds>3</linger-seconds> - <timeout>-1</timeout> - <buffer-size>32</buffer-size> - </socket-options> - <ssl enabled="false"> - <properites> - <property name="CertificateName">The_Certificate_Name</property> - <property name="ValidateCertificateChain">true</property> - <property name="ValidateCertificateName">true</property> - </properites> - </ssl> - </network> - - <executor-pool-size>40</executor-pool-size> - - <security> - <credentials>Hazelcast.Security.UsernamePasswordCredentials</credentials> - <credentials-factory class-name="Hazelcast.Security.DefaultCredentialsFactory"> - <properties> - <property name="username">dev-user</property> - <property name="password">pass123</property> - </properties> - </credentials-factory> - </security> - - <listeners> - <listener>Hazelcast.Examples.MembershipListener</listener> - <listener>Hazelcast.Examples.InstanceListener</listener> - <listener>Hazelcast.Examples.MigrationListener</listener> - </listeners> - - <serialization> - <portable-version>3</portable-version> - <use-native-byte-order>true</use-native-byte-order> - <byte-order>BIG_ENDIAN</byte-order> - <enable-shared-object>true</enable-shared-object> - <check-class-def-errors>true</check-class-def-errors> - <enable-compression>true</enable-compression>> - <data-serializable-factories> - <data-serializable-factory factory-id="1">com.hazelcast.examples.DataSerializableFactory</data-serializable-factory> - </data-serializable-factories> - <portable-factories> - <portable-factory factory-id="1">com.hazelcast.examples.PortableFactory</portable-factory> - </portable-factories> - <serializers> - <global-serializer>com.hazelcast.examples.GlobalSerializerFactory</global-serializer> - <serializer type-class="com.hazelcast.examples.DummyType">com.hazelcast.examples.SerializerFactory</serializer> - </serializers> - <check-class-def-errors>true</check-class-def-errors> - </serialization> - - <proxy-factories> - <proxy-factory class-name="com.hazelcast.examples.ProxyXYZ1" service="sampleService1" /> - <proxy-factory class-name="com.hazelcast.examples.ProxyXYZ2" service="sampleService2" /> - <proxy-factory class-name="com.hazelcast.examples.ProxyXYZ3" service="sampleService3" /> - - </proxy-factories> - - <load-balancer type="random"></load-balancer> - - <near-cache name="asd"> - <max-size>2000</max-size> - <time-to-live-seconds>100</time-to-live-seconds> - <max-idle-seconds>100</max-idle-seconds> - <eviction-policy>LFU</eviction-policy> - <invalidate-on-change>true</invalidate-on-change> - <in-memory-format>OBJECT</in-memory-format> - </near-cache> - - <license-key>ENTERPRISE_KEY</license-key> - - -</hazelcast-client> - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - - </network> - <security enabled="true"> - <client-permissions> - <all-permissions principal="dev"/> - </client-permissions> - <security-interceptors> - <interceptor class-name="com.hazelcast.security.DelaySecurityInterceptor"/> - </security-interceptors> - </security> -</hazelcast> - - - <?xml version="1.0" encoding="UTF-8"?> - -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>FF02:0:0:0:0:0:0:1</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false" /> - </join> - <public-address>PUBLIC_IP</public-address> - </network> -</hazelcast> - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <properties> - <property name="hazelcast.map.invalidation.batch.enabled">true</property> - <property name="hazelcast.cache.invalidation.batch.size">10</property> - <property name="hazelcast.partition.count">271</property> - </properties> - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - <ssl enabled="false"/> - <socket-interceptor enabled="false"/> - </network> - <serialization> - <data-serializable-factories> - <data-serializable-factory factory-id="66">com.hazelcast.client.test.IdentifiedFactory - </data-serializable-factory> - </data-serializable-factories> - </serialization> -</hazelcast> - - - <hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="false">http://localhost:8080/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - <ssl enabled="true"> - <factory-class-name> - com.hazelcast.nio.ssl.ClasspathSSLContextFactory - </factory-class-name> - <properties> - <property name="keyStore">com/hazelcast/nio/ssl-mutual-auth/server1.keystore</property> - <property name="keyStorePassword">password</property> - <!-- - <property name="trustStore">com/hazelcast/nio/ssl-mutual-auth/server1.truststore</property> - <property name="trustStorePassword">password</property> - <property name="trustManagerAlgorithm">SunX509</property> - --> - <property name="keyManagerAlgorithm">SunX509</property> - <property name="protocol">TLS</property> - </properties> - </ssl> - </network> - -</hazelcast> - - - <?xml version="1.0" encoding="UTF-8"?> -<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.8.xsd" - xmlns="http://www.hazelcast.com/schema/config" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <group> - <name>dev</name> - <password>dev-pass</password> - </group> - <management-center enabled="true">http://localhost:8083/mancenter</management-center> - <network> - <port auto-increment="true" port-count="100">5701</port> - <outbound-ports> - <!-- - Allowed port range when connecting to other nodes. - 0 or * means use system provided port. - --> - <ports>0</ports> - </outbound-ports> - <join> - <multicast enabled="true"> - <multicast-group>224.7.7.7</multicast-group> - <multicast-port>54327</multicast-port> - </multicast> - <tcp-ip enabled="false"> - <interface>127.0.0.1</interface> - </tcp-ip> - </join> - <public-address>127.0.0.1</public-address> - <ssl enabled="false"/> - <socket-interceptor enabled="false"/> - </network> - <serialization> - <data-serializable-factories> - <data-serializable-factory factory-id="66">com.hazelcast.client.test.IdentifiedFactory - </data-serializable-factory> - </data-serializable-factories> - </serialization> - - <queue name="ClientQueueTest*"> - <!-- - Maximum size of the queue. When a JVM's local queue size reaches the maximum, - all put/offer operations will get blocked until the queue size - of the JVM goes down below the maximum. - Any integer between 0 and Integer.MAX_VALUE. 0 means - Integer.MAX_VALUE. Default is 0. - --> - <max-size>6</max-size> - </queue> - <ringbuffer name="ClientRingbufferTest*"> - <capacity>10</capacity> - </ringbuffer> - <ringbuffer name="ClientRingbufferTestWithTTL*"> - <capacity>10</capacity> - <time-to-live-seconds>180</time-to-live-seconds> - </ringbuffer> - -</hazelcast> - - \ No newline at end of file diff --git a/Hazelcast.Test/Resources/client1.pfx b/Hazelcast.Test/Resources/client1.pfx new file mode 100644 index 0000000000000000000000000000000000000000..b7fbb45e484ba9498f47cfb68eaf3e297b057fd0 GIT binary patch literal 2550 zcmY+EcQ_k}8^@OS}|)JH7aINy;40xyI9Y&Ch~Ps65xj?xW#jxmK6x$- zhAWoPt(^JY-lX#!)pmtyA*9pae*gl(05B0u+tN?9_1oCrW2x06EKQuNjv?TnWy{a$yw_aO!P(uKf;|;|mfTIAilU+I zN>@|dkLA3p1IF90JWoc=iK7B*3C)=g)&O+#M=>mz+BJ))fb?whBKOBToNjrJOr>+! zonN6@ZvnfySmoDNWGH%M$U&_By78(VMZ$HpxflC(vE)q2U6|g(Sk=5>sf0zpxo;QZ zv&>(DtjnP2o$(y&cXh(q88Fnfs+ek)&MSgn)IC;BR_ml4yd3z%qiiP#G`?P*+xwdH zeh1X+5d&9S3T0)<-*PB^kF`wY(QiCf*l($SW>KA{j^r|n_I&4Kp(ZbFZ6`MiV(bqH z`f|0?UY`)X*G*DeYaF)_$z+{M<1W#=gDr$jKQv7yOx*{ zXD_d2t3I&r53%zqye*qOFwE}S$_nrhCSO0YvpoGR_8yZ4r5Q%Xd1ZD3C_UVF*V-kz zh58EHT)cR-oCqSB8;86cx0OP;kFqQuRz~5TS=GGiKxbt-F1GjSy_qRGup7&l^pgtO zM&z1NW}7+hcywF5qlQ;HT+_^p(;*I&rVg51FnM!?4q6-PuS~NRQ^?GY-06@Yr?lzB zax2uy-9j_lLrt#}@B~gzxMo#L*Ny~t}Ut8I|0QybWQO#T!2pIG*C6-wdxBOizM8S z4W^9XeG}wRL0qv{iMuOT0XigX({6D#yGuSna9Gb?hHH1`v~|CRNr+OO@=m?M6PKWysftNBE(=Uz23t?WmxWnqX ztQ^2f{8^*d18{iGct>Nho^WX^{^^zJZId)RHzenm-J_CQml`IxZFC>fNzqxd?k=~Cg9hfULaz&~+N^<&YW~dAN64KV8_{0^aPlr=SgyUG_;kbe{fD(sFaPw@0mH~(Id~oo5 z`eZRj@W+ITCQ|i-o?`duwq`ay8H?rQLvgb`KL>wh6UNdWX3Ve?rM`eT zymAprdK~LQKnXm~+HMT2V8!n|zpvSYONEo8ENugs##81g|h3*=;;O4&!QtI;NyJrefDXms_>Ul9TR(3S7UR$<46xZ;|Xbu8iDdhPky44dHLn zR+|Z~{99BVtVm>*q6?P%@78+J&2Tnoo(f||>Xa-f4w>oK?&`^DlyWmQ%2G`E~v zNF9XeKcQC2{ql~t5a z>?!e2iJk34sPGd61F`^47UbWAZwK@|Cwh!bG7$B{?R`>3rd`$VArw2|Ihfi|6mYjC0T)!wfeQCG zbGm-9wAySJ`}a;{$;&tM#*dbmk(K+IVp5W;c3-sm>L0)~R)-weRh*5x=6nL8J4ow| zScz)jQV|{WHi**ee(%|6r%kU=dw&`sevIw0Xm~uSUrlRtVJq~j;IJ&7Kw_W;w}cLy zb0ce3@7?0jh!U9l_-NRY53vwh5T)PdrLi7mB8H0vLLGR!g)& zPU&w|K2F-WM1wti_+5PHJE;%9kfe#>wF}2Xxp)YB1U6S&o+rG#O&=~2XJBMF3$oPS z--s0xVS4=eJd5Ni?f$bNn;v(ZSXhM-yTd%#pGYP|3fe`_o)#~0h&g2ei^D!DS&q0M zj}P(pmiy7OB;OB)i|&X1t}rV*x2*lmiCe+m@D-s<7m~~|o7J7H7*z~s;%Vg6S*f(t z5#d+45LCM3vWXX|ZM!NxKvxMl;N-d_c^4Uns5m=}{j7Hgcpb7I4;Rn%nz z#uj6noSbIVxf;Uur#=$X?KfACFe6{~T1^TvsGJ-AasEZ!=aC@IeELHizZ&JB=11bHBp$XkweFbVfxgd*Ty}k7 zk;d491qs>I?`%*&jEoBFqyFDZ%NgzY(xqvU>KMy8@+Z9Rw-!_KQX^{1{B4N{-!c0} z*(beMf6fEQGQx?|p}X;S#MhP$m6yuN@5w+5M|6>maOmq2^abk8g_c8uZEp978w`Wk z2n0Up)78vzU~?AI`W1!HC-m7;!tSdXOllIOLQ_+6#pctW!5Jy1RSTA#ffWoW* yFg(Ga*0}tU8lymRCUVM`O5m7eaDw5+PQeXD)K1zqnk-qhvb?bt&sO)h68-{|NU^T~ literal 0 HcmV?d00001 diff --git a/Hazelcast.Test/Resources/client2.pfx b/Hazelcast.Test/Resources/client2.pfx new file mode 100644 index 0000000000000000000000000000000000000000..c2ed4f1a293f0d56079e6e39f7f7aed2d41c760f GIT binary patch literal 2550 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 literal 0 HcmV?d00001 diff --git a/Hazelcast.Test/Resources/hazelcast-client-full.xml b/Hazelcast.Test/Resources/hazelcast-client-full.xml index a71aff8fac..e874ba957b 100644 --- a/Hazelcast.Test/Resources/hazelcast-client-full.xml +++ b/Hazelcast.Test/Resources/hazelcast-client-full.xml @@ -34,9 +34,13 @@ - The_Certificate_Name + CERT_NAME true - true + false + false + CLIENT_CERT_PATH + CLIENT_CERT_PASSWORD + Tls diff --git a/Hazelcast.Test/Resources/hazelcast-delay.xml b/Hazelcast.Test/Resources/hazelcast-delay.xml index 298605973f..981d115086 100644 --- a/Hazelcast.Test/Resources/hazelcast-delay.xml +++ b/Hazelcast.Test/Resources/hazelcast-delay.xml @@ -1,55 +1,39 @@ - - - - dev - dev-pass - - http://localhost:8080/mancenter - - 5701 - - - 0 - - - - 224.7.7.7 - 54327 - - - 127.0.0.1 - - - 127.0.0.1 + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-hb.xml b/Hazelcast.Test/Resources/hazelcast-hb.xml new file mode 100644 index 0000000000..4e55f97af6 --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-hb.xml @@ -0,0 +1,43 @@ + + + + + 8 + + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + + + + com.hazelcast.client.test.IdentifiedFactory + + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-ipv6.xml b/Hazelcast.Test/Resources/hazelcast-ipv6.xml new file mode 100644 index 0000000000..c4e40f61d0 --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-ipv6.xml @@ -0,0 +1,29 @@ + + + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + FF02:0:0:0:0:0:0:1 + 54327 + + + + PUBLIC_IP + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-ma-optional.xml b/Hazelcast.Test/Resources/hazelcast-ma-optional.xml new file mode 100644 index 0000000000..9dd0f85845 --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-ma-optional.xml @@ -0,0 +1,46 @@ + + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + com.hazelcast.nio.ssl.ClasspathSSLContextFactory + + + com/hazelcast/nio/ssl/letsencrypt.jks + 123456 + com/hazelcast/nio/ssl-mutual-auth/server1_knows_client1/server1.truststore + password + SunX509 + OPTIONAL + SunX509 + TLSv1 + + + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-ma-required.xml b/Hazelcast.Test/Resources/hazelcast-ma-required.xml new file mode 100644 index 0000000000..4f8c487492 --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-ma-required.xml @@ -0,0 +1,46 @@ + + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + com.hazelcast.nio.ssl.ClasspathSSLContextFactory + + + com/hazelcast/nio/ssl/letsencrypt.jks + 123456 + com/hazelcast/nio/ssl-mutual-auth/server1_knows_client1/server1.truststore + password + SunX509 + REQUIRED + SunX509 + TLSv1 + + + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-nearcache.xml b/Hazelcast.Test/Resources/hazelcast-nearcache.xml new file mode 100644 index 0000000000..5571ed1f0d --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-nearcache.xml @@ -0,0 +1,44 @@ + + + + + true + 10 + 271 + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + + + + com.hazelcast.client.test.IdentifiedFactory + + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-ssl-signed.xml b/Hazelcast.Test/Resources/hazelcast-ssl-signed.xml new file mode 100644 index 0000000000..3514f2430f --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-ssl-signed.xml @@ -0,0 +1,41 @@ + + + + dev + dev-pass + + http://localhost:8080/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + com.hazelcast.nio.ssl.ClasspathSSLContextFactory + + + com/hazelcast/nio/ssl/letsencrypt.jks + 123456 + SunX509 + TLSv1 + + + + diff --git a/Hazelcast.Test/Resources/hazelcast-ssl.xml b/Hazelcast.Test/Resources/hazelcast-ssl.xml index 90f848da04..45fe0de6ca 100644 --- a/Hazelcast.Test/Resources/hazelcast-ssl.xml +++ b/Hazelcast.Test/Resources/hazelcast-ssl.xml @@ -1,63 +1,41 @@ - - - - - dev - dev-pass - - http://localhost:8080/mancenter - - 5701 - - - 0 - - - - 224.7.7.7 - 54327 - - - 127.0.0.1 - - - 127.0.0.1 - - - com.hazelcast.nio.ssl.ClasspathSSLContextFactory - - - com/hazelcast/nio/ssl-mutual-auth/server1.keystore - password - - SunX509 - TLS - - - + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + com.hazelcast.nio.ssl.ClasspathSSLContextFactory + + + com/hazelcast/nio/ssl-mutual-auth/server1.keystore + password + SunX509 + TLS + + + - + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast-stat.xml b/Hazelcast.Test/Resources/hazelcast-stat.xml new file mode 100644 index 0000000000..638c11c9aa --- /dev/null +++ b/Hazelcast.Test/Resources/hazelcast-stat.xml @@ -0,0 +1,57 @@ + + + + dev + dev-pass + + http://localhost:8083/mancenter + + 5701 + + + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + + + + com.hazelcast.client.test.IdentifiedFactory + + + + + + + 6 + + + 10 + + + 10 + 180 + + + \ No newline at end of file diff --git a/Hazelcast.Test/Resources/hazelcast.xml b/Hazelcast.Test/Resources/hazelcast.xml index dc635494ea..83080c6a30 100644 --- a/Hazelcast.Test/Resources/hazelcast.xml +++ b/Hazelcast.Test/Resources/hazelcast.xml @@ -1,73 +1,65 @@ - - - - dev - dev-pass - - http://localhost:8080/mancenter - - 5701 - - - 0 - - - - 224.7.7.7 - 54327 - - - 127.0.0.1 - - - 127.0.0.1 - - - - - - com.hazelcast.client.test.IdentifiedFactory - - - + 0 + + + + 224.7.7.7 + 54327 + + + 127.0.0.1 + + + 127.0.0.1 + + + + + + + com.hazelcast.client.test.IdentifiedFactory + + + - - - 6 - - - 10 - - - 10 - 180 - + 6 + + + 10 + + + 10 + 180 + \ No newline at end of file diff --git a/build.bat b/build.bat index f04f844fd9..ae8154bbdb 100644 --- a/build.bat +++ b/build.bat @@ -1,133 +1,2 @@ @echo off -setlocal EnableDelayedExpansion -pushd %~dp0 - -REM TODO UPDATE PARAMETER PARSING -IF -%1-==-- (set COVERAGE="--no-coverage") ELSE (set COVERAGE=%1) -IF -%2-==-- ( - set SERVER_TYPE=--oss - set EXLUDE_PARAM=/exclude:enterprise -) ELSE ( - set SERVER_TYPE=%2 - set EXLUDE_PARAM= -) - -IF -%3-==-- ( - set FRAMEWORK=net40 -) ELSE ( - IF -%3-==-net40- ( - set FRAMEWORK=net40 - ) ELSE ( - IF -%3-==-netcore- ( - set FRAMEWORK=netstandard2.0 - ) ELSE ( - echo "Invalide .Net Framework type, use net40 or netcore" - exit /b - ) - ) -) - -set HZ_VERSION=3.10.5 -set HAZELCAST_TEST_VERSION=%HZ_VERSION% -set HAZELCAST_VERSION=%HZ_VERSION% -set HAZELCAST_ENTERPRISE_VERSION=%HZ_VERSION% -set HAZELCAST_RC_VERSION=0.5-SNAPSHOT -set SNAPSHOT_REPO=https://oss.sonatype.org/content/repositories/snapshots -set RELEASE_REPO=http://repo1.maven.apache.org/maven2 -set ENTERPRISE_RELEASE_REPO=https://repository-hazelcast-l337.forge.cloudbees.com/release/ -set ENTERPRISE_SNAPSHOT_REPO=https://repository-hazelcast-l337.forge.cloudbees.com/snapshot/ - -if not "x%HZ_VERSION:SNAPSHOT=%"=="x%HZ_VERSION%" ( - set REPO=%SNAPSHOT_REPO% - set ENTERPRISE_REPO=%ENTERPRISE_SNAPSHOT_REPO% -) else ( - set REPO=%RELEASE_REPO% - set ENTERPRISE_REPO=%ENTERPRISE_RELEASE_REPO% -) - -echo "PARAMETERS:" -echo %COVERAGE% -echo %SERVER_TYPE% -echo %CP_PARAM% -echo Exclude param: %EXCLUDE_PARAM% -echo Framework : %FRAMEWORK% -echo Starting build... - -REM nuget locals all -clear -nuget restore - -if -%FRAMEWORK%-==-net40- ( - msbuild Hazelcast.Test\Hazelcast.Test.csproj /p:Configuration=Release /p:TargetFramework=net46 /target:Restore;Build -) ELSE ( - msbuild Hazelcast.Test\Hazelcast.Test.csproj /p:Configuration=Release /p:TargetFramework=netcoreapp2.0 /target:Restore;Build -) - -IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% - -echo Downloading ... -if not exist hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar ( - echo Downloading hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar ... - call mvn -q dependency:get -DrepoUrl=%SNAPSHOT_REPO% -Dartifact=com.hazelcast:hazelcast-remote-controller:%HAZELCAST_RC_VERSION% -Ddest=hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar -) else ( - echo remote controller already exist, not downloading from maven. -) - -if not exist hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar ( - echo Downloading hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar ... - call mvn -q dependency:get -DrepoUrl=%SNAPSHOT_REPO% -Dartifact=com.hazelcast:hazelcast:%HAZELCAST_TEST_VERSION%:jar:tests -Ddest=hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar -) else ( - echo hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar already exist, not downloading from maven. -) - -set CLASSPATH=hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar;hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar -if %SERVER_TYPE%==--enterprise ( - if exist hazelcast-%HAZELCAST_VERSION%.jar ( - echo hazelcast.jar already exists, not downloading from maven. - ) else ( - echo Downloading Hazelcast %HAZELCAST_VERSION% ... - call mvn -q dependency:get -DrepoUrl=%REPO% -Dartifact=com.hazelcast:hazelcast:%HAZELCAST_VERSION% -Ddest=hazelcast-%HAZELCAST_VERSION%.jar - ) - set CLASSPATH=%CLASSPATH%;hazelcast-%HAZELCAST_VERSION%.jar -) else ( - if exist hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%.jar ( - echo hazelcast-enterprise.jar already exists, not downloading from maven. - ) else ( - echo Downloading Hazelcast Enterprise %HAZELCAST_ENTERPRISE_VERSION%... - call mvn -q dependency:get -DrepoUrl=%ENTERPRISE_REPO% -Dartifact=com.hazelcast:hazelcast-enterprise:%HAZELCAST_ENTERPRISE_VERSION% -Ddest=hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%.jar - ) - set CLASSPATH=%CLASSPATH%;hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%.jar -) - -taskkill /T /F /FI "WINDOWTITLE eq hazelcast-remote-controller" -if exist errorlevel del errorlevel - -echo "Starting hazelcast-remote-controller" -start /min "hazelcast-remote-controller" cmd /c "java -Dhazelcast.enterprise.license.key=%HAZELCAST_ENTERPRISE_KEY% -cp %CLASSPATH% com.hazelcast.remotecontroller.Main> rc_stdout.txt 2>rc_stderr.txt || call echo %^errorlevel% > errorlevel" - -REM Wait for Hazelcast RC to start -ping -n 4 127.0.0.1 > nul -if exist errorlevel ( - set /p exitcode=