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 8dcb622f49 IGNITE-19193 Store sensitive CLI config separately (#1942)
8dcb622f49 is described below
commit 8dcb622f493493366c4ef2b29f72badc77b1375b
Author: Ivan Gagarkin <[email protected]>
AuthorDate: Tue Apr 18 10:31:52 2023 +0400
IGNITE-19193 Store sensitive CLI config separately (#1942)
---
...liCommandTestNotInitializedIntegrationBase.java | 3 +-
.../commands/questions/ItConnectToClusterTest.java | 3 +-
.../questions/ItConnectToSslClusterTest.java | 6 +-
.../cli/config/CachedConfigManagerProvider.java | 5 +-
.../ignite/internal/cli/config/CliConfigKeys.java | 21 ++++
.../internal/cli/config/ConfigConstants.java | 31 +++++-
.../apache/ignite/internal/cli/config/Profile.java | 27 +----
.../internal/cli/config/ini/IniConfigManager.java | 90 +++++++++++++--
.../ignite/internal/cli/config/ini/IniProfile.java | 79 +++++++++++--
.../ignite/internal/cli/util/OperatingSystem.java | 106 ++++++++++++++++++
.../internal/cli/commands/CliCommandTestBase.java | 5 +-
.../cli/commands/UrlOptionsNegativeTest.java | 5 +-
.../cliconfig/CliConfigCommandTestBase.java | 3 +-
.../cliconfig/CliConfigProfileListCommandTest.java | 5 +-
.../cliconfig/CliConfigProfileShowCommandTest.java | 3 +-
.../cliconfig/CliConfigShowCommandTest.java | 12 +-
.../cli/commands/cliconfig/ConfigManagerTest.java | 14 ++-
.../cli/config/ini/IniConfigManagerTest.java | 124 +++++++++++++++++++++
.../cliconfig/TestConfigManagerHelper.java | 26 +++++
.../cliconfig/TestConfigManagerProvider.java | 10 +-
.../src/testFixtures/resources/empty_secret.ini | 0
21 files changed, 506 insertions(+), 72 deletions(-)
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
index 7b6d7c14e0..d5278a6f59 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
@@ -29,7 +29,6 @@ import
org.apache.ignite.internal.cli.commands.cliconfig.TestConfigManagerHelper
import
org.apache.ignite.internal.cli.commands.cliconfig.TestConfigManagerProvider;
import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
import org.apache.ignite.internal.cli.config.ConfigDefaultValueProvider;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.apache.ignite.internal.cli.core.converters.NodeNameOrUrlConverter;
import org.apache.ignite.internal.cli.core.repl.Session;
import
org.apache.ignite.internal.cli.core.repl.context.CommandLineContextProvider;
@@ -86,7 +85,7 @@ public class CliCommandTestNotInitializedIntegrationBase
extends CliIntegrationT
@BeforeEach
public void setUp(TestInfo testInfo) throws Exception {
super.setUp(testInfo);
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createIntegrationTests());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createIntegrationTests());
cmd = new CommandLine(getCommandClass(), new MicronautFactory(context))
.registerConverter(NodeNameOrUrl.class, new
NodeNameOrUrlConverter(nodeNameRegistry));
cmd.setDefaultValueProvider(configDefaultValueProvider);
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
index 959cf622e9..e3fad527e6 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
@@ -24,7 +24,6 @@ import java.io.IOException;
import
org.apache.ignite.internal.cli.commands.cliconfig.TestConfigManagerHelper;
import org.apache.ignite.internal.cli.config.CliConfigKeys;
import org.apache.ignite.internal.cli.config.TestStateConfigHelper;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -64,7 +63,7 @@ class ItConnectToClusterTest extends
ItConnectToClusterTestBase {
assertThat(promptBefore).isEqualTo("[disconnected]> ");
// And last connected URL is not equal to the default URL
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createClusterUrlNonDefault());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createClusterUrlNonDefault());
stateConfigProvider.config =
TestStateConfigHelper.createLastConnectedDefault();
// And answer to both questions is "y"
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToSslClusterTest.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToSslClusterTest.java
index 34a46dc11a..07336c8407 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToSslClusterTest.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToSslClusterTest.java
@@ -26,7 +26,6 @@ import org.apache.ignite.internal.NodeConfig;
import
org.apache.ignite.internal.cli.commands.cliconfig.TestConfigManagerHelper;
import org.apache.ignite.internal.cli.config.CliConfigKeys;
import org.apache.ignite.internal.cli.config.TestStateConfigHelper;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -44,8 +43,7 @@ class ItConnectToSslClusterTest extends
ItConnectToClusterTestBase {
assertThat(promptBefore).isEqualTo("[disconnected]> ");
// And default URL is HTTPS
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createClusterUrlSsl());
-
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createClusterUrlSsl());
// And trust store is configured
configManagerProvider.configManager.setProperty(CliConfigKeys.REST_TRUST_STORE_PATH.value(),
NodeConfig.resolvedTruststorePath);
configManagerProvider.configManager.setProperty(CliConfigKeys.REST_TRUST_STORE_PASSWORD.value(),
NodeConfig.trustStorePassword);
@@ -77,7 +75,7 @@ class ItConnectToSslClusterTest extends
ItConnectToClusterTestBase {
assertThat(promptBefore).isEqualTo("[disconnected]> ");
// And default URL is HTTPS
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createClusterUrlSsl());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createClusterUrlSsl());
// And trust store is not configured
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CachedConfigManagerProvider.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CachedConfigManagerProvider.java
index c00c2353d7..6e621bbb51 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CachedConfigManagerProvider.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CachedConfigManagerProvider.java
@@ -17,6 +17,9 @@
package org.apache.ignite.internal.cli.config;
+import static
org.apache.ignite.internal.cli.config.ConfigConstants.getConfigFile;
+import static
org.apache.ignite.internal.cli.config.ConfigConstants.getSecretConfigFile;
+
import jakarta.inject.Singleton;
import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
@@ -25,7 +28,7 @@ import
org.apache.ignite.internal.cli.config.ini.IniConfigManager;
*/
@Singleton
public class CachedConfigManagerProvider implements ConfigManagerProvider {
- private final ConfigManager configManager = new
IniConfigManager(ConfigConstants.getConfigFile());
+ private final ConfigManager configManager = new
IniConfigManager(getConfigFile(), getSecretConfigFile());
@Override
public ConfigManager get() {
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CliConfigKeys.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CliConfigKeys.java
index 85d8cc53ec..7fb9888d3f 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CliConfigKeys.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/CliConfigKeys.java
@@ -17,6 +17,10 @@
package org.apache.ignite.internal.cli.config;
+import static java.util.stream.Collectors.toUnmodifiableSet;
+
+import java.util.Set;
+
/** CLI config keys and constants. */
public enum CliConfigKeys {
@@ -53,6 +57,23 @@ public enum CliConfigKeys {
return value;
}
+ /**
+ * Returns all secret config keys.
+ */
+ public static Set<String> secretConfigKeys() {
+ return Set.of(
+ REST_KEY_STORE_PASSWORD,
+ REST_KEY_STORE_PATH,
+ REST_TRUST_STORE_PASSWORD,
+ REST_TRUST_STORE_PATH,
+ BASIC_AUTHENTICATION_USERNAME,
+ BASIC_AUTHENTICATION_PASSWORD
+ )
+ .stream()
+ .map(CliConfigKeys::value)
+ .collect(toUnmodifiableSet());
+ }
+
/** Constants for CLI config. */
public static final class Constants {
public static final String CLUSTER_URL = "ignite.cluster-endpoint-url";
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ConfigConstants.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ConfigConstants.java
index d0bda13167..4075e1c371 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ConfigConstants.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ConfigConstants.java
@@ -39,11 +39,21 @@ public final class ConfigConstants {
*/
private static final String CONFIG_FILE_NAME = "defaults";
+ /**
+ * Secret configuration file name.
+ */
+ private static final String SECRET_CONFIG_FILE_NAME = "secrets";
+
/**
* Environment variable which points to the configuration file.
*/
private static final String IGNITE_CLI_CONFIG_FILE =
"IGNITE_CLI_CONFIG_FILE";
+ /**
+ * Environment variable which points to the secret configuration file.
+ */
+ private static final String IGNITE_CLI_SECRET_CONFIG_FILE =
"IGNITE_CLI_SECRET_CONFIG_FILE";
+
/**
* Environment variable which points to the CLI logs folder.
*/
@@ -58,9 +68,8 @@ public final class ConfigConstants {
}
/**
- * Gets the {@link File} with user-specific configuration file.
- * The file location can be overridden using {@code
IGNITE_CLI_CONFIG_FILE} environment variable,
- * otherwise base directory is specified by the
+ * Gets the {@link File} with user-specific configuration file. The file
location can be overridden using
+ * {@link ConfigConstants#IGNITE_CLI_CONFIG_FILE} environment variable,
otherwise base directory is specified by the
* <a
href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG
Base Directory Specification</a>
* and the configuration file name is {@code ignitecli/defaults} under the
base directory.
*
@@ -74,6 +83,22 @@ public final class ConfigConstants {
return
getConfigRoot().resolve(PARENT_FOLDER_NAME).resolve(CONFIG_FILE_NAME).toFile();
}
+ /**
+ * Gets the {@link File} with user-specific configuration file. The file
location can be overridden using
+ * {@link ConfigConstants#IGNITE_CLI_SECRET_CONFIG_FILE} environment
variable, otherwise base directory is specified by the
+ * <a
href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG
Base Directory Specification</a>
+ * and the configuration file name is {@code ignitecli/secrets} under the
base directory.
+ *
+ * @return configuration file.
+ */
+ public static File getSecretConfigFile() {
+ String configFile = System.getenv(IGNITE_CLI_SECRET_CONFIG_FILE);
+ if (configFile != null) {
+ return new File(configFile);
+ }
+ return
getConfigRoot().resolve(PARENT_FOLDER_NAME).resolve(SECRET_CONFIG_FILE_NAME).toFile();
+ }
+
private static Path getConfigRoot() {
String xdgConfigHome = System.getenv(XDG_CONFIG_HOME);
if (xdgConfigHome != null) {
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/Profile.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/Profile.java
index 790107716e..179427100d 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/Profile.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/Profile.java
@@ -30,21 +30,12 @@ public interface Profile {
*/
String getName();
- /**
- * Gets a {@link Config} stored in this profile.
- *
- * @return config
- */
- Config getConfig();
-
/**
* Convenience method to get all properties from this profile.
*
* @return map of all properties
*/
- default Map<String, String> getAll() {
- return getConfig().getAll();
- }
+ Map<String, String> getAll();
/**
* Convenience method to get a property from this profile.
@@ -52,9 +43,7 @@ public interface Profile {
* @param key property to get
* @return property value or {@code null} if config doesn't contain this
property
*/
- default String getProperty(String key) {
- return getConfig().getProperty(key);
- }
+ String getProperty(String key);
/**
* Convenience method to get a property from this profile.
@@ -64,9 +53,7 @@ public interface Profile {
*
* @return property value or {@code defaultValue} if config doesn't
contain this property
*/
- default String getProperty(String key, String defaultValue) {
- return getConfig().getProperty(key, defaultValue);
- }
+ String getProperty(String key, String defaultValue);
/**
* Convenience method to set a property to this profile.
@@ -74,16 +61,12 @@ public interface Profile {
* @param key property to set
* @param value value to set
*/
- default void setProperty(String key, String value) {
- getConfig().setProperty(key, value);
- }
+ void setProperty(String key, String value);
/**
* Convenience method to set properties to this profile.
*
* @param values map of properties to set
*/
- default void setProperties(Map<String, String> values) {
- getConfig().setProperties(values);
- }
+ void setProperties(Map<String, String> values);
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniConfigManager.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniConfigManager.java
index 98ab2f9f8c..3b07171ccf 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniConfigManager.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniConfigManager.java
@@ -29,13 +29,19 @@ import static
org.apache.ignite.internal.cli.config.ConfigConstants.CURRENT_PROF
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
import java.util.Collection;
import java.util.NoSuchElementException;
+import java.util.Set;
import org.apache.ignite.internal.cli.config.ConfigInitializationException;
import org.apache.ignite.internal.cli.config.ConfigManager;
import org.apache.ignite.internal.cli.config.Profile;
import org.apache.ignite.internal.cli.config.ProfileNotFoundException;
+import org.apache.ignite.internal.cli.core.exception.IgniteCliException;
import org.apache.ignite.internal.cli.logger.CliLoggers;
+import org.apache.ignite.internal.cli.util.OperatingSystem;
import org.apache.ignite.internal.logger.IgniteLogger;
/**
@@ -48,24 +54,57 @@ public class IniConfigManager implements ConfigManager {
private final IniFile configFile;
+ private final IniFile secretConfigFile;
+
private String currentProfileName;
/**
* Constructor.
*
- * @param file ini file.
+ * @param configFile ini file.
+ * @param secretConfigFile secret ini file.
*/
- public IniConfigManager(File file) {
+ public IniConfigManager(File configFile, File secretConfigFile) {
+ this.configFile = configFile(configFile);
+ this.secretConfigFile = secretConfigFile(secretConfigFile);
+ this.currentProfileName = findCurrentProfileName(this.configFile);
+ }
+
+ private IniFile configFile(File file) {
IniFile configFile;
try {
configFile = new IniFile(file);
findCurrentProfileName(configFile);
} catch (IOException | NoSuchElementException e) {
LOG.warn("User config is corrupted or doesn't exist.", e);
- configFile = createDefaultConfig(file);
+ try {
+ configFile = createDefaultConfig(file);
+ } catch (Exception ex) {
+ throw new IgniteCliException("Couldn't create default config",
ex);
+ }
}
- this.configFile = configFile;
- this.currentProfileName = findCurrentProfileName(configFile);
+ return configFile;
+ }
+
+ private IniFile secretConfigFile(File file) {
+ IniFile configFile;
+ try {
+ if (OperatingSystem.current() != OperatingSystem.WINDOWS) {
+ Set<PosixFilePermission> posixFilePermissions =
Files.getPosixFilePermissions(file.toPath());
+ if (!secretPermission().equals(posixFilePermissions)) {
+ throw new IgniteCliException("The secret configuration
file must have 700 permissions");
+ }
+ }
+ configFile = new IniFile(file);
+ } catch (IOException e) {
+ LOG.warn("User secret config is corrupted or doesn't exist.", e);
+ try {
+ configFile = createDefaultSecretConfig(file);
+ } catch (Exception ex) {
+ throw new IgniteCliException("Couldn't create secret default
config", ex);
+ }
+ }
+ return configFile;
}
private static String findCurrentProfileName(IniFile configFile) {
@@ -91,12 +130,25 @@ public class IniConfigManager implements ConfigManager {
if (section == null) {
throw new ProfileNotFoundException(profile);
}
- return new IniProfile(section, configFile::store);
+
+ IniSection secretSection = secretConfigFile.getSection(profile) == null
+ ? secretConfigFile.createSection(profile)
+ : secretConfigFile.getSection(profile);
+
+ IniConfig config = new IniConfig(section, configFile::store);
+ IniConfig secretConfig = new IniConfig(secretSection,
secretConfigFile::store);
+ return new IniProfile(section.getName(), config, secretConfig);
}
@Override
public Profile createProfile(String profileName) {
- return new IniProfile(configFile.createSection(profileName),
configFile::store);
+ IniSection section = configFile.createSection(profileName);
+ IniSection secretSection = secretConfigFile.createSection(profileName);
+
+ IniConfig config = new IniConfig(section, configFile::store);
+ IniConfig secretConfig = new IniConfig(secretSection,
secretConfigFile::store);
+
+ return new IniProfile(profileName, config, secretConfig);
}
@Override
@@ -125,6 +177,26 @@ public class IniConfigManager implements ConfigManager {
IniSection defaultSection =
ini.createSection(DEFAULT_PROFILE_NAME);
defaultSection.setProperty(CLUSTER_URL.value(),
"http://localhost:10300");
defaultSection.setProperty(JDBC_URL.value(),
"jdbc:ignite:thin://127.0.0.1:10800");
+ ini.store();
+ return ini;
+ } catch (IOException e) {
+ throw new ConfigInitializationException(file.getAbsolutePath(), e);
+ }
+ }
+
+ private static IniFile createDefaultSecretConfig(File file) {
+ try {
+ file.getParentFile().mkdirs();
+ file.delete();
+
+ if (OperatingSystem.current() == OperatingSystem.WINDOWS) {
+ Files.createFile(file.toPath());
+ } else {
+ Files.createFile(file.toPath(),
PosixFilePermissions.asFileAttribute(secretPermission()));
+ }
+
+ IniFile ini = new IniFile(file);
+ IniSection defaultSection =
ini.createSection(DEFAULT_PROFILE_NAME);
defaultSection.setProperty(REST_KEY_STORE_PATH.value(), "");
defaultSection.setProperty(REST_KEY_STORE_PASSWORD.value(), "");
defaultSection.setProperty(REST_TRUST_STORE_PATH.value(), "");
@@ -137,4 +209,8 @@ public class IniConfigManager implements ConfigManager {
throw new ConfigInitializationException(file.getAbsolutePath(), e);
}
}
+
+ private static Set<PosixFilePermission> secretPermission() {
+ return Set.of(PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
+ }
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniProfile.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniProfile.java
index c1b3e5f159..0cabe5e53e 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniProfile.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/config/ini/IniProfile.java
@@ -17,30 +17,93 @@
package org.apache.ignite.internal.cli.config.ini;
-import org.apache.ignite.internal.cli.config.Config;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.cli.config.CliConfigKeys;
import org.apache.ignite.internal.cli.config.Profile;
/**
* Implementation of {@link Profile} based on {@link IniSection}.
*/
public class IniProfile implements Profile {
- private final IniSection section;
+ private final String name;
private final IniConfig config;
+ private final IniConfig secretConfig;
- public IniProfile(IniSection section, Runnable saveAction) {
- this.section = section;
- this.config = new IniConfig(section, saveAction);
+ /**
+ * Constructor.
+ *
+ * @param name Profile name.
+ * @param config Ini config.
+ * @param secretConfig Ini secret config.
+ */
+ public IniProfile(String name, IniConfig config, IniConfig secretConfig) {
+ this.name = name;
+ this.config = config;
+ this.secretConfig = secretConfig;
}
/** {@inheritDoc} */
@Override
public String getName() {
- return section.getName();
+ return name;
}
/** {@inheritDoc} */
@Override
- public Config getConfig() {
- return config;
+ public Map<String, String> getAll() {
+ Map<String, String> all = new HashMap<>(config.getAll());
+ all.putAll(secretConfig.getAll());
+ return all;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getProperty(String key) {
+ if (CliConfigKeys.secretConfigKeys().contains(key)) {
+ return secretConfig.getProperty(key);
+ } else {
+ return config.getProperty(key);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getProperty(String key, String defaultValue) {
+ if (CliConfigKeys.secretConfigKeys().contains(key)) {
+ return secretConfig.getProperty(key, defaultValue);
+ } else {
+ return config.getProperty(key, defaultValue);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setProperty(String key, String value) {
+ if (CliConfigKeys.secretConfigKeys().contains(key)) {
+ secretConfig.setProperty(key, value);
+ } else {
+ config.setProperty(key, value);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setProperties(Map<String, String> values) {
+ Map<Boolean, Map<String, String>> secretToValues =
values.entrySet().stream()
+ .collect(Collectors.groupingBy(it ->
CliConfigKeys.secretConfigKeys().contains(it.getKey()),
+ Collectors.toMap(Entry::getKey, Entry::getValue)));
+
+ Map<String, String> configValues = secretToValues.get(false);
+ if (configValues != null) {
+ config.setProperties(configValues);
+ }
+
+ Map<String, String> secretConfigValues = secretToValues.get(true);
+ if (secretConfigValues != null) {
+ secretConfig.setProperties(secretConfigValues);
+ }
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/util/OperatingSystem.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/util/OperatingSystem.java
new file mode 100644
index 0000000000..d8b8a99e53
--- /dev/null
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/util/OperatingSystem.java
@@ -0,0 +1,106 @@
+/*
+ * 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.util;
+
+import java.util.Locale;
+
+/** Utility class for detection OS. */
+public enum OperatingSystem {
+
+ /**
+ * IBM AIX operating system.
+ */
+ AIX,
+
+ /**
+ * FreeBSD operating system.
+ */
+ FREEBSD,
+
+ /**
+ * Linux-based operating system.
+ */
+ LINUX,
+
+ /**
+ * Apple Macintosh operating system (e.g., macOS).
+ */
+ MAC,
+
+ /**
+ * OpenBSD operating system.
+ */
+ OPENBSD,
+
+ /**
+ * Oracle Solaris operating system.
+ */
+ SOLARIS,
+
+ /**
+ * Microsoft Windows operating system.
+ */
+ WINDOWS,
+
+ /**
+ * An operating system other than {@link #AIX}, {@link #FREEBSD}, {@link
#LINUX}, {@link #MAC}, {@link #OPENBSD}, {@link #SOLARIS}, or
+ * {@link #WINDOWS}.
+ */
+ OTHER;
+
+ private static final OperatingSystem CURRENT_OS = determineCurrentOs();
+
+ public static OperatingSystem current() {
+ return CURRENT_OS;
+ }
+
+ private static OperatingSystem determineCurrentOs() {
+ String osName = System.getProperty("os.name");
+ if (osName == null) {
+ throw new IllegalStateException("Unable to determine current
operating system: system property 'os.name' is not set.");
+ }
+ return parse(osName);
+ }
+
+ private static OperatingSystem parse(String osName) {
+ osName = osName.toLowerCase(Locale.ENGLISH);
+
+ if (osName.contains("aix")) {
+ return AIX;
+ }
+ if (osName.contains("freebsd")) {
+ return FREEBSD;
+ }
+ if (osName.contains("linux")) {
+ return LINUX;
+ }
+ if (osName.contains("mac")) {
+ return MAC;
+ }
+ if (osName.contains("openbsd")) {
+ return OPENBSD;
+ }
+ if (osName.contains("sunos") || osName.contains("solaris")) {
+ return SOLARIS;
+ }
+ if (osName.contains("win")) {
+ return WINDOWS;
+ }
+ return OTHER;
+ }
+}
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/CliCommandTestBase.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/CliCommandTestBase.java
index a0e767c2c4..a5d5decb29 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/CliCommandTestBase.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/CliCommandTestBase.java
@@ -25,6 +25,7 @@ import
io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
@@ -102,9 +103,9 @@ public abstract class CliCommandTestBase {
.isEqualTo(expectedOutput);
}
- protected void assertOutputContains(String expectedOutput) {
+ protected void assertOutputContains(String... expectedOutput) {
assertThat(sout.toString())
- .as("Expected command output to contain: " + expectedOutput +
" but was " + sout.toString())
+ .as("Expected command output to contain: " +
Arrays.toString(expectedOutput) + " but was " + sout.toString())
.contains(expectedOutput);
}
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
index 6e9e7d63ae..147fbe3655 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/UrlOptionsNegativeTest.java
@@ -65,7 +65,6 @@ import
org.apache.ignite.internal.cli.commands.unit.UnitStatusCommand;
import org.apache.ignite.internal.cli.commands.unit.UnitStatusReplCommand;
import org.apache.ignite.internal.cli.commands.unit.UnitUndeployCommand;
import org.apache.ignite.internal.cli.commands.unit.UnitUndeployReplCommand;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.apache.ignite.internal.cli.core.converters.NodeNameOrUrlConverter;
import
org.apache.ignite.internal.cli.core.repl.context.CommandLineContextProvider;
import org.apache.ignite.internal.cli.core.repl.registry.NodeNameRegistry;
@@ -104,7 +103,7 @@ public class UrlOptionsNegativeTest {
NodeNameRegistry nodeNameRegistry;
private void setUp(Class<?> cmdClass) {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createSectionWithDefaultProfile());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createSectionWithDefaultProfile());
MicronautFactory factory = new MicronautFactory(context);
cmd = new CommandLine(cmdClass, factory)
.registerConverter(NodeNameOrUrl.class, new
NodeNameOrUrlConverter(nodeNameRegistry));
@@ -287,7 +286,7 @@ public class UrlOptionsNegativeTest {
@Test
void testConnectCommandWithoutParametersWithEmptyConfig() {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createEmptyConfig());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createEmptyConfig());
setUp(ConnectReplCommand.class);
cmd.execute();
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigCommandTestBase.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigCommandTestBase.java
index 9a6f9b4c89..d9d558fa7b 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigCommandTestBase.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigCommandTestBase.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.cli.commands.cliconfig;
import jakarta.inject.Inject;
import org.apache.ignite.internal.cli.commands.CliCommandTestBase;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.junit.jupiter.api.BeforeEach;
/**
@@ -31,6 +30,6 @@ public abstract class CliConfigCommandTestBase extends
CliCommandTestBase {
@BeforeEach
void configManagerRefresh() {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createSectionWithDefaultProfile());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createSectionWithDefaultProfile());
}
}
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileListCommandTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileListCommandTest.java
index 2ae6a624b6..0385ca5454 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileListCommandTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileListCommandTest.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.cli.commands.cliconfig;
import static org.junit.jupiter.api.Assertions.assertAll;
import
org.apache.ignite.internal.cli.commands.cliconfig.profile.CliConfigProfileListCommand;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.junit.jupiter.api.Test;
class CliConfigProfileListCommandTest extends CliConfigCommandTestBase {
@@ -43,7 +42,7 @@ class CliConfigProfileListCommandTest extends
CliConfigCommandTestBase {
@Test
public void testSingleProfile() {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createOneSectionWithDefaultProfile());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createOneSectionWithDefaultProfile());
execute();
String expectedResult = "default" + System.lineSeparator();
@@ -55,7 +54,7 @@ class CliConfigProfileListCommandTest extends
CliConfigCommandTestBase {
@Test
public void testEmptyConfig() {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createEmptyConfig());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createEmptyConfig());
execute();
String expectedResult = "default" + System.lineSeparator();
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileShowCommandTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileShowCommandTest.java
index dcaaa7fdd4..33e8f1f4f5 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileShowCommandTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigProfileShowCommandTest.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.cli.commands.cliconfig;
import static org.junit.jupiter.api.Assertions.assertAll;
import
org.apache.ignite.internal.cli.commands.cliconfig.profile.CliConfigProfileShowCommand;
-import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
import org.junit.jupiter.api.Test;
class CliConfigProfileShowCommandTest extends CliConfigCommandTestBase {
@@ -41,7 +40,7 @@ class CliConfigProfileShowCommandTest extends
CliConfigCommandTestBase {
@Test
public void testWithoutDefaultProfile() {
- configManagerProvider.configManager = new
IniConfigManager(TestConfigManagerHelper.createSectionWithoutDefaultProfile());
+
configManagerProvider.setConfigFile(TestConfigManagerHelper.createSectionWithoutDefaultProfile());
execute();
assertAll(
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigShowCommandTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigShowCommandTest.java
index 29dfadeb48..04f13910dd 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigShowCommandTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/CliConfigShowCommandTest.java
@@ -33,14 +33,16 @@ class CliConfigShowCommandTest extends
CliConfigCommandTestBase {
void noKey() {
execute();
- String expectedResult = "[database]" + System.lineSeparator()
- + "server=127.0.0.1" + System.lineSeparator()
- + "port=8080" + System.lineSeparator()
- + "file=\"apache.ignite\"" + System.lineSeparator();
+ String[] expectedResult = {
+ "[database]" + System.lineSeparator(),
+ "server=127.0.0.1" + System.lineSeparator(),
+ "port=8080" + System.lineSeparator(),
+ "file=\"apache.ignite\"" + System.lineSeparator()
+ };
assertAll(
this::assertExitCodeIsZero,
- () -> assertOutputIs(expectedResult),
+ () -> assertOutputContains(expectedResult),
this::assertErrOutputIsEmpty
);
}
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/ConfigManagerTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/ConfigManagerTest.java
index a3fae86612..b1179ceb94 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/ConfigManagerTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/cliconfig/ConfigManagerTest.java
@@ -27,18 +27,20 @@ class ConfigManagerTest {
@Test
public void testSaveLoadConfig() {
File tempFile =
TestConfigManagerHelper.createSectionWithDefaultProfile();
- IniConfigManager configManager = new IniConfigManager(tempFile);
+ File tempSecretFile =
TestConfigManagerHelper.createEmptySecretConfig();
+ IniConfigManager configManager = new IniConfigManager(tempFile,
tempSecretFile);
configManager.setProperty("ignite.cluster-endpoint-url", "test");
- IniConfigManager configAfterSave = new IniConfigManager(tempFile);
+ IniConfigManager configAfterSave = new IniConfigManager(tempFile,
tempSecretFile);
assertThat(configAfterSave.getCurrentProperty("ignite.cluster-endpoint-url")).isEqualTo("test");
}
@Test
public void testLoadConfigWithoutDefaultProfile() {
File tempFile =
TestConfigManagerHelper.createSectionWithoutDefaultProfile();
- IniConfigManager configManager = new IniConfigManager(tempFile);
+ File tempSecretFile =
TestConfigManagerHelper.createEmptySecretConfig();
+ IniConfigManager configManager = new IniConfigManager(tempFile,
tempSecretFile);
assertThat(configManager.getCurrentProfile().getName()).isEqualTo("owner");
@@ -47,7 +49,8 @@ class ConfigManagerTest {
@Test
public void testEmptyConfigLoad() {
File tempFile = TestConfigManagerHelper.createEmptyConfig();
- IniConfigManager configManager = new IniConfigManager(tempFile);
+ File tempSecretFile =
TestConfigManagerHelper.createEmptySecretConfig();
+ IniConfigManager configManager = new IniConfigManager(tempFile,
tempSecretFile);
assertThat(configManager.getCurrentProfile().getName()).isEqualTo("default");
}
@@ -56,7 +59,8 @@ class ConfigManagerTest {
@Test
public void testRemoveConfigFileOnRuntime() {
File tempFile =
TestConfigManagerHelper.createSectionWithDefaultProfile();
- IniConfigManager configManager = new IniConfigManager(tempFile);
+ File tempSecretFile =
TestConfigManagerHelper.createEmptySecretConfig();
+ IniConfigManager configManager = new IniConfigManager(tempFile,
tempSecretFile);
assertThat(configManager.getCurrentProfile().getName()).isEqualTo("database");
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/config/ini/IniConfigManagerTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/config/ini/IniConfigManagerTest.java
new file mode 100644
index 0000000000..475ed2abb0
--- /dev/null
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/config/ini/IniConfigManagerTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.config.ini;
+
+import static java.nio.file.Files.lines;
+import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.cli.config.CliConfigKeys;
+import org.apache.ignite.internal.cli.core.exception.IgniteCliException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.junit.jupiter.api.io.TempDir;
+
+class IniConfigManagerTest {
+
+ File configFile;
+ File secretConfigFile;
+
+ @BeforeEach
+ void setUp(@TempDir File configDir) {
+ configFile = new File(configDir, "config.ini");
+ secretConfigFile = new File(configDir, "secret.ini");
+ }
+
+ @Test
+ void managerWritesConfigKeysProperly() throws IOException {
+ // when
+ IniConfigManager manager = new IniConfigManager(configFile,
secretConfigFile);
+
+ Arrays.stream(CliConfigKeys.values())
+ .map(CliConfigKeys::value)
+ .forEach(it -> {
+ manager.getCurrentProfile().setProperty(it, "1234");
+ });
+
+ String[] secretKeys = CliConfigKeys.secretConfigKeys().toArray(new
String[0]);
+
+ // then secret config file contains secret keys
+ List<String> secretConfigFileKeys = readKeysFromFile(secretConfigFile,
2);
+
+ assertThat(secretConfigFileKeys, hasSize(secretKeys.length));
+ assertThat(secretConfigFileKeys, containsInAnyOrder(secretKeys));
+
+ // and config file does not contain secret keys
+ List<String> configFileKeys = readKeysFromFile(configFile, 3);
+ String[] notSecretConfigKeys = Arrays.stream(CliConfigKeys.values())
+ .map(CliConfigKeys::value)
+ .filter(it -> !CliConfigKeys.secretConfigKeys().contains(it))
+ .toArray(String[]::new);
+
+ assertThat(configFileKeys, hasSize(notSecretConfigKeys.length));
+ assertThat(configFileKeys, containsInAnyOrder(notSecretConfigKeys));
+
+ }
+
+ @Test
+ @DisabledOnOs(OS.WINDOWS)
+ void secretConfigFileIsCreatedWithCorrectPermissions() throws IOException {
+ // when
+ IniConfigManager manager = new IniConfigManager(configFile,
secretConfigFile);
+
+ // then
+ Set<PosixFilePermission> permissions =
Files.getPosixFilePermissions(secretConfigFile.toPath());
+ assertThat(permissions, containsInAnyOrder(OWNER_READ, OWNER_WRITE,
OWNER_EXECUTE));
+ }
+
+ @Test
+ @DisabledOnOs(OS.WINDOWS)
+ void managerValidatesSecretConfigFilePermissions() throws IOException {
+ // when
+ Files.createFile(secretConfigFile.toPath(),
PosixFilePermissions.asFileAttribute(Set.of(OWNER_READ, GROUP_READ)));
+
+ // then
+ IgniteCliException igniteCliException =
assertThrows(IgniteCliException.class,
+ () -> new IniConfigManager(configFile, secretConfigFile));
+ assertThat(igniteCliException.getMessage(),
+ containsString("The secret configuration file must have 700
permissions"));
+ }
+
+ private static List<String> readKeysFromFile(File file, int headerLength)
throws IOException {
+ try (Stream<String> lines = lines(file.toPath())) {
+ return lines.skip(headerLength) // skip header
+ .map(it -> it.split("="))
+ .map(it -> it[0].trim())
+ .filter(it -> !it.isBlank())
+ .collect(Collectors.toList());
+ }
+ }
+}
diff --git
a/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerHelper.java
b/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerHelper.java
index b0c97a00a6..6373e03ffb 100644
---
a/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerHelper.java
+++
b/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerHelper.java
@@ -17,6 +17,10 @@
package org.apache.ignite.internal.cli.commands.cliconfig;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -24,13 +28,18 @@ import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
import org.apache.ignite.internal.cli.config.ConfigManager;
+import org.apache.ignite.internal.cli.util.OperatingSystem;
/**
* Test factory for {@link ConfigManager}.
*/
public class TestConfigManagerHelper {
private static final String EMPTY = "empty.ini";
+ private static final String EMPTY_SECRET = "empty_secret.ini";
private static final String ONE_SECTION_WITH_DEFAULT_PROFILE =
"one_section_with_default_profile.ini";
private static final String TWO_SECTION_WITH_DEFAULT_PROFILE =
"two_section_with_default_profile.ini";
private static final String TWO_SECTION_WITHOUT_DEFAULT_PROFILE =
"two_section_without_default_profile.ini";
@@ -44,6 +53,17 @@ public class TestConfigManagerHelper {
return copyResourceToTempFile(EMPTY);
}
+ /** Creates and returns the empty secret file config. */
+ public static File createEmptySecretConfig() {
+ File file = copyResourceToTempFile(EMPTY_SECRET);
+ try {
+ setFilePermissions(file, Set.of(OWNER_READ, OWNER_WRITE,
OWNER_EXECUTE));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return file;
+ }
+
public static File createOneSectionWithDefaultProfile() {
return copyResourceToTempFile(ONE_SECTION_WITH_DEFAULT_PROFILE);
}
@@ -90,4 +110,10 @@ public class TestConfigManagerHelper {
throw new RuntimeException(e);
}
}
+
+ private static void setFilePermissions(File file, Set<PosixFilePermission>
perms) throws IOException {
+ if (OperatingSystem.current() != OperatingSystem.WINDOWS) {
+ Files.setPosixFilePermissions(file.toPath(), perms);
+ }
+ }
}
diff --git
a/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerProvider.java
b/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerProvider.java
index 9e78b1b134..4a8e3b5b3b 100644
---
a/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerProvider.java
+++
b/modules/cli/src/testFixtures/java/org/apache/ignite/internal/cli/commands/cliconfig/TestConfigManagerProvider.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.cli.commands.cliconfig;
import io.micronaut.context.annotation.Replaces;
import jakarta.inject.Singleton;
+import java.io.File;
import org.apache.ignite.internal.cli.config.ConfigManager;
import org.apache.ignite.internal.cli.config.ConfigManagerProvider;
import org.apache.ignite.internal.cli.config.ini.IniConfigManager;
@@ -30,10 +31,17 @@ import
org.apache.ignite.internal.cli.config.ini.IniConfigManager;
@Replaces(ConfigManagerProvider.class)
public class TestConfigManagerProvider implements ConfigManagerProvider {
- public ConfigManager configManager = new
IniConfigManager(TestConfigManagerHelper.createIntegrationTests());
+ public ConfigManager configManager = new IniConfigManager(
+ TestConfigManagerHelper.createIntegrationTests(),
+ TestConfigManagerHelper.createEmptySecretConfig()
+ );
@Override
public ConfigManager get() {
return configManager;
}
+
+ public void setConfigFile(File configFile) {
+ configManager = new IniConfigManager(configFile,
TestConfigManagerHelper.createEmptySecretConfig());
+ }
}
diff --git a/modules/cli/src/testFixtures/resources/empty_secret.ini
b/modules/cli/src/testFixtures/resources/empty_secret.ini
new file mode 100644
index 0000000000..e69de29bb2