This is an automated email from the ASF dual-hosted git repository.
zhfeng pushed a commit to branch 3.15.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/3.15.x by this push:
new f4981d1fc4 fixes #4127 - splunk, splunk-hec SSL tests (#6314) (#6650)
f4981d1fc4 is described below
commit f4981d1fc4370c9eb237d9359258ff6c5998d594
Author: JiriOndrusek <[email protected]>
AuthorDate: Thu Oct 17 03:09:34 2024 +0200
fixes #4127 - splunk, splunk-hec SSL tests (#6314) (#6650)
---
integration-tests-support/splunk/README.adoc | 16 ++
.../support/splunk/FakeSplunkTestResource.java | 51 +++++++
.../test/support/splunk/SplunkTestResource.java | 162 +++++++++++++++++++--
integration-tests/splunk-hec/pom.xml | 133 +++++++++++++++++
.../component/splunk/hec/it/SplunkHecResource.java | 89 ++++++++++-
.../src/main/resources/application.properties | 17 +++
.../component/splunk/hec/it/SplunkHecTest.java | 30 +++-
.../src/test/resources/local_inputs.conf | 6 +
.../src/test/resources/local_server.conf | 33 +++++
integration-tests/splunk/pom.xml | 5 +
.../component/splunk/it/SplunkResource.java | 72 +++++++--
.../quarkus/component/splunk/it/SplunkTest.java | 103 +++++++------
.../splunk/src/test/resources/local_inputs.conf | 6 +
.../splunk/src/test/resources/local_server.conf | 25 ++++
14 files changed, 667 insertions(+), 81 deletions(-)
diff --git a/integration-tests-support/splunk/README.adoc
b/integration-tests-support/splunk/README.adoc
new file mode 100644
index 0000000000..08a2402e7e
--- /dev/null
+++ b/integration-tests-support/splunk/README.adoc
@@ -0,0 +1,16 @@
+=== Development information
+
+* `Security` If no custom certificate is provided, splunk server creates its
own one and the `SplunkTestResource` copies it from the container into
`test-classes`
+* `Security` Server certificate has to be signed (that is the reason of using
keytool in the pom.xml)
+* `Security` SSL connection can be verified by openssl tool
+```
+openssl s_client -connect localhost:32825 -CAfile cacert.pem
+```
+* `Security` Server certificate has to contain a private key, which could not
be done via keytool itself. Proper way of achieving such certificate is to use
Openssl tool. The `TestResource` is concatenating certificates and keys
programmatically.
+```
+openssl pkcs12 -export -out combined.p12 -inkey localhost-key.pem -in
localhost.pem -certfile splunkca.pem
+openssl pkcs12 -in combined.p12 -out combined.pem -nodes
+```
+* Set log level to debug for `org.apache.camel.quarkus.test.support.splunk`
(by adding
`quarkus.log.category.\"org.apache.camel.quarkus.test.support.splunk\".level=DEBUG`
into application.properties) to see more important information from runtime.
+* `TestResource` is exporting configuration files, log and certificates to the
`test-classes` folder.
+* Splunk server takes a lot of time to start. It might be handy to start a
test with a different process with some timeout (like several hours) and use
FakeSplunkTestResource with hardcoded ports.
\ No newline at end of file
diff --git
a/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/FakeSplunkTestResource.java
b/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/FakeSplunkTestResource.java
new file mode 100644
index 0000000000..c2094bee5f
--- /dev/null
+++
b/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/FakeSplunkTestResource.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.test.support.splunk;
+
+import java.util.Map;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Test Resource meant for development. Replace port numbers with the real
ports of the container running in different
+ * process.
+ * See README.adoc for more hints.
+ */
+public class FakeSplunkTestResource implements
QuarkusTestResourceLifecycleManager {
+
+ @Override
+ public Map<String, String> start() {
+
+ String banner = StringUtils.repeat("*", 50);
+
+ Map<String, String> m = Map.of(
+ SplunkConstants.PARAM_REMOTE_HOST, "localhost",
+ SplunkConstants.PARAM_TCP_PORT, "328854",
+ SplunkConstants.PARAM_HEC_TOKEN,
"TESTTEST-TEST-TEST-TEST-TESTTESTTEST",
+ SplunkConstants.PARAM_TEST_INDEX,
SplunkTestResource.TEST_INDEX,
+ SplunkConstants.PARAM_REMOTE_PORT, "32885",
+ SplunkConstants.PARAM_HEC_PORT, "32886");
+
+ return m;
+
+ }
+
+ @Override
+ public void stop() {
+ }
+}
diff --git
a/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/SplunkTestResource.java
b/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/SplunkTestResource.java
index e34ca450de..69a951a950 100644
---
a/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/SplunkTestResource.java
+++
b/integration-tests-support/splunk/src/test/java/org/apache/camel/quarkus/test/support/splunk/SplunkTestResource.java
@@ -16,16 +16,36 @@
*/
package org.apache.camel.quarkus.test.support.splunk;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
import java.time.Duration;
+import java.util.Base64;
import java.util.Map;
import java.util.TimeZone;
+import java.util.stream.Collectors;
+import io.quarkus.logging.Log;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.config.ConfigProvider;
-import org.jboss.logging.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.images.builder.Transferable;
+import org.testcontainers.utility.MountableFile;
public class SplunkTestResource implements QuarkusTestResourceLifecycleManager
{
@@ -36,12 +56,28 @@ public class SplunkTestResource implements
QuarkusTestResourceLifecycleManager {
private static final int REMOTE_PORT = 8089;
private static final int WEB_PORT = 8000;
private static final int HEC_PORT = 8088;
- private static final Logger LOG =
Logger.getLogger(SplunkTestResource.class);
+ private static final Logger LOG =
LoggerFactory.getLogger(SplunkTestResource.class);
private GenericContainer<?> container;
+ private String localhostCertPath;
+ private String localhostKeystorePath;
+ private String caCertPath;
+ private String keystorePassword;
+
+ @Override
+ public void init(Map<String, String> initArgs) {
+ localhostCertPath = initArgs.get("localhost_cert");
+ caCertPath = initArgs.get("ca_cert");
+ localhostKeystorePath = initArgs.get("localhost_keystore");
+ keystorePassword = initArgs.get("keystore_password");
+ }
+
@Override
public Map<String, String> start() {
+
+ String banner = StringUtils.repeat("*", 50);
+
try {
container = new GenericContainer<>(SPLUNK_IMAGE_NAME)
.withExposedPorts(REMOTE_PORT, SplunkConstants.TCP_PORT,
WEB_PORT, HEC_PORT)
@@ -54,41 +90,137 @@ public class SplunkTestResource implements
QuarkusTestResourceLifecycleManager {
Wait.forLogMessage(".*Ansible playbook
complete.*\\n", 1)
.withStartupTimeout(Duration.ofMinutes(5)));
+ if (localhostCertPath != null && localhostKeystorePath != null &&
caCertPath != null && keystorePassword != null) {
+ //combine key + certificates into 1 pem - required for splunk
+ //extraction of private key can not be done by keytool (only
openssl), but it can be done programmatically
+ byte[] concatenate = concatenateKeyAndCertificates(banner);
+
+ container.withCopyToContainer(Transferable.of(concatenate),
"/opt/splunk/etc/auth/mycerts/myServerCert.pem")
+
.withCopyToContainer(Transferable.of(Files.readAllBytes(Paths.get(caCertPath))),
+ "/opt/splunk/etc/auth/mycerts/cacert.pem");
+ } else {
+ LOG.debug("Internal certificates are used for Splunk server.");
+ }
+
container.start();
- container.execInContainer("sudo", "sed", "-i",
"s/allowRemoteLogin=requireSetPassword/allowRemoteLogin=always/",
- "/opt/splunk/etc/system/default/server.conf");
- container.execInContainer("sudo", "sed", "-i", "s/enableSplunkdSSL
= true/enableSplunkdSSL = false/",
- "/opt/splunk/etc/system/default/server.conf");
+
container.copyFileToContainer(MountableFile.forClasspathResource("local_server.conf"),
+ "/opt/splunk/etc/system/local/server.conf");
+
container.copyFileToContainer(MountableFile.forClasspathResource("local_inputs.conf"),
+ "/opt/splunk/etc/system/local/inputs.conf");
+
+
container.copyFileToContainer(MountableFile.forClasspathResource("local_server.conf"),
+ "/opt/splunk/etc/system/local/server.conf");
+
container.copyFileToContainer(MountableFile.forClasspathResource("local_inputs.conf"),
+ "/opt/splunk/etc/system/local/inputs.conf");
+
container.execInContainer("sudo", "sed", "-i", "s/minFreeSpace =
5000/minFreeSpace = 100/",
- "/opt/splunk/etc/system/default/server.conf");
+ "/opt/splunk/etc/system/local/server.conf");
+
+ /* uncomment for troubleshooting purposes - copy configuration
from container
+
container.copyFileFromContainer("/opt/splunk/etc/system/local/server.conf",
+
Path.of(getClass().getResource("/").getPath()).resolve("local_server_from_container.conf").toFile()
+ .getAbsolutePath());*/
- container.execInContainer("sudo", "microdnf", "--nodocs",
"update", "tzdata");//install tzdata package so we can specify tz other than UTC
+ assertExecResult(container.execInContainer("sudo", "microdnf",
"--nodocs", "update", "tzdata"), "tzdata install");//install tzdata package so
we can specify tz other than UTC
+
+ LOG.debug(banner);
+ LOG.debug("Restarting splunk server.");
+ LOG.debug(banner);
+
+ assertExecResult(container.execInContainer("sudo", "./bin/splunk",
"restart"), "splunk restart");
- container.execInContainer("sudo", "./bin/splunk", "restart");
container.execInContainer("sudo", "./bin/splunk", "add", "index",
TEST_INDEX);
container.execInContainer("sudo", "./bin/splunk", "add", "tcp",
String.valueOf(SplunkConstants.TCP_PORT),
"-sourcetype", "TCP");
- String splunkHost = container.getHost();
+ /*uncomment for troubleshooting purposes - copy from container
conf and log files
+
container.copyFileFromContainer("/opt/splunk/etc/system/local/server.conf",
+
Path.of(getClass().getResource("/").getPath()).resolve("local-server-from-container.conf").toFile()
+ .getAbsolutePath());
+
container.copyFileFromContainer("/opt/splunk/etc/system/default/server.conf",
+
Path.of(getClass().getResource("/").getPath()).resolve("default-server-from-container.log").toFile()
+ .getAbsolutePath());
+ if (localhostCertPath != null && localhostKeystorePath != null &&
caCertPath != null && keystorePassword != null) {
+
container.copyFileFromContainer("/opt/splunk/etc/auth/mycerts/myServerCert.pem",
+
Path.of(getClass().getResource("/").getPath()).resolve("myServerCert-from-container.pem").toFile()
+ .getAbsolutePath());
+
container.copyFileFromContainer("/opt/splunk/etc/auth/mycerts/cacert.pem",
+
Path.of(getClass().getResource("/").getPath()).resolve("cacert-from-container.pem").toFile()
+ .getAbsolutePath());
+ } else {
+
container.copyFileFromContainer("/opt/splunk/etc/auth/server.pem",
+
Path.of(getClass().getResource("/").getPath()).resolve("myServerCert-from-container.pem").toFile()
+ .getAbsolutePath());
+
container.copyFileFromContainer("/opt/splunk/etc/auth/cacert.pem",
+
Path.of(getClass().getResource("/").getPath()).resolve("cacert-from-container.pem").toFile()
+ .getAbsolutePath());
+ }
+ */
- String banner = StringUtils.repeat("*", 50);
- LOG.info(banner);
- LOG.infof("Splunk UI running on: http://%s:%d", splunkHost,
container.getMappedPort(WEB_PORT));
- LOG.info(banner);
+ String splunkHost = container.getHost();
- return Map.of(
+ Map<String, String> m = Map.of(
SplunkConstants.PARAM_REMOTE_HOST, splunkHost,
SplunkConstants.PARAM_TCP_PORT,
container.getMappedPort(SplunkConstants.TCP_PORT).toString(),
SplunkConstants.PARAM_HEC_TOKEN, HEC_TOKEN,
SplunkConstants.PARAM_TEST_INDEX, TEST_INDEX,
SplunkConstants.PARAM_REMOTE_PORT,
container.getMappedPort(REMOTE_PORT).toString(),
SplunkConstants.PARAM_HEC_PORT,
container.getMappedPort(HEC_PORT).toString());
+
+ LOG.info(banner);
+ LOG.info(String.format("Splunk UI running on: http://%s:%d",
splunkHost, container.getMappedPort(WEB_PORT)));
+ LOG.info(banner);
+ LOG.debug(m.entrySet().stream().map(e -> e.getKey() + ": " +
e.getValue()).sorted()
+ .collect(Collectors.joining("\n")));
+ LOG.debug(banner);
+
+ return m;
+
} catch (Exception e) {
throw new RuntimeException(e);
}
}
+ private byte @NotNull [] concatenateKeyAndCertificates(String banner)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, UnrecoverableKeyException {
+ // Load the KeyStore
+ KeyStore keystore = KeyStore.getInstance("JKS");
+ try (FileInputStream fis = new FileInputStream(
+ Paths.get(localhostKeystorePath).toFile())) {
+ keystore.load(fis, keystorePassword.toCharArray());
+ }
+ // Get the private key
+ Key key = keystore.getKey(keystore.aliases().asIterator().next(),
keystorePassword.toCharArray());
+
+ // Encode the private key to PEM format
+ String encodedKey =
Base64.getEncoder().encodeToString(key.getEncoded());
+ String pemKey = "-----BEGIN PRIVATE KEY-----\n" + encodedKey +
"\n-----END PRIVATE KEY-----";
+
+ //localhost.pem and cacert.pem has to be concatenated
+ String localhost = Files.readString(
+ Paths.get(localhostCertPath),
+ StandardCharsets.UTF_8);
+ String ca = Files.readString(Path.of(caCertPath),
+ StandardCharsets.UTF_8);
+ Log.debug("cacert content:");
+ Log.debug(ca);
+ Log.debug(banner);
+ byte[] concatenate = (localhost + ca +
pemKey).getBytes(StandardCharsets.UTF_8);
+ return concatenate;
+ }
+
+ private static void assertExecResult(Container.ExecResult res, String cmd)
{
+ if (res.getExitCode() != 0) {
+ LOG.error("Command: " + cmd);
+ LOG.error("Stdout: " + res.getStdout());
+ LOG.error("Stderr: " + res.getStderr());
+ throw new RuntimeException("Command " + cmd + ") failed. " +
res.getStdout());
+ } else {
+ LOG.debug("Command: " + cmd + " succeeded!");
+ }
+ }
+
@Override
public void stop() {
try {
diff --git a/integration-tests/splunk-hec/pom.xml
b/integration-tests/splunk-hec/pom.xml
index 5fdf502182..9f031e657e 100644
--- a/integration-tests/splunk-hec/pom.xml
+++ b/integration-tests/splunk-hec/pom.xml
@@ -98,6 +98,139 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>full</id>
+ <activation>
+ <property>
+ <name>!quickly</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>keytool-maven-plugin</artifactId>
+ <configuration>
+ <keypass>password</keypass>
+ <validity>18250</validity>
+ <keyalg>RSA</keyalg>
+ <storepass>password</storepass>
+ </configuration>
+ <executions>
+ <execution>
+ <id>generate-splunkca-keypair</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>clean</goal>
+ <goal>generateKeyPair</goal>
+ </goals>
+ <configuration>
+ <alias>cxfca</alias>
+ <dname>CN=splunkca, OU=eng,
O=apache.org</dname>
+ <exts>
+
<ext>bc:c=ca:true,pathlen:2147483647</ext>
+
<ext>IssuerAlternativeName=DNS:NOT-FOR-PRODUCTION-USE</ext>
+ </exts>
+
<keystore>${project.basedir}/target/certs/splunkca.jks</keystore>
+ </configuration>
+ </execution>
+ <execution>
+ <id>export-splunkca-certificate</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>exportCertificate</goal>
+ </goals>
+ <configuration>
+ <alias>cxfca</alias>
+
<keystore>${project.basedir}/target/certs//splunkca.jks</keystore>
+ <rfc>true</rfc>
+
<file>${project.basedir}/target/certs/splunkca.pem</file>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-localhost-keypair</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>clean</goal>
+ <goal>generateKeyPair</goal>
+ </goals>
+ <configuration>
+ <alias>localhost</alias>
+ <dname>CN=localhost, OU=eng,
O=apache.org</dname>
+ <exts>
+
<ext>IssuerAlternativeName=DNS:NOT-FOR-PRODUCTION-USE</ext>
+
<ext>SubjectAlternativeName=DNS:localhost,IP:127.0.0.1</ext>
+ </exts>
+
<keystore>${project.basedir}/target/certs/localhost.jks</keystore>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-localhost-certificate-request</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generateCertificateRequest</goal>
+ </goals>
+ <configuration>
+ <alias>localhost</alias>
+
<keystore>${project.basedir}/target/certs/localhost.jks</keystore>
+
<file>${project.basedir}/target/certs/localhost.csr</file>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-localhost-certificate</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generateCertificate</goal>
+ </goals>
+ <configuration>
+ <alias>cxfca</alias>
+
<keystore>${project.basedir}/target/certs/splunkca.jks</keystore>
+ <rfc>true</rfc>
+
<infile>${project.basedir}/target/certs/localhost.csr</infile>
+
<outfile>${project.basedir}/target/certs/localhost.pem</outfile>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-wrong-splunkca-keypair</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>clean</goal>
+ <goal>generateKeyPair</goal>
+ </goals>
+ <configuration>
+ <alias>cxfca</alias>
+ <dname>CN=splunkca, OU=eng,
O=apache.org</dname>
+ <exts>
+
<ext>bc:c=ca:true,pathlen:2147483647</ext>
+
<ext>IssuerAlternativeName=DNS:NOT-FOR-PRODUCTION-USE</ext>
+ </exts>
+
<keystore>${project.basedir}/target/certs/wrong-splunkca.jks</keystore>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>ssl debug</id>
+ <activation>
+ <property>
+ <name>ssldebug</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>-Djavax.net.debug=ssl,handshake</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
<profile>
<id>virtualDependencies</id>
<activation>
diff --git
a/integration-tests/splunk-hec/src/main/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecResource.java
b/integration-tests/splunk-hec/src/main/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecResource.java
index a0fc5eb515..10c6f88627 100644
---
a/integration-tests/splunk-hec/src/main/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecResource.java
+++
b/integration-tests/splunk-hec/src/main/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecResource.java
@@ -16,16 +16,33 @@
*/
package org.apache.camel.quarkus.component.splunk.hec.it;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
+import jakarta.inject.Named;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.splunkhec.SplunkHECConstants;
import org.apache.camel.quarkus.test.support.splunk.SplunkConstants;
+import org.apache.camel.support.jsse.SSLContextParameters;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@Path("/splunk-hec")
@@ -47,11 +64,75 @@ public class SplunkHecResource {
@ConfigProperty(name = SplunkConstants.PARAM_HEC_TOKEN)
String token;
- @Path("/send")
+ @Path("/send/{sslContextParameters}")
@POST
@Produces(MediaType.TEXT_PLAIN)
- public String send(String data, @QueryParam("indexTime") Long indexTime) {
- String url =
String.format("splunk-hec:%s:%s?token=%s&skipTlsVerify=true&index=%s", host,
hecPort, token, index);
- return producer.requestBodyAndHeader(url, data,
SplunkHECConstants.INDEX_TIME, indexTime, String.class);
+ public Response send(String data,
+ @PathParam("sslContextParameters") String sslContextParameters,
+ @QueryParam("indexTime") Long indexTime) {
+ String url = String.format(
+
"splunk-hec:%s:%s?token=%s&sslContextParameters=#%s&skipTlsVerify=false&https=true&index=%s",
+ host, hecPort, token, sslContextParameters, index);
+ try {
+ return Response.status(200)
+ .entity(producer.requestBodyAndHeader(url, data,
SplunkHECConstants.INDEX_TIME, indexTime, String.class))
+ .build();
+ } catch (Exception e) {
+ if (e.getCause() instanceof SSLException) {
+ return Response.status(500).entity("ssl exception").build();
+ }
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Named("sslContextParameters")
+ public SSLContextParameters createServerSSLContextParameters() {
+ return createServerSSLContextParameters("target/certs/splunkca.jks");
+ }
+
+ /**
+ * Creates SSL Context Parameters for the server
+ *
+ * @return
+ */
+ @Named("wrongSslContextParameters")
+ public SSLContextParameters createWrongServerSSLContextParameters() {
+ return
createServerSSLContextParameters("target/certs/wrong-splunkca.jks");
+ }
+
+ private SSLContextParameters createServerSSLContextParameters(String
keystore) {
+ return new SSLContextParameters() {
+ @Override
+ public SSLContext createSSLContext(CamelContext camelContext)
throws GeneralSecurityException, IOException {
+
+ ///bealdung https://www.baeldung.com/java-custom-truststore
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory
+
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init((KeyStore) null);
+
+ try (FileInputStream myKeys = new FileInputStream(
+ Paths.get(keystore).toFile())) {
+ KeyStore myTrustStore =
KeyStore.getInstance(KeyStore.getDefaultType());
+ myTrustStore.load(myKeys, "password".toCharArray());
+ trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(myTrustStore);
+
+ X509TrustManager myTrustManager = null;
+ for (TrustManager tm :
trustManagerFactory.getTrustManagers()) {
+ if (tm instanceof X509TrustManager x509TrustManager) {
+ myTrustManager = x509TrustManager;
+ break;
+ }
+ }
+
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, new TrustManager[] { myTrustManager },
null);
+ return context;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+ };
}
}
diff --git
a/integration-tests/splunk-hec/src/main/resources/application.properties
b/integration-tests/splunk-hec/src/main/resources/application.properties
new file mode 100644
index 0000000000..47eb4f6786
--- /dev/null
+++ b/integration-tests/splunk-hec/src/main/resources/application.properties
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+quarkus.native.resources.includes = target/certs/*.jks
diff --git
a/integration-tests/splunk-hec/src/test/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecTest.java
b/integration-tests/splunk-hec/src/test/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecTest.java
index 701b9cb153..376f98d0f5 100644
---
a/integration-tests/splunk-hec/src/test/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecTest.java
+++
b/integration-tests/splunk-hec/src/test/java/org/apache/camel/quarkus/component/splunk/hec/it/SplunkHecTest.java
@@ -21,30 +21,36 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.apache.camel.quarkus.test.support.splunk.SplunkConstants;
import org.apache.camel.quarkus.test.support.splunk.SplunkTestResource;
import org.eclipse.microprofile.config.ConfigProvider;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.testcontainers.shaded.org.awaitility.Awaitility;
import org.testcontainers.shaded.org.hamcrest.core.StringContains;
@QuarkusTest
-@QuarkusTestResource(SplunkTestResource.class)
-class SplunkHecTest {
+@QuarkusTestResource(value = SplunkTestResource.class, initArgs = {
+ @ResourceArg(name = "localhost_cert", value =
"target/certs/localhost.pem"),
+ @ResourceArg(name = "ca_cert", value = "target/certs/splunkca.pem"),
+ @ResourceArg(name = "localhost_keystore", value =
"target/certs/localhost.jks"),
+ @ResourceArg(name = "keystore_password", value = "password") })
+public class SplunkHecTest {
@Test
public void produce() {
- String url = String.format("http://%s:%d",
+ String url = String.format("https://%s:%d",
getConfigValue(SplunkConstants.PARAM_REMOTE_HOST,
String.class),
getConfigValue(SplunkConstants.PARAM_REMOTE_PORT,
Integer.class));
RestAssured.given()
.body("Hello Sheldon")
- .post("/splunk-hec/send")
+ .post("/splunk-hec/send/sslContextParameters")
.then()
.statusCode(200);
@@ -60,12 +66,22 @@ class SplunkHecTest {
.then().statusCode(200)
.extract().asString(),
StringContains.containsString("Hello Sheldon"));
+ }
+ @Test
+ public void produceWithWrongCertificate() {
+ RestAssured.given()
+ .body("Hello Sheldon")
+ .post("/splunk-hec/send/wrongSslContextParameters")
+ .then()
+ .statusCode(500)
+
.body(Matchers.either(org.hamcrest.core.StringContains.containsString("ssl
exception"))
+
.or(org.hamcrest.core.StringContains.containsString("Connection refused")));
}
@Test
public void testIndexTime() {
- String url = String.format("http://%s:%d",
+ String url = String.format("https://%s:%d",
getConfigValue(SplunkConstants.PARAM_REMOTE_HOST,
String.class),
getConfigValue(SplunkConstants.PARAM_REMOTE_PORT,
Integer.class));
@@ -76,7 +92,7 @@ class SplunkHecTest {
//send an event with text 'Hello Time 01'
RestAssured.given()
.body("Hello time 01")
- .post("/splunk-hec/send")
+ .post("/splunk-hec/send/sslContextParameters")
.then()
.statusCode(200);
@@ -84,7 +100,7 @@ class SplunkHecTest {
RestAssured.given()
.body("Hello time 02")
.queryParam("indexTime", calendar.getTimeInMillis())
- .post("/splunk-hec/send")
+ .post("/splunk-hec/send/sslContextParameters")
.then()
.statusCode(200);
diff --git a/integration-tests/splunk-hec/src/test/resources/local_inputs.conf
b/integration-tests/splunk-hec/src/test/resources/local_inputs.conf
new file mode 100644
index 0000000000..03ce3b62fe
--- /dev/null
+++ b/integration-tests/splunk-hec/src/test/resources/local_inputs.conf
@@ -0,0 +1,6 @@
+[default]
+host = localhost
+
+[splunktcp-ssl:9997]
+
+disabled=0
\ No newline at end of file
diff --git a/integration-tests/splunk-hec/src/test/resources/local_server.conf
b/integration-tests/splunk-hec/src/test/resources/local_server.conf
new file mode 100644
index 0000000000..93a12d0e87
--- /dev/null
+++ b/integration-tests/splunk-hec/src/test/resources/local_server.conf
@@ -0,0 +1,33 @@
+[general]
+serverName = b66b768099db
+pass4SymmKey = $7$oeVDSaCZOSOMIVB0Yv2lBqldGvLt0pXWuQdDV7YvZ0d6Kwf/f0RwhQ==
+allowRemoteLogin = always
+
+[sslConfig]
+caTrustStore = splunk
+serverCert = /opt/splunk/etc/auth/mycerts/myServerCert.pem
+sslPassword = password
+requireClientCert = false
+cipherSuite = ECDHE-RSA-AES256-GCM-SHA384
+sslRootCAPath = /opt/splunk/etc/auth/mycerts/cacert.pem
+
+[lmpool:auto_generated_pool_download-trial]
+description = auto_generated_pool_download-trial
+peers = *
+quota = MAX
+stack_id = download-trial
+
+[lmpool:auto_generated_pool_forwarder]
+description = auto_generated_pool_forwarder
+peers = *
+quota = MAX
+stack_id = forwarder
+
+[lmpool:auto_generated_pool_free]
+description = auto_generated_pool_free
+peers = *
+quota = MAX
+stack_id = free
+
+[license]
+active_group = Free
diff --git a/integration-tests/splunk/pom.xml b/integration-tests/splunk/pom.xml
index 445fcbb8fc..be5241bc88 100644
--- a/integration-tests/splunk/pom.xml
+++ b/integration-tests/splunk/pom.xml
@@ -69,6 +69,11 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
diff --git
a/integration-tests/splunk/src/main/java/org/apache/camel/quarkus/component/splunk/it/SplunkResource.java
b/integration-tests/splunk/src/main/java/org/apache/camel/quarkus/component/splunk/it/SplunkResource.java
index 18fd9b8db2..c87ca43b54 100644
---
a/integration-tests/splunk/src/main/java/org/apache/camel/quarkus/component/splunk/it/SplunkResource.java
+++
b/integration-tests/splunk/src/main/java/org/apache/camel/quarkus/component/splunk/it/SplunkResource.java
@@ -42,6 +42,7 @@ import org.apache.camel.component.splunk.SplunkConfiguration;
import org.apache.camel.component.splunk.event.SplunkEvent;
import org.apache.camel.quarkus.test.support.splunk.SplunkConstants;
import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jetbrains.annotations.NotNull;
@Path("/splunk")
@ApplicationScoped
@@ -72,26 +73,37 @@ public class SplunkResource {
return component;
}
+ @Path("/ssl/results/{name}")
+ @POST
+ public String resultsSsl(@PathParam("name") String mapName) {
+ return results(true, mapName);
+ }
+
@Path("/results/{name}")
@POST
- public String results(@PathParam("name") String mapName) throws Exception {
+ public String results(@PathParam("name") String mapName) {
+ return results(false, mapName);
+ }
+
+ private String results(boolean ssl, String mapName) {
String url;
int count = 3;
if ("savedSearch".equals(mapName)) {
url = String.format(
-
"splunk://savedsearch?username=admin&password=changeit&scheme=http&host=%s&port=%d&delay=500&initEarliestTime=-10m&savedsearch=%s",
- host, port, SAVED_SEARCH_NAME);
+
"%s://savedsearch?username=admin&password=changeit&scheme=%s&host=%s&port=%d&delay=500&initEarliestTime=-10m&savedsearch=%s",
+ getComponent(ssl), ssl ?
"https&validateCertificates=false" : "http", host, port, SAVED_SEARCH_NAME);
} else if ("normalSearch".equals(mapName)) {
url = String.format(
-
"splunk://normal?username=admin&password=changeit&scheme=http&host=%s&port=%d&delay=5000&initEarliestTime=-10s&search="
+
"%s://normal?username=admin&password=changeit&scheme=%s&host=%s&port=%d&delay=5000&initEarliestTime=-10s&search="
+ "search sourcetype=\"SUBMIT\" | rex field=_raw
\"Name: (?<name>.*) From: (?<from>.*)\"",
- host, port);
+ getComponent(ssl), ssl ?
"https&validateCertificates=false" : "http", host, port);
} else {
url = String.format(
-
"splunk://realtime?username=admin&password=changeit&scheme=http&host=%s&port=%d&delay=3000&initEarliestTime=rt-10s&latestTime=RAW(rt+40s)&search="
+
"%s://realtime?username=admin&password=changeit&scheme=%s&host=%s&port=%d&delay=3000&initEarliestTime=rt-10s&latestTime=RAW(rt+40s)&search="
+ "search sourcetype=\"STREAM\" | rex field=_raw
\"Name: (?<name>.*) From: (?<from>.*)\"",
- host, port, ProducerType.STREAM.name());
+ getComponent(ssl), ssl ?
"https&validateCertificates=false" : "http", host, port,
+ ProducerType.STREAM.name());
}
List<SplunkEvent> events = new LinkedList<>();
@@ -113,6 +125,21 @@ public class SplunkResource {
return result.toString();
}
+ private static @NotNull String getComponent(boolean ssl) {
+ String component = ssl ? "splunk" : "splunk";
+ return component;
+ }
+
+ @Path("/ssl/write/{producerType}")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response writeSsl(Map<String, String> message,
+ @PathParam("producerType") String producerType,
+ @QueryParam("index") String index) throws URISyntaxException {
+ return write(true, message, producerType, index);
+ }
+
@Path("/write/{producerType}")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@@ -120,8 +147,15 @@ public class SplunkResource {
public Response write(Map<String, String> message,
@PathParam("producerType") String producerType,
@QueryParam("index") String index) throws URISyntaxException {
+ return write(false, message, producerType, index);
+ }
+
+ private Response write(boolean ssl, Map<String, String> message,
+ String producerType,
+ String index) throws URISyntaxException {
+
if (message.containsKey("_rawData")) {
- return writeRaw(message.get("_rawData"), producerType, index);
+ return writeRaw(ssl, message.get("_rawData"), producerType, index);
}
SplunkEvent se = new SplunkEvent();
@@ -129,23 +163,33 @@ public class SplunkResource {
se.addPair(e.getKey(), e.getValue());
}
- return writeRaw(se, producerType, index);
+ return writeRaw(ssl, se, producerType, index);
}
- private Response writeRaw(Object message,
+ private Response writeRaw(boolean ssl, Object message,
String producerType,
String index) throws URISyntaxException {
+
String url;
if (ProducerType.TCP == ProducerType.valueOf(producerType)) {
url = String.format(
-
"splunk:%s?raw=%b&username=admin&password=changeit&scheme=http&host=%s&port=%d&index=%s&sourceType=%s&source=%s&tcpReceiverLocalPort=%d&tcpReceiverPort=%d",
- producerType.toLowerCase(), !(message instanceof
SplunkEvent), host, port, index, producerType, SOURCE,
+
"%s:%s?raw=%b&username=admin&password=changeit&scheme=%s&host=%s&port=%d&index=%s&sourceType=%s&source=%s&tcpReceiverLocalPort=%d&tcpReceiverPort=%d",
+ getComponent(ssl), producerType.toLowerCase(), !(message
instanceof SplunkEvent),
+ ssl ? "https&validateCertificates=false" : "http",
+ host, port, index,
+ producerType,
+ SOURCE,
SplunkConstants.TCP_PORT, tcpPort);
} else {
url = String.format(
-
"splunk:%s?raw=%b&scheme=http&host=%s&port=%d&index=%s&sourceType=%s&source=%s",
- producerType.toLowerCase(), !(message instanceof
SplunkEvent), host, port, index, producerType, SOURCE);
+
"%s:%s?raw=%b&username=admin&password=changeit&scheme=%s&host=%s&port=%d&index=%s&sourceType=%s&source=%s",
+ getComponent(ssl), producerType.toLowerCase(), !(message
instanceof SplunkEvent),
+ ssl ? "https&validateCertificates=false" : "http",
+ host,
+ port, index,
+ producerType,
+ SOURCE);
}
final String response = producerTemplate.requestBody(url, message,
String.class);
return Response
diff --git
a/integration-tests/splunk/src/test/java/org/apache/camel/quarkus/component/splunk/it/SplunkTest.java
b/integration-tests/splunk/src/test/java/org/apache/camel/quarkus/component/splunk/it/SplunkTest.java
index 565b0e488b..d14dc6af7a 100644
---
a/integration-tests/splunk/src/test/java/org/apache/camel/quarkus/component/splunk/it/SplunkTest.java
+++
b/integration-tests/splunk/src/test/java/org/apache/camel/quarkus/component/splunk/it/SplunkTest.java
@@ -32,9 +32,11 @@ import io.restassured.http.ContentType;
import org.apache.camel.component.splunk.ProducerType;
import org.apache.camel.quarkus.test.support.splunk.SplunkConstants;
import org.apache.camel.quarkus.test.support.splunk.SplunkTestResource;
+import org.apache.http.NoHttpResponseException;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
import org.testcontainers.shaded.org.awaitility.Awaitility;
@@ -43,21 +45,24 @@ import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.is;
@QuarkusTest
-@QuarkusTestResource(SplunkTestResource.class)
-class SplunkTest {
+@QuarkusTestResource(value = SplunkTestResource.class)
+public class SplunkTest {
+
+ private final static int TIMEOUT_IN_SECONDS = 60;
@Test
- public void testNormalSearchWithSubmitWithRawData() {
+ public void testNormalSearchWithSubmitWithRawData() throws
InterruptedException {
String suffix = "_normalSearchOfSubmit";
+ String restUrl = "/splunk/ssl/results/normalSearch";
write(suffix, ProducerType.SUBMIT, 0, true);
- Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(60, TimeUnit.SECONDS).until(
+ Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS).until(
() -> {
String result = RestAssured.given()
.contentType(ContentType.TEXT)
- .post("/splunk/results/normalSearch")
+ .post(restUrl)
.then()
.statusCode(200)
.extract().asString();
@@ -70,44 +75,13 @@ class SplunkTest {
@Test
public void testSavedSearchWithTcp() throws InterruptedException {
- String suffix = "_SavedSearchOfTcp";
- //create saved search
- Config config = ConfigProvider.getConfig();
- RestAssured.given()
- .baseUri("http://" +
config.getValue(SplunkConstants.PARAM_REMOTE_HOST, String.class))
- .port(config.getValue(SplunkConstants.PARAM_REMOTE_PORT,
Integer.class))
- .contentType(ContentType.JSON)
- .param("name", SplunkResource.SAVED_SEARCH_NAME)
- .param("disabled", "0")
- .param("description", "descriptionText")
- .param("search",
- "sourcetype=\"TCP\" | rex field=_raw \"Name:
(?<name>.*) From: (?<from>.*)\"")
- .post("/services/saved/searches")
- .then()
- .statusCode(anyOf(is(201), is(409)));
-
- //write data via tcp
- write(suffix, ProducerType.TCP, 0, false);
-
- //there might by delay in receiving the data
- Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(60, TimeUnit.SECONDS).until(
- () -> {
- String result = RestAssured.given()
- .contentType(ContentType.TEXT)
- .post("/splunk/results/savedSearch")
- .then()
- .statusCode(200)
- .extract().asString();
-
- return result.contains("Name: Sheldon" + suffix)
- && result.contains("Name: Leonard" + suffix)
- && result.contains("Name: Irma" + suffix);
- });
+ testSavedSearchWithTcp(true);
}
@Test
public void testStreamForRealtime() throws InterruptedException,
ExecutionException {
String suffix = "_RealtimeSearchOfStream";
+ String restUrl = "/splunk/ssl/results/realtimeSearch";
//there is a buffer for stream writing, therefore about 1MB of data
has to be written into Splunk
//data are written in separated thread
@@ -122,12 +96,12 @@ class SplunkTest {
});
try {
- Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(60, TimeUnit.SECONDS).until(
+ Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS).until(
() -> {
String result = RestAssured.given()
.contentType(ContentType.TEXT)
- .post("/splunk/results/realtimeSearch")
+ .post(restUrl)
.then()
.statusCode(200)
.extract().asString();
@@ -141,12 +115,59 @@ class SplunkTest {
}
}
+ @Test
+ public void testSavedSearchWithTcpNoSSL() {
+ Assertions.assertThrowsExactly(NoHttpResponseException.class,
+ () -> testSavedSearchWithTcp(false));
+ }
+
+ void testSavedSearchWithTcp(boolean ssl) throws InterruptedException {
+ String suffix = "_SavedSearchOfTcp";
+ String urlPrefix = ssl ? "https://" : "http://";
+ String restUrl = ssl ? "/splunk/ssl/results/savedSearch" :
"/splunk/results/savedSearch";
+ //create saved search
+ Config config = ConfigProvider.getConfig();
+ RestAssured.given()
+ .relaxedHTTPSValidation()
+ .baseUri(urlPrefix +
config.getValue(SplunkConstants.PARAM_REMOTE_HOST, String.class))
+ .port(config.getValue(SplunkConstants.PARAM_REMOTE_PORT,
+ Integer.class))
+ .contentType(ContentType.JSON)
+ .param("name", SplunkResource.SAVED_SEARCH_NAME)
+ .param("disabled", "0")
+ .param("description", "descriptionText")
+ .param("search",
+ "sourcetype=\"TCP\" | rex field=_raw \"Name:
(?<name>.*) From: (?<from>.*)\"")
+ .post("/services/saved/searches")
+ .then()
+ .statusCode(anyOf(is(201), is(409)));
+
+ //write data via tcp
+ write(suffix, ProducerType.TCP, 0, false);
+
+ //there might by delay in receiving the data
+ Awaitility.await().pollInterval(1000,
TimeUnit.MILLISECONDS).atMost(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS).until(
+ () -> {
+ String result = RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .post(restUrl)
+ .then()
+ .statusCode(200)
+ .extract().asString();
+
+ return result.contains("Name: Sheldon" + suffix)
+ && result.contains("Name: Leonard" + suffix)
+ && result.contains("Name: Irma" + suffix);
+ });
+ }
+
private void write(String suffix, ProducerType producerType, int
lengthOfRandomString, boolean raw) {
+ String restUrl = "/splunk/ssl/write/";
Consumer<Map<String, String>> write = data -> RestAssured.given()
.contentType(ContentType.JSON)
.queryParam("index", SplunkTestResource.TEST_INDEX)
.body(data)
- .post("/splunk/write/" + producerType.name())
+ .post(restUrl + producerType.name())
.then()
.statusCode(201)
.body(Matchers.containsString(expectedResult(data)));
diff --git a/integration-tests/splunk/src/test/resources/local_inputs.conf
b/integration-tests/splunk/src/test/resources/local_inputs.conf
new file mode 100644
index 0000000000..03ce3b62fe
--- /dev/null
+++ b/integration-tests/splunk/src/test/resources/local_inputs.conf
@@ -0,0 +1,6 @@
+[default]
+host = localhost
+
+[splunktcp-ssl:9997]
+
+disabled=0
\ No newline at end of file
diff --git a/integration-tests/splunk/src/test/resources/local_server.conf
b/integration-tests/splunk/src/test/resources/local_server.conf
new file mode 100644
index 0000000000..ed21133c7a
--- /dev/null
+++ b/integration-tests/splunk/src/test/resources/local_server.conf
@@ -0,0 +1,25 @@
+[general]
+serverName = b66b768099db
+pass4SymmKey = $7$oeVDSaCZOSOMIVB0Yv2lBqldGvLt0pXWuQdDV7YvZ0d6Kwf/f0RwhQ==
+allowRemoteLogin = always
+
+[lmpool:auto_generated_pool_download-trial]
+description = auto_generated_pool_download-trial
+peers = *
+quota = MAX
+stack_id = download-trial
+
+[lmpool:auto_generated_pool_forwarder]
+description = auto_generated_pool_forwarder
+peers = *
+quota = MAX
+stack_id = forwarder
+
+[lmpool:auto_generated_pool_free]
+description = auto_generated_pool_free
+peers = *
+quota = MAX
+stack_id = free
+
+[license]
+active_group = Free