This is an automated email from the ASF dual-hosted git repository.
pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 8e973b54cda NIFI-16430 Switched to WebClientService for Splunk
Service.send (#11764)
8e973b54cda is described below
commit 8e973b54cdaefacef9853c86f53c22466f14a363
Author: David Handermann <[email protected]>
AuthorDate: Wed Oct 7 05:30:07 2026 -0500
NIFI-16430 Switched to WebClientService for Splunk Service.send (#11764)
* NIFI-16430 Switched to WebClientService for Splunk Service.send
- Extended Splunk SDK Service in WebClientSplunkService
- Added ConfiguredHostTrustManager to support TLS in Splunk Cloud
- Removed Class Loader isolation from Splunk Processors
---
.../nifi-splunk-processors/pom.xml | 22 +++
.../java/com/splunk/WebClientSplunkService.java | 131 +++++++++++++++++
.../splunk/ConfiguredHostTrustManager.java | 134 ++++++++++++++++++
.../apache/nifi/processors/splunk/GetSplunk.java | 61 +++++---
.../nifi/processors/splunk/SplunkAPICall.java | 54 +++----
.../nifi/processors/splunk/SplunkWebClients.java | 82 +++++++++++
.../nifi/processors/splunk/PutSplunkHTTPTest.java | 156 +++++++++++++++++++++
.../nifi/processors/splunk/TestGetSplunk.java | 46 ------
.../nifi/processors/splunk/TestPutSplunkHTTP.java | 45 ------
9 files changed, 582 insertions(+), 149 deletions(-)
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/pom.xml
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/pom.xml
index ea201bca089..49cf5a2c1f9 100644
--- a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/pom.xml
+++ b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/pom.xml
@@ -56,11 +56,33 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-web-client</artifactId>
+ <version>2.13.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-ssl-context-service</artifactId>
<version>2.13.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-cert-builder</artifactId>
+ <version>2.13.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-ssl</artifactId>
+ <version>2.13.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver3</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/com/splunk/WebClientSplunkService.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/com/splunk/WebClientSplunkService.java
new file mode 100644
index 00000000000..1efc370cda9
--- /dev/null
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/com/splunk/WebClientSplunkService.java
@@ -0,0 +1,131 @@
+/*
+ * 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 com.splunk;
+
+import org.apache.nifi.web.client.api.HttpRequestBodySpec;
+import org.apache.nifi.web.client.api.HttpRequestHeadersSpec;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.StandardHttpRequestMethod;
+import org.apache.nifi.web.client.api.WebClientService;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Map;
+import javax.net.ssl.HttpsURLConnection;
+
+/**
+ * Splunk Service extension using WebClientService for HTTP communication
+ */
+public class WebClientSplunkService extends Service {
+ private static final String AUTHORIZATION_HEADER = "Authorization";
+ private static final String SET_COOKIE_HEADER = "Set-Cookie";
+ private static final String COOKIE_HEADER = "Cookie";
+
+ private final WebClientService webClientService;
+
+ /**
+ * Standard constructor with required Service Arguments and optional
WebClientService for HTTP
+ *
+ * @param serviceArgs Service Arguments required
+ * @param webClientService Web Client Service can be null to use SDK
Service.send()
+ */
+ public WebClientSplunkService(final Map<String, Object> serviceArgs, final
WebClientService webClientService) {
+ super(serviceArgs);
+ this.webClientService = webClientService;
+ }
+
+ @Override
+ public ResponseMessage send(final String path, final RequestMessage
request) {
+ if (webClientService == null) {
+ return super.send(path, request);
+ }
+
+ if (token != null && !cookieStore.hasSplunkAuthCookie()) {
+ request.getHeader().put(AUTHORIZATION_HEADER, token);
+ }
+
+ return sendWithWebClient(fullpath(path), request);
+ }
+
+ private ResponseMessage sendWithWebClient(final String path, final
RequestMessage request) {
+ final StandardHttpRequestMethod requestMethod =
StandardHttpRequestMethod.valueOf(request.getMethod());
+
+ final URL url = getUrl(path);
+ final URI uri;
+ try {
+ uri = url.toURI();
+ } catch (final URISyntaxException e) {
+ throw new IllegalStateException("URI conversion failed for URL
[%s]".formatted(url), e);
+ }
+
+ final HttpRequestBodySpec requestSpec =
webClientService.method(requestMethod).uri(uri);
+ final Object content = request.getContent();
+ if (content instanceof String body) {
+ requestSpec.body(body);
+ }
+
+ applyHeaders(requestSpec, request);
+
+ final HttpResponseEntity responseEntity = requestSpec.retrieve();
+ for (final String setCookie :
responseEntity.headers().getHeader(SET_COOKIE_HEADER)) {
+ if (setCookie != null && !setCookie.isEmpty()) {
+ cookieStore.add(setCookie);
+ }
+ }
+
+ final int status = responseEntity.statusCode();
+ final ResponseMessage responseMessage = new ResponseMessage(status,
responseEntity.body());
+ if (status >= HttpsURLConnection.HTTP_BAD_REQUEST) {
+ final HttpException httpException =
HttpException.create(responseMessage);
+ try {
+ responseEntity.close();
+ } catch (final IOException e) {
+ httpException.addSuppressed(e);
+ }
+
+ throw httpException;
+ }
+
+ return responseMessage;
+ }
+
+ private void applyHeaders(final HttpRequestHeadersSpec requestSpec, final
RequestMessage request) {
+ final Map<String, String> header = request.getHeader();
+ for (final Map.Entry<String, String> entry : header.entrySet()) {
+ requestSpec.header(entry.getKey(), entry.getValue());
+ }
+
+ for (final Map.Entry<String, String> entry : defaultHeader.entrySet())
{
+ if (!header.containsKey(entry.getKey())) {
+ requestSpec.header(entry.getKey(), entry.getValue());
+ }
+ }
+
+ for (final Map.Entry<String, String> entry : customHeaders.entrySet())
{
+ if (!header.containsKey(entry.getKey())) {
+ requestSpec.header(entry.getKey(), entry.getValue());
+ }
+ }
+
+ final String cookies = cookieStore.getCookies();
+ if (!cookies.isEmpty()) {
+ requestSpec.header(COOKIE_HEADER, cookies);
+ }
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/ConfiguredHostTrustManager.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/ConfiguredHostTrustManager.java
new file mode 100644
index 00000000000..0fca865743a
--- /dev/null
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/ConfiguredHostTrustManager.java
@@ -0,0 +1,134 @@
+/*
+ * 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.nifi.processors.splunk;
+
+import org.apache.nifi.logging.ComponentLog;
+
+import java.net.Socket;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Trust manager that skips certificate subject name matching when the TLS
peer host is the hostname
+ * configured on the processor, and delegates certificate path validation. Any
other peer is checked
+ * by the delegate trust manager.
+ */
+class ConfiguredHostTrustManager extends X509ExtendedTrustManager {
+ private final X509TrustManager delegate;
+ private final String configuredHost;
+ private final ComponentLog logger;
+
+ ConfiguredHostTrustManager(final X509TrustManager delegate, final String
hostname, final ComponentLog logger) {
+ this.delegate = Objects.requireNonNull(delegate, "Trust Manager
required");
+ this.logger = Objects.requireNonNull(logger, "Logger required");
+ final String requiredHostname = Objects.requireNonNull(hostname,
"Hostname required");
+ if (requiredHostname.isBlank()) {
+ throw new IllegalArgumentException("Hostname required");
+ }
+
+ this.configuredHost = requiredHostname;
+ }
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String
authType) throws CertificateException {
+ delegate.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String
authType) throws CertificateException {
+ // Callers that do not supply a peer socket or engine cannot be
matched to the configured hostname.
+ delegate.checkServerTrusted(chain, authType);
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return delegate.getAcceptedIssuers();
+ }
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String
authType, final Socket socket) throws CertificateException {
+ if (delegate instanceof final X509ExtendedTrustManager
extendedTrustManager) {
+ extendedTrustManager.checkClientTrusted(chain, authType, socket);
+ } else {
+ delegate.checkClientTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String
authType, final Socket socket) throws CertificateException {
+ if (socket instanceof final SSLSocket sslSocket) {
+ final SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ final String peerHost = session.getPeerHost();
+ if (configuredHost.contentEquals(peerHost)) {
+ logger.debug("Peer Host [{}] matches Configured Host [{}]",
peerHost, configuredHost);
+ delegate.checkServerTrusted(chain, authType);
+ return;
+ }
+ }
+
+ if (delegate instanceof final X509ExtendedTrustManager
extendedTrustManager) {
+ extendedTrustManager.checkServerTrusted(chain, authType, socket);
+ } else {
+ delegate.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String
authType, final SSLEngine engine) throws CertificateException {
+ if (delegate instanceof final X509ExtendedTrustManager
extendedTrustManager) {
+ extendedTrustManager.checkClientTrusted(chain, authType, engine);
+ } else {
+ delegate.checkClientTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String
authType, final SSLEngine engine) throws CertificateException {
+ if (delegate instanceof final X509ExtendedTrustManager
extendedTrustManager) {
+ try {
+ extendedTrustManager.checkServerTrusted(chain, authType,
engine);
+ } catch (final CertificateException e) {
+ final String peerHost = engine == null ? null :
engine.getPeerHost();
+ if (peerHost == null) {
+ // Throw CertificateException when no further evaluation
is possible based on lack of peer host address
+ throw e;
+ } else {
+ // Check Server Trusted without SSLEngine for standard
validation before evaluating host match
+ extendedTrustManager.checkServerTrusted(chain, authType);
+
+ if (configuredHost.contentEquals(peerHost)) {
+ logger.debug("Peer Host [{}] matches Configured Host
[{}]", peerHost, configuredHost);
+ } else {
+ throw new CertificateException("Peer Host [%s] does
not match Configured Host [%s]".formatted(peerHost, configuredHost), e);
+ }
+ }
+ }
+ } else {
+ delegate.checkServerTrusted(chain, authType);
+ }
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/GetSplunk.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/GetSplunk.java
index 213bc5778c7..5c64bd8c31b 100644
---
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/GetSplunk.java
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/GetSplunk.java
@@ -23,7 +23,6 @@ import com.splunk.ServiceArgs;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.annotation.behavior.InputRequirement;
-import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading;
import org.apache.nifi.annotation.behavior.Stateful;
import org.apache.nifi.annotation.behavior.TriggerSerially;
import org.apache.nifi.annotation.behavior.WritesAttribute;
@@ -35,14 +34,12 @@ import org.apache.nifi.annotation.lifecycle.OnRemoved;
import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.annotation.lifecycle.OnStopped;
import org.apache.nifi.components.AllowableValue;
-import org.apache.nifi.components.ClassloaderIsolationKeyProvider;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.components.state.StateMap;
-import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.migration.PropertyConfiguration;
import org.apache.nifi.processor.AbstractProcessor;
@@ -53,10 +50,12 @@ import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.scheduling.SchedulingStrategy;
import org.apache.nifi.ssl.SSLContextProvider;
+import org.apache.nifi.web.client.StandardWebClientService;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@@ -79,12 +78,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
@WritesAttribute(attribute = "splunk.earliest.time", description =
"The value of the earliest time that was used when performing the query."),
@WritesAttribute(attribute = "splunk.latest.time", description = "The
value of the latest time that was used when performing the query.")
})
-@RequiresInstanceClassLoading(cloneAncestorResources = true)
@Stateful(scopes = Scope.CLUSTER, description = "If using one of the managed
Time Range Strategies, this processor will " +
"store the values of the latest and earliest times from the previous
execution so that the next execution of the " +
"can pick up where the last execution left off. The state will be
cleared and start over if the query is changed.")
@DefaultSchedule(strategy = SchedulingStrategy.TIMER_DRIVEN, period = "1 min")
-public class GetSplunk extends AbstractProcessor implements
ClassloaderIsolationKeyProvider {
+public class GetSplunk extends AbstractProcessor {
public static final String HTTP_SCHEME = "http";
public static final String HTTPS_SCHEME = "https";
@@ -313,6 +311,7 @@ public class GetSplunk extends AbstractProcessor implements
ClassloaderIsolation
private volatile String transitUri;
private volatile boolean resetState = false;
private volatile Service splunkService;
+ private volatile StandardWebClientService webClientService;
protected final AtomicBoolean isInitialized = new AtomicBoolean(false);
@Override
@@ -382,6 +381,8 @@ public class GetSplunk extends AbstractProcessor implements
ClassloaderIsolation
splunkService.logout();
splunkService = null;
}
+
+ closeWebClientService();
}
@OnRemoved
@@ -574,10 +575,11 @@ public class GetSplunk extends AbstractProcessor
implements ClassloaderIsolation
}
final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
- if (sslContextProvider != null) {
- // Service construction reapplies the static security protocol and
replaces the Socket Factory when that protocol changes.
- // Leaving the protocol unchanged keeps the Socket Factory
supplied by the SSL Context Service.
-
Service.setSSLSocketFactory(sslContextProvider.createContext().getSocketFactory());
+ final StandardWebClientService client;
+ if (sslContextProvider == null) {
+ client = null;
+ } else {
+ client = getWebClientService(sslContextProvider, host,
connectTimeout, readTimeout);
}
final String chosenApiVersion =
context.getProperty(API_VERSION).getValue();
@@ -585,7 +587,33 @@ public class GetSplunk extends AbstractProcessor
implements ClassloaderIsolation
serviceArgs.add("enableV2SearchApi", enableV2SearchApi);
- return Service.connect(serviceArgs);
+ return SplunkWebClients.connect(serviceArgs, client);
+ }
+
+ private StandardWebClientService getWebClientService(
+ final SSLContextProvider sslContextProvider,
+ final String host,
+ final int connectTimeout,
+ final int readTimeout
+ ) {
+ if (webClientService == null) {
+ webClientService = SplunkWebClients.create(sslContextProvider,
host, getLogger());
+ if (connectTimeout > 0) {
+
webClientService.setConnectTimeout(Duration.ofMillis(connectTimeout));
+ }
+ if (readTimeout > 0) {
+
webClientService.setReadTimeout(Duration.ofMillis(readTimeout));
+ }
+ }
+
+ return webClientService;
+ }
+
+ private void closeWebClientService() {
+ if (webClientService != null) {
+ webClientService.close();
+ webClientService = null;
+ }
}
private void saveState(final ProcessSession session, TimeRange timeRange)
throws IOException {
@@ -624,19 +652,6 @@ public class GetSplunk extends AbstractProcessor
implements ClassloaderIsolation
config.removeProperty(OBSOLETE_SECURITY_PROTOCOL);
}
- @Override
- public String getClassloaderIsolationKey(PropertyContext context) {
- final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
- if (sslContextProvider != null) {
- // Class loader isolation is only necessary when SSL is enabled,
as Service.setSSLSocketFactory
- // changes the Socket Factory for all instances.
- return sslContextProvider.getIdentifier();
- } else {
- // This workaround ensures that instances don't unnecessarily use
an isolated classloader.
- return getClass().getName();
- }
- }
-
static class TimeRange {
final String earliestTime;
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkAPICall.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkAPICall.java
index e5c9c1b8810..484eb22fe7d 100644
---
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkAPICall.java
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkAPICall.java
@@ -23,26 +23,23 @@ import com.splunk.RequestMessage;
import com.splunk.ResponseMessage;
import com.splunk.Service;
import com.splunk.ServiceArgs;
-import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading;
import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.annotation.lifecycle.OnStopped;
-import org.apache.nifi.components.ClassloaderIsolationKeyProvider;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.migration.PropertyConfiguration;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.ssl.SSLContextProvider;
+import org.apache.nifi.web.client.StandardWebClientService;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-@RequiresInstanceClassLoading(cloneAncestorResources = true)
@SuppressWarnings("PMD.LooseCoupling")
-abstract class SplunkAPICall extends AbstractProcessor implements
ClassloaderIsolationKeyProvider {
+abstract class SplunkAPICall extends AbstractProcessor {
private static final String REQUEST_CHANNEL_HEADER_NAME =
"X-Splunk-Request-Channel";
private static final String HTTP_SCHEME = "http";
@@ -143,6 +140,7 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
private volatile ServiceArgs splunkServiceArguments;
private volatile Service splunkService;
+ private volatile StandardWebClientService webClientService;
private volatile String requestChannel;
private volatile String transitBaseUri;
@@ -157,7 +155,13 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
@OnScheduled
public void onScheduled(final ProcessContext context) {
- configureSocketFactory(context);
+ closeWebClientService();
+ final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
+ if (sslContextProvider != null) {
+ final String hostname =
context.getProperty(HOSTNAME).evaluateAttributeExpressions().getValue();
+ webClientService = SplunkWebClients.create(sslContextProvider,
hostname, getLogger());
+ }
+
splunkServiceArguments = getSplunkServiceArgs(context);
splunkService = getSplunkService(splunkServiceArguments);
requestChannel =
context.getProperty(REQUEST_CHANNEL).evaluateAttributeExpressions().getValue();
@@ -167,17 +171,6 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
transitBaseUri = "%s://%s:%d".formatted(scheme, hostname, port);
}
- private void configureSocketFactory(final ProcessContext context) {
- final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
- if (sslContextProvider == null) {
- return;
- }
-
- // Service construction reapplies the static security protocol and
replaces the Socket Factory when that protocol changes.
- // Leaving the protocol unchanged keeps the Socket Factory supplied by
the SSL Context Service.
-
Service.setSSLSocketFactory(sslContextProvider.createContext().getSocketFactory());
- }
-
private ServiceArgs getSplunkServiceArgs(final ProcessContext context) {
final ServiceArgs splunkServiceArguments = new ServiceArgs();
@@ -205,7 +198,7 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
}
protected Service getSplunkService(final ServiceArgs
splunkServiceArguments) {
- return Service.connect(splunkServiceArguments);
+ return SplunkWebClients.connect(splunkServiceArguments,
webClientService);
}
@OnStopped
@@ -215,28 +208,12 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
splunkService = null;
}
+ closeWebClientService();
requestChannel = null;
splunkServiceArguments = null;
transitBaseUri = null;
}
- @Override
- public String getClassloaderIsolationKey(final PropertyContext context) {
- final String isolationKey;
-
- final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
- if (sslContextProvider == null) {
- // Instances that do not configure an SSL Context Service leave
the Socket Factory untouched and can share a ClassLoader.
- isolationKey = getClass().getName();
- } else {
- // Service.setSSLSocketFactory changes the Socket Factory for
every Splunk Service loaded by a given ClassLoader, so instances
- // are isolated by the identifier of the SSL Context Service
supplying that Socket Factory.
- isolationKey = sslContextProvider.getIdentifier();
- }
-
- return isolationKey;
- }
-
@Override
public void migrateProperties(PropertyConfiguration config) {
config.renameProperty("Port", PORT.getName());
@@ -270,4 +247,11 @@ abstract class SplunkAPICall extends AbstractProcessor
implements ClassloaderIso
protected String marshalRequest(final Object request) throws IOException {
return jsonObjectMapper.writeValueAsString(request);
}
+
+ private void closeWebClientService() {
+ if (webClientService != null) {
+ webClientService.close();
+ webClientService = null;
+ }
+ }
}
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkWebClients.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkWebClients.java
new file mode 100644
index 00000000000..e6fa93de2e3
--- /dev/null
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/main/java/org/apache/nifi/processors/splunk/SplunkWebClients.java
@@ -0,0 +1,82 @@
+/*
+ * 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.nifi.processors.splunk;
+
+import com.splunk.Service;
+import com.splunk.WebClientSplunkService;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.ssl.SSLContextProvider;
+import org.apache.nifi.web.client.StandardWebClientService;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.ssl.TlsContext;
+
+import java.net.http.HttpClient;
+import java.util.Map;
+import java.util.Optional;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+final class SplunkWebClients {
+ private static final String USERNAME_ARGUMENT = "username";
+
+ private SplunkWebClients() {
+ }
+
+ static StandardWebClientService create(final SSLContextProvider
sslContextProvider, final String hostname, final ComponentLog logger) {
+ final X509TrustManager delegateTrustManager =
sslContextProvider.createTrustManager();
+ final X509ExtendedTrustManager trustManager = new
ConfiguredHostTrustManager(delegateTrustManager, hostname, logger);
+ final Optional<X509KeyManager> keyManager =
sslContextProvider.createKeyManager().map(X509KeyManager.class::cast);
+ final SSLContext sslContext = sslContextProvider.createContext();
+
+ return getClient(sslContext, trustManager, keyManager);
+ }
+
+ static Service connect(final Map<String, Object> serviceArgs, final
WebClientService webClientService) {
+ final WebClientSplunkService service = new
WebClientSplunkService(serviceArgs, webClientService);
+ if (serviceArgs.containsKey(USERNAME_ARGUMENT)) {
+ service.login();
+ }
+
+ return service;
+ }
+
+ private static StandardWebClientService getClient(SSLContext sslContext,
X509ExtendedTrustManager trustManager, Optional<X509KeyManager> keyManager) {
+ final TlsContext tlsContext = new TlsContext() {
+ @Override
+ public String getProtocol() {
+ return sslContext.getProtocol();
+ }
+
+ @Override
+ public X509TrustManager getTrustManager() {
+ return trustManager;
+ }
+
+ @Override
+ public Optional<X509KeyManager> getKeyManager() {
+ return keyManager;
+ }
+ };
+
+ final StandardWebClientService client = new StandardWebClientService();
+ client.setHttpVersion(HttpClient.Version.HTTP_1_1);
+ client.setTlsContext(tlsContext);
+ return client;
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/PutSplunkHTTPTest.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/PutSplunkHTTPTest.java
new file mode 100644
index 00000000000..2824f1ebb71
--- /dev/null
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/PutSplunkHTTPTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.nifi.processors.splunk;
+
+import mockwebserver3.MockResponse;
+import mockwebserver3.MockWebServer;
+import mockwebserver3.RecordedRequest;
+import org.apache.nifi.reporting.InitializationException;
+import org.apache.nifi.security.cert.builder.StandardCertificateBuilder;
+import org.apache.nifi.security.ssl.EphemeralKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
+import org.apache.nifi.security.ssl.StandardTrustManagerBuilder;
+import org.apache.nifi.ssl.SSLContextProvider;
+import org.apache.nifi.util.MockFlowFile;
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.util.Optional;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class PutSplunkHTTPTest {
+ private static final String SSL_CONTEXT_SERVICE_ID = "ssl-context-service";
+
+ private static final String KEY_ALGORITHM = "RSA";
+
+ private static final String HTTPS_SCHEME = "https";
+
+ private static final String COLLECTOR_PATH = "/services/collector/raw";
+
+ private static final String AUTHORIZATION_HEADER = "Authorization";
+
+ private static final String REQUEST_CHANNEL_HEADER =
"X-Splunk-Request-Channel";
+
+ private static final String CERTIFICATE_SUBJECT_NAME =
"CN=splunk.internal";
+
+ private static final String TOKEN = "Splunk
888c5a81-8777-49a0-a3af-f76e050ab5d9";
+
+ private static final String REQUEST_CHANNEL =
"22bd7414-0d77-4c73-936d-c8f5d1b21862";
+
+ private static final String EVENT = "splunk-https-event";
+
+ private static final String ACK_ID = "1234";
+
+ private static final String SUCCESS_RESPONSE = """
+ {
+ "text": "Success",
+ "code": 0,
+ "ackId": %s
+ }""".formatted(ACK_ID);
+
+ private static final X500Principal CERTIFICATE_SUBJECT = new
X500Principal(CERTIFICATE_SUBJECT_NAME);
+
+ private MockWebServer mockWebServer;
+
+ private SSLContext sslContext;
+
+ private X509TrustManager trustManager;
+
+ @BeforeEach
+ void startServer() throws Exception {
+ final KeyPair keyPair =
KeyPairGenerator.getInstance(KEY_ALGORITHM).generateKeyPair();
+ final X509Certificate certificate = new
StandardCertificateBuilder(keyPair, CERTIFICATE_SUBJECT,
Duration.ofHours(1)).build();
+ final KeyStore keyStore = new EphemeralKeyStoreBuilder()
+ .addPrivateKeyEntry(new
KeyStore.PrivateKeyEntry(keyPair.getPrivate(), new Certificate[]{certificate}))
+ .addCertificate(certificate)
+ .build();
+ final char[] protectionParameter = new char[]{};
+
+ sslContext = new StandardSslContextBuilder()
+ .trustStore(keyStore)
+ .keyStore(keyStore)
+ .keyPassword(protectionParameter)
+ .build();
+ trustManager = new
StandardTrustManagerBuilder().trustStore(keyStore).build();
+
+ mockWebServer = new MockWebServer();
+ mockWebServer.useHttps(sslContext.getSocketFactory());
+ mockWebServer.start();
+ }
+
+ @AfterEach
+ void shutdownServer() {
+ mockWebServer.close();
+ }
+
+ @Test
+ void testHttpsPostTrustsConfiguredHost() throws InitializationException,
InterruptedException {
+ mockWebServer.enqueue(new MockResponse.Builder()
+ .code(HttpURLConnection.HTTP_OK)
+ .body(SUCCESS_RESPONSE)
+ .build());
+
+ final SSLContextProvider sslContextProvider =
mock(SSLContextProvider.class);
+
when(sslContextProvider.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_ID);
+ when(sslContextProvider.createContext()).thenReturn(sslContext);
+ when(sslContextProvider.createTrustManager()).thenReturn(trustManager);
+
when(sslContextProvider.createKeyManager()).thenReturn(Optional.empty());
+
+ final TestRunner runner =
TestRunners.newTestRunner(PutSplunkHTTP.class);
+ runner.addControllerService(SSL_CONTEXT_SERVICE_ID,
sslContextProvider);
+ runner.enableControllerService(sslContextProvider);
+ runner.setProperty(SplunkAPICall.SSL_CONTEXT_SERVICE,
SSL_CONTEXT_SERVICE_ID);
+ runner.setProperty(SplunkAPICall.SCHEME, HTTPS_SCHEME);
+ runner.setProperty(SplunkAPICall.HOSTNAME,
mockWebServer.getHostName());
+ runner.setProperty(SplunkAPICall.PORT,
Integer.toString(mockWebServer.getPort()));
+ runner.setProperty(SplunkAPICall.TOKEN, TOKEN);
+ runner.setProperty(SplunkAPICall.REQUEST_CHANNEL, REQUEST_CHANNEL);
+ runner.setProperty(PutSplunkHTTP.CHARSET,
StandardCharsets.UTF_8.name());
+
+ runner.enqueue(EVENT);
+ runner.run();
+
+
runner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_SUCCESS, 1);
+ final MockFlowFile outgoingFlowFile =
runner.getFlowFilesForRelationship(PutSplunkHTTP.RELATIONSHIP_SUCCESS).getFirst();
+ assertEquals(ACK_ID,
outgoingFlowFile.getAttribute(SplunkAPICall.ACKNOWLEDGEMENT_ID_ATTRIBUTE));
+
+ final RecordedRequest request = mockWebServer.takeRequest();
+ assertEquals(COLLECTOR_PATH, request.getTarget());
+ assertEquals(TOKEN, request.getHeaders().get(AUTHORIZATION_HEADER));
+ assertEquals(REQUEST_CHANNEL,
request.getHeaders().get(REQUEST_CHANNEL_HEADER));
+ assertNotNull(request.getBody());
+ assertEquals(EVENT, request.getBody().utf8());
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestGetSplunk.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestGetSplunk.java
index 37d04f54039..a55ef4a4adb 100644
---
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestGetSplunk.java
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestGetSplunk.java
@@ -23,8 +23,6 @@ import org.apache.nifi.components.state.StateMap;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.provenance.ProvenanceEventRecord;
import org.apache.nifi.provenance.ProvenanceEventType;
-import org.apache.nifi.reporting.InitializationException;
-import org.apache.nifi.ssl.SSLContextProvider;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.PropertyMigrationResult;
import org.apache.nifi.util.TestRunner;
@@ -42,13 +40,11 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
-import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
@@ -60,8 +56,6 @@ import static org.mockito.Mockito.when;
@SuppressWarnings("PMD.LooseCoupling")
public class TestGetSplunk {
- private static final String SSL_CONTEXT_SERVICE_ID = "ssl-context-service";
-
private Service service;
private TestableGetSplunk proc;
private TestRunner runner;
@@ -386,29 +380,6 @@ public class TestGetSplunk {
assertNotNull(actualArgs.get("index_latest"));
}
- @Test
- public void testSslContextServiceProvidesSplunkSocketFactory() throws
InitializationException {
- final SSLSocketFactory socketFactory =
Mockito.mock(SSLSocketFactory.class);
- final SSLContext sslContext = Mockito.mock(SSLContext.class);
- when(sslContext.getSocketFactory()).thenReturn(socketFactory);
-
- final SSLContextProvider sslContextProvider =
Mockito.mock(SSLContextProvider.class);
-
when(sslContextProvider.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_ID);
- when(sslContextProvider.createContext()).thenReturn(sslContext);
-
- final GetSplunk getSplunk = new GetSplunk();
- final TestRunner connectingRunner =
TestRunners.newTestRunner(getSplunk);
- connectingRunner.addControllerService(SSL_CONTEXT_SERVICE_ID,
sslContextProvider);
- connectingRunner.enableControllerService(sslContextProvider);
- connectingRunner.setProperty(GetSplunk.SSL_CONTEXT_SERVICE,
SSL_CONTEXT_SERVICE_ID);
- connectingRunner.setProperty(GetSplunk.SCHEME, GetSplunk.HTTPS_SCHEME);
- connectingRunner.setProperty(GetSplunk.TOKEN, "Splunk
888c5a81-8777-49a0-a3af-f76e050ab5d9");
-
- getSplunk.createSplunkService(connectingRunner.getProcessContext());
-
- assertSame(socketFactory, Service.getSSLSocketFactory());
- }
-
@Test
public void testMigrateProperties() {
final TestRunner migrationRunner =
TestRunners.newTestRunner(GetSplunk.class);
@@ -416,23 +387,6 @@ public class TestGetSplunk {
assertEquals(Set.of("Security Protocol"),
propertyMigrationResult.getPropertiesRemoved());
}
- @Test
- public void testClassloaderIsolationKey() throws InitializationException {
- final GetSplunk getSplunk = new GetSplunk();
- final TestRunner isolationKeyRunner =
TestRunners.newTestRunner(getSplunk);
-
- // Instances without an SSL Context Service leave the Splunk Socket
Factory untouched, so they can share a ClassLoader.
- assertEquals(GetSplunk.class.getName(),
getSplunk.getClassloaderIsolationKey(isolationKeyRunner.getProcessContext()));
-
- final SSLContextProvider sslContextProvider =
Mockito.mock(SSLContextProvider.class);
-
when(sslContextProvider.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_ID);
- isolationKeyRunner.addControllerService(SSL_CONTEXT_SERVICE_ID,
sslContextProvider);
- isolationKeyRunner.enableControllerService(sslContextProvider);
- isolationKeyRunner.setProperty(GetSplunk.SSL_CONTEXT_SERVICE,
SSL_CONTEXT_SERVICE_ID);
-
- assertEquals(SSL_CONTEXT_SERVICE_ID,
getSplunk.getClassloaderIsolationKey(isolationKeyRunner.getProcessContext()));
- }
-
/**
* Testable implementation of GetSplunk to return a Mock Splunk Service.
*/
diff --git
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestPutSplunkHTTP.java
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestPutSplunkHTTP.java
index 00f614ce2cc..adae4451d35 100644
---
a/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestPutSplunkHTTP.java
+++
b/nifi-extension-bundles/nifi-splunk-bundle/nifi-splunk-processors/src/test/java/org/apache/nifi/processors/splunk/TestPutSplunkHTTP.java
@@ -23,8 +23,6 @@ import com.splunk.ServiceArgs;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
-import org.apache.nifi.reporting.InitializationException;
-import org.apache.nifi.ssl.SSLContextProvider;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.PropertyMigrationResult;
import org.apache.nifi.util.TestRunner;
@@ -46,18 +44,15 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(MockitoExtension.class)
public class TestPutSplunkHTTP {
- private static final String SSL_CONTEXT_SERVICE_ID = "ssl-context-service";
private static final String ACK_ID = "1234";
private static final String EVENT =
"{\"a\"=\"á\",\"c\"=\"ő\",\"e\"=\"'ű'\"}"; // Intentionally uses UTF-8 character
private static final String SUCCESS_RESPONSE =
@@ -223,46 +218,6 @@ public class TestPutSplunkHTTP {
assertEquals("403",
outgoingFlowFile.getAttribute("splunk.status.code"));
}
- @Test
- public void testSslContextServiceProvidesSplunkSocketFactory() throws
InitializationException {
- final SSLSocketFactory socketFactory =
Mockito.mock(SSLSocketFactory.class);
- final SSLContext sslContext = Mockito.mock(SSLContext.class);
- Mockito.when(sslContext.getSocketFactory()).thenReturn(socketFactory);
-
- final SSLContextProvider sslContextProvider =
Mockito.mock(SSLContextProvider.class);
-
Mockito.when(sslContextProvider.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_ID);
-
Mockito.when(sslContextProvider.createContext()).thenReturn(sslContext);
-
- final TestRunner connectingRunner =
TestRunners.newTestRunner(PutSplunkHTTP.class);
- connectingRunner.addControllerService(SSL_CONTEXT_SERVICE_ID,
sslContextProvider);
- connectingRunner.enableControllerService(sslContextProvider);
- connectingRunner.setProperty(SplunkAPICall.SSL_CONTEXT_SERVICE,
SSL_CONTEXT_SERVICE_ID);
- connectingRunner.setProperty(SplunkAPICall.SCHEME, "https");
- connectingRunner.setProperty(SplunkAPICall.TOKEN, "Splunk
888c5a81-8777-49a0-a3af-f76e050ab5d9");
- connectingRunner.setProperty(SplunkAPICall.REQUEST_CHANNEL,
"22bd7414-0d77-4c73-936d-c8f5d1b21862");
-
- connectingRunner.run();
-
- assertSame(socketFactory, Service.getSSLSocketFactory());
- }
-
- @Test
- public void testClassloaderIsolationKey() throws InitializationException {
- final PutSplunkHTTP putSplunkHTTP = new PutSplunkHTTP();
- final TestRunner isolationKeyRunner =
TestRunners.newTestRunner(putSplunkHTTP);
-
- // Instances without an SSL Context Service leave the Splunk Socket
Factory untouched, so they can share a ClassLoader.
- assertEquals(PutSplunkHTTP.class.getName(),
putSplunkHTTP.getClassloaderIsolationKey(isolationKeyRunner.getProcessContext()));
-
- final SSLContextProvider sslContextProvider =
Mockito.mock(SSLContextProvider.class);
-
Mockito.when(sslContextProvider.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_ID);
- isolationKeyRunner.addControllerService(SSL_CONTEXT_SERVICE_ID,
sslContextProvider);
- isolationKeyRunner.enableControllerService(sslContextProvider);
- isolationKeyRunner.setProperty(SplunkAPICall.SSL_CONTEXT_SERVICE,
SSL_CONTEXT_SERVICE_ID);
-
- assertEquals(SSL_CONTEXT_SERVICE_ID,
putSplunkHTTP.getClassloaderIsolationKey(isolationKeyRunner.getProcessContext()));
- }
-
@Test
void testMigrateProperties() {
TestRunner testRunner = TestRunners.newTestRunner(PutSplunkHTTP.class);