diff --git a/imposter/README.md b/imposter/README.md
deleted file mode 100644
index d0b5ff6c..00000000
--- a/imposter/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-## Imposter Introduction
-
-Imposter is a mock server that we use to simulate responses from the Wazuh Manager API, allowing testing and development without a live backend.
-
-### Prerequisites
-
-To use Imposter, you will need a Java Virtual Machine (JVM) installed.
-
-### Installation
-
-To use Imposter for testing during development, you first need to install it by following the [Imposter installation guide](https://github.com/gatehill/imposter-cli/blob/main/docs/install.md).
-
-### Configuration
-
-The OpenAPI specification for our service is defined by the URL in the `specFile` attribute within `wazuh-server-config.yaml`. This setup ensures that the specification is automatically updated with new versions.
-
-In `wazuh-server-config.yaml`, you can also find the configurations for specific endpoints used in our plugins. If you need to modify the default response for any endpoint, adjust the `statusCode` attribute accordingly. The possible values for `statusCode` are outlined in the OpenAPI `specFile`.
-
-### Usage
-
-After installing Imposter, set up a new Imposter instance using the following command:
-
-```bash
-IMPOSTER_OPENAPI_REMOTE_FILE_CACHE=true IMPOSTER_JS_PLUGIN=js-graal-compat imposter up -p 55000 -t jvm
-```
-
-Runing Imposter with SSL / TSL.
-```bash
-IMPOSTER_OPENAPI_REMOTE_FILE_CACHE=true IMPOSTER_JS_PLUGIN=js-graal-compat java -jar ~/.imposter/engines/imposter-4.2.4.jar --plugin openapi --tlsEnabled --configDir ~/wazuh/wazuh-indexer-plugins/imposter --listenPort 55000 --keystorePath ~/wazuh/wazuh-indexer-plugins/imposter/imposter.jks --keystorePassword password
-```
-
-- `IMPOSTER_OPENAPI_REMOTE_FILE_CACHE=true` enables caching the `specFile`.
-- `IMPOSTER_JS_PLUGIN=js-graal-compat` allows compatibility with JavaScript libraries for dynamic loading.
-
-Once Imposter is running, you can access the Swagger documentation at [http://localhost:55000/_spec/](http://localhost:55000/_spec/). Use this interface for browsing specifications or testing with tools like `curl`, or integrate it directly into your development tests.
-
-### Useful Imposter Commands
-
-- **Check Setup**: Run the following command to verify that everything is in place to start Imposter:
-
- ```bash
- imposter doctor
- ```
-
-This command checks the configuration and dependencies to ensure Imposter can run correctly.
diff --git a/imposter/orders/response.js b/imposter/orders/response.js
deleted file mode 100644
index aee600cb..00000000
--- a/imposter/orders/response.js
+++ /dev/null
@@ -1,7 +0,0 @@
-console.log(
- JSON.stringify(
- JSON.parse(context.request.body),
- undefined,
- 2
- )
- )
\ No newline at end of file
diff --git a/imposter/security/login.js b/imposter/security/login.js
deleted file mode 100644
index 48893408..00000000
--- a/imposter/security/login.js
+++ /dev/null
@@ -1,46 +0,0 @@
-exports = {};
-
-console.log = function(message) {
- print("[Log]: " + message);
-};
-
-load('https://raw.githubusercontent.com/kjur/jsrsasign/master/npm/lib/jsrsasign.js', exports);
-header = {
- "alg": "HS256",
- "typ": "JWT",
- "kid": "vpaas-magic-cookie-1fc542a3e4414a44b2611668195e2bfe/4f4910"
-};
-
-// The second part of the token is the payload, which contains the claims.
-// Claims are statements about an entity (typically, the user) and
-// additional data. There are three types of claims:
-// registered, public, and private claims.
-
-nbf = Date.now() - 1000;
-
-claims = {
- "iss": "wazuh",
- "aud": "Wazuh API REST",
- "nbf": nbf,
- "exp": nbf + 3600000,
- "sub": "wazuh",
- "rbac_roles": [
- 1
- ],
- "rbac_mode": "white"
-};
-
-
-jwt = KJUR.jws.JWS.sign("HS256", JSON.stringify(header), JSON.stringify(claims), "616161");
-console.log("JWT generated: " + jwt);
-
-resp = {
- "data": {
- "token": jwt,
- "error": 0
- }
-};
-
-respond()
- .withStatusCode(200)
- .withData(JSON.stringify(resp));
\ No newline at end of file
diff --git a/imposter/wazuh-server-config.yaml b/imposter/wazuh-server-config.yaml
deleted file mode 100644
index 0df80ae5..00000000
--- a/imposter/wazuh-server-config.yaml
+++ /dev/null
@@ -1,55 +0,0 @@
-plugin: openapi
-specFile: https://raw.githubusercontent.com/wazuh/wazuh/refs/heads/master/api/api/spec/spec.yaml
-
-# ===================================================== #
-# SECURITY
-# ===================================================== #
-
-security:
- # no requests permitted by default
- default: Deny
-
- # only requests meeting these conditions are permitted
- conditions:
- - effect: Permit
- requestHeaders:
- Authorization:
- value: Bearer .*
- operator: Matches
-
-
-resources:
- - method: GET
- path: /_spec/*
- response:
- statusCode: 200
- security:
- default: Permit
-
- - method: GET
- path: /
- response:
- statusCode: 200
- security:
- default: Permit
-
- # Login
- - method: POST
- path: /security/user/authenticate
- response:
- statusCode: 200
- scriptFile: security/login.js
- security:
- conditions:
- - effect: Permit
- requestHeaders:
- Authorization:
- value: Basic .*
- operator: Matches
-
- # Orders
- - method: POST
- path: /orders
- response:
- scriptFile:
- orders/response.js
\ No newline at end of file
diff --git a/plugins/command-manager/build.gradle b/plugins/command-manager/build.gradle
index 05767572..6655e748 100644
--- a/plugins/command-manager/build.gradle
+++ b/plugins/command-manager/build.gradle
@@ -175,11 +175,6 @@ testClusters.integTest {
if (System.getProperty("test.debug") != null) {
jvmArgs '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'
}
-
- // add customized keystore
- keystore 'm_api.auth.username', 'wazuh'
- keystore 'm_api.auth.password', 'wazuh'
- keystore 'm_api.uri', 'https://127.0.0.1:55000' // base URI of the M_API
}
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 93ae2ff5..dd4c599b 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
@@ -24,7 +24,6 @@
import org.opensearch.cluster.node.DiscoveryNodes;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.common.UUIDs;
-import org.opensearch.common.settings.*;
import org.opensearch.common.settings.ClusterSettings;
import org.opensearch.common.settings.IndexScopedSettings;
import org.opensearch.common.settings.Settings;
@@ -42,7 +41,6 @@
import org.opensearch.jobscheduler.spi.schedule.ScheduleParser;
import org.opensearch.plugins.ActionPlugin;
import org.opensearch.plugins.Plugin;
-import org.opensearch.plugins.ReloadablePlugin;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.rest.*;
import org.opensearch.script.ScriptService;
@@ -51,7 +49,6 @@
import java.io.IOException;
import java.time.Instant;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -63,8 +60,6 @@
import com.wazuh.commandmanager.jobscheduler.CommandManagerJobRunner;
import com.wazuh.commandmanager.jobscheduler.JobDocument;
import com.wazuh.commandmanager.rest.RestPostCommandAction;
-import com.wazuh.commandmanager.settings.PluginSettings;
-import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
/**
* The Command Manager plugin exposes an HTTP API with a single endpoint to receive raw commands
@@ -75,8 +70,7 @@
*
*
The Command Manager plugin is also a JobScheduler extension plugin.
*/
-public class CommandManagerPlugin extends Plugin
- implements ActionPlugin, ReloadablePlugin, JobSchedulerExtension {
+public class CommandManagerPlugin extends Plugin implements ActionPlugin, JobSchedulerExtension {
public static final String COMMAND_MANAGER_BASE_URI = "/_plugins/_command_manager";
public static final String COMMANDS_URI = COMMAND_MANAGER_BASE_URI + "/commands";
public static final String INDEX_NAME = ".commands";
@@ -111,9 +105,6 @@ public Collection createComponents(
// Command index repository initialization.
this.commandIndex = new CommandIndex(client, clusterService, threadPool);
- // Plugin settings initialization.
- PluginSettings.getInstance(environment.settings());
-
// Scheduled job initialization
// NOTE it's very likely that client and thread pool may not be required as the command
// index
@@ -171,20 +162,6 @@ public List getRestHandlers(
return Collections.singletonList(new RestPostCommandAction(this.commandIndex));
}
- @Override
- public List> getSettings() {
- return Arrays.asList(
- // Register API settings
- PluginSettings.M_API_AUTH_USERNAME,
- PluginSettings.M_API_AUTH_PASSWORD,
- PluginSettings.M_API_URI);
- }
-
- @Override
- public void reload(Settings settings) {
- // TODO
- }
-
@Override
public String getJobType() {
return CommandManagerPlugin.JOB_TYPE;
@@ -253,15 +230,4 @@ private Instant parseInstantValue(XContentParser parser) throws IOException {
XContentParserUtils.throwUnknownToken(parser.currentToken(), parser.getTokenLocation());
return null;
}
-
- /**
- * Close the resources opened by this plugin.
- *
- * @throws IOException if the plugin failed to close its resources
- */
- @Override
- public void close() throws IOException {
- super.close();
- HttpRestClient.getInstance().stopHttpAsyncClient();
- }
}
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/jobscheduler/SearchThread.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/jobscheduler/SearchThread.java
index 8c1b1bf8..3f82cbc4 100644
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/jobscheduler/SearchThread.java
+++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/jobscheduler/SearchThread.java
@@ -16,8 +16,6 @@
*/
package com.wazuh.commandmanager.jobscheduler;
-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.action.index.IndexRequest;
@@ -27,11 +25,9 @@
import org.opensearch.action.search.SearchResponse;
import org.opensearch.client.Client;
import org.opensearch.common.action.ActionFuture;
+import org.opensearch.common.time.DateUtils;
import org.opensearch.common.unit.TimeValue;
-import org.opensearch.common.xcontent.XContentFactory;
import org.opensearch.core.action.ActionListener;
-import org.opensearch.core.rest.RestStatus;
-import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.index.query.QueryBuilders;
import org.opensearch.index.query.TermQueryBuilder;
import org.opensearch.search.SearchHit;
@@ -40,11 +36,7 @@
import org.opensearch.search.builder.SearchSourceBuilder;
import org.opensearch.search.sort.SortOrder;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -52,8 +44,6 @@
import com.wazuh.commandmanager.CommandManagerPlugin;
import com.wazuh.commandmanager.model.*;
-import com.wazuh.commandmanager.settings.PluginSettings;
-import com.wazuh.commandmanager.utils.httpclient.AuthHttpRestClient;
/**
* The class in charge of searching and managing commands in {@link Status#PENDING} status and of
@@ -107,92 +97,54 @@ public static T getNestedObject(Map map, String key, Class)
- () -> {
- final AuthHttpRestClient httpClient =
- new AuthHttpRestClient();
- return httpClient.post(host, orders, null);
- });
- } catch (URISyntaxException e) {
- log.error("Invalid URI: {}", e.getMessage());
- } catch (Exception e) {
- log.error("Error sending data: {}", e.getMessage());
+ for (SearchHit hit : searchHits) {
+ final ZonedDateTime deliveryTimestampFromSearchHit =
+ Document.deliveryTimestampFromSearchHit(hit);
+ if (deliveryTimestampFromSearchHit != null
+ && deliveryTimestampFromSearchHit.isBefore(current_time)) {
+ this.setFailureStatus(hit);
+ }
}
- return response;
}
/**
- * Retrieves the hit's contents and updates the {@link Status} field to {@link Status#SENT}.
+ * Retrieves the hit's contents and updates the {@link Status} field to {@link Status#FAILURE}.
*
* @param hit The page's result we are to update.
* @throws IllegalStateException Raised by {@link ActionFuture#actionGet(long)}.
*/
@SuppressWarnings("unchecked")
- private void setSentStatus(SearchHit hit, Status status) throws IllegalStateException {
+ private void setFailureStatus(SearchHit hit) throws IllegalStateException {
final Map commandMap =
getNestedObject(
hit.getSourceAsMap(),
CommandManagerPlugin.COMMAND_DOCUMENT_PARENT_OBJECT_NAME,
Map.class);
- commandMap.put(Command.STATUS, status);
- hit.getSourceAsMap()
- .put(CommandManagerPlugin.COMMAND_DOCUMENT_PARENT_OBJECT_NAME, commandMap);
- final IndexRequest indexRequest =
- new IndexRequest()
- .index(CommandManagerPlugin.INDEX_NAME)
- .source(hit.getSourceAsMap())
- .id(hit.getId());
- this.client
- .index(indexRequest)
- .actionGet(CommandManagerPlugin.DEFAULT_TIMEOUT_SECONDS * 1000);
+
+ if (commandMap != null) {
+ commandMap.put(Command.STATUS, Status.FAILURE);
+ hit.getSourceAsMap()
+ .put(CommandManagerPlugin.COMMAND_DOCUMENT_PARENT_OBJECT_NAME, commandMap);
+ final IndexRequest indexRequest =
+ new IndexRequest()
+ .index(CommandManagerPlugin.INDEX_NAME)
+ .source(hit.getSourceAsMap())
+ .id(hit.getId());
+ this.client
+ .index(indexRequest)
+ .actionGet(CommandManagerPlugin.DEFAULT_TIMEOUT_SECONDS * 1000);
+ }
}
/**
@@ -210,6 +162,7 @@ public SearchResponse pitQuery(PointInTimeBuilder pointInTimeBuilder, Object[] s
QueryBuilders.termQuery(SearchThread.COMMAND_STATUS_FIELD, Status.PENDING);
final TimeValue timeout =
TimeValue.timeValueSeconds(CommandManagerPlugin.DEFAULT_TIMEOUT_SECONDS);
+
this.searchSourceBuilder
.query(termQueryBuilder)
.size(CommandManagerPlugin.PAGE_SIZE)
@@ -223,6 +176,7 @@ public SearchResponse pitQuery(PointInTimeBuilder pointInTimeBuilder, Object[] s
this.searchSourceBuilder.searchAfter(searchAfter);
}
searchRequest.source(this.searchSourceBuilder);
+
return this.client.search(searchRequest).actionGet(timeout);
}
@@ -239,7 +193,7 @@ public void run() {
pointInTimeBuilder,
getSearchAfter(this.currentPage).orElse(new Object[0]));
if (firstPage) {
- log.debug("Query returned {} hits.", totalHits());
+ log.info("Query returned {} hits.", totalHits());
consumableHits = totalHits();
firstPage = false;
}
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Command.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Command.java
index 7120c293..35a22ac5 100644
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Command.java
+++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Command.java
@@ -217,6 +217,16 @@ public String getUser() {
return this.user;
}
+ /**
+ * Retrieves the status of this command.
+ *
+ * @return the status of the command.
+ * @see Status
+ */
+ public Status getStatus() {
+ return this.status;
+ }
+
@Override
public String toString() {
return "Command{"
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Document.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Document.java
index 23bd2356..744e0460 100644
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Document.java
+++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Document.java
@@ -16,13 +16,16 @@
*/
package com.wazuh.commandmanager.model;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.opensearch.common.UUIDs;
import org.opensearch.common.time.DateFormatter;
import org.opensearch.common.time.DateUtils;
import org.opensearch.common.time.FormatNames;
-import org.opensearch.core.xcontent.ToXContentObject;
-import org.opensearch.core.xcontent.XContentBuilder;
-import org.opensearch.core.xcontent.XContentParser;
+import org.opensearch.common.xcontent.XContentHelper;
+import org.opensearch.common.xcontent.XContentType;
+import org.opensearch.core.xcontent.*;
+import org.opensearch.search.SearchHit;
import java.io.IOException;
import java.time.ZonedDateTime;
@@ -40,6 +43,8 @@ public class Document implements ToXContentObject {
private final ZonedDateTime timestamp;
private final ZonedDateTime deliveryTimestamp;
+ private static final Logger log = LogManager.getLogger(Document.class);
+
/**
* Default constructor.
*
@@ -78,6 +83,44 @@ public static Document parse(XContentParser parser) throws IOException {
return new Document(agent, command);
}
+ /**
+ * Returns the delivery timestamp from a search hit.
+ *
+ * @param hit search hit parser.
+ * @return delivery timestamp from Document in search hit.
+ */
+ public static ZonedDateTime deliveryTimestampFromSearchHit(SearchHit hit) {
+ ZonedDateTime deliveryTimestamp = null;
+
+ try {
+ XContentParser parser =
+ XContentHelper.createParser(
+ NamedXContentRegistry.EMPTY,
+ DeprecationHandler.IGNORE_DEPRECATIONS,
+ hit.getSourceRef(),
+ XContentType.JSON);
+
+ parser.nextToken();
+ while (parser.nextToken() != null) {
+ if (parser.currentToken().equals(XContentParser.Token.FIELD_NAME)) {
+ String fieldName = parser.currentName();
+ if (fieldName.equals(Document.DELIVERY_TIMESTAMP)) {
+ parser.nextToken();
+ deliveryTimestamp = ZonedDateTime.from(DATE_FORMATTER.parse(parser.text()));
+ } else {
+ parser.skipChildren();
+ }
+ }
+ }
+
+ parser.close();
+
+ } catch (IOException e) {
+ log.error("Delivery timestamp could not be parsed: {}", e.getMessage());
+ }
+ return deliveryTimestamp;
+ }
+
/**
* Returns the document's "_id".
*
@@ -87,6 +130,24 @@ public String getId() {
return this.id;
}
+ /**
+ * Returns the Command object associated with this Document.
+ *
+ * @return Command object
+ */
+ public Command getCommand() {
+ return this.command;
+ }
+
+ /**
+ * Returns the timestamp at which the Command was delivered to the Agent.
+ *
+ * @return ZonedDateTime object representing the delivery timestamp
+ */
+ public ZonedDateTime getDeliveryTimestamp() {
+ return this.deliveryTimestamp;
+ }
+
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Orders.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Orders.java
index 78010bf3..1fd86c97 100644
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Orders.java
+++ b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/model/Orders.java
@@ -42,6 +42,7 @@ public Orders() {
* @param searchHits the commands search result
* @return A json string payload with an array of orders to be processed
*/
+
/**
* Static builder method that initializes an instance of Orders from a SearchHits instance.
*
@@ -61,6 +62,25 @@ public static Orders fromSearchHits(SearchHits searchHits) {
return orders;
}
+ /**
+ * Overwrites the array of orders
+ *
+ * @param orders the list of orders to be set.
+ */
+ public void setOrders(ArrayList orders) {
+ this.orders.clear();
+ this.orders.addAll(orders);
+ }
+
+ /**
+ * Retrieves the list of orders.
+ *
+ * @return the current list of Order objects.
+ */
+ public ArrayList getOrders() {
+ return this.orders;
+ }
+
/**
* Adds an order to the orders array.
*
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java
deleted file mode 100644
index 93cb8786..00000000
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/CommandManagerSettingsException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.settings;
-
-public class CommandManagerSettingsException extends Exception {
-
- // Constructor that accepts a message
- public CommandManagerSettingsException(String message) {
- super(message);
- }
-
- // Exception for the case when load keystore 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
- 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
deleted file mode 100644
index 1c773f82..00000000
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/settings/PluginSettings.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.settings;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-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 reactor.util.annotation.NonNull;
-
-/** Singleton class to manage the plugin's settings. */
-public class PluginSettings {
-
- private static final Logger log = LogManager.getLogger(PluginSettings.class);
-
- /** The access key (ie login username) for connecting to api. */
- 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_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);
-
- /** Singleton instance. */
- private static PluginSettings INSTANCE;
-
- /** The access key (ie login username) for connecting to api. */
- private final SecureString authUsername;
-
- /** The password for connecting to api. */
- private final SecureString authPassword;
-
- /** The uri for connecting to api. */
- private final SecureString uri;
-
- /**
- * Private default constructor
- *
- * @param settings as obtained in createComponents.
- */
- private PluginSettings(@NonNull final Settings settings) {
- log.info("Plugin created with the keystore information.");
-
- this.authUsername = M_API_AUTH_USERNAME.get(settings);
- this.authPassword = M_API_AUTH_PASSWORD.get(settings);
- this.uri = M_API_URI.get(settings);
- }
-
- /**
- * Singleton instance accessor. Initializes the settings
- *
- * @param settings as obtained in createComponents.
- * @return {@link PluginSettings#INSTANCE}
- */
- public static PluginSettings getInstance(@NonNull final Settings settings) {
- if (PluginSettings.INSTANCE == null) {
- INSTANCE = new PluginSettings(settings);
- }
- return INSTANCE;
- }
-
- /**
- * Singleton instance accessor
- *
- * @return {@link PluginSettings#INSTANCE}
- */
- public static PluginSettings getInstance() {
- if (PluginSettings.INSTANCE == null) {
- throw new IllegalStateException("Plugin settings have not been initialized.");
- }
- return INSTANCE;
- }
-
- /**
- * Get M_API password.
- *
- * @return M_API password.
- */
- public String getAuthPassword() {
- return this.authPassword.toString();
- }
-
- /**
- * Get M_API username.
- *
- * @return M_API username.
- */
- public String getAuthUsername() {
- return this.authUsername.toString();
- }
-
- /**
- * M_API URL. For example: https://127.0.0.1:55000.
- *
- * @return M_API URL.
- */
- public String getUri() {
- return this.uri.toString();
- }
-
- @Override
- public String toString() {
- return "PluginSettings{"
- + "authUsername='"
- + getAuthUsername()
- + '\''
- + ", authPassword='"
- + getAuthUsername()
- + '\''
- + ", uri='"
- + getUri()
- + '\''
- + '}';
- }
-}
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/AuthHttpRestClient.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/AuthHttpRestClient.java
deleted file mode 100644
index 5820a19e..00000000
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/AuthHttpRestClient.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.utils.httpclient;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.net.URIBuilder;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.opensearch.core.rest.RestStatus;
-
-import java.net.HttpRetryException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Locale;
-
-import com.wazuh.commandmanager.auth.AuthCredentials;
-import com.wazuh.commandmanager.auth.HTTPAuthenticator;
-import com.wazuh.commandmanager.settings.PluginSettings;
-
-/** HttpRestClient with authentication. */
-public class AuthHttpRestClient extends HttpRestClient implements HTTPAuthenticator {
-
- private static final Logger log = LogManager.getLogger(AuthHttpRestClient.class);
-
- /** Wazuh Server Management API endpoint for basic authentication. */
- public static final String SECURITY_USER_AUTHENTICATE = "/security/user/authenticate";
-
- /** Maximum number of authentication retries before giving up. */
- public static final int MAX_RETRIES = 3;
-
- private final AuthCredentials credentials;
-
- /** Default constructor */
- public AuthHttpRestClient() {
- super();
-
- this.credentials =
- new AuthCredentials(
- PluginSettings.getInstance().getAuthUsername(),
- PluginSettings.getInstance().getAuthPassword());
- }
-
- /**
- * Sends a POST request.
- *
- * @param receiverURI Well-formed URI
- * @param payload data to send
- * @param payloadId payload ID
- * @param headers auth value (Basic "user:password", "Bearer token")
- * @return SimpleHttpResponse response
- */
- @Override
- public SimpleHttpResponse post(
- URI receiverURI, String payload, String payloadId, Header... headers) {
- try {
- return this.post(receiverURI, payload, payloadId, 0);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Sends a POST request.
- *
- * @param receiverURI Well-formed URI
- * @param payload data to send
- * @param payloadId payload ID
- * @param retries retries counter
- * @return SimpleHttpResponse response
- * @throws HttpRetryException 429 (Too Many Requests)
- */
- public SimpleHttpResponse post(
- URI receiverURI, String payload, String payloadId, Integer retries)
- throws HttpRetryException {
-
- // Recursive calls exit condition.
- if (retries == MAX_RETRIES) {
- String message =
- String.format(
- Locale.ROOT,
- "Max retries [%d/%d] reached for POST request with id [%s]",
- retries,
- MAX_RETRIES,
- payloadId);
- throw new HttpRetryException(message, RestStatus.TOO_MANY_REQUESTS.getStatus());
- }
-
- // Authenticate if required.
- if (!this.credentials.isTokenSet()) {
- this.authenticate();
- }
-
- // Perform POST request.
- SimpleHttpResponse response =
- super.post(receiverURI, payload, payloadId, this.credentials.getAuthAsHeaders());
-
- // TODO handle 403 forbidden
- // TODO handle 429 maximum number of requests reached
- // TODO prevent the above from happening: cool down + sleep between retries
-
- if (response == null) {
- log.error("No reply from server.");
- return null;
- }
- // Handle unauthorized responses.
- if (response.getCode() == RestStatus.UNAUTHORIZED.getStatus()) {
- // Invalidate current token.
- this.credentials.setToken(null);
- log.info("Token invalidated.");
- // Retry request.
- this.post(receiverURI, payload, payloadId, ++retries);
- } else if (response.getCode() == RestStatus.OK.getStatus()) {
- return response;
- }
-
- return null;
- }
-
- @Override
- public void authenticate() {
- String mApiURI = PluginSettings.getInstance().getUri();
- try {
- URI loginUri = new URIBuilder(mApiURI).appendPath(SECURITY_USER_AUTHENTICATE).build();
-
- log.info("Attempting authentication at [{}]", loginUri);
- SimpleHttpResponse loginResponse =
- super.post(loginUri, null, null, this.credentials.getAuthAsHeaders());
-
- if (loginResponse == null) {
- log.error("Authentication failed. Failure establishing connection.");
- return;
- }
-
- if (loginResponse.getCode() == RestStatus.OK.getStatus()) {
- // Parse JSON response to extract and save the JWT token.
- ObjectMapper mapper = new ObjectMapper();
- JsonNode root = mapper.readTree(loginResponse.getBodyText());
- String token = root.path("data").path("token").asText();
- this.credentials.setToken(token);
- log.info("Authentication successful");
- } else {
- log.error(
- "Authentication failed due to: {} {}",
- loginResponse.getCode(),
- loginResponse.getBodyText());
- }
- } catch (URISyntaxException e) {
- log.error("Invalid URI. Is the IP to the Wazuh Server set? - {}", e.getMessage());
- } catch (JsonMappingException e) {
- log.error("Mapping error on JSON response: {}", e.getMessage());
- } catch (JsonProcessingException e) {
- log.error("Processing error on JSON response: {}", e.getMessage());
- }
- }
-}
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpResponseCallback.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpResponseCallback.java
deleted file mode 100644
index aa4e141f..00000000
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpResponseCallback.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.utils.httpclient;
-
-import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
-import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
-import org.apache.hc.core5.concurrent.FutureCallback;
-import org.apache.hc.core5.http.message.StatusLine;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-/**
- * Default callback class for SimpleHttpResponse that implements completed() and failed() response
- * methods.
- */
-public class HttpResponseCallback implements FutureCallback {
-
- private static final Logger log = LogManager.getLogger(HttpResponseCallback.class);
-
- /** The Http get request. */
- SimpleHttpRequest httpRequest;
-
- /** The error message. */
- String errorMessage;
-
- /**
- * Deafult constructor
- *
- * @param httpRequest the request
- * @param errorMessage the error message
- */
- public HttpResponseCallback(SimpleHttpRequest httpRequest, String errorMessage) {
- this.httpRequest = httpRequest;
- this.errorMessage = errorMessage;
- }
-
- @Override
- public void completed(SimpleHttpResponse response) {
- log.debug("{}->{}", httpRequest, new StatusLine(response));
- log.debug("Got response: {} {}", response.getCode(), response.getBodyText());
- }
-
- @Override
- public void failed(Exception ex) {
- log.error("{}->{}", httpRequest, ex);
- // throw new HttpException(errorMessage, ex);
- }
-
- @Override
- public void cancelled() {
- log.debug("{} cancelled", httpRequest);
- }
-}
diff --git a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClient.java b/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClient.java
deleted file mode 100644
index d4dd461b..00000000
--- a/plugins/command-manager/src/main/java/com/wazuh/commandmanager/utils/httpclient/HttpRestClient.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.utils.httpclient;
-
-import org.apache.hc.client5.http.async.methods.*;
-import org.apache.hc.client5.http.auth.AuthScope;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
-import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
-import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
-import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
-import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
-import org.apache.hc.core5.http.ContentType;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
-import org.apache.hc.core5.io.CloseMode;
-import org.apache.hc.core5.net.URIBuilder;
-import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.ssl.SSLContextBuilder;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import javax.net.ssl.SSLContext;
-
-import java.net.URI;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import com.wazuh.commandmanager.settings.PluginSettings;
-import reactor.util.annotation.NonNull;
-import reactor.util.annotation.Nullable;
-
-import static com.wazuh.commandmanager.utils.httpclient.AuthHttpRestClient.SECURITY_USER_AUTHENTICATE;
-
-/** HTTP Rest client. Currently used to perform POST requests against the Wazuh Server. */
-public class HttpRestClient {
-
- private static final Logger log = LogManager.getLogger(HttpRestClient.class);
-
- /** Seconds on which the request times outs. */
- public static final int TIMEOUT = 5;
-
- static HttpRestClient instance;
- private CloseableHttpAsyncClient httpClient;
-
- /** Private default constructor */
- HttpRestClient() {
- startHttpAsyncClient();
- }
-
- /**
- * Singleton instance accessor
- *
- * @return {@link HttpRestClient#instance}
- */
- public static HttpRestClient getInstance() {
- if (HttpRestClient.instance == null) {
- instance = new HttpRestClient();
- }
- return HttpRestClient.instance;
- }
-
- /** Starts http async client. */
- private void startHttpAsyncClient() {
- if (this.httpClient == null) {
- try {
- // From the official example on
- // https://opensearch.org/docs/latest/clients/java/#initializing-the-client-with-ssl-and-tls-enabled-using-apache-httpclient-5-transport
-
- // Basic auth
- final String mApiURI = PluginSettings.getInstance().getUri();
- final URI loginUri =
- new URIBuilder(mApiURI).appendPath(SECURITY_USER_AUTHENTICATE).build();
- final HttpHost host = HttpHost.create(loginUri);
- final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
- credentialsProvider.setCredentials(
- new AuthScope(host),
- new UsernamePasswordCredentials(
- PluginSettings.getInstance().getAuthUsername(),
- PluginSettings.getInstance().getAuthPassword().toCharArray()));
-
- // Create a custom TrustManager that trusts self-signed certificates
- final SSLContext sslContext =
- SSLContextBuilder.create()
- .loadTrustMaterial(null, (chains, authType) -> true)
- .build();
-
- final TlsStrategy tlsStrategy =
- ClientTlsStrategyBuilder.create().setSslContext(sslContext).build();
-
- final PoolingAsyncClientConnectionManager connectionManager =
- PoolingAsyncClientConnectionManagerBuilder.create()
- .setTlsStrategy(tlsStrategy)
- .build();
-
- final IOReactorConfig ioReactorConfig =
- IOReactorConfig.custom().setSoTimeout(TIMEOUT, TimeUnit.SECONDS).build();
-
- httpClient =
- HttpAsyncClients.custom()
- .setDefaultCredentialsProvider(credentialsProvider)
- .setIOReactorConfig(ioReactorConfig)
- .setConnectionManager(connectionManager)
- .build();
- httpClient.start();
- } catch (Exception e) { // FIXME catch of generic exception
- log.error("Error starting async Http client {}", e.getMessage());
- }
- }
- }
-
- /** Stop http async client. */
- public void stopHttpAsyncClient() {
- if (this.httpClient != null) {
- log.info("Shutting down.");
- httpClient.close(CloseMode.GRACEFUL);
- httpClient = null;
- }
- }
-
- /**
- * Sends a POST request.
- *
- * @param receiverURI Well-formed URI
- * @param payload data to send
- * @param payloadId payload ID
- * @param headers auth value (Basic "user:password", "Bearer token")
- * @return SimpleHttpResponse response
- */
- public SimpleHttpResponse post(
- @NonNull URI receiverURI,
- @Nullable String payload,
- @Nullable String payloadId,
- @Nullable Header... headers) {
- try {
- final HttpHost httpHost = HttpHost.create(receiverURI);
-
- log.info("Sending payload with id [{}] to [{}]", payloadId, receiverURI);
- log.debug("Headers {}", (Object) headers);
-
- final SimpleRequestBuilder builder = SimpleRequestBuilder.post();
- if (payload != null) {
- builder.setBody(payload, ContentType.APPLICATION_JSON);
- }
- if (headers != null) {
- builder.setHeaders(headers);
- }
-
- final SimpleHttpRequest httpPostRequest =
- builder.setHttpHost(httpHost).setPath(receiverURI.getPath()).build();
-
- final Future future =
- this.httpClient.execute(
- SimpleRequestProducer.create(httpPostRequest),
- SimpleResponseConsumer.create(),
- new HttpResponseCallback(
- httpPostRequest,
- "Failed to execute outgoing POST request with payload id ["
- + payloadId
- + "]"));
-
- return future.get(TIMEOUT, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- log.error("Operation interrupted {}", e.getMessage());
- } catch (ExecutionException e) {
- log.error("Execution failed {}", e.getMessage());
- } catch (TimeoutException e) {
- log.error("Operation timed out {}", e.getMessage());
- } catch (Exception e) {
- log.error("Error sending payload with id [{}] due to {}", payloadId, e.toString());
- }
-
- return null;
- }
-}
diff --git a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/CommandManagerTests.java b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/CommandManagerTests.java
index dcf304f4..ff6e7ca4 100644
--- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/CommandManagerTests.java
+++ b/plugins/command-manager/src/test/java/com/wazuh/commandmanager/CommandManagerTests.java
@@ -16,59 +16,9 @@
*/
package com.wazuh.commandmanager;
-import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.opensearch.test.OpenSearchTestCase;
-import org.junit.Assert;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
public class CommandManagerTests extends OpenSearchTestCase {
- // Add unit tests for your plugin
-
- private HttpRestClient httpClient;
-
- // FIXME Test is flaky
- @AwaitsFix(bugUrl = "https://github.com/wazuh/wazuh-indexer-plugins/issues/163")
- public void testPost_success() {
- try {
- AccessController.doPrivileged(
- (PrivilegedAction)
- () -> {
- this.httpClient = HttpRestClient.getInstance();
- URI uri;
- try {
- uri = new URI("https://httpbin.org/post");
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- String payload = "{\"message\": \"Hello world!\"}";
- SimpleHttpResponse postResponse =
- this.httpClient.post(
- uri,
- payload,
- "randomId",
- (org.apache.hc.core5.http.Header) null);
-
- String responseText = postResponse.getBodyText();
- assertNotEquals(null, postResponse);
- assertNotEquals(null, responseText);
- assertEquals(200, postResponse.getCode());
- assertNotEquals(0, responseText.length());
- assertTrue(responseText.contains("Hello world!"));
- return postResponse;
- });
- } catch (Exception e) {
- Assert.fail("Failed to execute HTTP request: " + e);
- } finally {
- this.httpClient.stopHttpAsyncClient();
- }
- }
-
public void testPost_badUri() {}
public void testPost_badPayload() {}
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 eea4ffe9..00000000
--- a/plugins/command-manager/src/test/java/com/wazuh/commandmanager/settings/PluginSettingsTests.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2024, Wazuh Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.wazuh.commandmanager.settings;
-
-import org.opensearch.common.settings.MockSecureSettings;
-import org.opensearch.common.settings.Settings;
-import org.opensearch.env.Environment;
-import org.opensearch.test.OpenSearchIntegTestCase;
-import org.junit.Before;
-
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import static org.mockito.Mockito.*;
-
-@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.SUITE)
-public class PluginSettingsTests extends OpenSearchIntegTestCase {
- @Mock private Environment mockEnvironment;
-
- @InjectMocks private PluginSettings pluginSettings;
-
- MockSecureSettings secureSettings;
-
- Settings testSettings;
-
- @Before
- @Override
- public void setUp() throws Exception {
- secureSettings = new MockSecureSettings();
- 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();
- mockEnvironment = mock(Environment.class);
- when(mockEnvironment.settings()).thenReturn(testSettings);
- pluginSettings = PluginSettings.getInstance(mockEnvironment.settings());
- super.setUp();
- }
-
- public void testInitializeWithValidValues() throws Exception {
- // Call getSettings and expect a PluginSettings object
- pluginSettings = PluginSettings.getInstance(mockEnvironment.settings());
-
- assertNotNull("Expect that the PluginSettings object is not null", pluginSettings);
- assertEquals(
- "The m_api.auth.username must be the same",
- "testUser",
- pluginSettings.getAuthUsername());
- assertEquals(
- "The m_api.auth.password must be the same",
- "testPassword",
- pluginSettings.getAuthPassword());
- assertEquals(
- "The m_api.uri must be the same",
- "https://httpbin.org/post",
- pluginSettings.getUri()); // Cleanup
- secureSettings.close();
- }
-
- public void testSingletonBehavior() throws Exception {
- final MockSecureSettings secureSettings = new MockSecureSettings();
- PluginSettings settings1 = PluginSettings.getInstance(mockEnvironment.settings());
- PluginSettings settings2 = PluginSettings.getInstance(mockEnvironment.settings());
- assertEquals("Both instances should be the same", settings1, settings2);
- }
-}