This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 5dd1f38c72 IGNITE-18579 Add SSL support to ScaleCube (#1659)
5dd1f38c72 is described below
commit 5dd1f38c72aecf836ce692ff2d74d283505b4a00
Author: Aleksandr <[email protected]>
AuthorDate: Fri Feb 10 18:55:25 2023 +0400
IGNITE-18579 Add SSL support to ScaleCube (#1659)
---
.../java/org/apache/ignite/lang/ErrorGroups.java | 3 +
.../AbstractSslConfigurationSchema.java | 54 ++++++
.../configuration/KeyStoreConfigurationSchema.java | 6 +-
.../configuration/NetworkConfigurationSchema.java | 4 +
...tionSchema.java => SslConfigurationSchema.java} | 14 +-
.../internal/network/netty/ConnectionManager.java | 7 +-
.../ignite/internal/network/netty/NettyClient.java | 36 ++--
.../ignite/internal/network/netty/NettyServer.java | 9 +-
.../internal/network/netty/PipelineUtils.java | 19 +-
.../internal/network/ssl/KeystoreLoader.java | 47 +++++
.../internal/network/ssl/SslContextProvider.java | 92 ++++++++++
.../internal/network/netty/NettyClientTest.java | 17 +-
.../network/ssl/SslContextProviderTest.java | 202 +++++++++++++++++++++
.../network/DefaultMessagingServiceTest.java | 51 +-----
.../ignite/internal/rest/ItPortRangeTest.java | 2 +-
.../ignite/internal/rest/ssl/ItRestSslTest.java | 2 +-
.../apache/ignite/internal/rest/ssl/RestNode.java | 2 +-
.../org/apache/ignite/internal/ssl/ItSslTest.java | 193 ++++++++++++++++++++
.../src/integrationTest/resources/ssl/keystore.p12 | Bin 4286 -> 4533 bytes
.../integrationTest/resources/ssl/truststore.jks | Bin 1558 -> 1738 bytes
20 files changed, 681 insertions(+), 79 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
index f9a7a38024..5ee9ea6f12 100755
--- a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
@@ -39,6 +39,9 @@ public class ErrorGroups {
/** Illegal argument or argument in a wrong format has been passed. */
public static final int ILLEGAL_ARGUMENT_ERR =
COMMON_ERR_GROUP.registerErrorCode(4);
+ /** SSL can not be configured error. */
+ public static final int SSL_CONFIGURATION_ERR =
COMMON_ERR_GROUP.registerErrorCode(5);
+
/** Unknown error. */
@Deprecated
public static final int UNKNOWN_ERR =
COMMON_ERR_GROUP.registerErrorCode(0xFFFF);
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
new file mode 100644
index 0000000000..2baf3a7fdf
--- /dev/null
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.internal.network.configuration;
+
+import org.apache.ignite.configuration.annotation.AbstractConfiguration;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.validation.OneOf;
+
+/** SSL configuration schema. */
+@AbstractConfiguration
+public class AbstractSslConfigurationSchema {
+ /** Enable/disable SSL. */
+ @Value(hasDefault = true)
+ public final boolean enabled = false;
+
+ /**
+ * Client authentication. Set to "none" by default.
+ *
+ * <p>If set to "optional", the server will request a certificate from the
client,
+ * but will not fail if the client does not provide one.
+ *
+ * <p>If set to "require", the server will request a certificate from the
client,
+ * and will fail if the client does not provide one.
+ */
+ @OneOf({"none", "optional", "require"})
+ @Value(hasDefault = true)
+ public final String clientAuth = "none";
+
+ /** SSL keystore configuration. */
+ @ConfigValue
+ @KeyStoreConfigurationValidator
+ public KeyStoreConfigurationSchema keyStore;
+
+ /** SSL truststore configuration. */
+ @ConfigValue
+ @KeyStoreConfigurationValidator
+ public KeyStoreConfigurationSchema trustStore;
+}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
index 895fa204d9..bfb3fb1664 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
@@ -20,16 +20,18 @@ package org.apache.ignite.internal.network.configuration;
import org.apache.ignite.configuration.annotation.Config;
import org.apache.ignite.configuration.annotation.Value;
-/** Key store configuration. */
+/** Keystore configuration schema. */
@Config
public class KeyStoreConfigurationSchema {
-
+ /** Keystore type. */
@Value(hasDefault = true)
public String type = "PKCS12";
+ /** Keystore path. */
@Value(hasDefault = true)
public String path = "";
+ /** Keystore password. */
@Value(hasDefault = true)
public String password = "";
}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
index dbe18bee72..3ab3a6041e 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
@@ -70,4 +70,8 @@ public class NetworkConfigurationSchema {
/** NodeFinder configuration. */
@ConfigValue
public NodeFinderConfigurationSchema nodeFinder;
+
+ /** SSL configuration.*/
+ @ConfigValue
+ public SslConfigurationSchema ssl;
}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
similarity index 74%
copy from
modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
copy to
modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
index 895fa204d9..0c1ca9094e 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
@@ -18,18 +18,8 @@
package org.apache.ignite.internal.network.configuration;
import org.apache.ignite.configuration.annotation.Config;
-import org.apache.ignite.configuration.annotation.Value;
-/** Key store configuration. */
+/** SSL configuration schema. */
@Config
-public class KeyStoreConfigurationSchema {
-
- @Value(hasDefault = true)
- public String type = "PKCS12";
-
- @Value(hasDefault = true)
- public String path = "";
-
- @Value(hasDefault = true)
- public String password = "";
+public class SslConfigurationSchema extends AbstractSslConfigurationSchema {
}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
index a9bd44c520..18ef33dbfd 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
@@ -97,6 +97,9 @@ public class ConnectionManager {
/** Recovery descriptor provider. */
private final RecoveryDescriptorProvider descriptorProvider = new
DefaultRecoveryDescriptorProvider();
+ /** Network Configuration. */
+ private final NetworkView networkConfiguration;
+
/**
* Constructor.
*
@@ -145,6 +148,7 @@ public class ConnectionManager {
this.launchId = launchId;
this.consistentId = consistentId;
this.clientHandhakeManagerFactory = clientHandhakeManagerFactory;
+ this.networkConfiguration = networkConfiguration;
this.server = new NettyServer(
networkConfiguration,
@@ -267,7 +271,8 @@ public class ConnectionManager {
address,
serializationService,
createClientHandshakeManager(connectionId),
- this::onMessage
+ this::onMessage,
+ this.networkConfiguration.ssl()
);
client.start(clientBootstrap).whenComplete((sender, throwable) -> {
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
index c3a40c6194..f4df8d905b 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
@@ -21,6 +21,7 @@ import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslContext;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Objects;
@@ -29,9 +30,11 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.ignite.internal.future.OrderingFuture;
+import org.apache.ignite.internal.network.configuration.SslView;
import org.apache.ignite.internal.network.handshake.HandshakeManager;
import
org.apache.ignite.internal.network.serialization.PerSessionSerializationService;
import org.apache.ignite.internal.network.serialization.SerializationService;
+import org.apache.ignite.internal.network.ssl.SslContextProvider;
import org.apache.ignite.lang.IgniteInternalException;
import org.jetbrains.annotations.Nullable;
@@ -48,44 +51,50 @@ public class NettyClient {
/** Destination address. */
private final SocketAddress address;
- /** Future that resolves when the client finished the handshake. */
- @Nullable
- private volatile OrderingFuture<NettySender> senderFuture = null;
-
/** Future that resolves when the client channel is opened. */
private final CompletableFuture<Void> channelFuture = new
CompletableFuture<>();
- /** Client channel. */
- @Nullable
- private volatile Channel channel = null;
-
/** Message listener. */
private final Consumer<InNetworkObject> messageListener;
/** Handshake manager. */
private final HandshakeManager handshakeManager;
+ /** SSL configuration. */
+ private final SslView sslConfiguration;
+
+ /** Future that resolves when the client finished the handshake. */
+ @Nullable
+ private volatile OrderingFuture<NettySender> senderFuture = null;
+
+ /** Client channel. */
+ @Nullable
+ private volatile Channel channel = null;
+
/** Flag indicating if {@link #stop()} has been called. */
private boolean stopped = false;
/**
- * Constructor.
+ * Constructor with SSL configuration.
*
* @param address Destination address.
* @param serializationService Serialization service.
* @param manager Client handshake manager.
* @param messageListener Message listener.
+ * @param sslConfiguration SSL configuration.
*/
public NettyClient(
InetSocketAddress address,
SerializationService serializationService,
HandshakeManager manager,
- Consumer<InNetworkObject> messageListener
+ Consumer<InNetworkObject> messageListener,
+ SslView sslConfiguration
) {
this.address = address;
this.serializationService = serializationService;
this.handshakeManager = manager;
this.messageListener = messageListener;
+ this.sslConfiguration = sslConfiguration;
}
/**
@@ -112,7 +121,12 @@ public class NettyClient {
public void initChannel(SocketChannel ch) {
var sessionSerializationService = new
PerSessionSerializationService(serializationService);
- PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, handshakeManager, messageListener);
+ if (sslConfiguration.enabled()) {
+ SslContext sslContext =
SslContextProvider.createClientSslContext(sslConfiguration);
+ PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, handshakeManager, messageListener, sslContext);
+ } else {
+ PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, handshakeManager, messageListener);
+ }
}
});
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
index 52d0e93910..7242c25725 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
@@ -23,6 +23,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ServerChannel;
import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslContext;
import java.net.SocketAddress;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -33,6 +34,7 @@ import
org.apache.ignite.internal.network.configuration.NetworkView;
import org.apache.ignite.internal.network.handshake.HandshakeManager;
import
org.apache.ignite.internal.network.serialization.PerSessionSerializationService;
import org.apache.ignite.internal.network.serialization.SerializationService;
+import org.apache.ignite.internal.network.ssl.SslContextProvider;
import org.apache.ignite.lang.IgniteInternalException;
import org.apache.ignite.network.NettyBootstrapFactory;
import org.jetbrains.annotations.Nullable;
@@ -129,7 +131,12 @@ public class NettyServer {
// Get handshake manager for the new channel.
HandshakeManager manager = handshakeManager.get();
- PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, manager, messageListener);
+ if (configuration.ssl().enabled()) {
+ SslContext sslContext =
SslContextProvider.createServerSslContext(configuration.ssl());
+ PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, manager, messageListener, sslContext);
+ } else {
+ PipelineUtils.setup(ch.pipeline(),
sessionSerializationService, manager, messageListener);
+ }
manager.handshakeFuture().thenAccept(newConnectionListener);
}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
index 036e81d5da..ec545bd894 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.network.netty;
import io.netty.channel.ChannelPipeline;
+import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler;
import java.util.function.Consumer;
import org.apache.ignite.internal.network.NetworkMessagesFactory;
@@ -30,6 +31,22 @@ public class PipelineUtils {
/** {@link ChunkedWriteHandler}'s name. */
private static final String CHUNKED_WRITE_HANDLER_NAME =
"chunked-write-handler";
+ /**
+ * Sets up initial pipeline with ssl.
+ *
+ * @param pipeline Channel pipeline.
+ * @param serializationService Serialization service.
+ * @param handshakeManager Handshake manager.
+ * @param messageListener Message listener.
+ * @param sslContext Netty SSL context.
+ */
+ public static void setup(ChannelPipeline pipeline,
PerSessionSerializationService serializationService,
+ HandshakeManager handshakeManager, Consumer<InNetworkObject>
messageListener, SslContext sslContext) {
+ pipeline.addFirst("ssl",
sslContext.newHandler(pipeline.channel().alloc()));
+
+ setup(pipeline, serializationService, handshakeManager,
messageListener);
+ }
+
/**
* Sets up initial pipeline.
*
@@ -39,7 +56,7 @@ public class PipelineUtils {
* @param messageListener Message listener.
*/
public static void setup(ChannelPipeline pipeline,
PerSessionSerializationService serializationService,
- HandshakeManager handshakeManager, Consumer<InNetworkObject>
messageListener) {
+ HandshakeManager handshakeManager, Consumer<InNetworkObject>
messageListener) {
pipeline.addLast(InboundDecoder.NAME, new
InboundDecoder(serializationService));
pipeline.addLast(HandshakeHandler.NAME, new
HandshakeHandler(handshakeManager, messageListener, serializationService));
pipeline.addLast(CHUNKED_WRITE_HANDLER_NAME, new
ChunkedWriteHandler());
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
new file mode 100644
index 0000000000..f60d087730
--- /dev/null
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import org.apache.ignite.internal.network.configuration.KeyStoreView;
+
+/** Java keystore loader. */
+public final class KeystoreLoader {
+
+ private KeystoreLoader() {
+ }
+
+ /** Initialize and load keystore with provided configuration. */
+ public static KeyStore load(KeyStoreView keyStoreConfiguration)
+ throws KeyStoreException, IOException, CertificateException,
NoSuchAlgorithmException {
+ char[] password = keyStoreConfiguration.password() == null ? null :
keyStoreConfiguration.password().toCharArray();
+
+ KeyStore ks = KeyStore.getInstance(keyStoreConfiguration.type());
+ try (var is =
Files.newInputStream(Path.of(keyStoreConfiguration.path()))) {
+ ks.load(is, password);
+ }
+
+ return ks;
+ }
+}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
new file mode 100644
index 0000000000..d50b1acc3f
--- /dev/null
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import java.io.IOException;
+import java.nio.file.NoSuchFileException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import org.apache.ignite.internal.network.configuration.SslView;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+
+/** SSL context provider. */
+public final class SslContextProvider {
+
+ private SslContextProvider() {
+ }
+
+ /** Create client SSL context. */
+ public static SslContext createClientSslContext(SslView ssl) {
+ try {
+ TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(KeystoreLoader.load(ssl.trustStore()));
+
+ var builder =
SslContextBuilder.forClient().trustManager(trustManagerFactory);
+
+ ClientAuth clientAuth =
ClientAuth.valueOf(ssl.clientAuth().toUpperCase());
+ if (ClientAuth.NONE == clientAuth) {
+ return builder.build();
+ }
+
+ KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(KeystoreLoader.load(ssl.keyStore()),
ssl.keyStore().password().toCharArray());
+
+ builder.keyManager(keyManagerFactory);
+
+ return builder.build();
+ } catch (NoSuchFileException e) {
+ throw new IgniteException(Common.SSL_CONFIGURATION_ERR,
String.format("File %s not found", e.getMessage()), e);
+ } catch (IOException | CertificateException | KeyStoreException |
NoSuchAlgorithmException | UnrecoverableKeyException e) {
+ throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+ }
+ }
+
+ /** Create server SSL context. */
+ public static SslContext createServerSslContext(SslView ssl) {
+ try {
+ KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(KeystoreLoader.load(ssl.keyStore()),
ssl.keyStore().password().toCharArray());
+
+ var builder = SslContextBuilder.forServer(keyManagerFactory);
+
+ ClientAuth clientAuth =
ClientAuth.valueOf(ssl.clientAuth().toUpperCase());
+ if (ClientAuth.NONE == clientAuth) {
+ return builder.build();
+ }
+
+ TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(KeystoreLoader.load(ssl.trustStore()));
+
+ builder.clientAuth(clientAuth).trustManager(trustManagerFactory);
+
+ return builder.build();
+ } catch (NoSuchFileException e) {
+ throw new IgniteException(Common.SSL_CONFIGURATION_ERR,
String.format("File %s not found", e.getMessage()), e);
+ } catch (KeyStoreException | NoSuchAlgorithmException |
CertificateException | UnrecoverableKeyException | IOException e) {
+ throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+ }
+ }
+}
diff --git
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
index 8aef53ff77..466278e413 100644
---
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
+++
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
@@ -32,23 +32,32 @@ import java.nio.channels.ClosedChannelException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
import org.apache.ignite.internal.future.OrderingFuture;
+import org.apache.ignite.internal.network.configuration.NetworkConfiguration;
import org.apache.ignite.internal.network.handshake.HandshakeManager;
import org.apache.ignite.lang.IgniteInternalException;
import org.apache.ignite.network.NetworkMessage;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
/**
* Tests for {@link NettyClient}.
*/
+@ExtendWith(ConfigurationExtension.class)
public class NettyClientTest {
/** Client. */
private NettyClient client;
private final InetSocketAddress address =
InetSocketAddress.createUnresolved("", 0);
+ /** Network configuration. */
+ @InjectConfiguration
+ private NetworkConfiguration networkConfiguration;
+
/**
* After each.
*/
@@ -169,8 +178,8 @@ public class NettyClientTest {
address,
null,
new MockClientHandshakeManager(channel),
- (message) -> {
- }
+ (message) -> {},
+ networkConfiguration.ssl().value()
);
client.start(bootstrap);
@@ -193,8 +202,8 @@ public class NettyClientTest {
address,
null,
new MockClientHandshakeManager(future.channel()),
- (message) -> {
- }
+ (message) -> {},
+ networkConfiguration.ssl().value()
);
Bootstrap bootstrap = mockBootstrap();
diff --git
a/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
b/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
new file mode 100644
index 0000000000..1f045f7a0c
--- /dev/null
+++
b/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.either;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThrows;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.util.SelfSignedCertificate;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
+import org.apache.ignite.internal.network.configuration.SslConfiguration;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+
+@ExtendWith(ConfigurationExtension.class)
+class SslContextProviderTest {
+
+ @InjectConfiguration
+ private SslConfiguration configuration;
+
+ private String password;
+
+ private String keyStorePkcs12Path;
+
+ private String trustStoreJks12Path;
+
+ @BeforeEach
+ void setUp(@TempDir Path tmpDir) throws KeyStoreException,
CertificateException, IOException, NoSuchAlgorithmException {
+ password = "changeit";
+ keyStorePkcs12Path =
tmpDir.resolve("keystore.p12").toAbsolutePath().toString();
+ trustStoreJks12Path =
tmpDir.resolve("truststore.jks").toAbsolutePath().toString();
+
+ SelfSignedCertificate cert = new SelfSignedCertificate("localhost");
+ generateKeystore(cert);
+ generateTruststore(cert);
+ }
+
+ private void generateTruststore(SelfSignedCertificate cert)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException {
+ KeyStore ts = KeyStore.getInstance("JKS");
+ ts.load(null, null);
+ ts.setCertificateEntry("cert", cert.cert());
+ try (FileOutputStream fos = new FileOutputStream(trustStoreJks12Path))
{
+ ts.store(fos, password.toCharArray());
+ }
+ }
+
+ private void generateKeystore(SelfSignedCertificate cert)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException {
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(null, null);
+ ks.setKeyEntry("key", cert.key(), password.toCharArray(), new
Certificate[]{cert.cert()});
+ try (FileOutputStream fos = new FileOutputStream(keyStorePkcs12Path)) {
+ ks.store(fos, password.toCharArray());
+ }
+ }
+
+ @Test
+ void createsSslContextForClient() throws Exception {
+ // Given valid self-signed certificate
+ configuration.trustStore().type().update("PKCS12").get();
+ configuration.trustStore().path().update(keyStorePkcs12Path).get();
+ configuration.trustStore().password().update(password).get();
+
+ // When
+ SslContext clientSslContext =
SslContextProvider.createClientSslContext(configuration.value());
+
+ // Then
+ assertThat(clientSslContext, notNullValue());
+ }
+
+ @Test
+ void createsSslContextForServer() throws Exception {
+ // Given valid self-signed certificate
+ configuration.keyStore().password().update(password).get();
+ configuration.keyStore().path().update(keyStorePkcs12Path).get();
+
+ // When
+ SslContext sslContext =
SslContextProvider.createServerSslContext(configuration.value());
+
+ // Then
+ assertThat(sslContext, notNullValue());
+ }
+
+ @Test
+ void createsSslContextForServerJks() throws Exception {
+ // Given valid self-signed certificate
+ configuration.keyStore().type().update("JKS").get();
+ configuration.keyStore().password().update(password).get();
+ configuration.keyStore().path().update(trustStoreJks12Path).get();
+
+ // When
+ SslContext sslContext =
SslContextProvider.createServerSslContext(configuration.value());
+
+ // Then
+ assertThat(sslContext, notNullValue());
+ }
+
+ @Test
+ void throwsIgniteExceptionWhenWrongKeystorePathConfigured() throws
Exception {
+ // Given wrong path configured for keystore
+ configuration.keyStore().path().update("/no/such/file.pfx").get();
+
+ // When
+ var thrown = assertThrows(
+ IgniteException.class,
+ () ->
SslContextProvider.createServerSslContext(configuration.value())
+ );
+
+ // Then
+ assertThat(thrown.groupName(),
equalTo(Common.COMMON_ERR_GROUP.name()));
+ assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+ assertThat(thrown.getMessage(), containsString("File /no/such/file.pfx
not found"));
+ }
+
+ @Test
+ void throwsIgniteExceptionWhenWrongTruststorePathConfigured() throws
Exception {
+ // Given wrong path configured for truststore
+ configuration.trustStore().path().update("/no/such/file.pfx").get();
+
+ // When
+ var thrown = assertThrows(
+ IgniteException.class,
+ () ->
SslContextProvider.createClientSslContext(configuration.value())
+ );
+
+ // Then
+ assertThat(thrown.groupName(),
equalTo(Common.COMMON_ERR_GROUP.name()));
+ assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+ assertThat(thrown.getMessage(), containsString("File /no/such/file.pfx
not found"));
+ }
+
+ @Test
+ void throwsIgniteExceptionWhenWrongKeystorePassword() throws Exception {
+ // Given wrong password for keystore
+ configuration.keyStore().path().update(keyStorePkcs12Path).get();
+ configuration.keyStore().password().update("wrong").get();
+
+ // When
+ var thrown = assertThrows(
+ IgniteException.class,
+ () ->
SslContextProvider.createServerSslContext(configuration.value())
+ );
+
+ // Then
+ assertThat(thrown.groupName(),
equalTo(Common.COMMON_ERR_GROUP.name()));
+ assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+ assertThat(thrown.getMessage(), containsString("keystore password was
incorrect"));
+ }
+
+ @Test
+ void throwsIgniteExceptionWhenWrongTruststorePassword() throws Exception {
+ // Given wrong password for truststore
+ configuration.trustStore().path().update(trustStoreJks12Path).get();
+ configuration.trustStore().password().update("wrong").get();
+
+ // When
+ var thrown = assertThrows(
+ IgniteException.class,
+ () ->
SslContextProvider.createClientSslContext(configuration.value())
+ );
+
+ // Then
+ assertThat(thrown.groupName(),
equalTo(Common.COMMON_ERR_GROUP.name()));
+ assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+ assertThat(thrown.getMessage(),
+ either(containsString("keystore password was incorrect"))
+ .or(containsString("password was incorrect")));
+ }
+}
diff --git
a/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
b/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
index aab1680c55..5b1754b349 100644
---
a/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
+++
b/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
@@ -25,19 +25,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
import org.apache.ignite.internal.network.NetworkMessagesFactory;
-import org.apache.ignite.internal.network.configuration.InboundView;
import org.apache.ignite.internal.network.configuration.NetworkConfiguration;
-import org.apache.ignite.internal.network.configuration.NetworkView;
-import org.apache.ignite.internal.network.configuration.OutboundView;
import org.apache.ignite.internal.network.messages.TestMessage;
import org.apache.ignite.internal.network.messages.TestMessageTypes;
import org.apache.ignite.internal.network.messages.TestMessagesFactory;
@@ -60,6 +59,7 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
+@ExtendWith(ConfigurationExtension.class)
class DefaultMessagingServiceTest {
private static final int SENDER_PORT = 2001;
private static final int RECEIVER_PORT = 2002;
@@ -67,23 +67,11 @@ class DefaultMessagingServiceTest {
@Mock
private TopologyService topologyService;
- @Mock
+ @InjectConfiguration("mock.port=" + SENDER_PORT)
private NetworkConfiguration senderNetworkConfig;
- @Mock
- private NetworkView senderNetworkConfigView;
- @Mock
- private OutboundView senderOutboundConfig;
- @Mock
- private InboundView senderInboundConfig;
- @Mock
+ @InjectConfiguration("mock.port=" + RECEIVER_PORT)
private NetworkConfiguration receiverNetworkConfig;
- @Mock
- private NetworkView receiverNetworkConfigView;
- @Mock
- private OutboundView receiverOutboundConfig;
- @Mock
- private InboundView receiverInboundConfig;
private final NetworkMessagesFactory networkMessagesFactory = new
NetworkMessagesFactory();
private final TestMessagesFactory testMessagesFactory = new
TestMessagesFactory();
@@ -102,10 +90,7 @@ class DefaultMessagingServiceTest {
);
@BeforeEach
- void setUp() {
- configureSender();
- configureReceiver();
-
+ void setUp() throws InterruptedException, ExecutionException {
lenient().when(topologyService.getByConsistentId(eq(senderNode.name()))).thenReturn(senderNode);
}
@@ -148,28 +133,6 @@ class DefaultMessagingServiceTest {
}
}
- private void configureSender() {
- when(senderNetworkConfigView.port()).thenReturn(SENDER_PORT);
- configureNetworkDefaults(senderNetworkConfig, senderNetworkConfigView,
senderOutboundConfig, senderInboundConfig);
- }
-
- private void configureReceiver() {
-
lenient().when(receiverNetworkConfigView.port()).thenReturn(RECEIVER_PORT);
- configureNetworkDefaults(receiverNetworkConfig,
receiverNetworkConfigView, receiverOutboundConfig, receiverInboundConfig);
- }
-
- private static void configureNetworkDefaults(
- NetworkConfiguration networkConfig,
- NetworkView networkConfigView,
- OutboundView outboundConfig,
- InboundView inboundConfig
- ) {
- lenient().when(networkConfig.value()).thenReturn(networkConfigView);
- lenient().when(networkConfigView.portRange()).thenReturn(0);
-
lenient().when(networkConfigView.outbound()).thenReturn(outboundConfig);
- lenient().when(networkConfigView.inbound()).thenReturn(inboundConfig);
- }
-
private static void awaitQuietly(CountDownLatch latch) {
try {
latch.await();
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
index 3098c447a4..fb5f7078ad 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
@@ -60,7 +60,7 @@ public class ItPortRangeTest {
private static final String trustStorePath = "ssl/truststore.jks";
/** Trust store password. */
- private static final String trustStorePassword = "changeIt";
+ private static final String trustStorePassword = "changeit";
/** Path to the working directory. */
@WorkDirectory
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
index 70b5f14722..e2e608cf31 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
@@ -60,7 +60,7 @@ public class ItRestSslTest {
private static final String trustStorePath = "ssl/truststore.jks";
/** Trust store password. */
- private static final String trustStorePassword = "changeIt";
+ private static final String trustStorePassword = "changeit";
/** Path to the working directory. */
@WorkDirectory
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
index f554526994..ca19ddb61f 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
@@ -27,7 +27,7 @@ public class RestNode {
private static final String keyStorePath = "ssl/keystore.p12";
/** Key store password. */
- private static final String keyStorePassword = "changeIt";
+ private static final String keyStorePassword = "changeit";
private final Path workDir;
private final String name;
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
new file mode 100644
index 0000000000..f24e9deb29
--- /dev/null
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.ignite.internal.ssl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.nio.file.Path;
+import org.apache.ignite.internal.Cluster;
+import org.apache.ignite.internal.testframework.WorkDirectory;
+import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
+import org.intellij.lang.annotations.Language;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/** SSL support integration test. */
+@ExtendWith(WorkDirectoryExtension.class)
+public class ItSslTest {
+
+ private static String password;
+
+ private static String trustStorePath;
+
+ private static String keyStorePath;
+
+ @BeforeAll
+ static void beforeAll() {
+ password = "changeit";
+ trustStorePath =
ItSslTest.class.getClassLoader().getResource("ssl/truststore.jks").getPath();
+ keyStorePath =
ItSslTest.class.getClassLoader().getResource("ssl/keystore.p12").getPath();
+ }
+
+ @Nested
+ @TestInstance(Lifecycle.PER_CLASS)
+ class ClusterWithoutSsl {
+
+ @WorkDirectory
+ private Path workDir;
+
+ private Cluster cluster;
+
+ @Language("JSON")
+ String sslDisabledBoostrapConfig = "{\n"
+ + " network: {\n"
+ + " ssl.enabled: false,\n"
+ + " port: 3355,\n"
+ + " portRange: 2,\n"
+ + " nodeFinder:{\n"
+ + " netClusterNodes: [ \"localhost:3355\",
\"localhost:3356\" ]\n"
+ + " }\n"
+ + " }\n"
+ + "}";
+
+ @BeforeEach
+ void setUp(TestInfo testInfo) {
+ cluster = new Cluster(testInfo, workDir,
sslDisabledBoostrapConfig);
+ cluster.startAndInit(2);
+ }
+
+ @AfterEach
+ void tearDown() {
+ cluster.shutdown();
+ }
+
+ @Test
+ @DisplayName("SSL disabled and cluster starts")
+ void clusterStartsWithDisabledSsl(TestInfo testInfo) {
+ assertThat(cluster.runningNodes().count(), is(2L));
+ }
+ }
+
+ @Nested
+ @TestInstance(Lifecycle.PER_CLASS)
+ class ClusterWithSsl {
+
+ @WorkDirectory
+ private Path workDir;
+
+ private Cluster cluster;
+
+ @Language("JSON")
+ String sslEnabledBoostrapConfig = "{\n"
+ + " network: {\n"
+ + " ssl : {"
+ + " enabled: true,\n"
+ + " trustStore: {\n"
+ + " password: \"" + password + "\","
+ + " path: \"" + trustStorePath + "\""
+ + " },\n"
+ + " keyStore: {\n"
+ + " password: \"" + password + "\","
+ + " path: \"" + keyStorePath + "\""
+ + " }\n"
+ + " },\n"
+ + " port: 3345,\n"
+ + " portRange: 2,\n"
+ + " nodeFinder:{\n"
+ + " netClusterNodes: [ \"localhost:3345\",
\"localhost:3346\" ]\n"
+ + " }\n"
+ + " }\n"
+ + "}";
+
+ @BeforeEach
+ void setUp(TestInfo testInfo) {
+ cluster = new Cluster(testInfo, workDir, sslEnabledBoostrapConfig);
+ cluster.startAndInit(2);
+ }
+
+ @AfterEach
+ void tearDown() {
+ cluster.shutdown();
+ }
+
+ @Test
+ @DisplayName("SSL enabled and setup correctly then cluster starts")
+ void clusterStartsWithEnabledSsl(TestInfo testInfo) {
+ assertThat(cluster.runningNodes().count(), is(2L));
+ }
+ }
+
+ @Nested
+ @TestInstance(Lifecycle.PER_CLASS)
+ class ClusterWithSslAndClientAuth {
+
+ @WorkDirectory
+ private Path workDir;
+
+ private Cluster cluster;
+
+ @Language("JSON")
+ String sslEnabledBoostrapConfig = "{\n"
+ + " network: {\n"
+ + " ssl : {"
+ + " enabled: true,\n"
+ + " clientAuth: \"require\",\n"
+ + " trustStore: {\n"
+ + " password: \"" + password + "\","
+ + " path: \"" + trustStorePath + "\""
+ + " },\n"
+ + " keyStore: {\n"
+ + " password: \"" + password + "\","
+ + " path: \"" + keyStorePath + "\""
+ + " }\n"
+ + " },\n"
+ + " port: 3365,\n"
+ + " portRange: 2,\n"
+ + " nodeFinder:{\n"
+ + " netClusterNodes: [ \"localhost:3365\",
\"localhost:3366\" ]\n"
+ + " }\n"
+ + " }\n"
+ + "}";
+
+ @BeforeEach
+ void setUp(TestInfo testInfo) {
+ cluster = new Cluster(testInfo, workDir, sslEnabledBoostrapConfig);
+ cluster.startAndInit(2);
+ }
+
+ @AfterEach
+ void tearDown() {
+ cluster.shutdown();
+ }
+
+ @Test
+ @DisplayName("SSL enabled and setup correctly then cluster starts")
+ void clusterStartsWithEnabledSsl(TestInfo testInfo) {
+ assertThat(cluster.runningNodes().count(), is(2L));
+ }
+ }
+}
diff --git a/modules/runner/src/integrationTest/resources/ssl/keystore.p12
b/modules/runner/src/integrationTest/resources/ssl/keystore.p12
index 1677d2a561..d929618bd6 100644
Binary files a/modules/runner/src/integrationTest/resources/ssl/keystore.p12
and b/modules/runner/src/integrationTest/resources/ssl/keystore.p12 differ
diff --git a/modules/runner/src/integrationTest/resources/ssl/truststore.jks
b/modules/runner/src/integrationTest/resources/ssl/truststore.jks
index a20d9db42d..45052de67f 100644
Binary files a/modules/runner/src/integrationTest/resources/ssl/truststore.jks
and b/modules/runner/src/integrationTest/resources/ssl/truststore.jks differ