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);

Reply via email to