diff --git a/data-prepper-plugins/http-common/build.gradle b/data-prepper-plugins/http-common/build.gradle index 54fa5d346d..fa0e1c3efb 100644 --- a/data-prepper-plugins/http-common/build.gradle +++ b/data-prepper-plugins/http-common/build.gradle @@ -6,6 +6,7 @@ dependencies { implementation 'org.apache.httpcomponents:httpcore:4.4.16' testImplementation testLibs.bundles.junit + testImplementation testLibs.mockito.inline } jacocoTestCoverageVerification { diff --git a/data-prepper-plugins/http-common/src/main/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProvider.java b/data-prepper-plugins/http-common/src/main/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProvider.java index 2979a6d7a1..fb28a5d7c4 100644 --- a/data-prepper-plugins/http-common/src/main/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProvider.java +++ b/data-prepper-plugins/http-common/src/main/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProvider.java @@ -5,7 +5,6 @@ package org.opensearch.dataprepper.plugins.truststore; -import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; import org.slf4j.Logger; @@ -63,6 +62,12 @@ private static KeyStore createKeyStore(final Path certificatePath) throws Except } } + private static KeyStore createKeyStore(final InputStream trustStoreInputStream, final String password) throws Exception { + final KeyStore trustStore = KeyStore.getInstance("JKS"); + trustStore.load(trustStoreInputStream, password.toCharArray()); + return trustStore; + } + private static KeyStore createKeyStore(final InputStream certificateInputStream) throws Exception { final CertificateFactory factory = CertificateFactory.getInstance("X.509"); final Certificate trustedCa = factory.generateCertificate(certificateInputStream); @@ -81,6 +86,15 @@ public static SSLContext createSSLContext(final Path certificatePath) { } } + public static SSLContext createSSLContext(final Path trustStorePath, final String password) { + LOG.info("Using the truststore path and password to create SSL context."); + try (InputStream is = Files.newInputStream(trustStorePath)) { + return createSSLContext(is, password); + } catch (Exception ex) { + throw new RuntimeException(ex.getMessage(), ex); + } + } + public static SSLContext createSSLContext(final String certificateContent) { LOG.info("Using the certificate content to create SSL context."); try (InputStream certificateInputStream = new ByteArrayInputStream(certificateContent.getBytes())) { @@ -91,10 +105,20 @@ public static SSLContext createSSLContext(final String certificateContent) { } private static SSLContext createSSLContext(final InputStream certificateInputStream) throws Exception { - KeyStore trustStore = createKeyStore(certificateInputStream); - SSLContextBuilder sslContextBuilder = SSLContexts.custom() - .loadTrustMaterial(trustStore, null); - return sslContextBuilder.build(); + final KeyStore trustStore = createKeyStore(certificateInputStream); + return SSLContexts.custom() + .loadTrustMaterial(trustStore, null).build(); + } + + private static SSLContext createSSLContext(final InputStream certificateInputStream, final String password) throws Exception { + final KeyStore trustStore = createKeyStore(certificateInputStream, password); + final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + // Create an SSLContext that uses the truststore + final SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + SSLContext.setDefault(sslContext); + return sslContext; } public static SSLContext createSSLContextWithTrustAllStrategy() { diff --git a/data-prepper-plugins/http-common/src/test/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProviderTest.java b/data-prepper-plugins/http-common/src/test/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProviderTest.java index c01b36c6a8..d89c1580cb 100644 --- a/data-prepper-plugins/http-common/src/test/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProviderTest.java +++ b/data-prepper-plugins/http-common/src/test/java/org/opensearch/dataprepper/plugins/truststore/TrustStoreProviderTest.java @@ -1,15 +1,18 @@ package org.opensearch.dataprepper.plugins.truststore; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.security.KeyStore; +import java.util.UUID; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; @@ -17,46 +20,41 @@ import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; @ExtendWith(MockitoExtension.class) class TrustStoreProviderTest { - private TrustStoreProvider trustStoreProvider; - - @BeforeEach - void setUp() { - trustStoreProvider = new TrustStoreProvider(); - } - @Test void createTrustManagerWithCertificatePath() { final Path certFilePath = Path.of("data/certificate/test_cert.crt"); - final TrustManager[] trustManagers = trustStoreProvider.createTrustManager(certFilePath); + final TrustManager[] trustManagers = TrustStoreProvider.createTrustManager(certFilePath); assertThat(trustManagers, is(notNullValue())); } @Test void createTrustManagerWithInvalidCertificatePath() { final Path certFilePath = Path.of("data/certificate/cert_doesnt_exist.crt"); - assertThrows(RuntimeException.class, () -> trustStoreProvider.createTrustManager(certFilePath)); + assertThrows(RuntimeException.class, () -> TrustStoreProvider.createTrustManager(certFilePath)); } @Test void createTrustManagerWithCertificateContent() throws IOException { final Path certFilePath = Path.of("data/certificate/test_cert.crt"); final String certificateContent = Files.readString(certFilePath); - final TrustManager[] trustManagers = trustStoreProvider.createTrustManager(certificateContent); + final TrustManager[] trustManagers = TrustStoreProvider.createTrustManager(certificateContent); assertThat(trustManagers, is(notNullValue())); } @Test void createTrustManagerWithInvalidCertificateContent() { - assertThrows(RuntimeException.class, () -> trustStoreProvider.createTrustManager("invalid certificate content")); + assertThrows(RuntimeException.class, () -> TrustStoreProvider.createTrustManager("invalid certificate content")); } @Test void createTrustAllManager() { - final TrustManager[] trustManagers = trustStoreProvider.createTrustAllManager(); + final TrustManager[] trustManagers = TrustStoreProvider.createTrustAllManager(); assertThat(trustManagers, is(notNullValue())); assertThat(trustManagers, is(arrayWithSize(1))); assertThat(trustManagers[0], is(instanceOf(X509TrustAllManager.class))); @@ -65,21 +63,36 @@ void createTrustAllManager() { @Test void createSSLContextWithCertificatePath() { final Path certFilePath = Path.of("data/certificate/test_cert.crt"); - final SSLContext sslContext = trustStoreProvider.createSSLContext(certFilePath); + final SSLContext sslContext = TrustStoreProvider.createSSLContext(certFilePath); assertThat(sslContext, is(notNullValue())); } + @Test + void createSSLContextWithTrustStorePathAndPassword() throws Exception { + final Path certFilePath = Path.of("data/certificate/test_cert.crt"); + final KeyStore trustStore = mock(KeyStore.class); + final TrustManagerFactory trustManagerFactory = mock(TrustManagerFactory.class); + try (MockedStatic keyStoreMockedStatic = mockStatic(KeyStore.class); + MockedStatic trustManagerFactoryMockedStatic = mockStatic(TrustManagerFactory.class)) { + keyStoreMockedStatic.when(() -> KeyStore.getInstance("JKS")).thenReturn(trustStore); + trustManagerFactoryMockedStatic.when(() -> + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())).thenReturn(trustManagerFactory); + final SSLContext sslContext = TrustStoreProvider.createSSLContext(certFilePath, UUID.randomUUID().toString()); + assertThat(sslContext, is(notNullValue())); + } + } + @Test void createSSLContextWithCertificateContent() throws IOException { final Path certFilePath = Path.of("data/certificate/test_cert.crt"); final String certificateContent = Files.readString(certFilePath); - final SSLContext sslContext = trustStoreProvider.createSSLContext(certificateContent); + final SSLContext sslContext = TrustStoreProvider.createSSLContext(certificateContent); assertThat(sslContext, is(notNullValue())); } @Test void createSSLContextWithTrustAllStrategy() { - final SSLContext sslContext = trustStoreProvider.createSSLContextWithTrustAllStrategy(); + final SSLContext sslContext = TrustStoreProvider.createSSLContextWithTrustAllStrategy(); assertThat(sslContext, is(notNullValue())); } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 2824ecff2d..2335fcd2a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -168,4 +168,3 @@ include 'data-prepper-plugins:decompress-processor' include 'data-prepper-plugins:split-event-processor' include 'data-prepper-plugins:http-common' include 'data-prepper-plugins:flatten-processor' -