Skip to content

Commit fd7c3e2

Browse files
committed
Documenting changes and existing problem in code for demonstration purposes.
Signed-off-by: CatiaCorreia <[email protected]>
1 parent 8d5bde9 commit fd7c3e2

File tree

8 files changed

+356
-111
lines changed

8 files changed

+356
-111
lines changed

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

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,45 @@
1616

1717
package org.springframework.boot.ldap.autoconfigure.embedded;
1818

19+
import java.io.IOException;
1920
import java.io.InputStream;
21+
import java.security.KeyManagementException;
22+
import java.security.KeyStore;
23+
import java.security.KeyStoreException;
24+
import java.security.NoSuchAlgorithmException;
25+
import java.security.SecureRandom;
26+
import java.security.UnrecoverableKeyException;
27+
import java.security.cert.CertificateException;
2028
import java.util.Collections;
2129
import java.util.HashMap;
2230
import java.util.List;
2331
import java.util.Map;
2432

33+
import javax.net.ssl.KeyManager;
34+
import javax.net.ssl.KeyManagerFactory;
2535
import javax.net.ssl.SSLContext;
2636
import javax.net.ssl.SSLServerSocketFactory;
2737
import javax.net.ssl.SSLSocketFactory;
38+
import javax.net.ssl.TrustManager;
39+
import javax.net.ssl.TrustManagerFactory;
2840

2941
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
3042
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
3143
import com.unboundid.ldap.listener.InMemoryListenerConfig;
3244
import com.unboundid.ldap.sdk.LDAPException;
33-
import com.unboundid.ldap.sdk.ResultCode;
3445
import com.unboundid.ldap.sdk.schema.Schema;
3546
import com.unboundid.ldif.LDIFReader;
3647
import org.jspecify.annotations.Nullable;
3748

3849
import org.springframework.aot.hint.RuntimeHints;
3950
import org.springframework.aot.hint.RuntimeHintsRegistrar;
4051
import org.springframework.beans.factory.DisposableBean;
52+
import org.springframework.beans.factory.ObjectProvider;
4153
import org.springframework.boot.autoconfigure.AutoConfiguration;
4254
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4355
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
4456
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
4557
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
46-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
4758
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4859
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4960
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
@@ -53,6 +64,7 @@
5364
import org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;
5465
import org.springframework.boot.ldap.autoconfigure.LdapProperties;
5566
import org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration.EmbeddedLdapAutoConfigurationRuntimeHints;
67+
import org.springframework.boot.ssl.SslBundle;
5668
import org.springframework.boot.ssl.SslBundles;
5769
import org.springframework.context.ApplicationContext;
5870
import org.springframework.context.ConfigurableApplicationContext;
@@ -67,9 +79,12 @@
6779
import org.springframework.core.env.MutablePropertySources;
6880
import org.springframework.core.env.PropertySource;
6981
import org.springframework.core.io.Resource;
82+
import org.springframework.core.io.ResourceLoader;
83+
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
7084
import org.springframework.core.type.AnnotatedTypeMetadata;
7185
import org.springframework.ldap.core.ContextSource;
7286
import org.springframework.ldap.core.support.LdapContextSource;
87+
import org.springframework.util.Assert;
7388
import org.springframework.util.StringUtils;
7489

7590
/**
@@ -91,14 +106,18 @@ public final class EmbeddedLdapAutoConfiguration implements DisposableBean {
91106

92107
private final EmbeddedLdapProperties embeddedProperties;
93108

109+
private final ResourceLoader resourceLoader = new PathMatchingResourcePatternResolver();
110+
94111
private @Nullable InMemoryDirectoryServer server;
95112

96113
EmbeddedLdapAutoConfiguration(EmbeddedLdapProperties embeddedProperties) {
97114
this.embeddedProperties = embeddedProperties;
98115
}
99116

100117
@Bean
101-
InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext) throws LDAPException {
118+
InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext, ObjectProvider<SslBundles> sslBundles)
119+
throws LDAPException, KeyStoreException, IOException,
120+
NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException {
102121
String[] baseDn = StringUtils.toStringArray(this.embeddedProperties.getBaseDn());
103122
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(baseDn);
104123
String username = this.embeddedProperties.getCredential().getUsername();
@@ -107,8 +126,13 @@ InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext) t
107126
config.addAdditionalBindCredentials(username, password);
108127
}
109128
setSchema(config);
110-
if (this.embeddedProperties.isLdaps()) {
111-
this.setLdapsListener(applicationContext, config);
129+
if (this.embeddedProperties.getSsl().isEnabled()) {
130+
EmbeddedLdapProperties.Ssl ssl = this.embeddedProperties.getSsl();
131+
SSLContext sslContext = getSslContext(ssl, sslBundles.getIfAvailable());
132+
SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();
133+
SSLSocketFactory clientSocketFactory = sslContext.getSocketFactory();
134+
config.setListenerConfigs(InMemoryListenerConfig.createLDAPSConfig("LDAPS", null,
135+
this.embeddedProperties.getPort(), serverSocketFactory, clientSocketFactory));
112136
}
113137
else {
114138
config
@@ -148,22 +172,6 @@ private void setSchema(InMemoryDirectoryServerConfig config, Resource resource)
148172
}
149173
}
150174

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-
167175
private void importLdif(InMemoryDirectoryServer server, ApplicationContext applicationContext) {
168176
String location = this.embeddedProperties.getLdif();
169177
if (StringUtils.hasText(location)) {
@@ -208,6 +216,71 @@ public void destroy() throws Exception {
208216
}
209217
}
210218

219+
private SSLContext getSslContext(EmbeddedLdapProperties.Ssl ssl, @Nullable SslBundles sslBundles)
220+
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
221+
UnrecoverableKeyException, KeyManagementException {
222+
if (sslBundles != null && StringUtils.hasText(ssl.getBundle())) {
223+
SslBundle sslBundle = sslBundles.getBundle(ssl.getBundle());
224+
Assert.notNull(sslBundle, "SSL bundle name has been set but no SSL bundles found in context");
225+
return sslBundle.createSslContext();
226+
227+
}
228+
else {
229+
Assert.notNull(ssl.getAlgorithm(), "SSL algorithm must be specified");
230+
SSLContext sslContext = SSLContext.getInstance(ssl.getAlgorithm());
231+
KeyManager[] keyManagers = configureKeyManagers(ssl);
232+
TrustManager[] trustManagers = configureTrustManagers(ssl);
233+
sslContext.init(keyManagers, trustManagers, new SecureRandom());
234+
return sslContext;
235+
}
236+
}
237+
238+
private KeyManager @Nullable [] configureKeyManagers(EmbeddedLdapProperties.Ssl ssl) throws KeyStoreException,
239+
IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
240+
String keyStoreName = ssl.getKeyStore();
241+
String keyStorePassword = ssl.getKeyStorePassword();
242+
String storeType = ssl.getKeyStoreType();
243+
char[] keyPassphrase = null;
244+
if (keyStorePassword != null) {
245+
keyPassphrase = keyStorePassword.toCharArray();
246+
}
247+
KeyManager[] keyManagers = null;
248+
if (StringUtils.hasText(keyStoreName)) {
249+
Resource resource = this.resourceLoader.getResource(keyStoreName);
250+
KeyStore ks = KeyStore.getInstance(storeType);
251+
try (InputStream inputStream = resource.getInputStream()) {
252+
ks.load(inputStream, keyPassphrase);
253+
}
254+
KeyManagerFactory kmf = KeyManagerFactory.getInstance(ssl.getKeyStoreAlgorithm());
255+
kmf.init(ks, keyPassphrase);
256+
keyManagers = kmf.getKeyManagers();
257+
}
258+
return keyManagers;
259+
}
260+
261+
private TrustManager @Nullable [] configureTrustManagers(EmbeddedLdapProperties.Ssl ssl)
262+
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
263+
String trustStoreName = ssl.getTrustStore();
264+
String trustStorePassword = ssl.getTrustStorePassword();
265+
String storeType = ssl.getTrustStoreType();
266+
char[] trustPassphrase = null;
267+
if (trustStorePassword != null) {
268+
trustPassphrase = trustStorePassword.toCharArray();
269+
}
270+
TrustManager[] trustManagers = null;
271+
if (StringUtils.hasText(trustStoreName)) {
272+
Resource resource = this.resourceLoader.getResource(trustStoreName);
273+
KeyStore tks = KeyStore.getInstance(storeType);
274+
try (InputStream inputStream = resource.getInputStream()) {
275+
tks.load(inputStream, trustPassphrase);
276+
}
277+
TrustManagerFactory tmf = TrustManagerFactory.getInstance(ssl.getTrustStoreAlgorithm());
278+
tmf.init(tks);
279+
trustManagers = tmf.getTrustManagers();
280+
}
281+
return trustManagers;
282+
}
283+
211284
/**
212285
* {@link SpringBootCondition} to determine when to apply embedded LDAP
213286
* auto-configuration.

0 commit comments

Comments
 (0)