You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2021/11/16 16:35:57 UTC

[ignite] branch ignite-2.12 updated: IGNITE-15915 .NET: Allow null SslStreamFactory.CertificatePath (#9566)

This is an automated email from the ASF dual-hosted git repository.

ptupitsyn pushed a commit to branch ignite-2.12
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/ignite-2.12 by this push:
     new 22ff78d  IGNITE-15915 .NET: Allow null SslStreamFactory.CertificatePath (#9566)
22ff78d is described below

commit 22ff78d80c9c487cf904854a0e435960a4b0d836
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue Nov 16 19:32:50 2021 +0300

    IGNITE-15915 .NET: Allow null SslStreamFactory.CertificatePath (#9566)
    
    Allow thin client to establish SSL connection without client-side certificate when `ClientConnectorConfiguration.sslClientAuth` is `false` on server.
    
    (cherry picked from commit 52553241ea2986b966610592db180ac2291ea71a)
---
 .../Apache.Ignite.Core.Tests.DotNetCore.csproj     |  3 ++
 .../Client/ClientConnectionTest.cs                 | 62 +++++++++++++++++++++
 .../Client/RawSecureSocketTest.cs                  | 63 +++++++++++++++-------
 ...-ssl.xml => server-with-ssl-no-client-auth.xml} |  6 +--
 .../Config/Client/server-with-ssl.xml              |  2 +-
 .../Apache.Ignite.Core/Client/SslStreamFactory.cs  |  9 +++-
 6 files changed, 120 insertions(+), 25 deletions(-)

diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj
index bcdedc2..a1dd4f1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.DotNetCore.csproj
@@ -107,6 +107,9 @@
     <None Update="Examples\ExpectedOutput\**">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Update="Config\Client\server-with-ssl-no-client-auth.xml">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
index 457d261..0cfe809 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Tests.Client
     using System.Linq;
     using System.Net;
     using System.Net.Sockets;
+    using System.Security.Authentication;
     using System.Text.RegularExpressions;
     using System.Threading;
     using System.Threading.Tasks;
@@ -666,6 +667,67 @@ namespace Apache.Ignite.Core.Tests.Client
         }
 
         /// <summary>
+        /// Tests SSL connection with client-side SSL certificate.
+        /// </summary>
+        [Test]
+        public void TestSslConnectionWithClientAuth()
+        {
+            Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl.xml")
+            });
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1:11110" },
+                SslStreamFactory = new SslStreamFactory
+                {
+                    CertificatePath = Path.Combine("Config", "Client", "thin-client-cert.pfx"),
+                    CertificatePassword = "123456",
+                    SkipServerCertificateValidation = true,
+                    CheckCertificateRevocation = true,
+                    SslProtocols = SslProtocols.Tls12
+                }
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                Assert.AreEqual(1, client.GetCluster().GetNodes().Count);
+            }
+
+            // Does not connect without client certificate.
+            cfg.SslStreamFactory = new SslStreamFactory { SkipServerCertificateValidation = true };
+            Assert.Catch<Exception>(() => Ignition.StartClient(cfg));
+        }
+
+        /// <summary>
+        /// Tests SSL connection without client-side SSL certificate.
+        /// </summary>
+        [Test]
+        public void TestSslConnectionWithoutClientAuth()
+        {
+            Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl-no-client-auth.xml"),
+            });
+
+            var cfg = new IgniteClientConfiguration
+            {
+                Endpoints = new[] { "127.0.0.1:11120" },
+                SslStreamFactory = new SslStreamFactory
+                {
+                    SkipServerCertificateValidation = true,
+                    SslProtocols = SslProtocols.Tls12
+                }
+            };
+
+            using (var client = Ignition.StartClient(cfg))
+            {
+                Assert.AreEqual(1, client.GetCluster().GetNodes().Count);
+            }
+        }
+
+        /// <summary>
         /// Starts the client.
         /// </summary>
         private static IIgniteClient StartClient()
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSecureSocketTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSecureSocketTest.cs
index 799c6c6..69b6f38 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSecureSocketTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSecureSocketTest.cs
@@ -31,35 +31,59 @@ namespace Apache.Ignite.Core.Tests.Client
     /// </summary>
     public class RawSecureSocketTest
     {
+        [TestFixtureSetUp]
+        public void FixtureSetUp()
+        {
+            var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl.xml")
+            };
+
+            Ignition.Start(cfg);
+
+            var cfgNoClientAuth = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+            {
+                SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl-no-client-auth.xml"),
+                AutoGenerateIgniteInstanceName = true
+            };
+
+            Ignition.Start(cfgNoClientAuth);
+        }
+
+        [TestFixtureTearDown]
+        public void FixtureTearDown()
+        {
+            Ignition.StopAll(true);
+        }
+
         /// <summary>
         /// Tests that we can do handshake over SSL without using Ignite.NET APIs.
         /// </summary>
         [Test]
-        public void TestHandshake()
+        public void TestHandshake([Values(true, false)] bool clientCert)
         {
-            var igniteConfiguration = new IgniteConfiguration(TestUtils.GetTestConfiguration())
-            {
-                SpringConfigUrl = Path.Combine("Config", "Client", "server-with-ssl.xml")
-            };
+            const string host = "127.0.0.1";
+            var port = clientCert ? 11110 : 11120;
 
-            using (Ignition.Start(igniteConfiguration))
+            using (var client = new TcpClient(host, port))
+            using (var sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null))
             {
-                const string host = "127.0.0.1";
-                const int port = 11110;
+                var certsCollection = new X509CertificateCollection(new X509Certificate[] { LoadCertificateFile() });
 
-                using (var client = new TcpClient(host, port))
-                using (var sslStream = new SslStream(client.GetStream(), false, ValidateServerCertificate, null))
+                if (clientCert)
                 {
-                    var certsCollection = new X509CertificateCollection(new X509Certificate[] {LoadCertificateFile()});
-
                     sslStream.AuthenticateAsClient(host, certsCollection, SslProtocols.Tls12, false);
+                }
+                else
+                {
+                    sslStream.AuthenticateAsClient(host);
+                }
 
-                    Assert.IsTrue(sslStream.IsAuthenticated);
-                    Assert.IsTrue(sslStream.IsMutuallyAuthenticated);
-                    Assert.IsTrue(sslStream.IsEncrypted);
+                Assert.IsTrue(sslStream.IsAuthenticated);
+                Assert.AreEqual(clientCert, sslStream.IsMutuallyAuthenticated);
+                Assert.IsTrue(sslStream.IsEncrypted);
 
-                    DoHandshake(sslStream);
-                }
+                DoHandshake(sslStream);
             }
         }
 
@@ -123,7 +147,9 @@ namespace Apache.Ignite.Core.Tests.Client
         private static byte[] ReceiveMessage(Stream sock)
         {
             var buf = new byte[4];
-            sock.Read(buf, 0, 4);
+            var read = sock.Read(buf, 0, 4);
+
+            Assert.AreEqual(4, read);
 
             using (var stream = new BinaryHeapStream(buf))
             {
@@ -150,6 +176,5 @@ namespace Apache.Ignite.Core.Tests.Client
                 sock.Write(stream.GetArray(), 0, stream.Position);
             }
         }
-
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl-no-client-auth.xml
similarity index 96%
copy from modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml
copy to modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl-no-client-auth.xml
index 7ef8e17..731e162 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl-no-client-auth.xml
@@ -31,11 +31,11 @@
         <property name="clientConnectorConfiguration">
             <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
                 <property name="host" value="127.0.0.1"/>
-                <property name="port" value="11110"/>
+                <property name="port" value="11120"/>
                 <property name="portRange" value="10"/>
                 <property name="sslEnabled" value="true"/>
                 <property name="useIgniteSslContextFactory" value="false"/>
-                <property name="sslClientAuth" value="true"/>
+                <property name="sslClientAuth" value="false"/>
 
                 <property name="sslContextFactory">
                     <bean class="org.apache.ignite.ssl.SslContextFactory">
@@ -64,4 +64,4 @@
             </bean>
         </property>
     </bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml
index 7ef8e17..821031f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/Client/server-with-ssl.xml
@@ -64,4 +64,4 @@
             </bean>
         </property>
     </bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Client/SslStreamFactory.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Client/SslStreamFactory.cs
index 3961b09..f7a656c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Client/SslStreamFactory.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Client/SslStreamFactory.cs
@@ -49,8 +49,13 @@ namespace Apache.Ignite.Core.Client
 
             var sslStream = new SslStream(stream, false, ValidateServerCertificate, null);
 
-            var cert = new X509Certificate2(CertificatePath, CertificatePassword);
-            var certs = new X509CertificateCollection(new X509Certificate[] { cert });
+            var cert = string.IsNullOrEmpty(CertificatePath)
+                ? null
+                : new X509Certificate2(CertificatePath, CertificatePassword);
+
+            var certs = cert == null
+                ? null
+                : new X509CertificateCollection(new X509Certificate[] { cert });
 
             sslStream.AuthenticateAsClient(targetHost, certs, SslProtocols, CheckCertificateRevocation);