Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add imposter #130

Merged
merged 3 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions imposter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## 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
```

- `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.
46 changes: 46 additions & 0 deletions imposter/security/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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));
19 changes: 19 additions & 0 deletions imposter/wazuh-server-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugin: openapi
specFile: https://raw.githubusercontent.com/wazuh/wazuh/refs/heads/master/api/api/spec/spec.yaml
resources:
# ===================================================== #
# SECURITY
# ===================================================== #

# Login
- method: POST
path: /security/user/authenticate
response:
statusCode: 200
scriptFile: security/login.js

# Orders
- method: POST
path: /orders
response:
statusCode: 200
6 changes: 3 additions & 3 deletions plugins/command-manager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ dependencies {
implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson_databind}"
implementation "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}"

// imposter
testImplementation "org.mockito:mockito-core:${versions.mockito}"
testImplementation "junit:junit:${versions.junit}"

// imposter
testImplementation "io.gatehill.imposter:distro-embedded:${versions.imposter}"
testImplementation "io.gatehill.imposter:imposter-server:${versions.imposter}"
testImplementation "io.gatehill.imposter:config-dynamic:${versions.imposter}"
Expand Down Expand Up @@ -142,7 +143,6 @@ task integTest(type: RestIntegTestTask) {
}
tasks.named("check").configure { dependsOn(integTest) }


integTest {
// The --debug-jvm command-line option makes the cluster debuggable; this makes the tests debuggable
if (System.getProperty("test.debug") != null) {
Expand All @@ -159,7 +159,7 @@ testClusters.integTest {
// add customized keystore
keystore 'm_api.auth.username', 'admin'
keystore 'm_api.auth.password', 'test'
keystore 'm_api.uri', 'http://127.0.0.1:9200/_plugins/_command_manager' // base URI of the M_API
keystore 'm_api.uri', 'http://127.0.0.1:55000' // base URI of the M_API
}

run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,6 @@ protected RestChannelConsumer prepareRequest(final RestRequest request, final No
throws IOException {
switch (request.method()) {
case POST:
if (request.uri().contains(SECURITY_USER_AUTHENTICATE)) {
log.info("Mocking M_API basic authentication");
return channel -> {
BytesRestResponse mockResponse =
new BytesRestResponse(
RestStatus.OK,
"application/json",
"{\"data\": { \"token\": \"test-jwt-token\" } }");
channel.sendResponse(mockResponse);
};
}

return handlePost(request);
default:
throw new IllegalArgumentException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
*/
package com.wazuh.commandmanager.settings;

import org.apache.hc.core5.net.URIBuilder;
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 java.net.URISyntaxException;

import reactor.util.annotation.NonNull;

public class PluginSettings {
Expand Down Expand Up @@ -88,6 +91,10 @@ public String getUri() {
return this.uri.toString();
}

public String getUri(String path) throws URISyntaxException {
return new URIBuilder(getUri()).setPath(path).build().toString();
}

@Override
public String toString() {
return "PluginSettings{"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class HttpRestClientDemo {

public static final String SECURITY_USER_AUTHENTICATE =
COMMAND_MANAGER_BASE_URI + "/security/user/authenticate";
public static final String ORDERS = "orders";
public static final String ORDERS = "/orders";
private static final Logger log = LogManager.getLogger(HttpRestClientDemo.class);

/**
Expand Down Expand Up @@ -60,9 +60,10 @@ public static void run(String endpoint, String body) {
* @param body POST's request body as a JSON string.
* @return
*/
public static SimpleHttpResponse runWithResponse(String body, String docId) {
public static SimpleHttpResponse runWithResponse(String body, String docId)
throws URISyntaxException {
log.info("Executing POST request");
String mApiURI = PluginSettings.getInstance().getUri();
String mApiURI = PluginSettings.getInstance().getUri(ORDERS);
SimpleHttpResponse response;
response =
AccessController.doPrivileged(
Expand Down