Skip to content

Commit 2f560c1

Browse files
committed
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 <catia.correia97@gmail.com>
1 parent bd5264e commit 2f560c1

File tree

7 files changed

+136
-4
lines changed

7 files changed

+136
-4
lines changed

module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222
import java.util.List;
2323
import java.util.Map;
2424

25+
import javax.net.ssl.SSLContext;
26+
import javax.net.ssl.SSLServerSocketFactory;
27+
import javax.net.ssl.SSLSocketFactory;
28+
2529
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
2630
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
2731
import com.unboundid.ldap.listener.InMemoryListenerConfig;
2832
import com.unboundid.ldap.sdk.LDAPException;
33+
import com.unboundid.ldap.sdk.ResultCode;
2934
import com.unboundid.ldap.sdk.schema.Schema;
3035
import com.unboundid.ldif.LDIFReader;
3136
import org.jspecify.annotations.Nullable;
@@ -38,6 +43,7 @@
3843
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
3944
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
4045
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
46+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
4147
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4248
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4349
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
@@ -47,6 +53,7 @@
4753
import org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;
4854
import org.springframework.boot.ldap.autoconfigure.LdapProperties;
4955
import org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration.EmbeddedLdapAutoConfigurationRuntimeHints;
56+
import org.springframework.boot.ssl.SslBundles;
5057
import org.springframework.context.ApplicationContext;
5158
import org.springframework.context.ConfigurableApplicationContext;
5259
import org.springframework.context.annotation.Bean;
@@ -100,9 +107,13 @@ InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext) t
100107
config.addAdditionalBindCredentials(username, password);
101108
}
102109
setSchema(config);
103-
InMemoryListenerConfig listenerConfig = InMemoryListenerConfig.createLDAPConfig("LDAP",
104-
this.embeddedProperties.getPort());
105-
config.setListenerConfigs(listenerConfig);
110+
if (this.embeddedProperties.isLdaps()) {
111+
this.setLdapsListener(applicationContext, config);
112+
}
113+
else {
114+
config
115+
.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", this.embeddedProperties.getPort()));
116+
}
106117
this.server = new InMemoryDirectoryServer(config);
107118
importLdif(this.server, applicationContext);
108119
this.server.startListening();
@@ -137,6 +148,22 @@ private void setSchema(InMemoryDirectoryServerConfig config, Resource resource)
137148
}
138149
}
139150

151+
@ConditionalOnBean(SslBundles.class)
152+
private void setLdapsListener(ApplicationContext applicationContext, InMemoryDirectoryServerConfig config)
153+
throws LDAPException {
154+
if (StringUtils.hasText(this.embeddedProperties.getSslBundleName())) {
155+
SslBundles sslBundles = applicationContext.getBean(SslBundles.class);
156+
SSLContext sslContext = sslBundles.getBundle(this.embeddedProperties.getSslBundleName()).createSslContext();
157+
SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();
158+
SSLSocketFactory clientSocketFactory = sslContext.getSocketFactory();
159+
config.setListenerConfigs(InMemoryListenerConfig.createLDAPSConfig("LDAPS", null,
160+
this.embeddedProperties.getPort(), serverSocketFactory, clientSocketFactory));
161+
}
162+
else {
163+
throw new LDAPException(ResultCode.PARAM_ERROR, "SslBundleName property not specified");
164+
}
165+
}
166+
140167
private void importLdif(InMemoryDirectoryServer server, ApplicationContext applicationContext) {
141168
String location = this.embeddedProperties.getLdif();
142169
if (StringUtils.hasText(location)) {

module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ public class EmbeddedLdapProperties {
5757
*/
5858
private String ldif = "classpath:schema.ldif";
5959

60+
/**
61+
* Listener type.
62+
*/
63+
private boolean ldaps;
64+
65+
/**
66+
* Embedded LDAPS client SSL bundle name.
67+
*/
68+
@Nullable private String sslBundleName;
69+
6070
/**
6171
* Schema validation.
6272
*/
@@ -94,6 +104,22 @@ public void setLdif(String ldif) {
94104
this.ldif = ldif;
95105
}
96106

107+
public boolean isLdaps() {
108+
return this.ldaps;
109+
}
110+
111+
public void setLdaps(boolean bool) {
112+
this.ldaps = bool;
113+
}
114+
115+
public @Nullable String getSslBundleName() {
116+
return this.sslBundleName;
117+
}
118+
119+
public void setSslBundleName(@Nullable String sslBundleName) {
120+
this.sslBundleName = sslBundleName;
121+
}
122+
97123
public Validation getValidation() {
98124
return this.validation;
99125
}

module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.lang.annotation.Retention;
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
23+
import java.util.ArrayList;
24+
import java.util.List;
2325

2426
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
2527
import com.unboundid.ldap.sdk.BindResult;
@@ -32,7 +34,9 @@
3234
import org.springframework.beans.factory.annotation.Value;
3335
import org.springframework.boot.autoconfigure.AutoConfigurations;
3436
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
37+
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
3538
import org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;
39+
import org.springframework.boot.ssl.SslBundles;
3640
import org.springframework.boot.test.context.FilteredClassLoader;
3741
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3842
import org.springframework.boot.test.util.TestPropertyValues;
@@ -54,7 +58,7 @@
5458
class EmbeddedLdapAutoConfigurationTests {
5559

5660
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
57-
.withConfiguration(AutoConfigurations.of(EmbeddedLdapAutoConfiguration.class));
61+
.withConfiguration(AutoConfigurations.of(EmbeddedLdapAutoConfiguration.class, SslAutoConfiguration.class));
5862

5963
@Test
6064
void testSetDefaultPort() {
@@ -66,6 +70,30 @@ void testSetDefaultPort() {
6670
});
6771
}
6872

73+
@Test
74+
void testLdapsVersion() {
75+
List<String> propertyValues = new ArrayList<>();
76+
String location = "classpath:org/springframework/boot/ldap/autoconfigure/embedded/";
77+
propertyValues.add("spring.ssl.bundle.pem.test.key.alias=alias1");
78+
propertyValues.add("spring.ssl.bundle.pem.test.key.password=secret1");
79+
propertyValues.add("spring.ssl.bundle.pem.test.keystore.certificate=" + location + "rsa-cert.pem");
80+
propertyValues.add("spring.ssl.bundle.pem.test.keystore.keystore.private-key=" + location + "rsa-key.pem");
81+
propertyValues.add("spring.ssl.bundle.pem.test.truststore.certificate=" + location + "rsa-cert.pem");
82+
propertyValues.add("spring.ldap.embedded.port:1234");
83+
propertyValues.add("spring.ldap.embedded.base-dn:dc=spring,dc=org");
84+
propertyValues.add("spring.ldap.embedded.ldaps:true");
85+
propertyValues.add("spring.ldap.embedded.sslBundleName:test");
86+
propertyValues.add("spring.ldap.embedded.credential.username:uid=root");
87+
propertyValues.add("spring.ldap.embedded.credential.password:boot");
88+
this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {
89+
context.getBean(SslBundles.class);
90+
InMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);
91+
assertThat(server.getListenPort()).isEqualTo(1234);
92+
BindResult result = server.bind("uid=root", "boot");
93+
assertThat(result).isNotNull();
94+
});
95+
}
96+
6997
@Test
7098
void testRandomPortWithEnvironment() {
7199
this.contextRunner.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org").run((context) -> {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL
3+
BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI
4+
Q2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55
5+
U2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MTExMjExNTha
6+
Fw0zMzA5MDgxMjExNThaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h
7+
bWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG
8+
A1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi
9+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfdkeEiCk+5mpXUhJ1FLmOCx6/
10+
jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dgpHqds/84pb+3
11+
OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1U6zk1iwrbiO3
12+
hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf4RhoE6krDdV1
13+
JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAPuwXHO5BNw504
14+
3Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3TOhyA1ueXAgMB
15+
AAGjUzBRMB0GA1UdDgQWBBRHYz8OjqU/4JZMegJaN/jQbdj4MjAfBgNVHSMEGDAW
16+
gBRHYz8OjqU/4JZMegJaN/jQbdj4MjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
17+
DQEBCwUAA4IBAQBr9zqlNx7Mr1ordGfhk+xFrDtyBnk1vXbwVdnog66REqpPLH+K
18+
MfCKdj6wFoPa8ZjPb4VYFp2DvMxVXtFMzqGfLjYJPqefEzQCleOcA5aiE/ENIaaD
19+
ybYh99V5CsFAqyKuHLBFEzeYJ028SR3QsCISom0k/Fh6y2IwHJJEHykjqJKvL4bb
20+
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds
21+
HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb
22+
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8
23+
-----END CERTIFICATE-----
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfdkeEiCk+5mpX
3+
UhJ1FLmOCx6/jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dg
4+
pHqds/84pb+3OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1
5+
U6zk1iwrbiO3hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf
6+
4RhoE6krDdV1JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAP
7+
uwXHO5BNw5043Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3T
8+
OhyA1ueXAgMBAAECggEAPK1LqmULWMlhdoeeyVlQ//lAQn+6X4/MwycG/UsCSJC2
9+
BCV4nfgyv853UFRkM0jPBhDQ7h1wz1ohuWbs11xaBcqgKE7ywe3ZQULD5tqnO64y
10+
BU8V2+rnO4gjpbdMHQLlxdgy5KHxtR3Q4+6Kj+rlFMOMqLWZSmke8na7H+SczzGf
11+
+dZO4LRTbjGmFdUidehovm2icSM8OdU2w3FHlFRu2NBsTHGeAhRw86Yw24KfJp4R
12+
GSDQIBdwp1wCs5w7w4zPjxS7Zi+Uwspyq31KDJwyfK2O1WLI05bQ6FLqVRD/xy+Y
13+
b4WCse1O08SYWze2No915LB07sokgmomr3//bOwuEQKBgQDPBrPQXokn0BoTlgsa
14+
JohgWzQ5P9u/2WY+u2SG/xgNEx0s+lk/AmAH80wsBJ68FV6z5Non7TzD7xCsf2HJ
15+
3cP/EHl2ngTctz/eqpCcS5UPZBHmay60q6WKIkH/3ml7c0UhlqSqS3EDVyEe05hk
16+
msWAN+fV4ajVlhWgiUZRVdxMpwKBgQDFLyPBOEn6zLOHfkQWcibVf8s2LTe76R/S
17+
8Gk3jbk5mimR3vNm0L/rHqGwl75rOuFiFOHVkfuY9Dawaht0QnagjayT5hDqr6aD
18+
s5Chyoy9qpXnfnqOgk6rQZqj+/ODkjqEkBdRCKWvCVnDIi3Au2kS3QIc4iTsGrBW
19+
ygZdbxM7kQKBgEuzS7T5nHVuZtqaltytElkJgIMekqAIQpbVtuCWDplZT+XOdSvR
20+
FoRRtpyx48kql0J4gDzxRrLui85Hld5WtQBjacax6V07tKMbA13jVVIXaWQz9RQj
21+
X5ivBisljLSTZcfuaa/LfjuWdIntHWBMJ8PGrYNLzIytIKNfDtNW7gMpAoGAIRZQ
22+
5JpCZ7Azq9e3KyEKfSbNfZDG2mQ679Vhgm3ol87TjOOhai47FgP008IStMGTkja4
23+
0nKFilvoVV/orXB9oWFEhSjEy+yff1gBO/TV+vmF3+tsOz+IXdpLTZr4eKpv4VCg
24+
aPuPebiS9Fhm3wFTl1O4iAo2cdvknRuXR9RcoNECgYADksGk1lJGW5kMIMJ+6os+
25+
CJdGnJiX7XsnM0VzkagswnqDe03SqkJuFOmIp96eitxLT4EfB+585pYQRSy2fyJX
26+
WR2AAnC7oqUcQFkgDt9WBZAazI6aLXYO+trRoGKuWynGM8mjetr5C75g0auj4lsN
27+
rGiie2UnjshJ67FrG4kZoA==
28+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)