This is an automated email from the ASF dual-hosted git repository. apkhmv 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 1828f6524d IGNITE-18951 Test SSL for JDBC in CLI (#1795) 1828f6524d is described below commit 1828f6524d0a62f8f645271f4152bc520b016ab6 Author: Aleksandr Pakhomov <apk...@gmail.com> AuthorDate: Thu Mar 16 17:24:56 2023 +0400 IGNITE-18951 Test SSL for JDBC in CLI (#1795) --- .../cli/call/unit/ItDeployUndeployCallsTest.java | 1 - .../CliSslClientConnectorIntegrationTestBase.java | 63 ++++++++++++ ...> CliSslNotInitializedIntegrationTestBase.java} | 34 +++--- .../ignite/internal/cli/ssl/ItJdbcSslTest.java | 114 +++++++++++++++++++++ .../apache/ignite/internal/cli/ssl/ItSslTest.java | 18 +--- 5 files changed, 192 insertions(+), 38 deletions(-) diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/unit/ItDeployUndeployCallsTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/unit/ItDeployUndeployCallsTest.java index b6205be1c0..c6873ee74d 100644 --- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/unit/ItDeployUndeployCallsTest.java +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/call/unit/ItDeployUndeployCallsTest.java @@ -118,7 +118,6 @@ public class ItDeployUndeployCallsTest extends CallInitializedIntegrationTestBas // Then assertThat(output.hasError()).isTrue(); assertThat(output.errorCause()).isInstanceOf(FileNotFoundException.class); - assertThat(output.errorCause()).hasMessage("wrong/path"); } @Test diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslClientConnectorIntegrationTestBase.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslClientConnectorIntegrationTestBase.java new file mode 100644 index 0000000000..c760279c2d --- /dev/null +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslClientConnectorIntegrationTestBase.java @@ -0,0 +1,63 @@ +/* + * 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.cli.ssl; + +import static org.apache.ignite.internal.testframework.IgniteTestUtils.escapeWindowsPath; +import static org.apache.ignite.internal.testframework.IgniteTestUtils.getResourcePath; + +import org.apache.ignite.internal.cli.commands.CliCommandTestInitializedIntegrationBase; + +/** + * Test base for SSL tests with client connector. The cluster is initialized with SSL enabled for clients. + */ +public class CliSslClientConnectorIntegrationTestBase extends CliCommandTestInitializedIntegrationBase { + static final String keyStorePath = "ssl/keystore.p12"; + static final String keyStorePassword = "changeit"; + static final String trustStorePath = "ssl/truststore.jks"; + static final String trustStorePassword = "changeit"; + + static final String resolvedKeystorePath = getResourcePath(CliSslClientConnectorIntegrationTestBase.class, keyStorePath); + static final String resolvedTruststorePath = getResourcePath(CliSslClientConnectorIntegrationTestBase.class, trustStorePath); + + @Override + protected String nodeBootstrapConfigTemplate() { + return "{\n" + + " network: {\n" + + " port: {},\n" + + " nodeFinder: {\n" + + " netClusterNodes: [ {} ]\n" + + " },\n" + + " },\n" + + " clientConnector: {" + + " ssl: {\n" + + " enabled: " + true + ",\n" + + " clientAuth: \"require\",\n" + + " keyStore: {\n" + + " path: \"" + escapeWindowsPath(resolvedKeystorePath) + "\",\n" + + " password: " + keyStorePassword + "\n" + + " }, \n" + + " trustStore: {\n" + + " type: JKS,\n" + + " path: \"" + escapeWindowsPath(resolvedTruststorePath) + "\",\n" + + " password: " + trustStorePassword + "\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + } +} diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslIntegrationTestBase.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslNotInitializedIntegrationTestBase.java similarity index 62% rename from modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslIntegrationTestBase.java rename to modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslNotInitializedIntegrationTestBase.java index 6b33a91e3b..8302094a91 100644 --- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslIntegrationTestBase.java +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/CliSslNotInitializedIntegrationTestBase.java @@ -17,21 +17,22 @@ package org.apache.ignite.internal.cli.ssl; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.util.Objects; +import static org.apache.ignite.internal.testframework.IgniteTestUtils.escapeWindowsPath; +import static org.apache.ignite.internal.testframework.IgniteTestUtils.getResourcePath; + import org.apache.ignite.internal.cli.commands.CliCommandTestNotInitializedIntegrationBase; /** * Integration test base for SSL tests. */ -public class CliSslIntegrationTestBase extends CliCommandTestNotInitializedIntegrationBase { +public class CliSslNotInitializedIntegrationTestBase extends CliCommandTestNotInitializedIntegrationBase { + protected static final String keyStorePath = "ssl/keystore.p12"; + protected static final String keyStorePassword = "changeit"; + protected static final String trustStorePath = "ssl/truststore.jks"; + protected static final String trustStorePassword = "changeit"; - private static final String keyStorePath = "ssl/keystore.p12"; - private static final String keyStorePassword = "changeit"; - private static final String trustStorePath = "ssl/truststore.jks"; - private static final String trustStorePassword = "changeit"; + static final String resolvedKeystorePath = getResourcePath(CliSslClientConnectorIntegrationTestBase.class, keyStorePath); + static final String resolvedTruststorePath = getResourcePath(CliSslClientConnectorIntegrationTestBase.class, trustStorePath); /** * Template for node bootstrap config with Scalecube and Logical Topology settings for fast failure detection. @@ -49,29 +50,18 @@ public class CliSslIntegrationTestBase extends CliCommandTestNotInitializedInteg + " enabled: " + true + ",\n" + " clientAuth: \"require\",\n" + " keyStore: {\n" - + " path: \"" + getResourcePath(keyStorePath) + "\",\n" + + " path: \"" + escapeWindowsPath(resolvedKeystorePath) + "\",\n" + " password: " + keyStorePassword + "\n" + " }, \n" + " trustStore: {\n" + " type: JKS,\n" - + " path: \"" + getResourcePath(trustStorePath) + "\",\n" + + " path: \"" + escapeWindowsPath(resolvedTruststorePath) + "\",\n" + " password: " + trustStorePassword + "\n" + " }\n" + " }\n" + " }\n" + "}"; - protected static String getResourcePath(String resource) { - try { - URL url = CliSslIntegrationTestBase.class.getClassLoader().getResource(resource); - Objects.requireNonNull(url, "Resource " + resource + " not found."); - Path path = Path.of(url.toURI()); // Properly extract file system path from the "file:" URL - return path.toString().replace("\\", "\\\\"); // Escape backslashes for the config parser - } catch (URISyntaxException e) { - throw new RuntimeException(e); // Shouldn't happen since URL is obtained from the class loader - } - } - @Override protected String nodeBootstrapConfigTemplate() { return REST_SSL_BOOTSTRAP_CONFIG; diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItJdbcSslTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItJdbcSslTest.java new file mode 100644 index 0000000000..16ca15d2a7 --- /dev/null +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItJdbcSslTest.java @@ -0,0 +1,114 @@ +/* + * 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.cli.ssl; + +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +/** Tests for SSL connection with JDBC URL. */ +public class ItJdbcSslTest extends CliSslClientConnectorIntegrationTestBase { + + @BeforeEach + @Override + public void setUp(TestInfo testInfo) throws Exception { + super.setUp(testInfo); + createAndPopulateTable(); + } + + @AfterEach + void tearDown() { + dropAllTables(); + } + + @Test + @DisplayName("Should connect with JDBC URL with SSL configured") + void jdbcOkWithSslConfigured() { + // Given valid JDBC connection string with SSL configured + String jdbcUrl = JDBC_URL + + "?sslEnabled=true" + + "&trustStorePath=" + resolvedTruststorePath + + "&trustStoreType=JKS" + + "&trustStorePassword=" + trustStorePassword + + "&clientAuth=require" + + "&keyStorePath=" + resolvedKeystorePath + + "&keyStoreType=PKCS12" + + "&keyStorePassword=" + keyStorePassword; + + // When + execute("sql", "--jdbc-url", jdbcUrl, "select * from person"); + + // Then the query is executed successfully + assertAll( + this::assertExitCodeIsZero, + this::assertOutputIsNotEmpty, + this::assertErrOutputIsEmpty + ); + } + + @Test + @DisplayName("Should fail to connect with JDBC URL with SSL configured but truststore is not configured") + void jdbcFailWithSslConfiguredButTruststoreNotConfigured() { + // Given valid JDBC connection string with SSL configured + String jdbcUrl = JDBC_URL + + "?sslEnabled=true" + + "&clientAuth=require" + + "&keyStorePath=" + resolvedKeystorePath + + "&keyStoreType=PKCS12" + + "&keyStorePassword=" + keyStorePassword; + + // When + execute("sql", "--jdbc-url", jdbcUrl, "select * from person"); + + // Then the query is executed successfully + assertAll( + () -> assertExitCodeIs(1), + this::assertOutputIsEmpty, + () -> assertErrOutputContains("Connection failed"), + () -> assertErrOutputContains("Failed to send handshake request") + ); + } + + @Test + @DisplayName("Should fail to connect with JDBC URL with SSL configured but keystore is not configured") + void jdbcFailWithSslConfiguredButKeystoreNotConfigured() { + // Given valid JDBC connection string with SSL configured + String jdbcUrl = JDBC_URL + + "?sslEnabled=true" + + "&trustStorePath=" + resolvedTruststorePath + + "&trustStoreType=JKS" + + "&trustStorePassword=" + trustStorePassword + + "&clientAuth=require"; + + // When + execute("sql", "--jdbc-url", jdbcUrl, "select * from person"); + + // Then the query is executed successfully + assertAll( + () -> assertExitCodeIs(1), + this::assertOutputIsEmpty, + () -> assertErrOutputContains("Connection failed"), + () -> assertErrOutputContains("Channel is closed") + ); + } + +} diff --git a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItSslTest.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItSslTest.java index 5c831545ef..2928f2aec0 100644 --- a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItSslTest.java +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/ssl/ItSslTest.java @@ -23,19 +23,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; /** Tests for SSL. */ -public class ItSslTest extends CliSslIntegrationTestBase { - - /** Trust store path. */ - private static final String trustStorePath = "ssl/truststore.jks"; - - /** Trust store password. */ - private static final String trustStorePassword = "changeit"; - - /** Key store path. */ - private static final String keyStorePath = "ssl/keystore.p12"; - - /** Key store password. */ - private static final String keyStorePassword = "changeit"; +public class ItSslTest extends CliSslNotInitializedIntegrationTestBase { @Test @DisplayName("Should get SSL error, when connect to secured node without SSL settings") @@ -54,9 +42,9 @@ public class ItSslTest extends CliSslIntegrationTestBase { @DisplayName("Should connect to cluster with given url") void connectToSecuredNode() { // When set up ssl configuration - execute("cli", "config", "set", "ignite.rest.key-store.path=" + getResourcePath(keyStorePath)); + execute("cli", "config", "set", "ignite.rest.key-store.path=" + resolvedKeystorePath); execute("cli", "config", "set", "ignite.rest.key-store.password=" + keyStorePassword); - execute("cli", "config", "set", "ignite.rest.trust-store.path=" + getResourcePath(trustStorePath)); + execute("cli", "config", "set", "ignite.rest.trust-store.path=" + resolvedTruststorePath); execute("cli", "config", "set", "ignite.rest.trust-store.password=" + trustStorePassword); resetOutput();