From 4abf7d0edad99e84304f879ab5c94bd0f180d7f8 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Tue, 19 Nov 2024 18:21:00 -0500 Subject: [PATCH 1/8] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Updated=20to=20Spring?= =?UTF-8?q?=20Boot=203.3.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/fluentforms-sample-cli-app/pom.xml | 2 +- spring/fluentforms-sample-web-app/pom.xml | 2 +- spring/fluentforms-spring-boot-autoconfigure/pom.xml | 2 +- spring/fluentforms-spring-boot-starter/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring/fluentforms-sample-cli-app/pom.xml b/spring/fluentforms-sample-cli-app/pom.xml index 3102e342..e6401873 100644 --- a/spring/fluentforms-sample-cli-app/pom.xml +++ b/spring/fluentforms-sample-cli-app/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.4 + 3.3.5 com._4point.aem.fluentforms diff --git a/spring/fluentforms-sample-web-app/pom.xml b/spring/fluentforms-sample-web-app/pom.xml index d2f3c9a3..a7a80ec2 100644 --- a/spring/fluentforms-sample-web-app/pom.xml +++ b/spring/fluentforms-sample-web-app/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.4 + 3.3.5 com._4point.aem.fluentforms fluentforms-sample-web-app diff --git a/spring/fluentforms-spring-boot-autoconfigure/pom.xml b/spring/fluentforms-spring-boot-autoconfigure/pom.xml index 8ddcac76..075aef3a 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/pom.xml +++ b/spring/fluentforms-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.4 + 3.3.5 com._4point.aem.fluentforms diff --git a/spring/fluentforms-spring-boot-starter/pom.xml b/spring/fluentforms-spring-boot-starter/pom.xml index 6656702f..f2348b1f 100644 --- a/spring/fluentforms-spring-boot-starter/pom.xml +++ b/spring/fluentforms-spring-boot-starter/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.4 + 3.3.5 fluentforms-spring-boot-starter From f0705e8c5939b495709d49d0bc37eb36adce5e55 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Tue, 19 Nov 2024 18:23:48 -0500 Subject: [PATCH 2/8] =?UTF-8?q?=E2=9C=A8=20Added=20sslBundle=20to=20AEM=20?= =?UTF-8?q?Configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be used to designate the SSLBundle name that will be used when contacting AEM. --- .../aem/fluentforms/spring/AemConfiguration.java | 3 ++- .../aem/fluentforms/spring/AemConfigurationTest.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemConfiguration.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemConfiguration.java index 45d537a9..f8a6615b 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemConfiguration.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemConfiguration.java @@ -22,7 +22,8 @@ public record AemConfiguration( Integer port, // "aem.port" String user, // "aem.user" String password, // "aem.password" - @DefaultValue("false") Boolean useSsl // "aem.useSsl" + @DefaultValue("false") Boolean useSsl, // "aem.useSsl" + @DefaultValue("aem") String sslBundle // "aem.sslBundle" - Spring SSL Bundle for trust store ) { public String url() { diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemConfigurationTest.java b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemConfigurationTest.java index b29170da..80e66136 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemConfigurationTest.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemConfigurationTest.java @@ -68,6 +68,11 @@ void testGetUrl() { assertEquals("http://" + EXPECTED_SERVERNAME + ":" + EXPECTED_PORT + "/", underTest.url()); } + @Test + void testGetSslBundle() { + assertEquals("aem", underTest.sslBundle()); + } + @SpringBootTest(classes = {com._4point.aem.fluentforms.spring.AemConfigurationTest.TestApplication.class}, properties = { "fluentforms.aem.servername=" + EXPECTED_SERVERNAME, @@ -75,6 +80,7 @@ void testGetUrl() { "fluentforms.aem.user=" + EXPECTED_USER, "fluentforms.aem.password=" + EXPECTED_PASSWORD, "fluentforms.aem.useSsl=true", + "fluentforms.aem.sslBundle=notAem" }) static class AemConfigurationTests2 { protected static final int EXPECTED_PORT = 80; @@ -98,7 +104,10 @@ void testGetUrl() { assertEquals("https://" + EXPECTED_SERVERNAME + "/", underTest.url()); } - + @Test + void testGetSslBundle() { + assertEquals("notAem", underTest.sslBundle()); + } } @SpringBootApplication From 4698f8fc29acbc16d68e9c9f5a5a3a080a698081 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 09:56:35 -0500 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=93=9D=20Updated=20ConfigurationPrope?= =?UTF-8?q?rties=20doc=20with=20new=20SslBundles=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/ConfigurationProperties.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring/ConfigurationProperties.md b/spring/ConfigurationProperties.md index d4bc8126..5c80769a 100644 --- a/spring/ConfigurationProperties.md +++ b/spring/ConfigurationProperties.md @@ -26,6 +26,9 @@ spring boot starter web site for more details. can be `true` or `false`. `true` will tell FLuentForms to log in with https, `false` will result in an http connection. This property is optional, and it defaults to `false` if it is not supplied. +`fluentforms.aem.sslBundle` - This is the name used to locate a Spring Security SSL Bundle that will be used as a trust store +for SSL HTTPS connections to AEM. This property is optional, and it defaults to `aem` if it is not supplied. + ### Adaptive Forms `fluentforms.rproxy.enabled` - This is used to enable/disable the reverse proxying of secondary resources to AEM. If it is From 1262052fd9f97041d763a2cc68f1cbba9edf7a87 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 13:46:28 -0500 Subject: [PATCH 4/8] =?UTF-8?q?=E2=9C=A8=20Created=20JerseyClientFactory?= =?UTF-8?q?=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/JerseyClientFactory.java | 43 +++++++++++ .../spring/JerseyClientFactoryTest.java | 75 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/JerseyClientFactory.java create mode 100644 spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/JerseyClientFactory.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/JerseyClientFactory.java new file mode 100644 index 00000000..6d4f6f86 --- /dev/null +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/JerseyClientFactory.java @@ -0,0 +1,43 @@ +package com._4point.aem.fluentforms.spring; + +import javax.net.ssl.SSLContext; + +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ssl.NoSuchSslBundleException; +import org.springframework.boot.ssl.SslBundle; +import org.springframework.boot.ssl.SslBundles; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; + +/** + * + */ +public class JerseyClientFactory { + private final static Logger logger = LoggerFactory.getLogger(JerseyClientFactory.class); + + public static Client createClient(SslBundles sslBundles, String bundleName, String username, String password) { + return createClient(sslBundles, bundleName) + .register(HttpAuthenticationFeature.basic(username, password)) + .register(MultiPartFeature.class); + } + + public static Client createClient(SslBundles sslBundles, String bundleName) { + if (sslBundles != null) { + logger.info("SslBundles is not null"); + try { + SslBundle bundle = sslBundles.getBundle(bundleName); + logger.info("Client sslBundle is not null"); + SSLContext sslContext = bundle.createSslContext(); + return ClientBuilder.newBuilder().sslContext(sslContext).build(); + } catch (NoSuchSslBundleException e) { + // Eat the exception and fall through to the default client + } + } + logger.info("Creating default client"); + return ClientBuilder.newClient(); + } +} diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java new file mode 100644 index 00000000..e3229b69 --- /dev/null +++ b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java @@ -0,0 +1,75 @@ +package com._4point.aem.fluentforms.spring; + +import static org.junit.jupiter.api.Assertions.*; + +import java.security.NoSuchAlgorithmException; + +import javax.net.ssl.SSLContext; + +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.ssl.SslBundle; +import org.springframework.boot.ssl.SslBundles; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.Configuration; + +@ExtendWith(MockitoExtension.class) +class JerseyClientFactoryTest { + + @Test + void testCreateClientSslBundlesStringStringString(@Mock SslBundles mockSslBundles, + @Captor ArgumentCaptor bundleName, + @Mock SslBundle mockSslBundle, + @Mock SSLContext mockSslContext + ) { + Mockito.when(mockSslBundles.getBundle(bundleName.capture())).thenReturn(mockSslBundle); + Mockito.when(mockSslBundle.createSslContext()).thenReturn(mockSslContext); + + String expectedBundleName = "expectedBundle"; + + Client client = JerseyClientFactory.createClient(mockSslBundles, expectedBundleName, "user", "password"); + + Configuration configuration = client.getConfiguration(); + assertAll( + ()->assertEquals(expectedBundleName, bundleName.getValue()), + ()->assertSame(mockSslContext, client.getSslContext()), + ()->assertTrue(configuration.isRegistered(MultiPartFeature.class), "MultiPartFeature should be registered."), + ()->assertTrue(configuration.isRegistered(HttpAuthenticationFeature.class), "HttpAuthenticationFeature should be registered.") + ); + } + + @Test + void testCreateClientSslBundlesString(@Mock SslBundles mockSslBundles, + @Captor ArgumentCaptor bundleName, + @Mock SslBundle mockSslBundle, + @Mock SSLContext mockSslContext + ) { + Mockito.when(mockSslBundles.getBundle(bundleName.capture())).thenReturn(mockSslBundle); + Mockito.when(mockSslBundle.createSslContext()).thenReturn(mockSslContext); + + String expectedBundleName = "expectedBundle"; + + Client client = JerseyClientFactory.createClient(mockSslBundles, expectedBundleName); + + assertAll( + ()->assertEquals(expectedBundleName, bundleName.getValue()), + ()->assertSame(mockSslContext, client.getSslContext()) + ); + } + + @Test + void testCreateClient_NullSslBundles_NullString() throws Exception { + Client client = JerseyClientFactory.createClient(null, null); + + assertNotNull(client.getSslContext()); + } + +} From dbb6b2eea0b33017740b163712b8456a8803fce3 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 13:46:59 -0500 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=8E=A8=20Removed=20unused=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java index e3229b69..80cf0470 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java @@ -2,8 +2,6 @@ import static org.junit.jupiter.api.Assertions.*; -import java.security.NoSuchAlgorithmException; - import javax.net.ssl.SSLContext; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; From f2797cf362078ef9e92658b6df6cab9d21b0c05f Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 14:33:14 -0500 Subject: [PATCH 6/8] =?UTF-8?q?=E2=9C=A8=20Tied=20the=20SslBundles=20confi?= =?UTF-8?q?guration=20to=20the=20JerseyClientFactory.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/AemProxyAfSubmission.java | 8 ++-- .../spring/AemProxyAutoConfiguration.java | 14 ++++--- .../fluentforms/spring/AemProxyEndpoint.java | 23 +++++------ .../spring/FluentFormsAutoConfiguration.java | 41 ++++++++++--------- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmission.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmission.java index 25e490a7..7fce01ed 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmission.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmission.java @@ -16,14 +16,13 @@ import org.glassfish.jersey.client.ChunkedInput; import org.glassfish.jersey.client.ClientProperties; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.glassfish.jersey.media.multipart.BodyPartEntity; import org.glassfish.jersey.media.multipart.FormDataBodyPart; import org.glassfish.jersey.media.multipart.FormDataMultiPart; -import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ssl.SslBundles; import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMapAdapter; @@ -34,7 +33,6 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.Context; @@ -176,9 +174,9 @@ static class AfSubmitAemProxyProcessor implements AfSubmitProcessor { private final AemConfiguration aemConfig; private final Client httpClient; - public AfSubmitAemProxyProcessor(AemConfiguration aemConfig) { + public AfSubmitAemProxyProcessor(AemConfiguration aemConfig, SslBundles sslBundles) { this.aemConfig = aemConfig; - this.httpClient = ClientBuilder.newClient().register(HttpAuthenticationFeature.basic(aemConfig.user(), aemConfig.password())).register(MultiPartFeature.class); + this.httpClient = JerseyClientFactory.createClient(sslBundles, aemConfig.sslBundle(), aemConfig.user(), aemConfig.password()); } @Override diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAutoConfiguration.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAutoConfiguration.java index 74503e41..80d956f1 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAutoConfiguration.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyAutoConfiguration.java @@ -2,6 +2,7 @@ import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -10,6 +11,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.ssl.SslBundles; import org.springframework.context.annotation.Bean; import com._4point.aem.fluentforms.spring.AemProxyAfSubmission.AfSubmissionHandler; @@ -43,8 +45,8 @@ public class AemProxyAutoConfiguration { * JAX-RS Resources (i.e. endpoints) */ @Bean - public ResourceConfigCustomizer afProxyConfigurer(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig) { - return config->config.register(new AemProxyEndpoint(aemConfig, aemProxyConfig)) + public ResourceConfigCustomizer afProxyConfigurer(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig, @Autowired(required = false) SslBundles sslBundles) { + return config->config.register(new AemProxyEndpoint(aemConfig, aemProxyConfig, sslBundles)) .register(new AemProxyAfSubmission()) ; } @@ -85,8 +87,8 @@ public AfSubmitProcessor localSubmitProcessor(List submissi */ @ConditionalOnMissingBean({AfSubmitProcessor.class, AfSubmissionHandler.class}) @Bean() - public AfSubmitProcessor aemSubmitProcessor(AemConfiguration aemConfig) { - return new AfSubmitAemProxyProcessor(aemConfig); + public AfSubmitProcessor aemSubmitProcessor(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + return new AfSubmitAemProxyProcessor(aemConfig, sslBundles); } /** @@ -105,7 +107,7 @@ public AfSubmitProcessor aemSubmitProcessor(AemConfiguration aemConfig) { @ConditionalOnMissingBean(InternalAfSubmitAemProxyProcessor.class) @ConditionalOnBean(AfSubmissionHandler.class) @Bean - public InternalAfSubmitAemProxyProcessor aemProxyProcessor(AemConfiguration aemConfig) { - return ()->new AfSubmitAemProxyProcessor(aemConfig); + public InternalAfSubmitAemProxyProcessor aemProxyProcessor(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + return ()->new AfSubmitAemProxyProcessor(aemConfig, sslBundles); } } diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyEndpoint.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyEndpoint.java index 977d14ff..bea1c4fc 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyEndpoint.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/AemProxyEndpoint.java @@ -7,28 +7,27 @@ import java.util.stream.Collectors; import javax.naming.ConfigurationException; + +import org.glassfish.jersey.client.ChunkedInput; +import org.glassfish.jersey.server.ChunkedOutput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ssl.SslBundles; + +import com._4point.aem.docservices.rest_services.client.helpers.ReplacingInputStream; + import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import org.glassfish.jersey.client.ChunkedInput; -import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; -import org.glassfish.jersey.media.multipart.MultiPartFeature; -import org.glassfish.jersey.server.ChunkedOutput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com._4point.aem.docservices.rest_services.client.helpers.ReplacingInputStream; - /** * Reverse Proxy Code which reverse proxies secondary resources (.css, .js, etc.) that the browser will request. * These requests are forwarded to AEM. @@ -55,10 +54,10 @@ public class AemProxyEndpoint { /** * */ - public AemProxyEndpoint(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig) { + public AemProxyEndpoint(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig, SslBundles sslBundles) { this.aemProxyConfig = aemProxyConfig; this.aemConfig = aemConfig; - this.httpClient = ClientBuilder.newClient().register(HttpAuthenticationFeature.basic(aemConfig.user(), aemConfig.password())).register(MultiPartFeature.class); + this.httpClient = JerseyClientFactory.createClient(sslBundles, aemConfig.sslBundle(), aemConfig.user(), aemConfig.password()); } @Path("libs/granite/csrf/token.json") diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/FluentFormsAutoConfiguration.java b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/FluentFormsAutoConfiguration.java index 256943e6..3bcfe699 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/FluentFormsAutoConfiguration.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/main/java/com/_4point/aem/fluentforms/spring/FluentFormsAutoConfiguration.java @@ -3,9 +3,11 @@ import java.io.InputStream; import java.util.function.Function; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.ssl.SslBundles; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; @@ -52,18 +54,19 @@ public class FluentFormsAutoConfiguration { @SuppressWarnings("unchecked") - private T setAemFields(T builder, AemConfiguration aemConfig) { + private T setAemFields(T builder, AemConfiguration aemConfig, SslBundles sslBundles) { return (T)(builder.machineName(aemConfig.servername()) .port(aemConfig.port()) .basicAuthentication(aemConfig.user(), aemConfig.password()) .useSsl(aemConfig.useSsl()) + .clientFactory(()->JerseyClientFactory.createClient(sslBundles, aemConfig.sslBundle())) ); } @ConditionalOnMissingBean @Bean - public AdaptiveFormsService adaptiveFormsService(AemConfiguration aemConfig, Function afInputStreamFilter) { - return setAemFields(AdaptiveFormsService.builder(), aemConfig) + public AdaptiveFormsService adaptiveFormsService(AemConfiguration aemConfig, Function afInputStreamFilter, @Autowired(required = false) SslBundles sslBundles) { + return setAemFields(AdaptiveFormsService.builder(), aemConfig, sslBundles) .addRenderResultFilter(afInputStreamFilter) .build(); } @@ -83,58 +86,58 @@ private Function buildInputFilter(String aemPrefix, St @ConditionalOnMissingBean @Bean - public AssemblerService assemblerService(AemConfiguration aemConfig) { - RestServicesDocAssemblerServiceAdapter adapter = setAemFields(RestServicesDocAssemblerServiceAdapter.builder(), aemConfig).build(); + public AssemblerService assemblerService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesDocAssemblerServiceAdapter adapter = setAemFields(RestServicesDocAssemblerServiceAdapter.builder(), aemConfig, sslBundles).build(); return new AssemblerServiceImpl(adapter, UsageContext.CLIENT_SIDE); } @ConditionalOnMissingBean @Bean - public DocAssuranceService docAssuranceService(AemConfiguration aemConfig) { - RestServicesDocAssuranceServiceAdapter adapter = setAemFields(RestServicesDocAssuranceServiceAdapter.builder(), aemConfig).build(); + public DocAssuranceService docAssuranceService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesDocAssuranceServiceAdapter adapter = setAemFields(RestServicesDocAssuranceServiceAdapter.builder(), aemConfig, sslBundles).build(); return new DocAssuranceServiceImpl(adapter); } @ConditionalOnMissingBean @Bean - public FormsService formsService(AemConfiguration aemConfig) { - RestServicesFormsServiceAdapter adapter = setAemFields(RestServicesFormsServiceAdapter.builder(), aemConfig).build(); + public FormsService formsService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesFormsServiceAdapter adapter = setAemFields(RestServicesFormsServiceAdapter.builder(), aemConfig, sslBundles).build(); return new FormsServiceImpl(adapter, UsageContext.CLIENT_SIDE); } @ConditionalOnMissingBean @Bean - public GeneratePDFService generatePDFService(AemConfiguration aemConfig) { - RestServicesGeneratePDFServiceAdapter adapter = setAemFields(RestServicesGeneratePDFServiceAdapter.builder(), aemConfig).build(); + public GeneratePDFService generatePDFService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesGeneratePDFServiceAdapter adapter = setAemFields(RestServicesGeneratePDFServiceAdapter.builder(), aemConfig, sslBundles).build(); return new GeneratePDFServiceImpl(adapter); } @ConditionalOnMissingBean @Bean - public Html5FormsService html5FormsService(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig) { - return setAemFields(Html5FormsService.builder(), aemConfig) + public Html5FormsService html5FormsService(AemConfiguration aemConfig, AemProxyConfiguration aemProxyConfig, @Autowired(required = false) SslBundles sslBundles) { + return setAemFields(Html5FormsService.builder(), aemConfig, sslBundles) .addRenderResultFilter(afInputStreamFilter(aemProxyConfig)) .build(); } @ConditionalOnMissingBean @Bean - public OutputService outputService(AemConfiguration aemConfig) { - RestServicesOutputServiceAdapter adapter = setAemFields(RestServicesOutputServiceAdapter.builder(), aemConfig).build(); + public OutputService outputService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesOutputServiceAdapter adapter = setAemFields(RestServicesOutputServiceAdapter.builder(), aemConfig, sslBundles).build(); return new OutputServiceImpl(adapter, UsageContext.CLIENT_SIDE); } @ConditionalOnMissingBean @Bean - public PdfUtilityService pdfUtilityService(AemConfiguration aemConfig) { - RestServicesPdfUtilityServiceAdapter adapter = setAemFields(RestServicesPdfUtilityServiceAdapter.builder(), aemConfig).build(); + public PdfUtilityService pdfUtilityService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesPdfUtilityServiceAdapter adapter = setAemFields(RestServicesPdfUtilityServiceAdapter.builder(), aemConfig, sslBundles).build(); return new PdfUtilityServiceImpl(adapter); } @ConditionalOnMissingBean @Bean - public ConvertPdfService convertPdfService(AemConfiguration aemConfig) { - RestServicesConvertPdfServiceAdapter adapter = setAemFields(RestServicesConvertPdfServiceAdapter.builder(), aemConfig).build(); + public ConvertPdfService convertPdfService(AemConfiguration aemConfig, @Autowired(required = false) SslBundles sslBundles) { + RestServicesConvertPdfServiceAdapter adapter = setAemFields(RestServicesConvertPdfServiceAdapter.builder(), aemConfig, sslBundles).build(); return new ConvertPdfServiceImpl(adapter); } From 5ae3eb581cdf2654deb33e776a75cfc1bc192203 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 17:33:08 -0500 Subject: [PATCH 7/8] =?UTF-8?q?=E2=9C=85=20Updated=20test=20to=20uise=20SS?= =?UTF-8?q?L=20(and=20Spring=20SSLBundles).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/AemProxyAfSubmissionTest.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmissionTest.java b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmissionTest.java index c4af4bff..39a739b3 100644 --- a/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmissionTest.java +++ b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/AemProxyAfSubmissionTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.EnumSource; @@ -44,7 +45,8 @@ import com._4point.aem.fluentforms.spring.AemProxyAfSubmission.AfSubmitLocalProcessor.InternalAfSubmitAemProxyProcessor; import com._4point.aem.fluentforms.spring.AemProxyAfSubmissionTest.AemProxyAfSubmissionTestWithLocalAfSubmitProcessorTest.MockAemProxy; import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; @@ -99,10 +101,6 @@ public static JakartaRestClient setUpRestClient(int port) { return getPdfForm; } - private static String getBaseUriString(int port) { - return getBaseUri(port).toString(); - } - private static URI getBaseUri(int port) { return URI.create("http://localhost:" + port); } @@ -121,10 +119,9 @@ public static class JerseyConfig extends ResourceConfig { } /** - * Tests the AemAfSubmitProcessor + * Tests the AemAfSubmitProcessor. It utilizes an SSL connection to test the SslBundle code. * */ - @WireMockTest(httpPort = 8502) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = {TestApplication.class, JerseyConfig.class, AfSubmitAemProxyProcessor.class}, properties = { @@ -133,10 +130,26 @@ public static class JerseyConfig extends ResourceConfig { "fluentforms.aem.port=" + "8502", "fluentforms.aem.user=admin", "fluentforms.aem.password=admin", + "fluentforms.aem.useSsl=true", + "spring.ssl.bundle.jks.aem.truststore.location=file:src/test/resources/aemforms.p12", + "spring.ssl.bundle.jks.aem.truststore.password=Pa$$123", + "spring.ssl.bundle.jks.aem.truststore.type=PKCS12" } ) public static class AemProxyAfSubmissionTestWithAemAfSubmitProcessorTest { + @RegisterExtension + static WireMockExtension wm1 = WireMockExtension.newInstance() + .options(WireMockConfiguration.wireMockConfig().httpsPort(8502) + .httpDisabled(true) + .keystorePath("src/test/resources/aemforms.p12") + .keyManagerPassword("Pa$$123") + .keystorePassword("Pa$$123") + .keystoreType("PKCS12") + ) + .configureStaticDsl(true) // Use with Static DSL + .build(); + @LocalServerPort private int port; From 492189656e38bf25a60057a06e511788e62d5fe4 Mon Sep 17 00:00:00 2001 From: Rob McDougall Date: Thu, 21 Nov 2024 17:33:38 -0500 Subject: [PATCH 8/8] =?UTF-8?q?=E2=9C=85=20Updated=20test=20to=20use=20SSL?= =?UTF-8?q?=20(and=20Spring=20SSL=20Bundles)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/resources/aemforms.p12 | Bin 0 -> 4204 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 spring/fluentforms-spring-boot-autoconfigure/src/test/resources/aemforms.p12 diff --git a/spring/fluentforms-spring-boot-autoconfigure/src/test/resources/aemforms.p12 b/spring/fluentforms-spring-boot-autoconfigure/src/test/resources/aemforms.p12 new file mode 100644 index 0000000000000000000000000000000000000000..2e835490b7346df936babab35bbbe09f14073271 GIT binary patch literal 4204 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 literal 0 HcmV?d00001