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 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-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/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); } 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/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 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; 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..80cf0470 --- /dev/null +++ b/spring/fluentforms-spring-boot-autoconfigure/src/test/java/com/_4point/aem/fluentforms/spring/JerseyClientFactoryTest.java @@ -0,0 +1,73 @@ +package com._4point.aem.fluentforms.spring; + +import static org.junit.jupiter.api.Assertions.*; + +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()); + } + +} 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 00000000..2e835490 Binary files /dev/null and b/spring/fluentforms-spring-boot-autoconfigure/src/test/resources/aemforms.p12 differ 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