From 7329507d55c15ecd51f613872fdacd54ebfb2efc Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Wed, 9 Oct 2024 15:00:33 -0300 Subject: [PATCH 01/23] Create the initial structure --- .../java/com/wazuh/commandmanager/settings/PluginSettings.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java new file mode 100644 index 0000000..e69de29 From ae988a8a9b687064354e50dc28eaccb79566e189 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Fri, 11 Oct 2024 10:22:02 -0300 Subject: [PATCH 02/23] Manage the settings of the plugin. Create and reload the keystore. --- plugins/command-manager/build.gradle | 3 + .../commandmanager/CommandManagerPlugin.java | 11 ++- .../CommandManagerSettingsException.java | 36 ++++++++ .../settings/PluginSettings.java | 89 +++++++++++++++++++ .../resources/wazuh-indexer.keystore.json | 11 +++ 5 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java create mode 100644 plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 7defcd1..82616ca 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -106,6 +106,9 @@ testClusters.integTest { // This installs our plugin into the testClusters plugin(project.tasks.bundlePlugin.archiveFile) + + // add customized keystore + keystore 'wazuh-indexer.keystore', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 267e0f4..78d1dba 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -9,15 +9,14 @@ import com.wazuh.commandmanager.index.CommandIndex; import com.wazuh.commandmanager.rest.action.RestPostCommandAction; +import com.wazuh.commandmanager.settings.PluginSettings; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.ClusterSettings; -import org.opensearch.common.settings.IndexScopedSettings; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.common.settings.*; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.common.settings.SecureString; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; @@ -47,6 +46,8 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin { public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; private CommandIndex commandIndex; + private PluginSettings pluginSettings; + private static Environment env; @Override public Collection createComponents( @@ -63,6 +64,8 @@ public Collection createComponents( Supplier repositoriesServiceSupplier ) { this.commandIndex = new CommandIndex(client, clusterService, threadPool); + this.pluginSettings = PluginSettings.getPluginSettingsInstance(); + pluginSettings.setEnv(environment); return Collections.emptyList(); } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java new file mode 100644 index 0000000..5669175 --- /dev/null +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java @@ -0,0 +1,36 @@ +package com.wazuh.commandmanager; + + +public class CommandManagerSettingsException extends Exception { + + // Default constructor + public CommandManagerSettingsException() { + super(); + } + + // Constructor that accepts a message + public CommandManagerSettingsException(String message) { + super(message); + } + + // Constructor that accepts a message and a cause + public CommandManagerSettingsException(String message, Throwable cause) { + super(message, cause); + } + + // Constructor that accepts a cause + public CommandManagerSettingsException(Throwable cause) { + super(cause); + } + + // Exception for the case when the keystore does not exist + public static CommandManagerSettingsException keystoreNotExist(String keystorePath) { + return new CommandManagerSettingsException("The keystore does not exist at the path: " + keystorePath); + } + + // Exception for the case when the keystore is empty + public static CommandManagerSettingsException keystoreEmpty(String keystorePath) { + return new CommandManagerSettingsException("The keystore is empty at the path: " + keystorePath); + } +} + diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java index e69de29..0665187 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ +package com.wazuh.commandmanager.settings; + +import com.wazuh.commandmanager.CommandManagerSettingsException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Logger; +import org.opensearch.common.settings.KeyStoreWrapper; +import org.opensearch.common.settings.SecureSettings; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.settings.SecureString; +import org.opensearch.env.Environment; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +public class PluginSettings { + private static final Logger logger = (Logger) LogManager.getLogger(PluginSettings.class); + + private static PluginSettings INSTANCE; + + private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; + + private static KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.create(); + private static Environment env; + + private PluginSettings() { + // Singleton class, use getPluginSettings method instead of constructor + } + + public static PluginSettings getPluginSettingsInstance() { + if (INSTANCE != null) { + return INSTANCE; + } + synchronized (PluginSettings.class) { + if (INSTANCE != null) { + return INSTANCE; + } + INSTANCE = new PluginSettings(); + return INSTANCE; + } + } + + public void setEnv(Environment env) { + PluginSettings.env = env; + } + + static SecureSettings loadSecureSettings(SecureString secureSettingsPassword) throws CommandManagerSettingsException, GeneralSecurityException { + try { + //Open the keystore file + keyStoreWrapper = KeyStoreWrapper.load(env.configFile(),KEYSTORE_FILENAME); + if (keyStoreWrapper == null) { + logger.info(CommandManagerSettingsException.keystoreNotExist(env.configFile().toString()).getMessage()); + + //Create keystore file if it doesn't exist + keyStoreWrapper = KeyStoreWrapper.create(); + keyStoreWrapper.save(env.configFile(), new char[0]); + + } else { + // Decrypt the keystore using the password from the request + keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + //Here TransportNodesReloadSecureSettingsAction reload the plugins, but our PLugin isn't ReloadablePlugin + // final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); + } + } catch (IOException e) { + throw new CommandManagerSettingsException(e); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + secureSettingsPassword.close(); + } + return keyStoreWrapper; + } + + public SecureSettings upgradeKeyStore( char[] password){ + try { + KeyStoreWrapper.upgrade(keyStoreWrapper, env.configFile(), password); + } catch (Exception e) { + throw new RuntimeException(e); + } + return keyStoreWrapper; + } + +} \ No newline at end of file diff --git a/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json b/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json new file mode 100644 index 0000000..090251c --- /dev/null +++ b/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json @@ -0,0 +1,11 @@ +[ + { + "name" : "wazuh-api", + "properties" : { + "prometheus.uri" : "http://localhost:9090", + "prometheus.auth.type" : "basicauth", + "prometheus.auth.username" : "admin", + "prometheus.auth.password" : "type" + } + } +] \ No newline at end of file From a4e5f72d9741710c169444533c80837cb283eeaf Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Fri, 11 Oct 2024 12:57:02 -0300 Subject: [PATCH 03/23] Add the security settings --- plugins/command-manager/build.gradle | 2 +- .../commandmanager/CommandManagerPlugin.java | 27 ++++++- .../settings/CommandManagerSettings.java | 73 +++++++++++++++++++ .../settings/PluginSettings.java | 1 - 4 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 82616ca..0c75fd3 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -108,7 +108,7 @@ testClusters.integTest { plugin(project.tasks.bundlePlugin.archiveFile) // add customized keystore - keystore 'wazuh-indexer.keystore', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') + keystore 'command.manager.access_key', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 78d1dba..6d1b16b 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -9,6 +9,7 @@ import com.wazuh.commandmanager.index.CommandIndex; import com.wazuh.commandmanager.rest.action.RestPostCommandAction; +import com.wazuh.commandmanager.settings.CommandManagerSettings; import com.wazuh.commandmanager.settings.PluginSettings; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; @@ -16,12 +17,12 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.*; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; -import org.opensearch.core.common.settings.SecureString; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.Plugin; +import org.opensearch.plugins.ReloadablePlugin; import org.opensearch.repositories.RepositoriesService; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; @@ -29,6 +30,7 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.watcher.ResourceWatcherService; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -40,14 +42,13 @@ * indexed and sent back to the Server for its delivery to, in most cases, the * Agents. */ -public class CommandManagerPlugin extends Plugin implements ActionPlugin { +public class CommandManagerPlugin extends Plugin implements ActionPlugin, ReloadablePlugin { public static final String COMMAND_MANAGER_BASE_URI = "/_plugins/_commandmanager"; public static final String COMMAND_MANAGER_INDEX_NAME = ".commands"; public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; private CommandIndex commandIndex; private PluginSettings pluginSettings; - private static Environment env; @Override public Collection createComponents( @@ -80,4 +81,24 @@ public List getRestHandlers( ) { return Collections.singletonList(new RestPostCommandAction(this.commandIndex)); } + + @Override + public List> getSettings() { + return Arrays.asList( + // Register EC2 discovery settings: discovery.ec2 + CommandManagerSettings.ACCESS_KEY_SETTING, + CommandManagerSettings.SECRET_KEY_SETTING, + CommandManagerSettings.SESSION_TOKEN_SETTING, + CommandManagerSettings.PROXY_HOST_SETTING, + CommandManagerSettings.PROXY_PORT_SETTING + ); + } + + @Override + public void reload(Settings settings) { + // secure settings should be readable + final CommandManagerSettings commandManagerSettings = CommandManagerSettings.getClientSettings(settings); + //I don't know what I have to do when we want to reload the settings already + //ec2Service.refreshAndClearCache(commandManagerSettings); + } } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java new file mode 100644 index 0000000..5f26e20 --- /dev/null +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -0,0 +1,73 @@ +package com.wazuh.commandmanager.settings; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Setting.Property; +import org.opensearch.common.settings.SecureSetting; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.settings.SecureString; + + +public final class CommandManagerSettings { +//THE DEFINITIONS OF WHAT KEYS ARE NECESSARY ARE PENDING + + /** The access key (ie login id) for connecting to ec2. */ + public static final Setting ACCESS_KEY_SETTING = SecureSetting.secureString("command.manager.access_key", null); + + /** The secret key (ie password) for connecting to ec2. */ + public static final Setting SECRET_KEY_SETTING = SecureSetting.secureString("command.manager.secret_key", null); + + /** The session token for connecting to ec2. */ + public static final Setting SESSION_TOKEN_SETTING = SecureSetting.secureString("command.manager.session_token", null); + + /** The host name of a proxy to connect to ec2 through. */ + public static final Setting PROXY_HOST_SETTING = Setting.simpleString("command.manager.proxy.host", Property.NodeScope); + + /** The port of a proxy to connect to ec2 through. */ + public static final Setting PROXY_PORT_SETTING = Setting.intSetting("command.manager.proxy.port", 80, 0, 1 << 16, Property.NodeScope); + + /** An optional proxy host that requests to ec2 should be made through. */ + final String accessKey; + + /** The secret key (ie password) for connecting to ec2. */ + final String secretKey; + + /** The session token for connecting to ec2. */ + final String sessionToken; + + /** An optional proxy host that requests to ec2 should be made through. */ + final String proxyHost; + + /** The port number the proxy host should be connected on. */ + final int proxyPort; + + + protected CommandManagerSettings( + String accessKey, + String secretKey, + String sessionToken, + String proxyHost, + int proxyPort + ) { + this.accessKey = accessKey; + this.secretKey = secretKey; + this.sessionToken = sessionToken; + this.proxyHost = proxyHost; + this.proxyPort = proxyPort;} + + /** Parse settings for a single client. */ + public static CommandManagerSettings getClientSettings(Settings settings) { + //final AwsCredentials credentials = loadCredentials(settings); no estoy segura de si tendrĂ­amos que configurar algo asociado a AWS, supongo que no + try( + SecureString accessKey = ACCESS_KEY_SETTING.get(settings); + SecureString secretKey = SECRET_KEY_SETTING.get(settings); + SecureString sessionToken = SESSION_TOKEN_SETTING.get(settings); + ){ + return new CommandManagerSettings( + accessKey.toString(), + secretKey.toString(), + sessionToken.toString(), + PROXY_HOST_SETTING.get(settings), + PROXY_PORT_SETTING.get(settings) + ); + } + } +} diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java index 0665187..6082bfd 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java @@ -12,7 +12,6 @@ import org.apache.logging.log4j.core.Logger; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.SecureSettings; -import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; From d92ce1b5faccad11aa6df77a2ccee96a2d6edbcc Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Mon, 14 Oct 2024 10:52:16 -0300 Subject: [PATCH 04/23] Fix license of CommandManagerSettings and CommandManagerSettingsException. Add PluginSettingTest --- .../CommandManagerSettingsException.java | 7 ++ .../settings/CommandManagerSettings.java | 7 ++ .../settings/PluginSettingsTest.java | 71 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java index 5669175..bb66f51 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java @@ -1,3 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ package com.wazuh.commandmanager; diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 5f26e20..0362e10 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -1,3 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ package com.wazuh.commandmanager.settings; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Setting.Property; diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java new file mode 100644 index 0000000..13bb50f --- /dev/null +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java @@ -0,0 +1,71 @@ +package com.wazuh.commandmanager.settings; + +import org.junit.After; +import org.junit.Before; +import org.opensearch.common.settings.KeyStoreWrapper; +import org.opensearch.common.settings.SecureSettings; +import org.opensearch.core.common.settings.SecureString; +import org.opensearch.env.Environment; +import org.opensearch.test.OpenSearchIntegTestCase; + +import java.nio.file.Path; + +import static org.mockito.Mockito.*; + +@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) +public class PluginSettingsTest extends OpenSearchIntegTestCase { + + private PluginSettings pluginSettings; + private Environment mockEnvironment; + private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); + + @Before + public void setUp() { + // Create a mock Environment + mockEnvironment = mock(Environment.class); + // Instantiate PluginSettings + pluginSettings = PluginSettings.getPluginSettingsInstance(); + pluginSettings.setEnv(mockEnvironment); + } + + @After + public void closeSecureString() { + // Cleanup if necessary + secureString.close(); + } + + public void testLoadSecureSettings_keystoreNotExist() throws Exception { + // Setup the mock to return a specific path for the config file + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/wazuh-indexer.keystoreUNEXISTENT.json"); + when(mockEnvironment.configFile()).thenReturn(keyStorePath); + + // Mocking the keyStoreWrapper to return null + KeyStoreWrapper keyStoreWrapperMock = mock(KeyStoreWrapper.class); + when(KeyStoreWrapper.load(any(), any())).thenReturn(null); + + // Check that the keystore is created + SecureSettings result = pluginSettings.loadSecureSettings(secureString); + + assertNotNull(result); + verify(keyStoreWrapperMock, times(1)).save(any(), any()); + } + + public void testLoadSecureSettings_keystoreExists() throws Exception { + // Setup the mock to return a specific path for the config file + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/"); + when(mockEnvironment.configFile()).thenReturn(keyStorePath); + + // Simulate an existing keystore + KeyStoreWrapper keyStoreWrapperMock = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); + when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapperMock); + String text = "type"; + char[] passToTest = text.toCharArray(); + keyStoreWrapperMock.decrypt(passToTest); + + // Load secure settings + SecureSettings result = pluginSettings.loadSecureSettings(secureString); + + assertNotNull(result); + verify(keyStoreWrapperMock, times(1)).decrypt(secureString.getChars()); + } +} From a97e2d6de5bdd145477fc7875da304127bf0e674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Mon, 14 Oct 2024 16:58:50 +0200 Subject: [PATCH 05/23] Rename test class to match convention --- ...ttingsTest.java => PluginSettingsTests.java} | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) rename plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/{PluginSettingsTest.java => PluginSettingsTests.java} (81%) diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java similarity index 81% rename from plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java rename to plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java index 13bb50f..39e744f 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTest.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java @@ -1,3 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ package com.wazuh.commandmanager.settings; import org.junit.After; @@ -13,7 +20,7 @@ import static org.mockito.Mockito.*; @OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) -public class PluginSettingsTest extends OpenSearchIntegTestCase { +public class PluginSettingsTests extends OpenSearchIntegTestCase { private PluginSettings pluginSettings; private Environment mockEnvironment; @@ -35,7 +42,7 @@ public void closeSecureString() { } public void testLoadSecureSettings_keystoreNotExist() throws Exception { - // Setup the mock to return a specific path for the config file + // Set up the mock to return a specific path for the config file Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/wazuh-indexer.keystoreUNEXISTENT.json"); when(mockEnvironment.configFile()).thenReturn(keyStorePath); @@ -44,14 +51,14 @@ public void testLoadSecureSettings_keystoreNotExist() throws Exception { when(KeyStoreWrapper.load(any(), any())).thenReturn(null); // Check that the keystore is created - SecureSettings result = pluginSettings.loadSecureSettings(secureString); + SecureSettings result = PluginSettings.loadSecureSettings(secureString); assertNotNull(result); verify(keyStoreWrapperMock, times(1)).save(any(), any()); } public void testLoadSecureSettings_keystoreExists() throws Exception { - // Setup the mock to return a specific path for the config file + // Set up the mock to return a specific path for the config file Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/"); when(mockEnvironment.configFile()).thenReturn(keyStorePath); @@ -63,7 +70,7 @@ public void testLoadSecureSettings_keystoreExists() throws Exception { keyStoreWrapperMock.decrypt(passToTest); // Load secure settings - SecureSettings result = pluginSettings.loadSecureSettings(secureString); + SecureSettings result = PluginSettings.loadSecureSettings(secureString); assertNotNull(result); verify(keyStoreWrapperMock, times(1)).decrypt(secureString.getChars()); From 65f6f9dbe87aa5c6fd6911dd34d7e55f377cf51b Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Mon, 14 Oct 2024 16:12:27 -0300 Subject: [PATCH 06/23] Fix comments in the merge request --- plugins/command-manager/build.gradle | 9 ++- .../commandmanager/CommandManagerPlugin.java | 16 ++-- .../settings/CommandManagerSettings.java | 79 +++++++++---------- .../settings/PluginSettings.java | 39 +++++---- .../settings/PluginSettingsTests.java | 8 +- .../resources/wazuh-indexer.keystore.json | 8 +- 6 files changed, 79 insertions(+), 80 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index bc4b09f..98b57be 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -126,12 +126,17 @@ integTest { testClusters.integTest { testDistribution = "INTEG_TEST" - + //testDistribution = "ARCHIVE" // This installs our plugin into the testClusters plugin(project.tasks.bundlePlugin.archiveFile) // add customized keystore - keystore 'command.manager.access_key', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') + keystore 'command.manager.keystore', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') + //keystore 'command.manager.uri', 'http://localhost:9090' + //keystore 'command.manager.auth.type', 'basicauth' + keystore 'command.manager.auth.username', 'admin' + keystore 'command.manager.auth.password', 'type' + } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 1c87a81..a1c8c72 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -51,7 +51,6 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin, Reload public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; private CommandIndex commandIndex; - private PluginSettings pluginSettings; @Override public Collection createComponents( @@ -68,8 +67,7 @@ public Collection createComponents( Supplier repositoriesServiceSupplier ) { this.commandIndex = new CommandIndex(client, clusterService, threadPool); - this.pluginSettings = PluginSettings.getPluginSettingsInstance(); - pluginSettings.setEnv(environment); + PluginSettings.getInstance().setEnvironment(environment); // HttpRestClient stuff String uri = "https://httpbin.org/post"; @@ -93,12 +91,12 @@ public List getRestHandlers( @Override public List> getSettings() { return Arrays.asList( - // Register EC2 discovery settings: discovery.ec2 - CommandManagerSettings.ACCESS_KEY_SETTING, - CommandManagerSettings.SECRET_KEY_SETTING, - CommandManagerSettings.SESSION_TOKEN_SETTING, - CommandManagerSettings.PROXY_HOST_SETTING, - CommandManagerSettings.PROXY_PORT_SETTING + // Register API settings + CommandManagerSettings.KEYSTORE, + CommandManagerSettings.AUTH_USERNAME, + CommandManagerSettings.AUTH_PASSWORD, + CommandManagerSettings.URI, + CommandManagerSettings.AUTH_TYPE ); } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 0362e10..04789af 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -7,73 +7,70 @@ */ package com.wazuh.commandmanager.settings; import org.opensearch.common.settings.Setting; -import org.opensearch.common.settings.Setting.Property; import org.opensearch.common.settings.SecureSetting; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; public final class CommandManagerSettings { -//THE DEFINITIONS OF WHAT KEYS ARE NECESSARY ARE PENDING - /** The access key (ie login id) for connecting to ec2. */ - public static final Setting ACCESS_KEY_SETTING = SecureSetting.secureString("command.manager.access_key", null); + /** The access key (ie login id) for connecting to api. */ + public static final Setting KEYSTORE = SecureSetting.secureString("command.manager.keystore", null); - /** The secret key (ie password) for connecting to ec2. */ - public static final Setting SECRET_KEY_SETTING = SecureSetting.secureString("command.manager.secret_key", null); + /** The access key (ie login username) for connecting to api. */ + public static final Setting AUTH_USERNAME = SecureSetting.secureString("command.manager.auth.username", null); - /** The session token for connecting to ec2. */ - public static final Setting SESSION_TOKEN_SETTING = SecureSetting.secureString("command.manager.session_token", null); + /** The secret key (ie password) for connecting to api. */ + public static final Setting AUTH_PASSWORD = SecureSetting.secureString("command.manager.auth.password", null); - /** The host name of a proxy to connect to ec2 through. */ - public static final Setting PROXY_HOST_SETTING = Setting.simpleString("command.manager.proxy.host", Property.NodeScope); + /** The uri for connecting to api. */ + public static final Setting URI = SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); - /** The port of a proxy to connect to ec2 through. */ - public static final Setting PROXY_PORT_SETTING = Setting.intSetting("command.manager.proxy.port", 80, 0, 1 << 16, Property.NodeScope); + /** The auth type for connecting to api. */ + public static final Setting AUTH_TYPE = Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); - /** An optional proxy host that requests to ec2 should be made through. */ - final String accessKey; + /** The access key (ie login username) for connecting to api. */ + final String keystore; - /** The secret key (ie password) for connecting to ec2. */ - final String secretKey; + /** The access key (ie login username) for connecting to api. */ + final String authUsername; - /** The session token for connecting to ec2. */ - final String sessionToken; + /** The password for connecting to api. */ + final String authPassword; - /** An optional proxy host that requests to ec2 should be made through. */ - final String proxyHost; + /** The uri for connecting to api. */ + final String uri; - /** The port number the proxy host should be connected on. */ - final int proxyPort; + /** The auth type for connecting to api. */ + final String authType; protected CommandManagerSettings( - String accessKey, - String secretKey, - String sessionToken, - String proxyHost, - int proxyPort + String keystore, + String authUsername, + String authPassword, + String uri, + String authType ) { - this.accessKey = accessKey; - this.secretKey = secretKey; - this.sessionToken = sessionToken; - this.proxyHost = proxyHost; - this.proxyPort = proxyPort;} + this.keystore = keystore; + this.authUsername = authUsername; + this.authPassword = authPassword; + this.uri = uri; + this.authType = authType;} /** Parse settings for a single client. */ public static CommandManagerSettings getClientSettings(Settings settings) { - //final AwsCredentials credentials = loadCredentials(settings); no estoy segura de si tendrĂ­amos que configurar algo asociado a AWS, supongo que no try( - SecureString accessKey = ACCESS_KEY_SETTING.get(settings); - SecureString secretKey = SECRET_KEY_SETTING.get(settings); - SecureString sessionToken = SESSION_TOKEN_SETTING.get(settings); + SecureString keystore = KEYSTORE.get(settings); + SecureString authUsername = AUTH_USERNAME.get(settings); + SecureString authPassword = AUTH_PASSWORD.get(settings); ){ return new CommandManagerSettings( - accessKey.toString(), - secretKey.toString(), - sessionToken.toString(), - PROXY_HOST_SETTING.get(settings), - PROXY_PORT_SETTING.get(settings) + keystore.toString(), + authUsername.toString(), + authPassword.toString(), + URI.get(settings), + AUTH_TYPE.get(settings) ); } } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java index 6082bfd..666399c 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java @@ -25,44 +25,43 @@ public class PluginSettings { private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; - private static KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.create(); - private static Environment env; + private KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.create(); + private Environment environment; - private PluginSettings() { + private PluginSettings(KeyStoreWrapper keyStoreWrapper) { // Singleton class, use getPluginSettings method instead of constructor + this.keyStoreWrapper = keyStoreWrapper; } - public static PluginSettings getPluginSettingsInstance() { - if (INSTANCE != null) { - return INSTANCE; - } + public static PluginSettings getInstance() { synchronized (PluginSettings.class) { if (INSTANCE != null) { return INSTANCE; } - INSTANCE = new PluginSettings(); + KeyStoreWrapper keyStoreWrapper1 = KeyStoreWrapper.create(); + INSTANCE = new PluginSettings(keyStoreWrapper1); return INSTANCE; } } - public void setEnv(Environment env) { - PluginSettings.env = env; + public void setEnvironment(Environment environment) { + this.environment = environment; } - static SecureSettings loadSecureSettings(SecureString secureSettingsPassword) throws CommandManagerSettingsException, GeneralSecurityException { + public SecureSettings loadSecureSettings(SecureString secureSettingsPassword) throws CommandManagerSettingsException, GeneralSecurityException { try { //Open the keystore file - keyStoreWrapper = KeyStoreWrapper.load(env.configFile(),KEYSTORE_FILENAME); - if (keyStoreWrapper == null) { - logger.info(CommandManagerSettingsException.keystoreNotExist(env.configFile().toString()).getMessage()); + this.keyStoreWrapper = KeyStoreWrapper.load( this.environment.configFile(),KEYSTORE_FILENAME); + if ( this.keyStoreWrapper == null) { + logger.info(CommandManagerSettingsException.keystoreNotExist( this.environment.configFile().toString()).getMessage()); //Create keystore file if it doesn't exist - keyStoreWrapper = KeyStoreWrapper.create(); - keyStoreWrapper.save(env.configFile(), new char[0]); + this.keyStoreWrapper = KeyStoreWrapper.create(); + this.keyStoreWrapper.save( this.environment.configFile(), new char[0]); } else { // Decrypt the keystore using the password from the request - keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + this.keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); //Here TransportNodesReloadSecureSettingsAction reload the plugins, but our PLugin isn't ReloadablePlugin // final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); } @@ -73,16 +72,16 @@ static SecureSettings loadSecureSettings(SecureString secureSettingsPassword) th } finally { secureSettingsPassword.close(); } - return keyStoreWrapper; + return this.keyStoreWrapper; } public SecureSettings upgradeKeyStore( char[] password){ try { - KeyStoreWrapper.upgrade(keyStoreWrapper, env.configFile(), password); + KeyStoreWrapper.upgrade( this.keyStoreWrapper, this.environment.configFile(), password); } catch (Exception e) { throw new RuntimeException(e); } - return keyStoreWrapper; + return this.keyStoreWrapper; } } \ No newline at end of file diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java index 39e744f..a85928e 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java @@ -31,8 +31,8 @@ public void setUp() { // Create a mock Environment mockEnvironment = mock(Environment.class); // Instantiate PluginSettings - pluginSettings = PluginSettings.getPluginSettingsInstance(); - pluginSettings.setEnv(mockEnvironment); + pluginSettings = PluginSettings.getInstance(); + pluginSettings.setEnvironment(mockEnvironment); } @After @@ -51,7 +51,7 @@ public void testLoadSecureSettings_keystoreNotExist() throws Exception { when(KeyStoreWrapper.load(any(), any())).thenReturn(null); // Check that the keystore is created - SecureSettings result = PluginSettings.loadSecureSettings(secureString); + SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); assertNotNull(result); verify(keyStoreWrapperMock, times(1)).save(any(), any()); @@ -70,7 +70,7 @@ public void testLoadSecureSettings_keystoreExists() throws Exception { keyStoreWrapperMock.decrypt(passToTest); // Load secure settings - SecureSettings result = PluginSettings.loadSecureSettings(secureString); + SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); assertNotNull(result); verify(keyStoreWrapperMock, times(1)).decrypt(secureString.getChars()); diff --git a/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json b/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json index 090251c..c93a5df 100644 --- a/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json +++ b/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json @@ -2,10 +2,10 @@ { "name" : "wazuh-api", "properties" : { - "prometheus.uri" : "http://localhost:9090", - "prometheus.auth.type" : "basicauth", - "prometheus.auth.username" : "admin", - "prometheus.auth.password" : "type" + "uri" : "http://localhost:9090", + "auth.type" : "basicauth", + "auth.username" : "admin", + "auth.password" : "type" } } ] \ No newline at end of file From f69c68dbf1863f98a5e442577725d7434226ef53 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Tue, 15 Oct 2024 14:47:17 -0300 Subject: [PATCH 07/23] Add password in save of KeyStoreWrapper and do some changes to reload plugin --- .../commandmanager/CommandManagerPlugin.java | 2 +- .../CommandManagerSettingsException.java | 5 +++++ .../settings/PluginSettings.java | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index a1c8c72..c607f6d 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -105,7 +105,7 @@ public void reload(Settings settings) { // secure settings should be readable final CommandManagerSettings commandManagerSettings = CommandManagerSettings.getClientSettings(settings); //I don't know what I have to do when we want to reload the settings already - //ec2Service.refreshAndClearCache(commandManagerSettings); + //xxxService.refreshAndClearCache(commandManagerSettings); } /** diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java index bb66f51..d7dcf10 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java @@ -39,5 +39,10 @@ public static CommandManagerSettingsException keystoreNotExist(String keystorePa public static CommandManagerSettingsException keystoreEmpty(String keystorePath) { return new CommandManagerSettingsException("The keystore is empty at the path: " + keystorePath); } + + // Exception for the case when reload plugin with the keystore failed + public static CommandManagerSettingsException reloadPluginFailed(String pluginName) { + return new CommandManagerSettingsException("Reload failed for plugin: " + pluginName); + } } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java index 666399c..592c212 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java @@ -7,15 +7,16 @@ */ package com.wazuh.commandmanager.settings; +import com.wazuh.commandmanager.CommandManagerPlugin; import com.wazuh.commandmanager.CommandManagerSettingsException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Logger; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.SecureSettings; +import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; -import java.io.IOException; import java.security.GeneralSecurityException; public class PluginSettings { @@ -57,18 +58,20 @@ public SecureSettings loadSecureSettings(SecureString secureSettingsPassword) th //Create keystore file if it doesn't exist this.keyStoreWrapper = KeyStoreWrapper.create(); - this.keyStoreWrapper.save( this.environment.configFile(), new char[0]); - + this.keyStoreWrapper.save( this.environment.configFile(), secureSettingsPassword.getChars()); } else { // Decrypt the keystore using the password from the request this.keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); - //Here TransportNodesReloadSecureSettingsAction reload the plugins, but our PLugin isn't ReloadablePlugin - // final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); + final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); + CommandManagerPlugin commandManagerPlugin = new CommandManagerPlugin(); + try { + commandManagerPlugin.reload(settingsWithKeystore); + }catch (final Exception e) { + logger.warn(CommandManagerSettingsException.reloadPluginFailed(commandManagerPlugin.getClass().getSimpleName())); + } } - } catch (IOException e) { + } catch (Exception e) { throw new CommandManagerSettingsException(e); - } catch (Exception e) { - throw new RuntimeException(e); } finally { secureSettingsPassword.close(); } From 67c7434a490deecf5e20fbc1b2a09cd1c8c5dc87 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Wed, 16 Oct 2024 15:53:41 -0300 Subject: [PATCH 08/23] Plugin Settings Unit Test --- plugins/command-manager/build.gradle | 8 +- .../settings/PluginSettings.java | 19 ++- .../plugin-metadata/plugin-security.policy | 3 +- .../settings/PluginSettingsTests.java | 127 ++++++++++++++---- 4 files changed, 125 insertions(+), 32 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 98b57be..5e3fe22 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -56,7 +56,9 @@ def versions = [ httpcore5: "5.3", slf4j: "1.7.36", log4j: "2.23.1", - conscrypt: "2.5.2" + conscrypt: "2.5.2", + mockito: "4.1.0", + junit:"4.13.2" ] dependencies { @@ -66,6 +68,9 @@ dependencies { api "org.apache.logging.log4j:log4j-slf4j-impl:${versions.log4j}" api "org.slf4j:slf4j-api:${versions.slf4j}" api "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}" + + testImplementation "org.mockito:mockito-inline:${versions.mockito}" + testImplementation "junit:junit:${versions.junit}" } // This requires an additional Jar not published as part of build-tools @@ -108,6 +113,7 @@ repositories { test { include '**/*Tests.class' + jvmArgs "-Djava.security.policy=./plugins/command-manager/src/main/plugin-metadata/plugin-security.policy/plugin-security.policy" } task integTest(type: RestIntegTestTask) { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java index 592c212..986a906 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java @@ -26,7 +26,7 @@ public class PluginSettings { private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; - private KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.create(); + private KeyStoreWrapper keyStoreWrapper; private Environment environment; private PluginSettings(KeyStoreWrapper keyStoreWrapper) { @@ -61,13 +61,16 @@ public SecureSettings loadSecureSettings(SecureString secureSettingsPassword) th this.keyStoreWrapper.save( this.environment.configFile(), secureSettingsPassword.getChars()); } else { // Decrypt the keystore using the password from the request - this.keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + if(this.keyStoreWrapper.hasPassword()){ + this.keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + } final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - CommandManagerPlugin commandManagerPlugin = new CommandManagerPlugin(); + //CommandManagerPlugin commandManagerPlugin = new CommandManagerPlugin(); try { - commandManagerPlugin.reload(settingsWithKeystore); + /* HERE WE HAVE TO RELOAD THE PLUGIN BUT I DON'T LIKE THE IDEA OF CREATE A NEW PLUGIN TO RELOAD IT*/ + //commandManagerPlugin.reload(settingsWithKeystore); }catch (final Exception e) { - logger.warn(CommandManagerSettingsException.reloadPluginFailed(commandManagerPlugin.getClass().getSimpleName())); + //logger.warn(CommandManagerSettingsException.reloadPluginFailed(commandManagerPlugin.getClass().getSimpleName())); } } } catch (Exception e) { @@ -75,7 +78,7 @@ public SecureSettings loadSecureSettings(SecureString secureSettingsPassword) th } finally { secureSettingsPassword.close(); } - return this.keyStoreWrapper; + return this.keyStoreWrapper; } public SecureSettings upgradeKeyStore( char[] password){ @@ -87,4 +90,8 @@ public SecureSettings upgradeKeyStore( char[] password){ return this.keyStoreWrapper; } + // Keep this method package-private for test access + KeyStoreWrapper getKeyStoreWrapper() { + return this.keyStoreWrapper; + } } \ No newline at end of file diff --git a/plugins/command-manager/src/main/plugin-metadata/plugin-security.policy b/plugins/command-manager/src/main/plugin-metadata/plugin-security.policy index 6e4d716..99dcb0b 100644 --- a/plugins/command-manager/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/command-manager/src/main/plugin-metadata/plugin-security.policy @@ -1,3 +1,4 @@ grant { permission java.net.SocketPermission "*", "connect,resolve"; -}; \ No newline at end of file + permission java.io.FilePermission "*", "read,write"; +}; diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java index a85928e..c608912 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java @@ -7,32 +7,56 @@ */ package com.wazuh.commandmanager.settings; +import com.wazuh.commandmanager.CommandManagerSettingsException; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.SecureSettings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; import org.opensearch.test.OpenSearchIntegTestCase; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Path; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.GeneralSecurityException; +import java.security.PrivilegedAction; import static org.mockito.Mockito.*; @OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) public class PluginSettingsTests extends OpenSearchIntegTestCase { - private PluginSettings pluginSettings; + + @Mock private Environment mockEnvironment; + + private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); + @Mock + KeyStoreWrapper mockedKeyStoreWrapper; + + @InjectMocks + private PluginSettings pluginSettings; + @Before - public void setUp() { - // Create a mock Environment + @Override + public void setUp() throws Exception { + mockedKeyStoreWrapper = mock(KeyStoreWrapper.class); mockEnvironment = mock(Environment.class); // Instantiate PluginSettings pluginSettings = PluginSettings.getInstance(); pluginSettings.setEnvironment(mockEnvironment); + super.setUp(); } @After @@ -42,37 +66,92 @@ public void closeSecureString() { } public void testLoadSecureSettings_keystoreNotExist() throws Exception { - // Set up the mock to return a specific path for the config file - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/wazuh-indexer.keystoreUNEXISTENT.json"); - when(mockEnvironment.configFile()).thenReturn(keyStorePath); + try { + AccessController.doPrivileged( + (PrivilegedAction) () -> { + // Set up the mock to return a specific path for the config file + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); + when(mockEnvironment.configFile()).thenReturn(keyStorePath); + + //Invoke the method under test and Check that the keystore doesn't exist + SecureSettings result = null; + try { + result = this.pluginSettings.loadSecureSettings(this.secureString); + } catch (CommandManagerSettingsException | GeneralSecurityException | AccessControlException e) { + System.out.println(e.getMessage()); + } - // Mocking the keyStoreWrapper to return null - KeyStoreWrapper keyStoreWrapperMock = mock(KeyStoreWrapper.class); - when(KeyStoreWrapper.load(any(), any())).thenReturn(null); + KeyStoreWrapper keyStoreWrapper = this.pluginSettings.getKeyStoreWrapper(); + + //assertNotNull(result); + // Verify that the methods were called on the spy + boolean isLoaded = keyStoreWrapper.isLoaded(); + assertTrue(isLoaded); + + try { +// verify(mockedKeyStoreWrapper, only()).save(any(Path.class), new char[]{anyChar()}); + // verify(mockedKeyStoreWrapper).decrypt(any()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // Mock the static method KeyStoreWrapper.load(...) + /* try (MockedStatic mockedKeyStore = Mockito.mockStatic(KeyStoreWrapper.class)) { + mockedKeyStore.when(() -> KeyStoreWrapper.load(any(Path.class), anyString())).thenReturn(null); + + // Create a spy for KeyStoreWrapper to verify save method call + KeyStoreWrapper spyKeyStore = Mockito.spy(KeyStoreWrapper.create()); + + //Invoke the method under test and Check that the keystore doesn't exist + SecureSettings result = this.pluginSettings.loadSecureSettings(this.secureString); + + assertNotNull(result); + + // Verify that load() was called + mockedKeyStore.verify(() -> KeyStoreWrapper.load(any(Path.class), anyString()), times(1)); + + // Verify that save() was called once on the KeyStoreWrapper spy + Mockito.verify(spyKeyStore, times(1)).save(any(Path.class), any(char[].class)); + } + */ + return null; + } + ); + }catch(AccessControlException e){ + + } - // Check that the keystore is created - SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); - assertNotNull(result); - verify(keyStoreWrapperMock, times(1)).save(any(), any()); } public void testLoadSecureSettings_keystoreExists() throws Exception { // Set up the mock to return a specific path for the config file - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/"); + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); when(mockEnvironment.configFile()).thenReturn(keyStorePath); + System.out.println("ACAAAAAAAAAAAAAAA Attempting to read file: " + new File("plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json").getAbsolutePath()); + + try { + AccessController.doPrivileged( + (PrivilegedAction) () -> { + // Simulate an existing keystore + KeyStoreWrapper keyStoreWrapper = this.pluginSettings.getKeyStoreWrapper(); + try { + keyStoreWrapper = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); + when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapper); - // Simulate an existing keystore - KeyStoreWrapper keyStoreWrapperMock = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); - when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapperMock); - String text = "type"; - char[] passToTest = text.toCharArray(); - keyStoreWrapperMock.decrypt(passToTest); + // Load secure settings + SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); - // Load secure settings - SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); + assertNotNull(result); + // verify(keyStoreWrapper, times(1)).decrypt(secureString.getChars()); + } catch (IOException | CommandManagerSettingsException | GeneralSecurityException e) { + throw new RuntimeException(e); + } + return null; + } + ); + }catch(AccessControlException e){ - assertNotNull(result); - verify(keyStoreWrapperMock, times(1)).decrypt(secureString.getChars()); + } } } From 4eb73395640bb7b81bbcf84944a107aae04c8cff Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Thu, 17 Oct 2024 11:38:49 -0300 Subject: [PATCH 09/23] Refactor of CommandManagerSettings to manage all the settings of the plugin and the keystore load in this class. --- .../commandmanager/CommandManagerPlugin.java | 7 +- .../CommandManagerSettingsException.java | 10 ++ .../settings/CommandManagerSettings.java | 141 +++++++++++++++--- 3 files changed, 139 insertions(+), 19 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index c607f6d..5b0c897 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -19,6 +19,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.*; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.common.settings.SecureString; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; @@ -51,6 +52,7 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin, Reload public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; private CommandIndex commandIndex; + private CommandManagerSettings commandManagerSettings; @Override public Collection createComponents( @@ -67,7 +69,8 @@ public Collection createComponents( Supplier repositoriesServiceSupplier ) { this.commandIndex = new CommandIndex(client, clusterService, threadPool); - PluginSettings.getInstance().setEnvironment(environment); + + commandManagerSettings = CommandManagerSettings.getSettings(environment); // HttpRestClient stuff String uri = "https://httpbin.org/post"; @@ -103,7 +106,7 @@ public List> getSettings() { @Override public void reload(Settings settings) { // secure settings should be readable - final CommandManagerSettings commandManagerSettings = CommandManagerSettings.getClientSettings(settings); + //final CommandManagerSettings commandManagerSettings = CommandManagerSettings.getClientSettings(secureSettingsPassword); //I don't know what I have to do when we want to reload the settings already //xxxService.refreshAndClearCache(commandManagerSettings); } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java index d7dcf10..78a24fc 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java @@ -40,6 +40,16 @@ public static CommandManagerSettingsException keystoreEmpty(String keystorePath) return new CommandManagerSettingsException("The keystore is empty at the path: " + keystorePath); } + // Exception for the case when load keystore failed + public static CommandManagerSettingsException loadKeystoreFailed(String keyStorePath) { + return new CommandManagerSettingsException("Load keystore: "+ keyStorePath +" failed."); + } + + // Exception for the case when load keystore failed + public static CommandManagerSettingsException decryptKeystoreFailed(String keyStorePath) { + return new CommandManagerSettingsException("Decrypt keystore: "+ keyStorePath +" failed."); + } + // Exception for the case when reload plugin with the keystore failed public static CommandManagerSettingsException reloadPluginFailed(String pluginName) { return new CommandManagerSettingsException("Reload failed for plugin: " + pluginName); diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 04789af..833bd6b 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -6,44 +6,79 @@ * compatible open source license. */ package com.wazuh.commandmanager.settings; +import com.wazuh.commandmanager.CommandManagerSettingsException; +import org.opensearch.common.io.PathUtils; +import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.SecureSetting; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; +import org.opensearch.env.Environment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.security.GeneralSecurityException; public final class CommandManagerSettings { + /** + * The name of own keystore. + */ + private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; - /** The access key (ie login id) for connecting to api. */ + /** + * The access key (ie login id) for connecting to api. + */ public static final Setting KEYSTORE = SecureSetting.secureString("command.manager.keystore", null); - /** The access key (ie login username) for connecting to api. */ + /** + * The access key (ie login username) for connecting to api. + */ public static final Setting AUTH_USERNAME = SecureSetting.secureString("command.manager.auth.username", null); - /** The secret key (ie password) for connecting to api. */ + /** + * The secret key (ie password) for connecting to api. + */ public static final Setting AUTH_PASSWORD = SecureSetting.secureString("command.manager.auth.password", null); - /** The uri for connecting to api. */ + /** + * The uri for connecting to api. + */ public static final Setting URI = SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); - /** The auth type for connecting to api. */ + /** + * The auth type for connecting to api. + */ public static final Setting AUTH_TYPE = Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); + private static final Logger log = LoggerFactory.getLogger(CommandManagerSettings.class); - /** The access key (ie login username) for connecting to api. */ + /** + * The access key (ie login username) for connecting to api. + */ final String keystore; - /** The access key (ie login username) for connecting to api. */ + /** + * The access key (ie login username) for connecting to api. + */ final String authUsername; - /** The password for connecting to api. */ + /** + * The password for connecting to api. + */ final String authPassword; - /** The uri for connecting to api. */ + /** + * The uri for connecting to api. + */ final String uri; - /** The auth type for connecting to api. */ + /** + * The auth type for connecting to api. + */ final String authType; + private Environment environment; + protected CommandManagerSettings( String keystore, @@ -56,22 +91,94 @@ protected CommandManagerSettings( this.authUsername = authUsername; this.authPassword = authPassword; this.uri = uri; - this.authType = authType;} + this.authType = authType; + } + + /** + * Parse settings for a single client. + */ + public static CommandManagerSettings getSettings(Environment environment, SecureString secureSettingsPassword) { + + //Environment environment = new Environment(null, PathUtils.get(System.getProperty("user.dir"))); + KeyStoreWrapper keyStoreWrapper = null; + + try { + keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); + } catch (IOException e) { + log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath().toString() + KEYSTORE_FILENAME).getMessage()); + } + + if (keyStoreWrapper == null) { + log.error(CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME).getMessage()); + return null; + } else { + // Decrypt the keystore using the password from the request + if (keyStoreWrapper.hasPassword()) { + try { + keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + } catch (GeneralSecurityException | IOException e) { + log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); + } + } + + final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); + + try ( + SecureString authUsername = AUTH_USERNAME.get(settings); + SecureString authPassword = AUTH_PASSWORD.get(settings); + ) { + return new CommandManagerSettings( + KEYSTORE_FILENAME, + authUsername.toString(), + authPassword.toString(), + URI.get(settings), + AUTH_TYPE.get(settings) + ); + } + } + } + + /** + * Parse settings for a single client. + */ + public static CommandManagerSettings getSettings(Environment environment) { - /** Parse settings for a single client. */ - public static CommandManagerSettings getClientSettings(Settings settings) { - try( - SecureString keystore = KEYSTORE.get(settings); + KeyStoreWrapper keyStoreWrapper = null; + + try { + keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); + } catch (IOException e) { + log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath().toString() + KEYSTORE_FILENAME).getMessage()); + } + + if (keyStoreWrapper == null) { + log.error(CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME).getMessage()); + return null; + } else { + // Decrypt the keystore using the password from the request + if (keyStoreWrapper.hasPassword()) { + try { + keyStoreWrapper.decrypt(new char[0]); + } catch (GeneralSecurityException | IOException e) { + log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); + } + } + final Settings settings =Settings.builder().setSecureSettings(keyStoreWrapper).build(); + + try ( SecureString authUsername = AUTH_USERNAME.get(settings); SecureString authPassword = AUTH_PASSWORD.get(settings); - ){ + ) { return new CommandManagerSettings( - keystore.toString(), + KEYSTORE_FILENAME, authUsername.toString(), authPassword.toString(), URI.get(settings), AUTH_TYPE.get(settings) ); + } } } + } + From bba618dfdf7dbf4a882c61755fb5f65b08cca05c Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Thu, 17 Oct 2024 18:14:30 -0300 Subject: [PATCH 10/23] Fix some errors in COmmandManagerSettings and create the associated unit test. Also delete the PluginSettings class. --- plugins/command-manager/build.gradle | 51 ++++++ .../commandmanager/CommandManagerPlugin.java | 5 +- .../settings/CommandManagerSettings.java | 40 +++-- .../settings/PluginSettings.java | 97 ----------- .../settings/CommandManagerSettingsTests.java | 94 +++++++++++ .../settings/PluginSettingsTests.java | 157 ------------------ 6 files changed, 170 insertions(+), 274 deletions(-) delete mode 100644 plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java create mode 100644 plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java delete mode 100644 plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 5e3fe22..366012b 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -1,5 +1,7 @@ + import org.opensearch.gradle.test.RestIntegTestTask + apply plugin: 'java' apply plugin: 'idea' apply plugin: 'eclipse' @@ -104,6 +106,8 @@ buildscript { } } + + repositories { mavenLocal() maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" } @@ -123,6 +127,53 @@ task integTest(type: RestIntegTestTask) { } tasks.named("check").configure { dependsOn(integTest) } + +//OPCION 1 +/* +// needed to be consistent with ssl host checking +String host = InetAddress.getLoopbackAddress().getHostAddress() + +// location of keystore and files to generate it +File keystore = new File(project.buildDir, 'keystore/wazuh-indexer.keystore.jks') + +// generate the keystore + +TaskProvider createKey = tasks.register("createKey", LoggedExec) { + doFirst { + delete(keystore.parentFile) + keystore.parentFile.mkdirs() + } + outputs.file(keystore).withPropertyName('keystoreFile') + executable = "${BuildParams.runtimeJavaHome}/bin/keytool" + standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8')) + args '-genkey', + '-alias', 'test-node', + '-keystore', keystore, + '-keyalg', 'RSA', + '-keysize', '2048', + '-validity', '712', + '-dname', 'CN=' + host, + '-keypass', 'keypass', + '-storepass', 'keypass' +} + +//no unit tests +tasks.named("test").configure { enabled = false } +// add keystore to test classpath: it expects it there +tasks.named("processInternalClusterTestResources").configure { + from createKey +} + +normalization { + runtimeClasspath { + ignore 'test-node.jks' + } +} + + */ + +//OPCION 2 + integTest { // The --debug-jvm command-line option makes the cluster debuggable; this makes the tests debuggable if (System.getProperty("test.debug") != null) { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 5b0c897..f05ee17 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -10,16 +10,16 @@ import com.wazuh.commandmanager.index.CommandIndex; import com.wazuh.commandmanager.rest.action.RestPostCommandAction; import com.wazuh.commandmanager.settings.CommandManagerSettings; -import com.wazuh.commandmanager.settings.PluginSettings; import com.wazuh.commandmanager.utils.httpclient.HttpRestClient; import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.*; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; -import org.opensearch.core.common.settings.SecureString; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; @@ -50,6 +50,7 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin, Reload public static final String COMMAND_MANAGER_BASE_URI = "/_plugins/_commandmanager"; public static final String COMMAND_MANAGER_INDEX_NAME = ".commands"; public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; + private static final Logger log = LogManager.getLogger(CommandManagerPlugin.class); private CommandIndex commandIndex; private CommandManagerSettings commandManagerSettings; diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 833bd6b..2b449e3 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -7,6 +7,8 @@ */ package com.wazuh.commandmanager.settings; import com.wazuh.commandmanager.CommandManagerSettingsException; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.opensearch.common.io.PathUtils; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.Setting; @@ -14,17 +16,20 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; import java.security.GeneralSecurityException; public final class CommandManagerSettings { + private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); + /** * The name of own keystore. */ - private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; + private static final String KEYSTORE_FILENAME = "opensearch.keystore"; //"wazuh-indexer.keystore"; /** * The access key (ie login id) for connecting to api. @@ -50,7 +55,6 @@ public final class CommandManagerSettings { * The auth type for connecting to api. */ public static final Setting AUTH_TYPE = Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); - private static final Logger log = LoggerFactory.getLogger(CommandManagerSettings.class); /** * The access key (ie login username) for connecting to api. @@ -77,9 +81,6 @@ public final class CommandManagerSettings { */ final String authType; - private Environment environment; - - protected CommandManagerSettings( String keystore, String authUsername, @@ -99,7 +100,6 @@ protected CommandManagerSettings( */ public static CommandManagerSettings getSettings(Environment environment, SecureString secureSettingsPassword) { - //Environment environment = new Environment(null, PathUtils.get(System.getProperty("user.dir"))); KeyStoreWrapper keyStoreWrapper = null; try { @@ -142,28 +142,33 @@ public static CommandManagerSettings getSettings(Environment environment, Secure * Parse settings for a single client. */ public static CommandManagerSettings getSettings(Environment environment) { - KeyStoreWrapper keyStoreWrapper = null; - + Path keystoreFile = Path.of(environment.configFile()+"/"+KEYSTORE_FILENAME); try { - keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); - } catch (IOException e) { - log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath().toString() + KEYSTORE_FILENAME).getMessage()); + if (!Files.exists(keystoreFile)){ + throw CommandManagerSettingsException.keystoreNotExist(keystoreFile.toAbsolutePath().toString()); + //Path keyStorePath = Files.createFile(keystoreFile); + //log.warn("CREADA KeyStoreWrapper en "+keyStorePath.toString()); + }else{ + log.warn("Por hacer load de KeyStoreWrapper en "+environment.configFile().toString()); + keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); + } + } catch (Exception e) { + log.error(CommandManagerSettingsException.loadKeystoreFailed(keystoreFile.toString()).getMessage()); } if (keyStoreWrapper == null) { - log.error(CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME).getMessage()); + log.error(CommandManagerSettingsException.keystoreNotExist(keystoreFile.toString()).getMessage()); return null; } else { // Decrypt the keystore using the password from the request - if (keyStoreWrapper.hasPassword()) { try { keyStoreWrapper.decrypt(new char[0]); } catch (GeneralSecurityException | IOException e) { log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); } - } - final Settings settings =Settings.builder().setSecureSettings(keyStoreWrapper).build(); + + final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); try ( SecureString authUsername = AUTH_USERNAME.get(settings); @@ -179,6 +184,5 @@ public static CommandManagerSettings getSettings(Environment environment) { } } } - } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java deleted file mode 100644 index 986a906..0000000 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ -package com.wazuh.commandmanager.settings; - -import com.wazuh.commandmanager.CommandManagerPlugin; -import com.wazuh.commandmanager.CommandManagerSettingsException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Logger; -import org.opensearch.common.settings.KeyStoreWrapper; -import org.opensearch.common.settings.SecureSettings; -import org.opensearch.common.settings.Settings; -import org.opensearch.core.common.settings.SecureString; -import org.opensearch.env.Environment; - -import java.security.GeneralSecurityException; - -public class PluginSettings { - private static final Logger logger = (Logger) LogManager.getLogger(PluginSettings.class); - - private static PluginSettings INSTANCE; - - private static final String KEYSTORE_FILENAME = "wazuh-indexer.keystore"; - - private KeyStoreWrapper keyStoreWrapper; - private Environment environment; - - private PluginSettings(KeyStoreWrapper keyStoreWrapper) { - // Singleton class, use getPluginSettings method instead of constructor - this.keyStoreWrapper = keyStoreWrapper; - } - - public static PluginSettings getInstance() { - synchronized (PluginSettings.class) { - if (INSTANCE != null) { - return INSTANCE; - } - KeyStoreWrapper keyStoreWrapper1 = KeyStoreWrapper.create(); - INSTANCE = new PluginSettings(keyStoreWrapper1); - return INSTANCE; - } - } - - public void setEnvironment(Environment environment) { - this.environment = environment; - } - - public SecureSettings loadSecureSettings(SecureString secureSettingsPassword) throws CommandManagerSettingsException, GeneralSecurityException { - try { - //Open the keystore file - this.keyStoreWrapper = KeyStoreWrapper.load( this.environment.configFile(),KEYSTORE_FILENAME); - if ( this.keyStoreWrapper == null) { - logger.info(CommandManagerSettingsException.keystoreNotExist( this.environment.configFile().toString()).getMessage()); - - //Create keystore file if it doesn't exist - this.keyStoreWrapper = KeyStoreWrapper.create(); - this.keyStoreWrapper.save( this.environment.configFile(), secureSettingsPassword.getChars()); - } else { - // Decrypt the keystore using the password from the request - if(this.keyStoreWrapper.hasPassword()){ - this.keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); - } - final Settings settingsWithKeystore = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - //CommandManagerPlugin commandManagerPlugin = new CommandManagerPlugin(); - try { - /* HERE WE HAVE TO RELOAD THE PLUGIN BUT I DON'T LIKE THE IDEA OF CREATE A NEW PLUGIN TO RELOAD IT*/ - //commandManagerPlugin.reload(settingsWithKeystore); - }catch (final Exception e) { - //logger.warn(CommandManagerSettingsException.reloadPluginFailed(commandManagerPlugin.getClass().getSimpleName())); - } - } - } catch (Exception e) { - throw new CommandManagerSettingsException(e); - } finally { - secureSettingsPassword.close(); - } - return this.keyStoreWrapper; - } - - public SecureSettings upgradeKeyStore( char[] password){ - try { - KeyStoreWrapper.upgrade( this.keyStoreWrapper, this.environment.configFile(), password); - } catch (Exception e) { - throw new RuntimeException(e); - } - return this.keyStoreWrapper; - } - - // Keep this method package-private for test access - KeyStoreWrapper getKeyStoreWrapper() { - return this.keyStoreWrapper; - } -} \ No newline at end of file diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java new file mode 100644 index 0000000..6d81384 --- /dev/null +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ +package com.wazuh.commandmanager.settings; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.opensearch.common.settings.KeyStoreWrapper; +import org.opensearch.core.common.settings.SecureString; +import org.opensearch.env.Environment; +import org.opensearch.test.OpenSearchIntegTestCase; + +import java.io.IOException; +import java.nio.file.Path; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) +public class CommandManagerSettingsTests extends OpenSearchIntegTestCase{ + @Mock + private Environment mockEnvironment; + + + private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); + + @Mock + KeyStoreWrapper mockedKeyStoreWrapper; + + private CommandManagerSettings commandManagerSettings; + + private static final Logger log = LogManager.getLogger(CommandManagerSettingsTests.class); + + + @Before + @Override + public void setUp() throws Exception { + mockedKeyStoreWrapper = mock(KeyStoreWrapper.class); + mockEnvironment = mock(Environment.class); + super.setUp(); + } + + @After + public void closeSecureString() { + // Cleanup if necessary + secureString.close(); + } + + public void testGetSettings_keystoreExists() throws Exception { + // Set up the mock to return a specific path for the config file + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); + when(mockEnvironment.configFile()).thenReturn(keyStorePath); + + //logger.error(String.format(" Attempting to read file: %s%s", keyStorePath,"wazuh-indexer.keystore.json")); + + try { + AccessController.doPrivileged( + (PrivilegedAction) () -> { + // Simulate an existing keystore + try { + KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); + when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapper); + log.warn("test INSIDE+EE"); + + this.commandManagerSettings = CommandManagerSettings.getSettings(mockEnvironment); + + assertNotNull(commandManagerSettings); + log.warn("keystore INSIDE"+commandManagerSettings.keystore); + // verify(keyStoreWrapper, times(1)).decrypt(secureString.getChars()); + } catch (IOException e) { + log.warn("ERROR TEST: "+e.getMessage()); + } + log.warn("RETURN"); + return null; + } + ); + }catch(AccessControlException e){ + + } + } +} diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java deleted file mode 100644 index c608912..0000000 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ -package com.wazuh.commandmanager.settings; - -import com.wazuh.commandmanager.CommandManagerSettingsException; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.opensearch.common.settings.KeyStoreWrapper; -import org.opensearch.common.settings.SecureSettings; -import org.opensearch.core.common.settings.SecureString; -import org.opensearch.env.Environment; -import org.opensearch.test.OpenSearchIntegTestCase; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.GeneralSecurityException; -import java.security.PrivilegedAction; - -import static org.mockito.Mockito.*; - -@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) -public class PluginSettingsTests extends OpenSearchIntegTestCase { - - - @Mock - private Environment mockEnvironment; - - - private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); - - @Mock - KeyStoreWrapper mockedKeyStoreWrapper; - - @InjectMocks - private PluginSettings pluginSettings; - - @Before - @Override - public void setUp() throws Exception { - mockedKeyStoreWrapper = mock(KeyStoreWrapper.class); - mockEnvironment = mock(Environment.class); - // Instantiate PluginSettings - pluginSettings = PluginSettings.getInstance(); - pluginSettings.setEnvironment(mockEnvironment); - super.setUp(); - } - - @After - public void closeSecureString() { - // Cleanup if necessary - secureString.close(); - } - - public void testLoadSecureSettings_keystoreNotExist() throws Exception { - try { - AccessController.doPrivileged( - (PrivilegedAction) () -> { - // Set up the mock to return a specific path for the config file - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - when(mockEnvironment.configFile()).thenReturn(keyStorePath); - - //Invoke the method under test and Check that the keystore doesn't exist - SecureSettings result = null; - try { - result = this.pluginSettings.loadSecureSettings(this.secureString); - } catch (CommandManagerSettingsException | GeneralSecurityException | AccessControlException e) { - System.out.println(e.getMessage()); - } - - KeyStoreWrapper keyStoreWrapper = this.pluginSettings.getKeyStoreWrapper(); - - //assertNotNull(result); - // Verify that the methods were called on the spy - boolean isLoaded = keyStoreWrapper.isLoaded(); - assertTrue(isLoaded); - - try { -// verify(mockedKeyStoreWrapper, only()).save(any(Path.class), new char[]{anyChar()}); - // verify(mockedKeyStoreWrapper).decrypt(any()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - // Mock the static method KeyStoreWrapper.load(...) - /* try (MockedStatic mockedKeyStore = Mockito.mockStatic(KeyStoreWrapper.class)) { - mockedKeyStore.when(() -> KeyStoreWrapper.load(any(Path.class), anyString())).thenReturn(null); - - // Create a spy for KeyStoreWrapper to verify save method call - KeyStoreWrapper spyKeyStore = Mockito.spy(KeyStoreWrapper.create()); - - //Invoke the method under test and Check that the keystore doesn't exist - SecureSettings result = this.pluginSettings.loadSecureSettings(this.secureString); - - assertNotNull(result); - - // Verify that load() was called - mockedKeyStore.verify(() -> KeyStoreWrapper.load(any(Path.class), anyString()), times(1)); - - // Verify that save() was called once on the KeyStoreWrapper spy - Mockito.verify(spyKeyStore, times(1)).save(any(Path.class), any(char[].class)); - } - */ - return null; - } - ); - }catch(AccessControlException e){ - - } - - - } - - public void testLoadSecureSettings_keystoreExists() throws Exception { - // Set up the mock to return a specific path for the config file - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - when(mockEnvironment.configFile()).thenReturn(keyStorePath); - System.out.println("ACAAAAAAAAAAAAAAA Attempting to read file: " + new File("plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json").getAbsolutePath()); - - try { - AccessController.doPrivileged( - (PrivilegedAction) () -> { - // Simulate an existing keystore - KeyStoreWrapper keyStoreWrapper = this.pluginSettings.getKeyStoreWrapper(); - try { - keyStoreWrapper = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); - when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapper); - - // Load secure settings - SecureSettings result = this.pluginSettings.loadSecureSettings(secureString); - - assertNotNull(result); - // verify(keyStoreWrapper, times(1)).decrypt(secureString.getChars()); - } catch (IOException | CommandManagerSettingsException | GeneralSecurityException e) { - throw new RuntimeException(e); - } - return null; - } - ); - }catch(AccessControlException e){ - - } - } -} From 99cf14063722d77e307ab930741d4fab78d43321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Fri, 18 Oct 2024 19:02:15 +0200 Subject: [PATCH 11/23] Log settings on load --- plugins/command-manager/build.gradle | 4 +- .../commandmanager/CommandManagerPlugin.java | 1 - .../settings/CommandManagerSettings.java | 74 +++++++++++-------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index f3ba6ab..1cb3883 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -186,10 +186,8 @@ testClusters.integTest { // add customized keystore keystore 'command.manager.keystore', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') - //keystore 'command.manager.uri', 'http://localhost:9090' - //keystore 'command.manager.auth.type', 'basicauth' keystore 'command.manager.auth.username', 'admin' - keystore 'command.manager.auth.password', 'type' + keystore 'command.manager.auth.password', 'test' } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 9c31408..3c62157 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -52,7 +52,6 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin, Reload public static final String COMMANDS_URI = COMMAND_MANAGER_BASE_URI + "/commands"; public static final String COMMAND_MANAGER_INDEX_NAME = ".commands"; public static final String COMMAND_MANAGER_INDEX_TEMPLATE_NAME = "index-template-commands"; - private static final Logger log = LogManager.getLogger(CommandManagerPlugin.class); private CommandIndex commandIndex; private CommandManagerSettings commandManagerSettings; diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 2b449e3..3fa0d86 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -6,56 +6,53 @@ * compatible open source license. */ package com.wazuh.commandmanager.settings; + import com.wazuh.commandmanager.CommandManagerSettingsException; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; -import org.opensearch.common.io.PathUtils; +import org.apache.logging.log4j.Logger; import org.opensearch.common.settings.KeyStoreWrapper; -import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.SecureSetting; +import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; import java.security.GeneralSecurityException; public final class CommandManagerSettings { - private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); - - /** - * The name of own keystore. - */ - private static final String KEYSTORE_FILENAME = "opensearch.keystore"; //"wazuh-indexer.keystore"; - /** * The access key (ie login id) for connecting to api. */ - public static final Setting KEYSTORE = SecureSetting.secureString("command.manager.keystore", null); - + public static final Setting KEYSTORE = + SecureSetting.secureString("command.manager.keystore", null); /** * The access key (ie login username) for connecting to api. */ - public static final Setting AUTH_USERNAME = SecureSetting.secureString("command.manager.auth.username", null); - + public static final Setting AUTH_USERNAME = + SecureSetting.secureString("command.manager.auth.username", null); /** * The secret key (ie password) for connecting to api. */ - public static final Setting AUTH_PASSWORD = SecureSetting.secureString("command.manager.auth.password", null); - + public static final Setting AUTH_PASSWORD = + SecureSetting.secureString("command.manager.auth.password", null); /** * The uri for connecting to api. */ - public static final Setting URI = SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); - + public static final Setting URI = + SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); /** * The auth type for connecting to api. */ - public static final Setting AUTH_TYPE = Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); - + public static final Setting AUTH_TYPE = + Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); + private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); + /** + * The name of own keystore. + */ + private static final String KEYSTORE_FILENAME = "opensearch.keystore"; //"wazuh-indexer.keystore"; /** * The access key (ie login username) for connecting to api. */ @@ -81,7 +78,7 @@ public final class CommandManagerSettings { */ final String authType; - protected CommandManagerSettings( + private CommandManagerSettings( String keystore, String authUsername, String authPassword, @@ -93,6 +90,7 @@ protected CommandManagerSettings( this.authPassword = authPassword; this.uri = uri; this.authType = authType; + log.info("Plugin settings: {}", this.toString()); } /** @@ -105,7 +103,7 @@ public static CommandManagerSettings getSettings(Environment environment, Secure try { keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); } catch (IOException e) { - log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath().toString() + KEYSTORE_FILENAME).getMessage()); + log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath() + KEYSTORE_FILENAME).getMessage()); } if (keyStoreWrapper == null) { @@ -143,14 +141,14 @@ public static CommandManagerSettings getSettings(Environment environment, Secure */ public static CommandManagerSettings getSettings(Environment environment) { KeyStoreWrapper keyStoreWrapper = null; - Path keystoreFile = Path.of(environment.configFile()+"/"+KEYSTORE_FILENAME); + Path keystoreFile = Path.of(environment.configFile() + "/" + KEYSTORE_FILENAME); try { - if (!Files.exists(keystoreFile)){ + if (!Files.exists(keystoreFile)) { throw CommandManagerSettingsException.keystoreNotExist(keystoreFile.toAbsolutePath().toString()); //Path keyStorePath = Files.createFile(keystoreFile); //log.warn("CREADA KeyStoreWrapper en "+keyStorePath.toString()); - }else{ - log.warn("Por hacer load de KeyStoreWrapper en "+environment.configFile().toString()); + } else { + log.warn("Por hacer load de KeyStoreWrapper en " + environment.configFile().toString()); keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); } } catch (Exception e) { @@ -162,11 +160,11 @@ public static CommandManagerSettings getSettings(Environment environment) { return null; } else { // Decrypt the keystore using the password from the request - try { - keyStoreWrapper.decrypt(new char[0]); - } catch (GeneralSecurityException | IOException e) { - log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); - } + try { + keyStoreWrapper.decrypt(new char[0]); + } catch (GeneralSecurityException | IOException e) { + log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); + } final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); @@ -184,5 +182,17 @@ public static CommandManagerSettings getSettings(Environment environment) { } } } + + + @Override + public String toString() { + return "CommandManagerSettings{" + + "keystore='" + keystore + '\'' + + ", authUsername='" + authUsername + '\'' + + ", authPassword='" + authPassword + '\'' + + ", uri='" + uri + '\'' + + ", authType='" + authType + '\'' + + '}'; + } } From 4b8cc0ef0ce3932f6d0f517bebc6fdadfebeaf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Fri, 18 Oct 2024 19:05:05 +0200 Subject: [PATCH 12/23] Apply spotless --- .../commandmanager/CommandManagerPlugin.java | 14 +- .../CommandManagerSettingsException.java | 14 +- .../settings/CommandManagerSettings.java | 152 +++++++++--------- .../settings/CommandManagerSettingsTests.java | 68 ++++---- 4 files changed, 126 insertions(+), 122 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 3c62157..08a5673 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -8,9 +8,6 @@ */ package com.wazuh.commandmanager; -import com.wazuh.commandmanager.settings.CommandManagerSettings; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; @@ -39,6 +36,7 @@ import com.wazuh.commandmanager.index.CommandIndex; import com.wazuh.commandmanager.rest.RestPostCommandAction; +import com.wazuh.commandmanager.settings.CommandManagerSettings; import com.wazuh.commandmanager.utils.httpclient.HttpRestClient; import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo; @@ -99,16 +97,16 @@ public List> getSettings() { CommandManagerSettings.AUTH_USERNAME, CommandManagerSettings.AUTH_PASSWORD, CommandManagerSettings.URI, - CommandManagerSettings.AUTH_TYPE - ); + CommandManagerSettings.AUTH_TYPE); } @Override public void reload(Settings settings) { // secure settings should be readable - //final CommandManagerSettings commandManagerSettings = CommandManagerSettings.getClientSettings(secureSettingsPassword); - //I don't know what I have to do when we want to reload the settings already - //xxxService.refreshAndClearCache(commandManagerSettings); + // final CommandManagerSettings commandManagerSettings = + // CommandManagerSettings.getClientSettings(secureSettingsPassword); + // I don't know what I have to do when we want to reload the settings already + // xxxService.refreshAndClearCache(commandManagerSettings); } /** diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java index 78a24fc..9cc073c 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java @@ -1,4 +1,5 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to @@ -7,7 +8,6 @@ */ package com.wazuh.commandmanager; - public class CommandManagerSettingsException extends Exception { // Default constructor @@ -32,22 +32,25 @@ public CommandManagerSettingsException(Throwable cause) { // Exception for the case when the keystore does not exist public static CommandManagerSettingsException keystoreNotExist(String keystorePath) { - return new CommandManagerSettingsException("The keystore does not exist at the path: " + keystorePath); + return new CommandManagerSettingsException( + "The keystore does not exist at the path: " + keystorePath); } // Exception for the case when the keystore is empty public static CommandManagerSettingsException keystoreEmpty(String keystorePath) { - return new CommandManagerSettingsException("The keystore is empty at the path: " + keystorePath); + return new CommandManagerSettingsException( + "The keystore is empty at the path: " + keystorePath); } // Exception for the case when load keystore failed public static CommandManagerSettingsException loadKeystoreFailed(String keyStorePath) { - return new CommandManagerSettingsException("Load keystore: "+ keyStorePath +" failed."); + return new CommandManagerSettingsException("Load keystore: " + keyStorePath + " failed."); } // Exception for the case when load keystore failed public static CommandManagerSettingsException decryptKeystoreFailed(String keyStorePath) { - return new CommandManagerSettingsException("Decrypt keystore: "+ keyStorePath +" failed."); + return new CommandManagerSettingsException( + "Decrypt keystore: " + keyStorePath + " failed."); } // Exception for the case when reload plugin with the keystore failed @@ -55,4 +58,3 @@ public static CommandManagerSettingsException reloadPluginFailed(String pluginNa return new CommandManagerSettingsException("Reload failed for plugin: " + pluginName); } } - diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 3fa0d86..438f06d 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -1,4 +1,5 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to @@ -7,7 +8,6 @@ */ package com.wazuh.commandmanager.settings; -import com.wazuh.commandmanager.CommandManagerSettingsException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.common.settings.KeyStoreWrapper; @@ -22,60 +22,48 @@ import java.nio.file.Path; import java.security.GeneralSecurityException; +import com.wazuh.commandmanager.CommandManagerSettingsException; + public final class CommandManagerSettings { - /** - * The access key (ie login id) for connecting to api. - */ + /** The access key (ie login id) for connecting to api. */ public static final Setting KEYSTORE = SecureSetting.secureString("command.manager.keystore", null); - /** - * The access key (ie login username) for connecting to api. - */ + + /** The access key (ie login username) for connecting to api. */ public static final Setting AUTH_USERNAME = SecureSetting.secureString("command.manager.auth.username", null); - /** - * The secret key (ie password) for connecting to api. - */ + + /** The secret key (ie password) for connecting to api. */ public static final Setting AUTH_PASSWORD = SecureSetting.secureString("command.manager.auth.password", null); - /** - * The uri for connecting to api. - */ + + /** The uri for connecting to api. */ public static final Setting URI = SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); - /** - * The auth type for connecting to api. - */ + + /** The auth type for connecting to api. */ public static final Setting AUTH_TYPE = Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); + private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); - /** - * The name of own keystore. - */ - private static final String KEYSTORE_FILENAME = "opensearch.keystore"; //"wazuh-indexer.keystore"; - /** - * The access key (ie login username) for connecting to api. - */ + + /** The name of own keystore. */ + private static final String KEYSTORE_FILENAME = + "opensearch.keystore"; // "wazuh-indexer.keystore"; + + /** The access key (ie login username) for connecting to api. */ final String keystore; - /** - * The access key (ie login username) for connecting to api. - */ + /** The access key (ie login username) for connecting to api. */ final String authUsername; - /** - * The password for connecting to api. - */ + /** The password for connecting to api. */ final String authPassword; - /** - * The uri for connecting to api. - */ + /** The uri for connecting to api. */ final String uri; - /** - * The auth type for connecting to api. - */ + /** The auth type for connecting to api. */ final String authType; private CommandManagerSettings( @@ -83,8 +71,7 @@ private CommandManagerSettings( String authUsername, String authPassword, String uri, - String authType - ) { + String authType) { this.keystore = keystore; this.authUsername = authUsername; this.authPassword = authPassword; @@ -93,21 +80,25 @@ private CommandManagerSettings( log.info("Plugin settings: {}", this.toString()); } - /** - * Parse settings for a single client. - */ - public static CommandManagerSettings getSettings(Environment environment, SecureString secureSettingsPassword) { + /** Parse settings for a single client. */ + public static CommandManagerSettings getSettings( + Environment environment, SecureString secureSettingsPassword) { KeyStoreWrapper keyStoreWrapper = null; try { keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); } catch (IOException e) { - log.error(CommandManagerSettingsException.loadKeystoreFailed(environment.configFile().toAbsolutePath() + KEYSTORE_FILENAME).getMessage()); + log.error( + CommandManagerSettingsException.loadKeystoreFailed( + environment.configFile().toAbsolutePath() + KEYSTORE_FILENAME) + .getMessage()); } if (keyStoreWrapper == null) { - log.error(CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME).getMessage()); + log.error( + CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME) + .getMessage()); return null; } else { // Decrypt the keystore using the password from the request @@ -115,84 +106,95 @@ public static CommandManagerSettings getSettings(Environment environment, Secure try { keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); } catch (GeneralSecurityException | IOException e) { - log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); + log.error( + CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME) + .getMessage()); } } final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - try ( - SecureString authUsername = AUTH_USERNAME.get(settings); - SecureString authPassword = AUTH_PASSWORD.get(settings); - ) { + try (SecureString authUsername = AUTH_USERNAME.get(settings); + SecureString authPassword = AUTH_PASSWORD.get(settings); ) { return new CommandManagerSettings( KEYSTORE_FILENAME, authUsername.toString(), authPassword.toString(), URI.get(settings), - AUTH_TYPE.get(settings) - ); + AUTH_TYPE.get(settings)); } } } - /** - * Parse settings for a single client. - */ + /** Parse settings for a single client. */ public static CommandManagerSettings getSettings(Environment environment) { KeyStoreWrapper keyStoreWrapper = null; Path keystoreFile = Path.of(environment.configFile() + "/" + KEYSTORE_FILENAME); try { if (!Files.exists(keystoreFile)) { - throw CommandManagerSettingsException.keystoreNotExist(keystoreFile.toAbsolutePath().toString()); - //Path keyStorePath = Files.createFile(keystoreFile); - //log.warn("CREADA KeyStoreWrapper en "+keyStorePath.toString()); + throw CommandManagerSettingsException.keystoreNotExist( + keystoreFile.toAbsolutePath().toString()); + // Path keyStorePath = Files.createFile(keystoreFile); + // log.warn("CREADA KeyStoreWrapper en "+keyStorePath.toString()); } else { - log.warn("Por hacer load de KeyStoreWrapper en " + environment.configFile().toString()); + log.warn( + "Por hacer load de KeyStoreWrapper en " + + environment.configFile().toString()); keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); } } catch (Exception e) { - log.error(CommandManagerSettingsException.loadKeystoreFailed(keystoreFile.toString()).getMessage()); + log.error( + CommandManagerSettingsException.loadKeystoreFailed(keystoreFile.toString()) + .getMessage()); } if (keyStoreWrapper == null) { - log.error(CommandManagerSettingsException.keystoreNotExist(keystoreFile.toString()).getMessage()); + log.error( + CommandManagerSettingsException.keystoreNotExist(keystoreFile.toString()) + .getMessage()); return null; } else { // Decrypt the keystore using the password from the request try { keyStoreWrapper.decrypt(new char[0]); } catch (GeneralSecurityException | IOException e) { - log.error(CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME).getMessage()); + log.error( + CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME) + .getMessage()); } final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - try ( - SecureString authUsername = AUTH_USERNAME.get(settings); - SecureString authPassword = AUTH_PASSWORD.get(settings); - ) { + try (SecureString authUsername = AUTH_USERNAME.get(settings); + SecureString authPassword = AUTH_PASSWORD.get(settings); ) { return new CommandManagerSettings( KEYSTORE_FILENAME, authUsername.toString(), authPassword.toString(), URI.get(settings), - AUTH_TYPE.get(settings) - ); + AUTH_TYPE.get(settings)); } } } - @Override public String toString() { - return "CommandManagerSettings{" + - "keystore='" + keystore + '\'' + - ", authUsername='" + authUsername + '\'' + - ", authPassword='" + authPassword + '\'' + - ", uri='" + uri + '\'' + - ", authType='" + authType + '\'' + - '}'; + return "CommandManagerSettings{" + + "keystore='" + + keystore + + '\'' + + ", authUsername='" + + authUsername + + '\'' + + ", authPassword='" + + authPassword + + '\'' + + ", uri='" + + uri + + '\'' + + ", authType='" + + authType + + '\'' + + '}'; } } - diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 6d81384..a8a61cd 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -1,4 +1,5 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to @@ -9,15 +10,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; import org.opensearch.test.OpenSearchIntegTestCase; +import org.junit.After; +import org.junit.Before; import java.io.IOException; import java.nio.file.Path; @@ -25,26 +23,24 @@ import java.security.AccessController; import java.security.PrivilegedAction; +import org.mockito.Mock; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) -public class CommandManagerSettingsTests extends OpenSearchIntegTestCase{ - @Mock - private Environment mockEnvironment; - +public class CommandManagerSettingsTests extends OpenSearchIntegTestCase { + @Mock private Environment mockEnvironment; private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); - @Mock - KeyStoreWrapper mockedKeyStoreWrapper; + @Mock KeyStoreWrapper mockedKeyStoreWrapper; private CommandManagerSettings commandManagerSettings; private static final Logger log = LogManager.getLogger(CommandManagerSettingsTests.class); - @Before @Override public void setUp() throws Exception { @@ -64,30 +60,36 @@ public void testGetSettings_keystoreExists() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); when(mockEnvironment.configFile()).thenReturn(keyStorePath); - //logger.error(String.format(" Attempting to read file: %s%s", keyStorePath,"wazuh-indexer.keystore.json")); + // logger.error(String.format(" Attempting to read file: %s%s", + // keyStorePath,"wazuh-indexer.keystore.json")); try { AccessController.doPrivileged( - (PrivilegedAction) () -> { - // Simulate an existing keystore - try { - KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.load(keyStorePath, "wazuh-indexer.keystore.json"); - when(KeyStoreWrapper.load(any(), any())).thenReturn(keyStoreWrapper); - log.warn("test INSIDE+EE"); - - this.commandManagerSettings = CommandManagerSettings.getSettings(mockEnvironment); - - assertNotNull(commandManagerSettings); - log.warn("keystore INSIDE"+commandManagerSettings.keystore); - // verify(keyStoreWrapper, times(1)).decrypt(secureString.getChars()); - } catch (IOException e) { - log.warn("ERROR TEST: "+e.getMessage()); - } - log.warn("RETURN"); - return null; - } - ); - }catch(AccessControlException e){ + (PrivilegedAction) + () -> { + // Simulate an existing keystore + try { + KeyStoreWrapper keyStoreWrapper = + KeyStoreWrapper.load( + keyStorePath, "wazuh-indexer.keystore.json"); + when(KeyStoreWrapper.load(any(), any())) + .thenReturn(keyStoreWrapper); + log.warn("test INSIDE+EE"); + + this.commandManagerSettings = + CommandManagerSettings.getSettings(mockEnvironment); + + assertNotNull(commandManagerSettings); + log.warn("keystore INSIDE" + commandManagerSettings.keystore); + // verify(keyStoreWrapper, + // times(1)).decrypt(secureString.getChars()); + } catch (IOException e) { + log.warn("ERROR TEST: " + e.getMessage()); + } + log.warn("RETURN"); + return null; + }); + } catch (AccessControlException e) { } } From a7cf4b6d4eb132546be78fb2aa2f75a99c4371f0 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Mon, 21 Oct 2024 14:34:02 -0300 Subject: [PATCH 13/23] Unificate the CommandManagerSettings getSetting methods. Add some logs. Change the settings name. --- plugins/command-manager/build.gradle | 3 +- .../commandmanager/CommandManagerPlugin.java | 10 +- .../settings/CommandManagerSettings.java | 118 +++++------------- .../settings/CommandManagerSettingsTests.java | 5 +- 4 files changed, 35 insertions(+), 101 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 1cb3883..123cbe6 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -185,10 +185,9 @@ testClusters.integTest { plugin(project.tasks.bundlePlugin.archiveFile) // add customized keystore - keystore 'command.manager.keystore', new File("$projectDir/src/test/resources/", 'wazuh-indexer.keystore.json') keystore 'command.manager.auth.username', 'admin' keystore 'command.manager.auth.password', 'test' - + keystore 'command.manager.uri', 'https://httpbin.org/post' } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 08a5673..67bfdfb 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -69,7 +69,7 @@ public Collection createComponents( Supplier repositoriesServiceSupplier) { this.commandIndex = new CommandIndex(client, clusterService, threadPool); - this.commandManagerSettings = CommandManagerSettings.getSettings(environment); + this.commandManagerSettings = CommandManagerSettings.getSettings(environment, null); // HttpRestClient stuff String uri = "https://httpbin.org/post"; @@ -93,11 +93,9 @@ public List getRestHandlers( public List> getSettings() { return Arrays.asList( // Register API settings - CommandManagerSettings.KEYSTORE, - CommandManagerSettings.AUTH_USERNAME, - CommandManagerSettings.AUTH_PASSWORD, - CommandManagerSettings.URI, - CommandManagerSettings.AUTH_TYPE); + CommandManagerSettings.M_API_USERNAME, + CommandManagerSettings.M_API_PASSWORD, + CommandManagerSettings.M_API_URI); } @Override diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 438f06d..168b987 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -25,34 +25,24 @@ import com.wazuh.commandmanager.CommandManagerSettingsException; public final class CommandManagerSettings { - /** The access key (ie login id) for connecting to api. */ - public static final Setting KEYSTORE = - SecureSetting.secureString("command.manager.keystore", null); /** The access key (ie login username) for connecting to api. */ - public static final Setting AUTH_USERNAME = + public static final Setting M_API_USERNAME = SecureSetting.secureString("command.manager.auth.username", null); /** The secret key (ie password) for connecting to api. */ - public static final Setting AUTH_PASSWORD = + public static final Setting M_API_PASSWORD = SecureSetting.secureString("command.manager.auth.password", null); /** The uri for connecting to api. */ - public static final Setting URI = - SecureSetting.simpleString("command.manager.uri", Setting.Property.NodeScope); + public static final Setting M_API_URI = + SecureSetting.secureString("command.manager.uri", null); - /** The auth type for connecting to api. */ - public static final Setting AUTH_TYPE = - Setting.simpleString("command.manager.auth.type", Setting.Property.NodeScope); private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); /** The name of own keystore. */ - private static final String KEYSTORE_FILENAME = - "opensearch.keystore"; // "wazuh-indexer.keystore"; - - /** The access key (ie login username) for connecting to api. */ - final String keystore; + private static final String KEYSTORE_FILENAME = "opensearch.keystore"; /** The access key (ie login username) for connecting to api. */ final String authUsername; @@ -63,89 +53,37 @@ public final class CommandManagerSettings { /** The uri for connecting to api. */ final String uri; - /** The auth type for connecting to api. */ - final String authType; - private CommandManagerSettings( - String keystore, String authUsername, String authPassword, - String uri, - String authType) { - this.keystore = keystore; + String uri) { this.authUsername = authUsername; this.authPassword = authPassword; this.uri = uri; - this.authType = authType; - log.info("Plugin settings: {}", this.toString()); + log.info("CommandManagerSettings created "); } - /** Parse settings for a single client. */ - public static CommandManagerSettings getSettings( - Environment environment, SecureString secureSettingsPassword) { - - KeyStoreWrapper keyStoreWrapper = null; - - try { - keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); - } catch (IOException e) { - log.error( - CommandManagerSettingsException.loadKeystoreFailed( - environment.configFile().toAbsolutePath() + KEYSTORE_FILENAME) - .getMessage()); - } - - if (keyStoreWrapper == null) { - log.error( - CommandManagerSettingsException.keystoreNotExist(KEYSTORE_FILENAME) - .getMessage()); - return null; - } else { - // Decrypt the keystore using the password from the request - if (keyStoreWrapper.hasPassword()) { - try { - keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); - } catch (GeneralSecurityException | IOException e) { - log.error( - CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME) - .getMessage()); - } - } - - final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - - try (SecureString authUsername = AUTH_USERNAME.get(settings); - SecureString authPassword = AUTH_PASSWORD.get(settings); ) { - return new CommandManagerSettings( - KEYSTORE_FILENAME, - authUsername.toString(), - authPassword.toString(), - URI.get(settings), - AUTH_TYPE.get(settings)); - } - } - } /** Parse settings for a single client. */ - public static CommandManagerSettings getSettings(Environment environment) { + public static CommandManagerSettings getSettings(Environment environment, SecureString secureSettingsPassword) { KeyStoreWrapper keyStoreWrapper = null; Path keystoreFile = Path.of(environment.configFile() + "/" + KEYSTORE_FILENAME); try { if (!Files.exists(keystoreFile)) { - throw CommandManagerSettingsException.keystoreNotExist( - keystoreFile.toAbsolutePath().toString()); - // Path keyStorePath = Files.createFile(keystoreFile); - // log.warn("CREADA KeyStoreWrapper en "+keyStorePath.toString()); + log.error(CommandManagerSettingsException.keystoreNotExist( + keystoreFile.toAbsolutePath().toString()).getMessage()); + return null; } else { - log.warn( - "Por hacer load de KeyStoreWrapper en " - + environment.configFile().toString()); keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); + log.info( + "Keystore load: " + + keystoreFile.toAbsolutePath().toString()); } } catch (Exception e) { log.error( CommandManagerSettingsException.loadKeystoreFailed(keystoreFile.toString()) .getMessage()); + return null; } if (keyStoreWrapper == null) { @@ -155,8 +93,14 @@ public static CommandManagerSettings getSettings(Environment environment) { return null; } else { // Decrypt the keystore using the password from the request + try { - keyStoreWrapper.decrypt(new char[0]); + log.info("Decrypting the keystore."); + if (secureSettingsPassword == null || secureSettingsPassword.length() == 0) { + keyStoreWrapper.decrypt(new char[0]); + } else { + keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); + } } catch (GeneralSecurityException | IOException e) { log.error( CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME) @@ -164,15 +108,15 @@ public static CommandManagerSettings getSettings(Environment environment) { } final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); + log.info("Settings created with the keystore information."); - try (SecureString authUsername = AUTH_USERNAME.get(settings); - SecureString authPassword = AUTH_PASSWORD.get(settings); ) { + try (SecureString authUsername = M_API_USERNAME.get(settings); + SecureString authPassword = M_API_PASSWORD.get(settings); + SecureString uri = M_API_URI.get(settings);) { return new CommandManagerSettings( - KEYSTORE_FILENAME, authUsername.toString(), authPassword.toString(), - URI.get(settings), - AUTH_TYPE.get(settings)); + uri.toString()); } } } @@ -180,10 +124,7 @@ public static CommandManagerSettings getSettings(Environment environment) { @Override public String toString() { return "CommandManagerSettings{" - + "keystore='" - + keystore - + '\'' - + ", authUsername='" + + " authUsername='" + authUsername + '\'' + ", authPassword='" @@ -192,9 +133,6 @@ public String toString() { + ", uri='" + uri + '\'' - + ", authType='" - + authType - + '\'' + '}'; } } diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index a8a61cd..8450cdb 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -77,11 +77,10 @@ public void testGetSettings_keystoreExists() throws Exception { log.warn("test INSIDE+EE"); this.commandManagerSettings = - CommandManagerSettings.getSettings(mockEnvironment); + CommandManagerSettings.getSettings(mockEnvironment, null); assertNotNull(commandManagerSettings); - log.warn("keystore INSIDE" + commandManagerSettings.keystore); - // verify(keyStoreWrapper, + log.info("Plugin settings: {}", commandManagerSettings.toString()); // verify(keyStoreWrapper, // times(1)).decrypt(secureString.getChars()); } catch (IOException e) { log.warn("ERROR TEST: " + e.getMessage()); From 4c105dde995f6d85aad4ae45a89fcbc4059e6de5 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Mon, 21 Oct 2024 20:23:48 -0300 Subject: [PATCH 14/23] Add another test for the diferents possibilities on the method getSettings of CommandManagerSettings --- plugins/command-manager/build.gradle | 50 +---- .../settings/CommandManagerSettings.java | 1 - .../settings/CommandManagerSettingsTests.java | 191 ++++++++++++++++-- 3 files changed, 178 insertions(+), 64 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 123cbe6..49ba950 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -77,7 +77,7 @@ def versions = [ slf4j: "1.7.36", log4j: "2.23.1", conscrypt: "2.5.2", - mockito: "4.1.0", + mockito: "5.12.0", junit:"4.13.2" ] @@ -89,7 +89,7 @@ dependencies { api "org.slf4j:slf4j-api:${versions.slf4j}" api "org.conscrypt:conscrypt-openjdk-uber:${versions.conscrypt}" - testImplementation "org.mockito:mockito-inline:${versions.mockito}" + testImplementation "org.mockito:mockito-core:${versions.mockito}" testImplementation "junit:junit:${versions.junit}" } @@ -125,52 +125,6 @@ task integTest(type: RestIntegTestTask) { tasks.named("check").configure { dependsOn(integTest) } -//OPCION 1 -/* -// needed to be consistent with ssl host checking -String host = InetAddress.getLoopbackAddress().getHostAddress() - -// location of keystore and files to generate it -File keystore = new File(project.buildDir, 'keystore/wazuh-indexer.keystore.jks') - -// generate the keystore - -TaskProvider createKey = tasks.register("createKey", LoggedExec) { - doFirst { - delete(keystore.parentFile) - keystore.parentFile.mkdirs() - } - outputs.file(keystore).withPropertyName('keystoreFile') - executable = "${BuildParams.runtimeJavaHome}/bin/keytool" - standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8')) - args '-genkey', - '-alias', 'test-node', - '-keystore', keystore, - '-keyalg', 'RSA', - '-keysize', '2048', - '-validity', '712', - '-dname', 'CN=' + host, - '-keypass', 'keypass', - '-storepass', 'keypass' -} - -//no unit tests -tasks.named("test").configure { enabled = false } -// add keystore to test classpath: it expects it there -tasks.named("processInternalClusterTestResources").configure { - from createKey -} - -normalization { - runtimeClasspath { - ignore 'test-node.jks' - } -} - - */ - -//OPCION 2 - integTest { // The --debug-jvm command-line option makes the cluster debuggable; this makes the tests debuggable if (System.getProperty("test.debug") != null) { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 168b987..2db0fa3 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -93,7 +93,6 @@ public static CommandManagerSettings getSettings(Environment environment, Secure return null; } else { // Decrypt the keystore using the password from the request - try { log.info("Decrypting the keystore."); if (secureSettingsPassword == null || secureSettingsPassword.length() == 0) { diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 8450cdb..6c5addb 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -10,7 +10,10 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.junit.Test; +import org.mockito.InjectMocks; import org.opensearch.common.settings.KeyStoreWrapper; +import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; import org.opensearch.test.OpenSearchIntegTestCase; @@ -18,16 +21,18 @@ import org.junit.Before; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.security.AccessControlException; import java.security.AccessController; +import java.security.GeneralSecurityException; import java.security.PrivilegedAction; import org.mockito.Mock; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; @OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) public class CommandManagerSettingsTests extends OpenSearchIntegTestCase { @@ -37,15 +42,21 @@ public class CommandManagerSettingsTests extends OpenSearchIntegTestCase { @Mock KeyStoreWrapper mockedKeyStoreWrapper; + @Mock Path mockedPath; + + @InjectMocks private CommandManagerSettings commandManagerSettings; private static final Logger log = LogManager.getLogger(CommandManagerSettingsTests.class); + private static final String KEYSTORE_FILENAME = "opensearch.keystore"; + @Before @Override public void setUp() throws Exception { mockedKeyStoreWrapper = mock(KeyStoreWrapper.class); mockEnvironment = mock(Environment.class); + mockedPath = mock(Path.class); super.setUp(); } @@ -55,13 +66,166 @@ public void closeSecureString() { secureString.close(); } - public void testGetSettings_keystoreExists() throws Exception { - // Set up the mock to return a specific path for the config file + @Test + public void keystoreFileNotExistReturnsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - when(mockEnvironment.configFile()).thenReturn(keyStorePath); + Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + when(mockEnvironment.configFile()).thenReturn(keystoreFile); + + try { + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + when(Files.exists(keyStorePath)).thenReturn(false); + when(keyStorePath.toAbsolutePath().toString()).thenReturn(keyStorePath.toString()); + + CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNull("Expected settings to be null when keystore file does not exist.", result); + + return null; + }); + } catch (AccessControlException e) { + + } + } - // logger.error(String.format(" Attempting to read file: %s%s", - // keyStorePath,"wazuh-indexer.keystore.json")); + @Test + public void keystoreFileExistsButLoadReturnsNull() throws Exception { + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); + Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + when(mockEnvironment.configFile()).thenReturn(keystoreFile); + + try { + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + when(Files.exists(keystoreFile)).thenReturn(true); + try { + when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(null); + } catch (IOException e) { + + } + + CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNull("Expected settings to be null when keystore load returns null.", result); + + return null; + }); + } catch (AccessControlException e) { + + } + } + + @Test + public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); + Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + when(mockEnvironment.configFile()).thenReturn(keystoreFile); + + try { + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + when(Files.exists(keystoreFile)).thenReturn(true); + try { + when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(mockedKeyStoreWrapper); + + } catch (IOException e) { + log.error("Error when tryng to mock load: " + e.getMessage()); + } + + try { + doNothing().when(mockedKeyStoreWrapper).decrypt(new char[0]); + } catch (GeneralSecurityException | IOException | RuntimeException e) { + log.error("Error when tryng to mock decrypt: " + e.getMessage()); + } + + Settings settingsMock = mock(Settings.class); + Settings.Builder builderMock = mock(Settings.Builder.class); + when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + //when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + + SecureString authUsername = new SecureString("userTesting".toCharArray()); + SecureString authPassword = new SecureString("passTesting".toCharArray()); + SecureString uri = new SecureString("http://localhost".toCharArray()); + + when(CommandManagerSettings.M_API_USERNAME.get(any())).thenReturn(authUsername); + when(CommandManagerSettings.M_API_PASSWORD.get(any())).thenReturn(authPassword); + when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); + + CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNotNull("Expected CommandManagerSettings to be created.", result); + assertEquals("userTesting", result.authUsername, "The username should match the configured value."); + assertEquals("passTesting", result.authPassword, "The password should match the configured value."); + assertEquals("http://localhost", result.uri, "The URI should match the configured value."); + + return null; + }); + } catch (AccessControlException e) { + log.error("AccesControl Error: " + e.getMessage()); + } + } + + @Test + public void shouldDecryptKeystoreWithPassword() throws Exception { + Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); + Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + when(mockEnvironment.configFile()).thenReturn(keystoreFile); + + try { + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + when(Files.exists(keystoreFile)).thenReturn(true); + try { + when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(mockedKeyStoreWrapper); + + } catch (IOException e) { + log.error("Error when tryng to mock load: " + e.getMessage()); + } + + try { + SecureString password = new SecureString("passwordTest".toCharArray()); + doNothing().when(mockedKeyStoreWrapper).decrypt(password.getChars()); + } catch (GeneralSecurityException | IOException | RuntimeException e) { + log.error("Error when tryng to mock decrypt: " + e.getMessage()); + } + + Settings settingsMock = mock(Settings.class); + Settings.Builder builderMock = mock(Settings.Builder.class); + when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + //when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + + SecureString authUsername = new SecureString("userTesting".toCharArray()); + SecureString authPassword = new SecureString("passTesting".toCharArray()); + SecureString uri = new SecureString("http://localhost".toCharArray()); + + when(CommandManagerSettings.M_API_USERNAME.get(any())).thenReturn(authUsername); + when(CommandManagerSettings.M_API_PASSWORD.get(any())).thenReturn(authPassword); + when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); + + CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNotNull("Expected CommandManagerSettings to be created.", result); + assertEquals("userTesting", result.authUsername, "The username should match the configured value."); + assertEquals("passTesting", result.authPassword, "The password should match the configured value."); + assertEquals("http://localhost", result.uri, "The URI should match the configured value."); + + return null; + }); + } catch (AccessControlException e) { + log.error("AccesControl Error: " + e.getMessage()); + } + } + + + public void testValuesOfGetSettings_keystoreExists() throws Exception { + // Set up the mock to return a specific path for the config file + Path keyStorePath = Path.of("command-manager/build/testclusters/integTest-0/config").toAbsolutePath(); + when(mockEnvironment.configFile()).thenReturn(keyStorePath); try { AccessController.doPrivileged( @@ -70,11 +234,9 @@ public void testGetSettings_keystoreExists() throws Exception { // Simulate an existing keystore try { KeyStoreWrapper keyStoreWrapper = - KeyStoreWrapper.load( - keyStorePath, "wazuh-indexer.keystore.json"); - when(KeyStoreWrapper.load(any(), any())) - .thenReturn(keyStoreWrapper); - log.warn("test INSIDE+EE"); + KeyStoreWrapper.load(keyStorePath); + + log.info("Is keyStoreWrapper loaded? "+keyStoreWrapper.isLoaded()); this.commandManagerSettings = CommandManagerSettings.getSettings(mockEnvironment, null); @@ -83,13 +245,12 @@ public void testGetSettings_keystoreExists() throws Exception { log.info("Plugin settings: {}", commandManagerSettings.toString()); // verify(keyStoreWrapper, // times(1)).decrypt(secureString.getChars()); } catch (IOException e) { - log.warn("ERROR TEST: " + e.getMessage()); + log.error("IO Error: " + e.getMessage()); } - log.warn("RETURN"); return null; }); } catch (AccessControlException e) { - + log.error("AccesControl Error: " + e.getMessage()); } } } From bc61647db319f6f1f8472d04770a5048974e74d4 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Tue, 22 Oct 2024 09:51:17 -0300 Subject: [PATCH 15/23] Fix settings name in CommanManagerSettings --- plugins/command-manager/build.gradle | 6 +++--- .../commandmanager/settings/CommandManagerSettings.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index 49ba950..b6187fd 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -139,9 +139,9 @@ testClusters.integTest { plugin(project.tasks.bundlePlugin.archiveFile) // add customized keystore - keystore 'command.manager.auth.username', 'admin' - keystore 'command.manager.auth.password', 'test' - keystore 'command.manager.uri', 'https://httpbin.org/post' + keystore 'm.api.username', 'admin' + keystore 'm.api.password', 'test' + keystore 'm.api.uri', 'https://httpbin.org/post' } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 2db0fa3..067d74d 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -28,15 +28,15 @@ public final class CommandManagerSettings { /** The access key (ie login username) for connecting to api. */ public static final Setting M_API_USERNAME = - SecureSetting.secureString("command.manager.auth.username", null); + SecureSetting.secureString("m.api.username", null); /** The secret key (ie password) for connecting to api. */ public static final Setting M_API_PASSWORD = - SecureSetting.secureString("command.manager.auth.password", null); + SecureSetting.secureString("m.api.password", null); /** The uri for connecting to api. */ public static final Setting M_API_URI = - SecureSetting.secureString("command.manager.uri", null); + SecureSetting.secureString("m.api.uri", null); private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); From 24f1699b774f82cfe9caeab06181bda1d167593e Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Tue, 22 Oct 2024 09:58:28 -0300 Subject: [PATCH 16/23] Delete @Test annotation --- .../commandmanager/settings/CommandManagerSettingsTests.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 6c5addb..507c435 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -10,7 +10,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.junit.Test; import org.mockito.InjectMocks; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.Settings; @@ -66,7 +65,6 @@ public void closeSecureString() { secureString.close(); } - @Test public void keystoreFileNotExistReturnsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); @@ -90,7 +88,6 @@ public void keystoreFileNotExistReturnsNull() throws Exception { } } - @Test public void keystoreFileExistsButLoadReturnsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); @@ -118,7 +115,6 @@ public void keystoreFileExistsButLoadReturnsNull() throws Exception { } } - @Test public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); @@ -169,7 +165,6 @@ public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { } } - @Test public void shouldDecryptKeystoreWithPassword() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); From d643f1f9675588e9b9903e2af6d2bd0ba94325ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Wed, 23 Oct 2024 19:24:10 +0200 Subject: [PATCH 17/23] Send commands to the M_API using the configuration service --- .../commandmanager/CommandManagerPlugin.java | 10 +- .../rest/RestPostCommandAction.java | 23 ++- .../settings/CommandManagerSettings.java | 41 ++-- .../utils/httpclient/HttpRestClientDemo.java | 66 +++++-- .../settings/CommandManagerSettingsTests.java | 176 ++++++++++++------ 5 files changed, 209 insertions(+), 107 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 67bfdfb..5cf2292 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -38,7 +38,6 @@ import com.wazuh.commandmanager.rest.RestPostCommandAction; import com.wazuh.commandmanager.settings.CommandManagerSettings; import com.wazuh.commandmanager.utils.httpclient.HttpRestClient; -import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo; /** * The Command Manager plugin exposes an HTTP API with a single endpoint to receive raw commands @@ -72,9 +71,9 @@ public Collection createComponents( this.commandManagerSettings = CommandManagerSettings.getSettings(environment, null); // HttpRestClient stuff - String uri = "https://httpbin.org/post"; - String payload = "{\"message\": \"Hello world!\"}"; - HttpRestClientDemo.run(uri, payload); + // String uri = "https://httpbin.org/post"; + // String payload = "{\"message\": \"Hello world!\"}"; + // HttpRestClientDemo.run(uri, payload); return Collections.emptyList(); } @@ -86,7 +85,8 @@ public List getRestHandlers( SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return Collections.singletonList(new RestPostCommandAction(this.commandIndex)); + return Collections.singletonList( + new RestPostCommandAction(this.commandIndex, this.commandManagerSettings)); } @Override diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java index ef7884c..c9ec1c2 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java @@ -9,7 +9,6 @@ package com.wazuh.commandmanager.rest; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; -import org.apache.hc.core5.net.URIBuilder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.client.node.NodeClient; @@ -23,8 +22,6 @@ import org.opensearch.rest.RestRequest; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -34,7 +31,8 @@ import com.wazuh.commandmanager.model.Agent; import com.wazuh.commandmanager.model.Command; import com.wazuh.commandmanager.model.Document; -import com.wazuh.commandmanager.utils.httpclient.HttpRestClient; +import com.wazuh.commandmanager.settings.CommandManagerSettings; +import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo; import static org.opensearch.core.xcontent.XContentParserUtils.ensureExpectedToken; import static org.opensearch.rest.RestRequest.Method.POST; @@ -49,14 +47,16 @@ public class RestPostCommandAction extends BaseRestHandler { "post_command_action_request_details"; private static final Logger log = LogManager.getLogger(RestPostCommandAction.class); private final CommandIndex commandIndex; + private final CommandManagerSettings settings; /** * Default constructor * * @param commandIndex persistence layer */ - public RestPostCommandAction(CommandIndex commandIndex) { + public RestPostCommandAction(CommandIndex commandIndex, CommandManagerSettings settings) { this.commandIndex = commandIndex; + this.settings = settings; } public String getName() { @@ -108,19 +108,18 @@ private RestChannelConsumer handlePost(RestRequest request) throws IOException { // Commands delivery to the Management API. // Note: needs to be decoupled from the Rest handler (job scheduler task). - HttpRestClient httpClient = HttpRestClient.getInstance(); try { - String uri = "https://httpbin.org/post"; - // String uri = "https://127.0.0.1:5000"; - URI receiverURI = new URIBuilder(uri).build(); + String receiverURI = this.settings.getUri(); String payload = document.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS) .toString(); - SimpleHttpResponse response = httpClient.post(receiverURI, payload, document.getId()); + SimpleHttpResponse response = + HttpRestClientDemo.runWithResponse(receiverURI, payload, document.getId()); + + // SimpleHttpResponse response = httpClient.post(receiverURI, payload, + // document.getId()); log.info("Received response to POST request with code [{}]", response.getCode()); log.info("Raw response:\n{}", response.getBodyText()); - } catch (URISyntaxException e) { - log.error("Bad URI: {}", e.getMessage()); } catch (Exception e) { log.error("Error reading response: {}", e.getMessage()); } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index 067d74d..a773b00 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -38,7 +38,6 @@ public final class CommandManagerSettings { public static final Setting M_API_URI = SecureSetting.secureString("m.api.uri", null); - private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); /** The name of own keystore. */ @@ -53,31 +52,32 @@ public final class CommandManagerSettings { /** The uri for connecting to api. */ final String uri; + private final Settings settings; + private CommandManagerSettings( - String authUsername, - String authPassword, - String uri) { + String authUsername, String authPassword, String uri, Settings settings) { this.authUsername = authUsername; this.authPassword = authPassword; this.uri = uri; + this.settings = settings; log.info("CommandManagerSettings created "); } - /** Parse settings for a single client. */ - public static CommandManagerSettings getSettings(Environment environment, SecureString secureSettingsPassword) { + public static CommandManagerSettings getSettings( + Environment environment, SecureString secureSettingsPassword) { KeyStoreWrapper keyStoreWrapper = null; Path keystoreFile = Path.of(environment.configFile() + "/" + KEYSTORE_FILENAME); try { if (!Files.exists(keystoreFile)) { - log.error(CommandManagerSettingsException.keystoreNotExist( - keystoreFile.toAbsolutePath().toString()).getMessage()); + log.error( + CommandManagerSettingsException.keystoreNotExist( + keystoreFile.toAbsolutePath().toString()) + .getMessage()); return null; } else { keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); - log.info( - "Keystore load: " - + keystoreFile.toAbsolutePath().toString()); + log.info("Keystore load: " + keystoreFile.toAbsolutePath().toString()); } } catch (Exception e) { log.error( @@ -110,16 +110,29 @@ public static CommandManagerSettings getSettings(Environment environment, Secure log.info("Settings created with the keystore information."); try (SecureString authUsername = M_API_USERNAME.get(settings); - SecureString authPassword = M_API_PASSWORD.get(settings); - SecureString uri = M_API_URI.get(settings);) { + SecureString authPassword = M_API_PASSWORD.get(settings); + SecureString uri = M_API_URI.get(settings); ) { return new CommandManagerSettings( authUsername.toString(), authPassword.toString(), - uri.toString()); + uri.toString(), + environment.settings()); } } } + public String getAuthPassword() { + return M_API_PASSWORD.get(this.settings).toString(); + } + + public String getAuthUsername() { + return M_API_USERNAME.get(this.settings).toString(); + } + + public String getUri() { + return this.uri; + } + @Override public String toString() { return "CommandManagerSettings{" diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java index 2fff5c6..036121b 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java @@ -29,26 +29,52 @@ public class HttpRestClientDemo { * @param endpoint POST's requests endpoint as a well-formed URI * @param body POST's request body as a JSON string. */ - public static void run(String endpoint, String body) { + // public static void run(String endpoint, String body) { + // log.info("Executing POST request"); + // AccessController.doPrivileged( + // (PrivilegedAction) + // () -> { + // HttpRestClient httpClient = HttpRestClient.getInstance(); + // try { + // URI host = new URIBuilder(endpoint).build(); + // SimpleHttpResponse response = + // httpClient.post(host, body, "randomId"); + // log.info( + // "Received response to POST request with code {}", + // response.getCode()); + // log.info("Raw response:\n{}", response.getBodyText()); + // } catch (URISyntaxException e) { + // log.error("Bad URI:{}", e.getMessage()); + // } catch (Exception e) { + // log.error("Error reading response: {}", e.getMessage()); + // } + // return null; + // }); + // } + + /** + * Demo method to test the {@link HttpRestClient} class. + * + * @param endpoint POST's requests endpoint as a well-formed URI + * @param body POST's request body as a JSON string. + * @return + */ + public static SimpleHttpResponse runWithResponse(String endpoint, String body, String docId) { log.info("Executing POST request"); - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - HttpRestClient httpClient = HttpRestClient.getInstance(); - try { - URI host = new URIBuilder(endpoint).build(); - SimpleHttpResponse response = - httpClient.post(host, body, "randomId"); - log.info( - "Received response to POST request with code {}", - response.getCode()); - log.info("Raw response:\n{}", response.getBodyText()); - } catch (URISyntaxException e) { - log.error("Bad URI:{}", e.getMessage()); - } catch (Exception e) { - log.error("Error reading response: {}", e.getMessage()); - } - return null; - }); + SimpleHttpResponse response; + response = + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + HttpRestClient httpClient = HttpRestClient.getInstance(); + try { + URI host = new URIBuilder(endpoint).build(); + return httpClient.post(host, body, docId); + } catch (URISyntaxException e) { + log.error("Bad URI:{}", e.getMessage()); + } + return null; + }); + return response; } } diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 507c435..c627e69 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -10,7 +10,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.mockito.InjectMocks; import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; @@ -18,6 +17,7 @@ import org.opensearch.test.OpenSearchIntegTestCase; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import java.io.IOException; import java.nio.file.Files; @@ -27,6 +27,7 @@ import java.security.GeneralSecurityException; import java.security.PrivilegedAction; +import org.mockito.InjectMocks; import org.mockito.Mock; import static org.mockito.ArgumentMatchers.any; @@ -43,8 +44,7 @@ public class CommandManagerSettingsTests extends OpenSearchIntegTestCase { @Mock Path mockedPath; - @InjectMocks - private CommandManagerSettings commandManagerSettings; + @InjectMocks private CommandManagerSettings commandManagerSettings; private static final Logger log = LogManager.getLogger(CommandManagerSettingsTests.class); @@ -65,7 +65,8 @@ public void closeSecureString() { secureString.close(); } - public void keystoreFileNotExistReturnsNull() throws Exception { + @Ignore + public void testKeystoreFileNotExistReturnsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); @@ -75,11 +76,15 @@ public void keystoreFileNotExistReturnsNull() throws Exception { (PrivilegedAction) () -> { when(Files.exists(keyStorePath)).thenReturn(false); - when(keyStorePath.toAbsolutePath().toString()).thenReturn(keyStorePath.toString()); + when(keyStorePath.toAbsolutePath().toString()) + .thenReturn(keyStorePath.toString()); - CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings result = + CommandManagerSettings.getSettings(mockEnvironment, null); - assertNull("Expected settings to be null when keystore file does not exist.", result); + assertNull( + "Expected settings to be null when keystore file does not exist.", + result); return null; }); @@ -88,7 +93,8 @@ public void keystoreFileNotExistReturnsNull() throws Exception { } } - public void keystoreFileExistsButLoadReturnsNull() throws Exception { + @Ignore + public void testKeystoreFileExistsButLoadReturnsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); @@ -99,14 +105,18 @@ public void keystoreFileExistsButLoadReturnsNull() throws Exception { () -> { when(Files.exists(keystoreFile)).thenReturn(true); try { - when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(null); + when(KeyStoreWrapper.load(keystoreFile, anyString())) + .thenReturn(null); } catch (IOException e) { } - CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings result = + CommandManagerSettings.getSettings(mockEnvironment, null); - assertNull("Expected settings to be null when keystore load returns null.", result); + assertNull( + "Expected settings to be null when keystore load returns null.", + result); return null; }); @@ -115,7 +125,8 @@ public void keystoreFileExistsButLoadReturnsNull() throws Exception { } } - public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { + @Ignore + public void testShouldDecryptKeystoreWhenPasswordIsNull() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); @@ -126,7 +137,8 @@ public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { () -> { when(Files.exists(keystoreFile)).thenReturn(true); try { - when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(mockedKeyStoreWrapper); + when(KeyStoreWrapper.load(keystoreFile, anyString())) + .thenReturn(mockedKeyStoreWrapper); } catch (IOException e) { log.error("Error when tryng to mock load: " + e.getMessage()); @@ -134,29 +146,49 @@ public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { try { doNothing().when(mockedKeyStoreWrapper).decrypt(new char[0]); - } catch (GeneralSecurityException | IOException | RuntimeException e) { - log.error("Error when tryng to mock decrypt: " + e.getMessage()); + } catch (GeneralSecurityException + | IOException + | RuntimeException e) { + log.error( + "Error when tryng to mock decrypt: " + e.getMessage()); } Settings settingsMock = mock(Settings.class); Settings.Builder builderMock = mock(Settings.Builder.class); - when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - //when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - - SecureString authUsername = new SecureString("userTesting".toCharArray()); - SecureString authPassword = new SecureString("passTesting".toCharArray()); - SecureString uri = new SecureString("http://localhost".toCharArray()); - - when(CommandManagerSettings.M_API_USERNAME.get(any())).thenReturn(authUsername); - when(CommandManagerSettings.M_API_PASSWORD.get(any())).thenReturn(authPassword); + when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()) + .thenReturn(settingsMock); + // when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + + SecureString authUsername = + new SecureString("userTesting".toCharArray()); + SecureString authPassword = + new SecureString("passTesting".toCharArray()); + SecureString uri = + new SecureString("http://localhost".toCharArray()); + + when(CommandManagerSettings.M_API_USERNAME.get(any())) + .thenReturn(authUsername); + when(CommandManagerSettings.M_API_PASSWORD.get(any())) + .thenReturn(authPassword); when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); - CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); - - assertNotNull("Expected CommandManagerSettings to be created.", result); - assertEquals("userTesting", result.authUsername, "The username should match the configured value."); - assertEquals("passTesting", result.authPassword, "The password should match the configured value."); - assertEquals("http://localhost", result.uri, "The URI should match the configured value."); + CommandManagerSettings result = + CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNotNull( + "Expected CommandManagerSettings to be created.", result); + assertEquals( + "userTesting", + result.authUsername, + "The username should match the configured value."); + assertEquals( + "passTesting", + result.authPassword, + "The password should match the configured value."); + assertEquals( + "http://localhost", + result.uri, + "The URI should match the configured value."); return null; }); @@ -165,7 +197,8 @@ public void shouldDecryptKeystoreWhenPasswordIsNull() throws Exception { } } - public void shouldDecryptKeystoreWithPassword() throws Exception { + @Ignore + public void testShouldDecryptKeystoreWithPassword() throws Exception { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); @@ -176,38 +209,62 @@ public void shouldDecryptKeystoreWithPassword() throws Exception { () -> { when(Files.exists(keystoreFile)).thenReturn(true); try { - when(KeyStoreWrapper.load(keystoreFile, anyString())).thenReturn(mockedKeyStoreWrapper); + when(KeyStoreWrapper.load(keystoreFile, anyString())) + .thenReturn(mockedKeyStoreWrapper); } catch (IOException e) { log.error("Error when tryng to mock load: " + e.getMessage()); } try { - SecureString password = new SecureString("passwordTest".toCharArray()); - doNothing().when(mockedKeyStoreWrapper).decrypt(password.getChars()); - } catch (GeneralSecurityException | IOException | RuntimeException e) { - log.error("Error when tryng to mock decrypt: " + e.getMessage()); + SecureString password = + new SecureString("passwordTest".toCharArray()); + doNothing() + .when(mockedKeyStoreWrapper) + .decrypt(password.getChars()); + } catch (GeneralSecurityException + | IOException + | RuntimeException e) { + log.error( + "Error when tryng to mock decrypt: " + e.getMessage()); } Settings settingsMock = mock(Settings.class); Settings.Builder builderMock = mock(Settings.Builder.class); - when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - //when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - - SecureString authUsername = new SecureString("userTesting".toCharArray()); - SecureString authPassword = new SecureString("passTesting".toCharArray()); - SecureString uri = new SecureString("http://localhost".toCharArray()); - - when(CommandManagerSettings.M_API_USERNAME.get(any())).thenReturn(authUsername); - when(CommandManagerSettings.M_API_PASSWORD.get(any())).thenReturn(authPassword); + when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()) + .thenReturn(settingsMock); + // when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); + + SecureString authUsername = + new SecureString("userTesting".toCharArray()); + SecureString authPassword = + new SecureString("passTesting".toCharArray()); + SecureString uri = + new SecureString("http://localhost".toCharArray()); + + when(CommandManagerSettings.M_API_USERNAME.get(any())) + .thenReturn(authUsername); + when(CommandManagerSettings.M_API_PASSWORD.get(any())) + .thenReturn(authPassword); when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); - CommandManagerSettings result = CommandManagerSettings.getSettings(mockEnvironment, null); - - assertNotNull("Expected CommandManagerSettings to be created.", result); - assertEquals("userTesting", result.authUsername, "The username should match the configured value."); - assertEquals("passTesting", result.authPassword, "The password should match the configured value."); - assertEquals("http://localhost", result.uri, "The URI should match the configured value."); + CommandManagerSettings result = + CommandManagerSettings.getSettings(mockEnvironment, null); + + assertNotNull( + "Expected CommandManagerSettings to be created.", result); + assertEquals( + "userTesting", + result.authUsername, + "The username should match the configured value."); + assertEquals( + "passTesting", + result.authPassword, + "The password should match the configured value."); + assertEquals( + "http://localhost", + result.uri, + "The URI should match the configured value."); return null; }); @@ -216,10 +273,11 @@ public void shouldDecryptKeystoreWithPassword() throws Exception { } } - + @Ignore public void testValuesOfGetSettings_keystoreExists() throws Exception { // Set up the mock to return a specific path for the config file - Path keyStorePath = Path.of("command-manager/build/testclusters/integTest-0/config").toAbsolutePath(); + Path keyStorePath = + Path.of("command-manager/build/testclusters/integTest-0/config").toAbsolutePath(); when(mockEnvironment.configFile()).thenReturn(keyStorePath); try { @@ -231,13 +289,19 @@ public void testValuesOfGetSettings_keystoreExists() throws Exception { KeyStoreWrapper keyStoreWrapper = KeyStoreWrapper.load(keyStorePath); - log.info("Is keyStoreWrapper loaded? "+keyStoreWrapper.isLoaded()); + log.info( + "Is keyStoreWrapper loaded? " + + keyStoreWrapper.isLoaded()); this.commandManagerSettings = - CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings.getSettings( + mockEnvironment, null); assertNotNull(commandManagerSettings); - log.info("Plugin settings: {}", commandManagerSettings.toString()); // verify(keyStoreWrapper, + log.info( + "Plugin settings: {}", + commandManagerSettings + .toString()); // verify(keyStoreWrapper, // times(1)).decrypt(secureString.getChars()); } catch (IOException e) { log.error("IO Error: " + e.getMessage()); From 428b365995b02b39e6b61d5061be76817d3bf51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Wed, 23 Oct 2024 19:25:02 +0200 Subject: [PATCH 18/23] Commments --- .../rest/RestPostCommandAction.java | 3 -- .../utils/httpclient/HttpRestClientDemo.java | 44 +++++++++---------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java index c9ec1c2..f0a8034 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/rest/RestPostCommandAction.java @@ -115,9 +115,6 @@ private RestChannelConsumer handlePost(RestRequest request) throws IOException { .toString(); SimpleHttpResponse response = HttpRestClientDemo.runWithResponse(receiverURI, payload, document.getId()); - - // SimpleHttpResponse response = httpClient.post(receiverURI, payload, - // document.getId()); log.info("Received response to POST request with code [{}]", response.getCode()); log.info("Raw response:\n{}", response.getBodyText()); } catch (Exception e) { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java index 036121b..f8cde0e 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClientDemo.java @@ -29,28 +29,28 @@ public class HttpRestClientDemo { * @param endpoint POST's requests endpoint as a well-formed URI * @param body POST's request body as a JSON string. */ - // public static void run(String endpoint, String body) { - // log.info("Executing POST request"); - // AccessController.doPrivileged( - // (PrivilegedAction) - // () -> { - // HttpRestClient httpClient = HttpRestClient.getInstance(); - // try { - // URI host = new URIBuilder(endpoint).build(); - // SimpleHttpResponse response = - // httpClient.post(host, body, "randomId"); - // log.info( - // "Received response to POST request with code {}", - // response.getCode()); - // log.info("Raw response:\n{}", response.getBodyText()); - // } catch (URISyntaxException e) { - // log.error("Bad URI:{}", e.getMessage()); - // } catch (Exception e) { - // log.error("Error reading response: {}", e.getMessage()); - // } - // return null; - // }); - // } + public static void run(String endpoint, String body) { + log.info("Executing POST request"); + AccessController.doPrivileged( + (PrivilegedAction) + () -> { + HttpRestClient httpClient = HttpRestClient.getInstance(); + try { + URI host = new URIBuilder(endpoint).build(); + SimpleHttpResponse response = + httpClient.post(host, body, "randomId"); + log.info( + "Received response to POST request with code {}", + response.getCode()); + log.info("Raw response:\n{}", response.getBodyText()); + } catch (URISyntaxException e) { + log.error("Bad URI:{}", e.getMessage()); + } catch (Exception e) { + log.error("Error reading response: {}", e.getMessage()); + } + return null; + }); + } /** * Demo method to test the {@link HttpRestClient} class. From 49ef455f204da1977a87daf30dd5876dcfd4087f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Ruiz?= Date: Wed, 23 Oct 2024 19:32:26 +0200 Subject: [PATCH 19/23] Replace @Ignore with @AwaitsFix --- .../settings/CommandManagerSettingsTests.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index c627e69..3e5bf41 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -17,7 +17,6 @@ import org.opensearch.test.OpenSearchIntegTestCase; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import java.io.IOException; import java.nio.file.Files; @@ -65,10 +64,10 @@ public void closeSecureString() { secureString.close(); } - @Ignore - public void testKeystoreFileNotExistReturnsNull() throws Exception { + @AwaitsFix(bugUrl = "") + public void testKeystoreFileNotExistReturnsNull() { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); try { @@ -88,15 +87,15 @@ public void testKeystoreFileNotExistReturnsNull() throws Exception { return null; }); - } catch (AccessControlException e) { + } catch (AccessControlException ignored) { } } - @Ignore - public void testKeystoreFileExistsButLoadReturnsNull() throws Exception { + @AwaitsFix(bugUrl = "") + public void testKeystoreFileExistsButLoadReturnsNull() { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); try { @@ -125,10 +124,10 @@ public void testKeystoreFileExistsButLoadReturnsNull() throws Exception { } } - @Ignore - public void testShouldDecryptKeystoreWhenPasswordIsNull() throws Exception { + @AwaitsFix(bugUrl = "") + public void testShouldDecryptKeystoreWhenPasswordIsNull() { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); try { @@ -197,10 +196,10 @@ public void testShouldDecryptKeystoreWhenPasswordIsNull() throws Exception { } } - @Ignore - public void testShouldDecryptKeystoreWithPassword() throws Exception { + @AwaitsFix(bugUrl = "") + public void testShouldDecryptKeystoreWithPassword() { Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath.toString() + "/" + KEYSTORE_FILENAME); + Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); when(mockEnvironment.configFile()).thenReturn(keystoreFile); try { @@ -273,8 +272,8 @@ public void testShouldDecryptKeystoreWithPassword() throws Exception { } } - @Ignore - public void testValuesOfGetSettings_keystoreExists() throws Exception { + @AwaitsFix(bugUrl = "") + public void testValuesOfGetSettings_keystoreExists() { // Set up the mock to return a specific path for the config file Path keyStorePath = Path.of("command-manager/build/testclusters/integTest-0/config").toAbsolutePath(); From a6f60aefdebe0d1dc217265b80f3411321dc9eeb Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Thu, 24 Oct 2024 12:49:16 -0300 Subject: [PATCH 20/23] Simplify the general logic of CommandManagerSettings. Apply Singleton pattern to CommanfManagerSettings. --- plugins/command-manager/build.gradle | 6 +- .../commandmanager/CommandManagerPlugin.java | 10 +- .../settings/CommandManagerSettings.java | 107 ++++++------------ .../CommandManagerSettingsException.java | 24 +--- .../settings/CommandManagerSettingsTests.java | 30 ++--- 5 files changed, 64 insertions(+), 113 deletions(-) rename plugins/command-manager/src/main/java/com/wazuh/commandmanager/{ => settings}/CommandManagerSettingsException.java (52%) diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle index d2689d5..74a95d9 100644 --- a/plugins/command-manager/build.gradle +++ b/plugins/command-manager/build.gradle @@ -139,9 +139,9 @@ testClusters.integTest { plugin(project.tasks.bundlePlugin.archiveFile) // add customized keystore - keystore 'm.api.username', 'admin' - keystore 'm.api.password', 'test' - keystore 'm.api.uri', 'https://httpbin.org/post' + keystore 'm_api.auth.username', 'admin' + keystore 'm_api.auth.password', 'test' + keystore 'm_api.uri', 'https://httpbin.org/post' } run { diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 5cf2292..05dd42d 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -52,6 +52,7 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin, Reload private CommandIndex commandIndex; private CommandManagerSettings commandManagerSettings; + // private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); @Override public Collection createComponents( @@ -68,7 +69,10 @@ public Collection createComponents( Supplier repositoriesServiceSupplier) { this.commandIndex = new CommandIndex(client, clusterService, threadPool); - this.commandManagerSettings = CommandManagerSettings.getSettings(environment, null); + this.commandManagerSettings = CommandManagerSettings.getInstance(environment); + //log.info("Plugin uri: {}", commandManagerSettings.getUri()); + //log.info("Plugin username: {}", commandManagerSettings.getAuthUsername()); + //log.info("Plugin password: {}", commandManagerSettings.getAuthPassword()); // HttpRestClient stuff // String uri = "https://httpbin.org/post"; @@ -93,8 +97,8 @@ public List getRestHandlers( public List> getSettings() { return Arrays.asList( // Register API settings - CommandManagerSettings.M_API_USERNAME, - CommandManagerSettings.M_API_PASSWORD, + CommandManagerSettings.M_API_AUTH_USERNAME, + CommandManagerSettings.M_API_AUTH_PASSWORD, CommandManagerSettings.M_API_URI); } diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index a773b00..d013551 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -10,50 +10,41 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.common.settings.KeyStoreWrapper; import org.opensearch.common.settings.SecureSetting; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.GeneralSecurityException; -import com.wazuh.commandmanager.CommandManagerSettingsException; - -public final class CommandManagerSettings { +public class CommandManagerSettings { /** The access key (ie login username) for connecting to api. */ - public static final Setting M_API_USERNAME = - SecureSetting.secureString("m.api.username", null); + public static final Setting M_API_AUTH_USERNAME = + SecureSetting.secureString("m_api.auth.username", null); /** The secret key (ie password) for connecting to api. */ - public static final Setting M_API_PASSWORD = - SecureSetting.secureString("m.api.password", null); + public static final Setting M_API_AUTH_PASSWORD = + SecureSetting.secureString("m_api.auth.password", null); /** The uri for connecting to api. */ public static final Setting M_API_URI = - SecureSetting.secureString("m.api.uri", null); - - private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); - - /** The name of own keystore. */ - private static final String KEYSTORE_FILENAME = "opensearch.keystore"; + SecureSetting.secureString("m_api.uri", null); /** The access key (ie login username) for connecting to api. */ - final String authUsername; + private final String authUsername; /** The password for connecting to api. */ - final String authPassword; + private final String authPassword; /** The uri for connecting to api. */ - final String uri; + private final String uri; + private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); + private static CommandManagerSettings instance; private final Settings settings; + /** Private default constructor */ private CommandManagerSettings( String authUsername, String authPassword, String uri, Settings settings) { this.authUsername = authUsername; @@ -63,74 +54,48 @@ private CommandManagerSettings( log.info("CommandManagerSettings created "); } - /** Parse settings for a single client. */ - public static CommandManagerSettings getSettings( - Environment environment, SecureString secureSettingsPassword) { - KeyStoreWrapper keyStoreWrapper = null; - Path keystoreFile = Path.of(environment.configFile() + "/" + KEYSTORE_FILENAME); - try { - if (!Files.exists(keystoreFile)) { - log.error( - CommandManagerSettingsException.keystoreNotExist( - keystoreFile.toAbsolutePath().toString()) - .getMessage()); - return null; - } else { - keyStoreWrapper = KeyStoreWrapper.load(environment.configFile(), KEYSTORE_FILENAME); - log.info("Keystore load: " + keystoreFile.toAbsolutePath().toString()); - } - } catch (Exception e) { - log.error( - CommandManagerSettingsException.loadKeystoreFailed(keystoreFile.toString()) - .getMessage()); - return null; + /** + * Singleton instance accessor + * + * @return {@link CommandManagerSettings#instance} + */ + public static CommandManagerSettings getInstance(Environment environment) { + if (CommandManagerSettings.instance == null) { + instance = CommandManagerSettings.getSettings(environment); } + return CommandManagerSettings.instance; + } - if (keyStoreWrapper == null) { - log.error( - CommandManagerSettingsException.keystoreNotExist(keystoreFile.toString()) - .getMessage()); - return null; - } else { - // Decrypt the keystore using the password from the request - try { - log.info("Decrypting the keystore."); - if (secureSettingsPassword == null || secureSettingsPassword.length() == 0) { - keyStoreWrapper.decrypt(new char[0]); - } else { - keyStoreWrapper.decrypt(secureSettingsPassword.getChars()); - } - } catch (GeneralSecurityException | IOException e) { - log.error( - CommandManagerSettingsException.decryptKeystoreFailed(KEYSTORE_FILENAME) - .getMessage()); - } + /** Parse settings for a single client. */ + public static CommandManagerSettings getSettings( + Environment environment) { - final Settings settings = Settings.builder().setSecureSettings(keyStoreWrapper).build(); - log.info("Settings created with the keystore information."); + final Settings settings = environment.settings(); + assert settings != null; + log.info("Settings created with the keystore information."); - try (SecureString authUsername = M_API_USERNAME.get(settings); - SecureString authPassword = M_API_PASSWORD.get(settings); - SecureString uri = M_API_URI.get(settings); ) { + try (SecureString authUsername = M_API_AUTH_USERNAME.get(settings); + SecureString authPassword = M_API_AUTH_PASSWORD.get(settings); + SecureString uri = M_API_URI.get(settings); ) { return new CommandManagerSettings( authUsername.toString(), authPassword.toString(), uri.toString(), - environment.settings()); + settings); } } - } + public String getAuthPassword() { - return M_API_PASSWORD.get(this.settings).toString(); + return authPassword; } public String getAuthUsername() { - return M_API_USERNAME.get(this.settings).toString(); + return authUsername; } public String getUri() { - return this.uri; + return uri; } @Override diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java similarity index 52% rename from plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java rename to plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java index 9cc073c..7ff2fc8 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerSettingsException.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java @@ -6,7 +6,7 @@ * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ -package com.wazuh.commandmanager; +package com.wazuh.commandmanager.settings; public class CommandManagerSettingsException extends Exception { @@ -30,27 +30,9 @@ public CommandManagerSettingsException(Throwable cause) { super(cause); } - // Exception for the case when the keystore does not exist - public static CommandManagerSettingsException keystoreNotExist(String keystorePath) { - return new CommandManagerSettingsException( - "The keystore does not exist at the path: " + keystorePath); - } - - // Exception for the case when the keystore is empty - public static CommandManagerSettingsException keystoreEmpty(String keystorePath) { - return new CommandManagerSettingsException( - "The keystore is empty at the path: " + keystorePath); - } - - // Exception for the case when load keystore failed - public static CommandManagerSettingsException loadKeystoreFailed(String keyStorePath) { - return new CommandManagerSettingsException("Load keystore: " + keyStorePath + " failed."); - } - // Exception for the case when load keystore failed - public static CommandManagerSettingsException decryptKeystoreFailed(String keyStorePath) { - return new CommandManagerSettingsException( - "Decrypt keystore: " + keyStorePath + " failed."); + public static CommandManagerSettingsException loadSettingsFailed(String keyStorePath, String errorMessage) { + return new CommandManagerSettingsException("Load settings from: " + keyStorePath + " failed. Error: " + errorMessage); } // Exception for the case when reload plugin with the keystore failed diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 3e5bf41..86a9a1f 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -79,7 +79,7 @@ public void testKeystoreFileNotExistReturnsNull() { .thenReturn(keyStorePath.toString()); CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings.getSettings(mockEnvironment); assertNull( "Expected settings to be null when keystore file does not exist.", @@ -111,7 +111,7 @@ public void testKeystoreFileExistsButLoadReturnsNull() { } CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings.getSettings(mockEnvironment); assertNull( "Expected settings to be null when keystore load returns null.", @@ -165,28 +165,28 @@ public void testShouldDecryptKeystoreWhenPasswordIsNull() { SecureString uri = new SecureString("http://localhost".toCharArray()); - when(CommandManagerSettings.M_API_USERNAME.get(any())) + when(CommandManagerSettings.M_API_AUTH_USERNAME.get(any())) .thenReturn(authUsername); - when(CommandManagerSettings.M_API_PASSWORD.get(any())) + when(CommandManagerSettings.M_API_AUTH_PASSWORD.get(any())) .thenReturn(authPassword); when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings.getSettings(mockEnvironment); assertNotNull( "Expected CommandManagerSettings to be created.", result); assertEquals( "userTesting", - result.authUsername, + result.getAuthUsername(), "The username should match the configured value."); assertEquals( "passTesting", - result.authPassword, + result.getAuthPassword(), "The password should match the configured value."); assertEquals( "http://localhost", - result.uri, + result.getUri(), "The URI should match the configured value."); return null; @@ -241,28 +241,28 @@ public void testShouldDecryptKeystoreWithPassword() { SecureString uri = new SecureString("http://localhost".toCharArray()); - when(CommandManagerSettings.M_API_USERNAME.get(any())) + when(CommandManagerSettings.M_API_AUTH_USERNAME.get(any())) .thenReturn(authUsername); - when(CommandManagerSettings.M_API_PASSWORD.get(any())) + when(CommandManagerSettings.M_API_AUTH_PASSWORD.get(any())) .thenReturn(authPassword); when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment, null); + CommandManagerSettings.getSettings(mockEnvironment); assertNotNull( "Expected CommandManagerSettings to be created.", result); assertEquals( "userTesting", - result.authUsername, + result.getAuthUsername(), "The username should match the configured value."); assertEquals( "passTesting", - result.authPassword, + result.getAuthPassword(), "The password should match the configured value."); assertEquals( "http://localhost", - result.uri, + result.getUri(), "The URI should match the configured value."); return null; @@ -294,7 +294,7 @@ public void testValuesOfGetSettings_keystoreExists() { this.commandManagerSettings = CommandManagerSettings.getSettings( - mockEnvironment, null); + mockEnvironment); assertNotNull(commandManagerSettings); log.info( From 8e587e54bfe581ad27c577d9f3c3717d1dc3699c Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Thu, 24 Oct 2024 16:51:46 -0300 Subject: [PATCH 21/23] Modify the test according to the new behavior of CommandManagerSettings --- .../settings/CommandManagerSettings.java | 15 +- .../settings/CommandManagerSettingsTests.java | 307 ++---------------- 2 files changed, 39 insertions(+), 283 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java index d013551..5023102 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettings.java @@ -42,15 +42,13 @@ public class CommandManagerSettings { private static final Logger log = LogManager.getLogger(CommandManagerSettings.class); private static CommandManagerSettings instance; - private final Settings settings; /** Private default constructor */ private CommandManagerSettings( - String authUsername, String authPassword, String uri, Settings settings) { + String authUsername, String authPassword, String uri) { this.authUsername = authUsername; this.authPassword = authPassword; this.uri = uri; - this.settings = settings; log.info("CommandManagerSettings created "); } @@ -71,19 +69,20 @@ public static CommandManagerSettings getSettings( Environment environment) { final Settings settings = environment.settings(); - assert settings != null; - log.info("Settings created with the keystore information."); - + if (settings != null) { + log.info("Settings created with the keystore information."); try (SecureString authUsername = M_API_AUTH_USERNAME.get(settings); SecureString authPassword = M_API_AUTH_PASSWORD.get(settings); SecureString uri = M_API_URI.get(settings); ) { return new CommandManagerSettings( authUsername.toString(), authPassword.toString(), - uri.toString(), - settings); + uri.toString()); } + }else{ + return null; } + } public String getAuthPassword() { diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java index 86a9a1f..50b3595 100644 --- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java +++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/CommandManagerSettingsTests.java @@ -8,307 +8,64 @@ */ package com.wazuh.commandmanager.settings; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.common.settings.KeyStoreWrapper; +import org.opensearch.common.settings.MockSecureSettings; import org.opensearch.common.settings.Settings; -import org.opensearch.core.common.settings.SecureString; import org.opensearch.env.Environment; import org.opensearch.test.OpenSearchIntegTestCase; -import org.junit.After; import org.junit.Before; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.GeneralSecurityException; -import java.security.PrivilegedAction; - import org.mockito.InjectMocks; import org.mockito.Mock; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE) public class CommandManagerSettingsTests extends OpenSearchIntegTestCase { @Mock private Environment mockEnvironment; - private final SecureString secureString = new SecureString("dummyPassword".toCharArray()); - - @Mock KeyStoreWrapper mockedKeyStoreWrapper; - - @Mock Path mockedPath; - @InjectMocks private CommandManagerSettings commandManagerSettings; - private static final Logger log = LogManager.getLogger(CommandManagerSettingsTests.class); - - private static final String KEYSTORE_FILENAME = "opensearch.keystore"; + Settings testSettings; @Before @Override public void setUp() throws Exception { - mockedKeyStoreWrapper = mock(KeyStoreWrapper.class); mockEnvironment = mock(Environment.class); - mockedPath = mock(Path.class); + commandManagerSettings = CommandManagerSettings.getInstance(mockEnvironment); super.setUp(); } - @After - public void closeSecureString() { - // Cleanup if necessary - secureString.close(); - } - - @AwaitsFix(bugUrl = "") - public void testKeystoreFileNotExistReturnsNull() { - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); - when(mockEnvironment.configFile()).thenReturn(keystoreFile); - - try { - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - when(Files.exists(keyStorePath)).thenReturn(false); - when(keyStorePath.toAbsolutePath().toString()) - .thenReturn(keyStorePath.toString()); - - CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment); - - assertNull( - "Expected settings to be null when keystore file does not exist.", - result); - - return null; - }); - } catch (AccessControlException ignored) { - - } - } - - @AwaitsFix(bugUrl = "") - public void testKeystoreFileExistsButLoadReturnsNull() { - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); - when(mockEnvironment.configFile()).thenReturn(keystoreFile); - - try { - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - when(Files.exists(keystoreFile)).thenReturn(true); - try { - when(KeyStoreWrapper.load(keystoreFile, anyString())) - .thenReturn(null); - } catch (IOException e) { - - } - - CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment); - - assertNull( - "Expected settings to be null when keystore load returns null.", - result); - - return null; - }); - } catch (AccessControlException e) { - - } - } - - @AwaitsFix(bugUrl = "") - public void testShouldDecryptKeystoreWhenPasswordIsNull() { - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); - when(mockEnvironment.configFile()).thenReturn(keystoreFile); - - try { - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - when(Files.exists(keystoreFile)).thenReturn(true); - try { - when(KeyStoreWrapper.load(keystoreFile, anyString())) - .thenReturn(mockedKeyStoreWrapper); - - } catch (IOException e) { - log.error("Error when tryng to mock load: " + e.getMessage()); - } - - try { - doNothing().when(mockedKeyStoreWrapper).decrypt(new char[0]); - } catch (GeneralSecurityException - | IOException - | RuntimeException e) { - log.error( - "Error when tryng to mock decrypt: " + e.getMessage()); - } - - Settings settingsMock = mock(Settings.class); - Settings.Builder builderMock = mock(Settings.Builder.class); - when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()) - .thenReturn(settingsMock); - // when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - - SecureString authUsername = - new SecureString("userTesting".toCharArray()); - SecureString authPassword = - new SecureString("passTesting".toCharArray()); - SecureString uri = - new SecureString("http://localhost".toCharArray()); - - when(CommandManagerSettings.M_API_AUTH_USERNAME.get(any())) - .thenReturn(authUsername); - when(CommandManagerSettings.M_API_AUTH_PASSWORD.get(any())) - .thenReturn(authPassword); - when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); - - CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment); - - assertNotNull( - "Expected CommandManagerSettings to be created.", result); - assertEquals( - "userTesting", - result.getAuthUsername(), - "The username should match the configured value."); - assertEquals( - "passTesting", - result.getAuthPassword(), - "The password should match the configured value."); - assertEquals( - "http://localhost", - result.getUri(), - "The URI should match the configured value."); - - return null; - }); - } catch (AccessControlException e) { - log.error("AccesControl Error: " + e.getMessage()); + public void testGetSettingsWithValidValues() throws Exception{ + final MockSecureSettings secureSettings = new MockSecureSettings(); + try{ + secureSettings.setString("m_api.auth.username", "testUser"); + secureSettings.setString("m_api.auth.password", "testPassword"); + secureSettings.setString("m_api.uri", "https://httpbin.org/post"); + testSettings = Settings.builder().setSecureSettings(secureSettings).build(); + }finally { + when(mockEnvironment.settings()).thenReturn(testSettings); + + // Call getSettings and expect a CommandManagerSettings object + commandManagerSettings = CommandManagerSettings.getSettings(mockEnvironment); + + assertNotNull("Expect that the CommandManagerSettings object is not null",commandManagerSettings); + assertEquals("The m_api.auth.username must be the same","testUser", commandManagerSettings.getAuthUsername()); + assertEquals("The m_api.auth.password must be the same","testPassword", commandManagerSettings.getAuthPassword()); + assertEquals("The m_api.uri must be the same","https://httpbin.org/post", commandManagerSettings.getUri());// Cleanup + secureSettings.close(); } } - @AwaitsFix(bugUrl = "") - public void testShouldDecryptKeystoreWithPassword() { - Path keyStorePath = Path.of("plugins/command-manager/src/test/resources/").toAbsolutePath(); - Path keystoreFile = Path.of(keyStorePath + "/" + KEYSTORE_FILENAME); - when(mockEnvironment.configFile()).thenReturn(keystoreFile); - - try { - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - when(Files.exists(keystoreFile)).thenReturn(true); - try { - when(KeyStoreWrapper.load(keystoreFile, anyString())) - .thenReturn(mockedKeyStoreWrapper); - - } catch (IOException e) { - log.error("Error when tryng to mock load: " + e.getMessage()); - } - - try { - SecureString password = - new SecureString("passwordTest".toCharArray()); - doNothing() - .when(mockedKeyStoreWrapper) - .decrypt(password.getChars()); - } catch (GeneralSecurityException - | IOException - | RuntimeException e) { - log.error( - "Error when tryng to mock decrypt: " + e.getMessage()); - } - - Settings settingsMock = mock(Settings.class); - Settings.Builder builderMock = mock(Settings.Builder.class); - when(builderMock.setSecureSettings(mockedKeyStoreWrapper).build()) - .thenReturn(settingsMock); - // when(Settings.builder().setSecureSettings(mockedKeyStoreWrapper).build()).thenReturn(settingsMock); - - SecureString authUsername = - new SecureString("userTesting".toCharArray()); - SecureString authPassword = - new SecureString("passTesting".toCharArray()); - SecureString uri = - new SecureString("http://localhost".toCharArray()); - - when(CommandManagerSettings.M_API_AUTH_USERNAME.get(any())) - .thenReturn(authUsername); - when(CommandManagerSettings.M_API_AUTH_PASSWORD.get(any())) - .thenReturn(authPassword); - when(CommandManagerSettings.M_API_URI.get(any())).thenReturn(uri); - - CommandManagerSettings result = - CommandManagerSettings.getSettings(mockEnvironment); - - assertNotNull( - "Expected CommandManagerSettings to be created.", result); - assertEquals( - "userTesting", - result.getAuthUsername(), - "The username should match the configured value."); - assertEquals( - "passTesting", - result.getAuthPassword(), - "The password should match the configured value."); - assertEquals( - "http://localhost", - result.getUri(), - "The URI should match the configured value."); - - return null; - }); - } catch (AccessControlException e) { - log.error("AccesControl Error: " + e.getMessage()); - } - } - - @AwaitsFix(bugUrl = "") - public void testValuesOfGetSettings_keystoreExists() { - // Set up the mock to return a specific path for the config file - Path keyStorePath = - Path.of("command-manager/build/testclusters/integTest-0/config").toAbsolutePath(); - when(mockEnvironment.configFile()).thenReturn(keyStorePath); - - try { - AccessController.doPrivileged( - (PrivilegedAction) - () -> { - // Simulate an existing keystore - try { - KeyStoreWrapper keyStoreWrapper = - KeyStoreWrapper.load(keyStorePath); - - log.info( - "Is keyStoreWrapper loaded? " - + keyStoreWrapper.isLoaded()); - - this.commandManagerSettings = - CommandManagerSettings.getSettings( - mockEnvironment); - - assertNotNull(commandManagerSettings); - log.info( - "Plugin settings: {}", - commandManagerSettings - .toString()); // verify(keyStoreWrapper, - // times(1)).decrypt(secureString.getChars()); - } catch (IOException e) { - log.error("IO Error: " + e.getMessage()); - } - return null; - }); - } catch (AccessControlException e) { - log.error("AccesControl Error: " + e.getMessage()); + public void testSingletonBehavior() throws Exception { + final MockSecureSettings secureSettings = new MockSecureSettings(); + try{ + secureSettings.setString("m_api.auth.username", "testUser"); + testSettings = Settings.builder().setSecureSettings(secureSettings).build(); + }finally { + when(mockEnvironment.settings()).thenReturn(testSettings); + + CommandManagerSettings settings1 = CommandManagerSettings.getInstance(mockEnvironment); + CommandManagerSettings settings2 = CommandManagerSettings.getInstance(mockEnvironment); + assertEquals("Both instances should be the same",settings1, settings2); } } } From 0d14eda542184fd46d6291c8bb382ef5723e7679 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Fri, 25 Oct 2024 10:59:00 -0300 Subject: [PATCH 22/23] Delete testing logs of CommandManagerPlugin --- .../com/wazuh/commandmanager/CommandManagerPlugin.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java index 05dd42d..f044e9a 100644 --- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java +++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/CommandManagerPlugin.java @@ -70,14 +70,7 @@ public Collection createComponents( this.commandIndex = new CommandIndex(client, clusterService, threadPool); this.commandManagerSettings = CommandManagerSettings.getInstance(environment); - //log.info("Plugin uri: {}", commandManagerSettings.getUri()); - //log.info("Plugin username: {}", commandManagerSettings.getAuthUsername()); - //log.info("Plugin password: {}", commandManagerSettings.getAuthPassword()); - - // HttpRestClient stuff - // String uri = "https://httpbin.org/post"; - // String payload = "{\"message\": \"Hello world!\"}"; - // HttpRestClientDemo.run(uri, payload); + return Collections.emptyList(); } From ad18cad3049d9da898fd7f5b2c4778b0af329d35 Mon Sep 17 00:00:00 2001 From: Malena Casas Date: Fri, 25 Oct 2024 11:08:02 -0300 Subject: [PATCH 23/23] Delete unnecesary resource wazuh-indexer.keystore.json --- .../src/test/resources/wazuh-indexer.keystore.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json diff --git a/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json b/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json deleted file mode 100644 index c93a5df..0000000 --- a/plugins/command-manager/src/test/resources/wazuh-indexer.keystore.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "name" : "wazuh-api", - "properties" : { - "uri" : "http://localhost:9090", - "auth.type" : "basicauth", - "auth.username" : "admin", - "auth.password" : "type" - } - } -] \ No newline at end of file