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 e1d01ca8020 NIFI-10386 Added SSL Context Service to PutSplunkHTTP and
QuerySplunk (#11725)
e1d01ca8020 is described below
commit e1d01ca8020acf93ded752164248f05817a82e07
Author: David Handermann <[email protected]>
AuthorDate: Mon Sep 28 02:56:50 2026 -0500
NIFI-10386 Added SSL Context Service to PutSplunkHTTP and QuerySplunk
(#11725)
---
.../apache/nifi/processors/splunk/GetSplunk.java | 11 ++-
.../nifi/processors/splunk/SplunkAPICall.java | 66 +++++++++++++++-
.../nifi/processors/splunk/TestGetSplunk.java | 69 ++++++++++++++++
.../nifi/processors/splunk/TestPutSplunkHTTP.java | 91 +++++++++++++++++-----
4 files changed, 214 insertions(+), 23 deletions(-)
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 f023e674cbe..381e71dd690 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
@@ -595,12 +595,19 @@ public class GetSplunk extends AbstractProcessor
implements ClassloaderIsolation
}
final String secProtocol =
context.getProperty(SECURITY_PROTOCOL).getValue();
- if (!StringUtils.isBlank(secProtocol) && HTTPS_SCHEME.equals(scheme)) {
-
serviceArgs.setSSLSecurityProtocol(SSLSecurityProtocol.valueOf(secProtocol));
+ final SSLSecurityProtocol securityProtocol =
(!StringUtils.isBlank(secProtocol) && HTTPS_SCHEME.equals(scheme)) ?
SSLSecurityProtocol.valueOf(secProtocol) : null;
+ if (securityProtocol != null) {
+ serviceArgs.setSSLSecurityProtocol(securityProtocol);
}
final SSLContextProvider sslContextProvider =
context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextProvider.class);
if (sslContextProvider != null) {
+ // Constructing a Splunk Service applies the Security Protocol to
static configuration, and changing the protocol discards the
+ // current Socket Factory. Applying the protocol first leaves the
configured Socket Factory in place once the Service connects.
+ if (securityProtocol != null) {
+ Service.setSslSecurityProtocol(securityProtocol);
+ }
+
Service.setSSLSocketFactory(sslContextProvider.createContext().getSocketFactory());
}
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 f49d048ff87..184eeacfef1 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
@@ -24,22 +24,27 @@ import com.splunk.ResponseMessage;
import com.splunk.SSLSecurityProtocol;
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.AllowableValue;
+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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
+@RequiresInstanceClassLoading(cloneAncestorResources = true)
@SuppressWarnings("PMD.LooseCoupling")
-abstract class SplunkAPICall extends AbstractProcessor {
+abstract class SplunkAPICall extends AbstractProcessor implements
ClassloaderIsolationKeyProvider {
private static final String REQUEST_CHANNEL_HEADER_NAME =
"X-Splunk-Request-Channel";
private static final String HTTP_SCHEME = "http";
@@ -87,6 +92,13 @@ abstract class SplunkAPICall extends AbstractProcessor {
.defaultValue(TLS_1_2_VALUE.getValue())
.build();
+ static final PropertyDescriptor SSL_CONTEXT_SERVICE = new
PropertyDescriptor.Builder()
+ .name("SSL Context Service")
+ .description("The SSL Context Service used to provide client
certificate information for TLS/SSL connections.")
+ .required(false)
+ .identifiesControllerService(SSLContextProvider.class)
+ .build();
+
static final PropertyDescriptor OWNER = new PropertyDescriptor.Builder()
.name("Owner")
.description("The owner to pass to Splunk.")
@@ -132,6 +144,7 @@ abstract class SplunkAPICall extends AbstractProcessor {
HOSTNAME,
PORT,
SECURITY_PROTOCOL,
+ SSL_CONTEXT_SERVICE,
OWNER,
TOKEN,
USERNAME,
@@ -158,6 +171,7 @@ abstract class SplunkAPICall extends AbstractProcessor {
@OnScheduled
public void onScheduled(final ProcessContext context) {
+ configureSocketFactory(context);
splunkServiceArguments = getSplunkServiceArgs(context);
splunkService = getSplunkService(splunkServiceArguments);
requestChannel =
context.getProperty(REQUEST_CHANNEL).evaluateAttributeExpressions().getValue();
@@ -167,6 +181,22 @@ abstract class SplunkAPICall extends AbstractProcessor {
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;
+ }
+
+ // Constructing a Splunk Service applies the Security Protocol to
static configuration, and changing the protocol discards the
+ // current Socket Factory. Applying the protocol first leaves the
configured Socket Factory in place once the Service connects.
+ final SSLSecurityProtocol securityProtocol =
getSecurityProtocol(context);
+ if (securityProtocol != null) {
+ Service.setSslSecurityProtocol(securityProtocol);
+ }
+
+
Service.setSSLSocketFactory(sslContextProvider.createContext().getSocketFactory());
+ }
+
private ServiceArgs getSplunkServiceArgs(final ProcessContext context) {
final ServiceArgs splunkServiceArguments = new ServiceArgs();
@@ -190,13 +220,26 @@ abstract class SplunkAPICall extends AbstractProcessor {
splunkServiceArguments.setPassword(context.getProperty(PASSWORD).getValue());
}
- if (HTTPS_SCHEME.equals(context.getProperty(SCHEME).getValue()) &&
context.getProperty(SECURITY_PROTOCOL).isSet()) {
-
splunkServiceArguments.setSSLSecurityProtocol(SSLSecurityProtocol.valueOf(context.getProperty(SECURITY_PROTOCOL).getValue()));
+ final SSLSecurityProtocol securityProtocol =
getSecurityProtocol(context);
+ if (securityProtocol != null) {
+ splunkServiceArguments.setSSLSecurityProtocol(securityProtocol);
}
return splunkServiceArguments;
}
+ private SSLSecurityProtocol getSecurityProtocol(final ProcessContext
context) {
+ final SSLSecurityProtocol sslSecurityProtocol;
+
+ if (HTTPS_SCHEME.equals(context.getProperty(SCHEME).getValue()) &&
context.getProperty(SECURITY_PROTOCOL).isSet()) {
+ sslSecurityProtocol =
SSLSecurityProtocol.valueOf(context.getProperty(SECURITY_PROTOCOL).getValue());
+ } else {
+ sslSecurityProtocol = null;
+ }
+
+ return sslSecurityProtocol;
+ }
+
protected Service getSplunkService(final ServiceArgs
splunkServiceArguments) {
return Service.connect(splunkServiceArguments);
}
@@ -213,6 +256,23 @@ abstract class SplunkAPICall extends AbstractProcessor {
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());
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 0681473aceb..8059ac823f1 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
@@ -17,15 +17,19 @@
package org.apache.nifi.processors.splunk;
import com.splunk.JobExportArgs;
+import com.splunk.SSLSecurityProtocol;
import com.splunk.Service;
import org.apache.nifi.components.state.Scope;
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.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 org.mockito.ArgumentCaptor;
@@ -37,10 +41,13 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
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;
@@ -52,16 +59,32 @@ 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;
+ // The Splunk Service holds the Security Protocol and the Socket Factory
in static state shared by every test running in the
+ // same JVM, so both are captured and restored around each test.
+ private SSLSecurityProtocol splunkSecurityProtocol;
+ private SSLSocketFactory splunkSocketFactory;
+
@BeforeEach
public void setup() {
service = Mockito.mock(Service.class);
proc = new TestableGetSplunk(service);
runner = TestRunners.newTestRunner(proc);
+
+ splunkSecurityProtocol = Service.getSslSecurityProtocol();
+ splunkSocketFactory = Service.getSSLSocketFactory();
+ }
+
+ @AfterEach
+ public void restoreSplunkTlsConfiguration() {
+ Service.setSslSecurityProtocol(splunkSecurityProtocol);
+ Service.setSSLSocketFactory(splunkSocketFactory);
}
@Test
@@ -369,6 +392,52 @@ public class TestGetSplunk {
assertNotNull(actualArgs.get("index_latest"));
}
+ @Test
+ public void testSslContextServiceProvidesSplunkSocketFactory() throws
InitializationException {
+ // Splunk discards the configured Socket Factory when the static
Security Protocol changes, so the Processor is configured with
+ // a protocol other than the one applied here to confirm the Socket
Factory survives connecting the Splunk Service.
+ Service.setSslSecurityProtocol(SSLSecurityProtocol.TLSv1_1);
+
+ 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.SECURITY_PROTOCOL,
SSLSecurityProtocol.TLSv1_2.name());
+ connectingRunner.setProperty(GetSplunk.TOKEN, "Splunk
888c5a81-8777-49a0-a3af-f76e050ab5d9");
+
+ getSplunk.createSplunkService(connectingRunner.getProcessContext());
+
+ assertSame(socketFactory, Service.getSSLSocketFactory());
+ assertEquals(SSLSecurityProtocol.TLSv1_2,
Service.getSslSecurityProtocol());
+ }
+
+ @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 1a1b301227a..0bd18b44356 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
@@ -18,15 +18,20 @@ package org.apache.nifi.processors.splunk;
import com.splunk.RequestMessage;
import com.splunk.ResponseMessage;
+import com.splunk.SSLSecurityProtocol;
import com.splunk.Service;
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;
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 org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
@@ -41,14 +46,18 @@ import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+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 =
@@ -78,6 +87,23 @@ public class TestPutSplunkHTTP {
private MockedPutSplunkHTTP processor;
private TestRunner testRunner;
+ private SSLSecurityProtocol splunkSecurityProtocol;
+ private SSLSocketFactory splunkSocketFactory;
+
+ // The Splunk Service holds the Security Protocol and the Socket Factory
in static state shared by every test running in the
+ // same JVM, so both are captured and restored around each test.
+ @BeforeEach
+ public void captureSplunkTlsConfiguration() {
+ splunkSecurityProtocol = Service.getSslSecurityProtocol();
+ splunkSocketFactory = Service.getSSLSocketFactory();
+ }
+
+ @AfterEach
+ public void restoreSplunkTlsConfiguration() {
+ Service.setSslSecurityProtocol(splunkSecurityProtocol);
+ Service.setSSLSocketFactory(splunkSocketFactory);
+ }
+
public void setUpMocks() {
processor = new MockedPutSplunkHTTP(service);
testRunner = TestRunners.newTestRunner(processor);
@@ -91,14 +117,11 @@ public class TestPutSplunkHTTP {
@Test
public void testRunSuccess() {
setUpMocks();
- // given
givenSplunkReturnsWithSuccess();
- // when
testRunner.enqueue(givenFlowFile());
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_SUCCESS, 1);
final MockFlowFile outgoingFlowFile =
testRunner.getFlowFilesForRelationship(PutSplunkHTTP.RELATIONSHIP_SUCCESS).getFirst();
@@ -112,16 +135,13 @@ public class TestPutSplunkHTTP {
@Test
public void testHappyPathWithCustomQueryParameters() {
setUpMocks();
- // given
testRunner.setProperty(PutSplunkHTTP.SOURCE, "test_source");
testRunner.setProperty(PutSplunkHTTP.SOURCE_TYPE, "test?source?type");
givenSplunkReturnsWithSuccess();
- // when
testRunner.enqueue(EVENT);
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_SUCCESS, 1);
assertTrue(path.getValue().startsWith("/services/collector/raw"));
}
@@ -129,7 +149,6 @@ public class TestPutSplunkHTTP {
@Test
public void testHappyPathWithCustomQueryParametersFromFlowFile() {
setUpMocks();
- // given
testRunner.setProperty(PutSplunkHTTP.SOURCE, "${ff_source}");
testRunner.setProperty(PutSplunkHTTP.SOURCE_TYPE, "${ff_source_type}");
testRunner.setProperty(PutSplunkHTTP.HOST, "${ff_host}");
@@ -150,11 +169,9 @@ public class TestPutSplunkHTTP {
incomingFlowFile.putAttributes(attributes);
incomingFlowFile.setData(EVENT.getBytes(StandardCharsets.UTF_8));
- // when
testRunner.enqueue(incomingFlowFile);
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_SUCCESS, 1);
assertTrue(path.getValue().startsWith("/services/collector/raw"));
@@ -165,15 +182,13 @@ public class TestPutSplunkHTTP {
@Test
public void testHappyPathWithContentType() {
setUpMocks();
- // given
testRunner.setProperty(PutSplunkHTTP.CONTENT_TYPE, "text/xml");
givenSplunkReturnsWithSuccess();
- // when
+
testRunner.enqueue(givenFlowFile());
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_SUCCESS, 1);
assertEquals("text/xml",
request.getValue().getHeader().get("Content-Type"));
}
@@ -181,14 +196,11 @@ public class TestPutSplunkHTTP {
@Test
public void testSplunkCallFailure() {
setUpMocks();
- // given
givenSplunkReturnsWithFailure();
- // when
testRunner.enqueue(givenFlowFile());
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_FAILURE, 1);
final MockFlowFile outgoingFlowFile =
testRunner.getFlowFilesForRelationship(PutSplunkHTTP.RELATIONSHIP_FAILURE).getFirst();
@@ -202,14 +214,11 @@ public class TestPutSplunkHTTP {
@Test
public void testSplunkApplicationFailure() {
setUpMocks();
- // given
givenSplunkReturnsWithApplicationFailure(403);
- // when
testRunner.enqueue(givenFlowFile());
testRunner.run();
- // then
testRunner.assertAllFlowFilesTransferred(PutSplunkHTTP.RELATIONSHIP_FAILURE, 1);
final MockFlowFile outgoingFlowFile =
testRunner.getFlowFilesForRelationship(PutSplunkHTTP.RELATIONSHIP_FAILURE).getFirst();
@@ -220,6 +229,52 @@ public class TestPutSplunkHTTP {
assertEquals("403",
outgoingFlowFile.getAttribute("splunk.status.code"));
}
+ @Test
+ public void testSslContextServiceProvidesSplunkSocketFactory() throws
InitializationException {
+ // Splunk discards the configured Socket Factory when the static
Security Protocol changes, so the Processor is configured with
+ // a protocol other than the one applied here to confirm the Socket
Factory survives connecting the Splunk Service.
+ Service.setSslSecurityProtocol(SSLSecurityProtocol.TLSv1_1);
+
+ 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.SECURITY_PROTOCOL,
SSLSecurityProtocol.TLSv1_2.name());
+ 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());
+ assertEquals(SSLSecurityProtocol.TLSv1_2,
Service.getSslSecurityProtocol());
+ }
+
+ @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);