From 2f560c1b9f47da5c9810a24cd1d3345d27ac2f43 Mon Sep 17 00:00:00 2001 From: CatiaCorreia Date: Thu, 27 Nov 2025 16:13:26 +0000 Subject: [PATCH] Add support for LDAPS testing Add to EmbeddedLdapProperties: -boolean ldaps -String sslBundleName Create setLdapsListener method to create and set the LDAPS listener for the server. Add test for new embedded LDAP setup. Issue#48060 Signed-off-by: CatiaCorreia --- .../EmbeddedLdapAutoConfiguration.java | 33 ++++++++++++++++-- .../embedded/EmbeddedLdapProperties.java | 26 ++++++++++++++ .../EmbeddedLdapAutoConfigurationTests.java | 30 +++++++++++++++- .../ldap/autoconfigure/embedded/keystore.jks | Bin 0 -> 32 bytes .../autoconfigure/embedded/keystore.pkcs12 | Bin 0 -> 103 bytes .../ldap/autoconfigure/embedded/rsa-cert.pem | 23 ++++++++++++ .../ldap/autoconfigure/embedded/rsa-key.pem | 28 +++++++++++++++ 7 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.jks create mode 100644 module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.pkcs12 create mode 100644 module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/rsa-cert.pem create mode 100644 module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/rsa-key.pem diff --git a/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java b/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java index 823ab1dd3e59..3fc2ea3f689b 100644 --- a/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java +++ b/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java @@ -22,10 +22,15 @@ import java.util.List; import java.util.Map; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocketFactory; + import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.sdk.LDAPException; +import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.ldap.sdk.schema.Schema; import com.unboundid.ldif.LDIFReader; import org.jspecify.annotations.Nullable; @@ -38,6 +43,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; @@ -47,6 +53,7 @@ import org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration; import org.springframework.boot.ldap.autoconfigure.LdapProperties; import org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration.EmbeddedLdapAutoConfigurationRuntimeHints; +import org.springframework.boot.ssl.SslBundles; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -100,9 +107,13 @@ InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext) t config.addAdditionalBindCredentials(username, password); } setSchema(config); - InMemoryListenerConfig listenerConfig = InMemoryListenerConfig.createLDAPConfig("LDAP", - this.embeddedProperties.getPort()); - config.setListenerConfigs(listenerConfig); + if (this.embeddedProperties.isLdaps()) { + this.setLdapsListener(applicationContext, config); + } + else { + config + .setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", this.embeddedProperties.getPort())); + } this.server = new InMemoryDirectoryServer(config); importLdif(this.server, applicationContext); this.server.startListening(); @@ -137,6 +148,22 @@ private void setSchema(InMemoryDirectoryServerConfig config, Resource resource) } } + @ConditionalOnBean(SslBundles.class) + private void setLdapsListener(ApplicationContext applicationContext, InMemoryDirectoryServerConfig config) + throws LDAPException { + if (StringUtils.hasText(this.embeddedProperties.getSslBundleName())) { + SslBundles sslBundles = applicationContext.getBean(SslBundles.class); + SSLContext sslContext = sslBundles.getBundle(this.embeddedProperties.getSslBundleName()).createSslContext(); + SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); + SSLSocketFactory clientSocketFactory = sslContext.getSocketFactory(); + config.setListenerConfigs(InMemoryListenerConfig.createLDAPSConfig("LDAPS", null, + this.embeddedProperties.getPort(), serverSocketFactory, clientSocketFactory)); + } + else { + throw new LDAPException(ResultCode.PARAM_ERROR, "SslBundleName property not specified"); + } + } + private void importLdif(InMemoryDirectoryServer server, ApplicationContext applicationContext) { String location = this.embeddedProperties.getLdif(); if (StringUtils.hasText(location)) { diff --git a/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java b/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java index d348491af48a..e5b480a94edf 100644 --- a/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java +++ b/module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java @@ -57,6 +57,16 @@ public class EmbeddedLdapProperties { */ private String ldif = "classpath:schema.ldif"; + /** + * Listener type. + */ + private boolean ldaps; + + /** + * Embedded LDAPS client SSL bundle name. + */ + @Nullable private String sslBundleName; + /** * Schema validation. */ @@ -94,6 +104,22 @@ public void setLdif(String ldif) { this.ldif = ldif; } + public boolean isLdaps() { + return this.ldaps; + } + + public void setLdaps(boolean bool) { + this.ldaps = bool; + } + + public @Nullable String getSslBundleName() { + return this.sslBundleName; + } + + public void setSslBundleName(@Nullable String sslBundleName) { + this.sslBundleName = sslBundleName; + } + public Validation getValidation() { return this.validation; } diff --git a/module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java b/module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java index 14b4d020638c..00e0d23a6978 100644 --- a/module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java +++ b/module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java @@ -20,6 +20,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.List; import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.sdk.BindResult; @@ -32,7 +34,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration; import org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration; +import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.util.TestPropertyValues; @@ -54,7 +58,7 @@ class EmbeddedLdapAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(EmbeddedLdapAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(EmbeddedLdapAutoConfiguration.class, SslAutoConfiguration.class)); @Test void testSetDefaultPort() { @@ -66,6 +70,30 @@ void testSetDefaultPort() { }); } + @Test + void testLdapsVersion() { + List propertyValues = new ArrayList<>(); + String location = "classpath:org/springframework/boot/ldap/autoconfigure/embedded/"; + propertyValues.add("spring.ssl.bundle.pem.test.key.alias=alias1"); + propertyValues.add("spring.ssl.bundle.pem.test.key.password=secret1"); + propertyValues.add("spring.ssl.bundle.pem.test.keystore.certificate=" + location + "rsa-cert.pem"); + propertyValues.add("spring.ssl.bundle.pem.test.keystore.keystore.private-key=" + location + "rsa-key.pem"); + propertyValues.add("spring.ssl.bundle.pem.test.truststore.certificate=" + location + "rsa-cert.pem"); + propertyValues.add("spring.ldap.embedded.port:1234"); + propertyValues.add("spring.ldap.embedded.base-dn:dc=spring,dc=org"); + propertyValues.add("spring.ldap.embedded.ldaps:true"); + propertyValues.add("spring.ldap.embedded.sslBundleName:test"); + propertyValues.add("spring.ldap.embedded.credential.username:uid=root"); + propertyValues.add("spring.ldap.embedded.credential.password:boot"); + this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> { + context.getBean(SslBundles.class); + InMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class); + assertThat(server.getListenPort()).isEqualTo(1234); + BindResult result = server.bind("uid=root", "boot"); + assertThat(result).isNotNull(); + }); + } + @Test void testRandomPortWithEnvironment() { this.contextRunner.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org").run((context) -> { diff --git a/module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.jks b/module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..4e5e1399aee491f1765c8ff8a833c7c1103380ae GIT binary patch literal 32 mcmezO_TO6u1_mY|W@tFi`n=R{PU>QDACY&KEuvWkKVksZ3=H4^ literal 0 HcmV?d00001 diff --git a/module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.pkcs12 b/module/spring-boot-ldap/src/test/resources/org/springframework/boot/ldap/autoconfigure/embedded/keystore.pkcs12 new file mode 100644 index 0000000000000000000000000000000000000000..8c9a6ffa62f44dc739e0849bacce4b3bd6b2f2a6 GIT binary patch literal 103 zcmV-t0GR(UWdZ>MFcAg`Duzgg_YDCD0iXl~0x$qDO)xPq4F(BdhDZTr0|WvA1povf zvJZ7z`bbPmL!}G_MScP$r~?xi3ALqBRfwXz2zS1)1QaQ|@ehK>n61?5=jVJYDi7ZE JuxSDUClLO2A6)