1616
1717package org .springframework .boot .ldap .autoconfigure .embedded ;
1818
19+ import java .io .IOException ;
1920import 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 ;
2028import java .util .Collections ;
2129import java .util .HashMap ;
2230import java .util .List ;
2331import java .util .Map ;
2432
33+ import javax .net .ssl .KeyManager ;
34+ import javax .net .ssl .KeyManagerFactory ;
35+ import javax .net .ssl .SSLContext ;
36+ import javax .net .ssl .SSLServerSocketFactory ;
37+ import javax .net .ssl .SSLSocketFactory ;
38+ import javax .net .ssl .TrustManager ;
39+ import javax .net .ssl .TrustManagerFactory ;
40+
2541import com .unboundid .ldap .listener .InMemoryDirectoryServer ;
2642import com .unboundid .ldap .listener .InMemoryDirectoryServerConfig ;
2743import com .unboundid .ldap .listener .InMemoryListenerConfig ;
3349import org .springframework .aot .hint .RuntimeHints ;
3450import org .springframework .aot .hint .RuntimeHintsRegistrar ;
3551import org .springframework .beans .factory .DisposableBean ;
52+ import org .springframework .beans .factory .ObjectProvider ;
3653import org .springframework .boot .autoconfigure .AutoConfiguration ;
3754import org .springframework .boot .autoconfigure .EnableAutoConfiguration ;
3855import org .springframework .boot .autoconfigure .condition .ConditionMessage ;
4764import org .springframework .boot .ldap .autoconfigure .LdapAutoConfiguration ;
4865import org .springframework .boot .ldap .autoconfigure .LdapProperties ;
4966import org .springframework .boot .ldap .autoconfigure .embedded .EmbeddedLdapAutoConfiguration .EmbeddedLdapAutoConfigurationRuntimeHints ;
67+ import org .springframework .boot .ssl .SslBundle ;
68+ import org .springframework .boot .ssl .SslBundles ;
5069import org .springframework .context .ApplicationContext ;
5170import org .springframework .context .ConfigurableApplicationContext ;
5271import org .springframework .context .annotation .Bean ;
6079import org .springframework .core .env .MutablePropertySources ;
6180import org .springframework .core .env .PropertySource ;
6281import org .springframework .core .io .Resource ;
82+ import org .springframework .core .io .ResourceLoader ;
83+ import org .springframework .core .io .support .PathMatchingResourcePatternResolver ;
6384import org .springframework .core .type .AnnotatedTypeMetadata ;
6485import org .springframework .ldap .core .ContextSource ;
6586import org .springframework .ldap .core .support .LdapContextSource ;
87+ import org .springframework .util .Assert ;
6688import org .springframework .util .StringUtils ;
6789
6890/**
@@ -84,14 +106,18 @@ public final class EmbeddedLdapAutoConfiguration implements DisposableBean {
84106
85107 private final EmbeddedLdapProperties embeddedProperties ;
86108
109+ private final ResourceLoader resourceLoader = new PathMatchingResourcePatternResolver ();
110+
87111 private @ Nullable InMemoryDirectoryServer server ;
88112
89113 EmbeddedLdapAutoConfiguration (EmbeddedLdapProperties embeddedProperties ) {
90114 this .embeddedProperties = embeddedProperties ;
91115 }
92116
93117 @ Bean
94- InMemoryDirectoryServer directoryServer (ApplicationContext applicationContext ) throws LDAPException {
118+ InMemoryDirectoryServer directoryServer (ApplicationContext applicationContext ,
119+ ObjectProvider <SslBundles > sslBundles ) throws LDAPException , KeyStoreException , IOException ,
120+ NoSuchAlgorithmException , CertificateException , UnrecoverableKeyException , KeyManagementException {
95121 String [] baseDn = StringUtils .toStringArray (this .embeddedProperties .getBaseDn ());
96122 InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig (baseDn );
97123 String username = this .embeddedProperties .getCredential ().getUsername ();
@@ -100,9 +126,18 @@ InMemoryDirectoryServer directoryServer(ApplicationContext applicationContext) t
100126 config .addAdditionalBindCredentials (username , password );
101127 }
102128 setSchema (config );
103- InMemoryListenerConfig listenerConfig = InMemoryListenerConfig .createLDAPConfig ("LDAP" ,
104- this .embeddedProperties .getPort ());
105- config .setListenerConfigs (listenerConfig );
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 ));
136+ }
137+ else {
138+ config
139+ .setListenerConfigs (InMemoryListenerConfig .createLDAPConfig ("LDAP" , this .embeddedProperties .getPort ()));
140+ }
106141 this .server = new InMemoryDirectoryServer (config );
107142 importLdif (this .server , applicationContext );
108143 this .server .startListening ();
@@ -181,6 +216,70 @@ public void destroy() throws Exception {
181216 }
182217 }
183218
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+ SSLContext sslContext = SSLContext .getInstance (ssl .getAlgorithm ());
230+ KeyManager [] keyManagers = configureKeyManagers (ssl );
231+ TrustManager [] trustManagers = configureTrustManagers (ssl );
232+ sslContext .init (keyManagers , trustManagers , new SecureRandom ());
233+ return sslContext ;
234+ }
235+ }
236+
237+ private KeyManager @ Nullable [] configureKeyManagers (EmbeddedLdapProperties .Ssl ssl ) throws KeyStoreException ,
238+ IOException , NoSuchAlgorithmException , CertificateException , UnrecoverableKeyException {
239+ String keyStoreName = ssl .getKeyStore ();
240+ String keyStorePassword = ssl .getKeyStorePassword ();
241+ String storeType = ssl .getKeyStoreType ();
242+ char [] keyPassphrase = null ;
243+ if (keyStorePassword != null ) {
244+ keyPassphrase = keyStorePassword .toCharArray ();
245+ }
246+ KeyManager [] keyManagers = null ;
247+ if (StringUtils .hasText (keyStoreName )) {
248+ Resource resource = this .resourceLoader .getResource (keyStoreName );
249+ KeyStore ks = KeyStore .getInstance (storeType );
250+ try (InputStream inputStream = resource .getInputStream ()) {
251+ ks .load (inputStream , keyPassphrase );
252+ }
253+ KeyManagerFactory kmf = KeyManagerFactory .getInstance (ssl .getKeyStoreAlgorithm ());
254+ kmf .init (ks , keyPassphrase );
255+ keyManagers = kmf .getKeyManagers ();
256+ }
257+ return keyManagers ;
258+ }
259+
260+ private TrustManager @ Nullable [] configureTrustManagers (EmbeddedLdapProperties .Ssl ssl )
261+ throws KeyStoreException , IOException , NoSuchAlgorithmException , CertificateException {
262+ String trustStoreName = ssl .getTrustStore ();
263+ String trustStorePassword = ssl .getTrustStorePassword ();
264+ String storeType = ssl .getTrustStoreType ();
265+ char [] trustPassphrase = null ;
266+ if (trustStorePassword != null ) {
267+ trustPassphrase = trustStorePassword .toCharArray ();
268+ }
269+ TrustManager [] trustManagers = null ;
270+ if (StringUtils .hasText (trustStoreName )) {
271+ Resource resource = this .resourceLoader .getResource (trustStoreName );
272+ KeyStore tks = KeyStore .getInstance (storeType );
273+ try (InputStream inputStream = resource .getInputStream ()) {
274+ tks .load (inputStream , trustPassphrase );
275+ }
276+ TrustManagerFactory tmf = TrustManagerFactory .getInstance (ssl .getTrustStoreAlgorithm ());
277+ tmf .init (tks );
278+ trustManagers = tmf .getTrustManagers ();
279+ }
280+ return trustManagers ;
281+ }
282+
184283 /**
185284 * {@link SpringBootCondition} to determine when to apply embedded LDAP
186285 * auto-configuration.
0 commit comments