-
Notifications
You must be signed in to change notification settings - Fork 41.7k
Add support for LDAPS testing #48315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't have any effect here as conditions only work on classes and |
||
| 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)) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
Comment on lines
+60
to
+68
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency with other SSL configuration in Spring Boot, the properties should be grouped together in an SSL inner-class. That class should have an |
||
|
|
||
| /** | ||
| * 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; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That doesn't test the SSL bundles, nor the binding. It doesn't work atm anyway (see previous comment). |
||
| List<String> 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) -> { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| -----BEGIN CERTIFICATE----- | ||
| MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL | ||
| BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI | ||
| Q2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55 | ||
| U2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MTExMjExNTha | ||
| Fw0zMzA5MDgxMjExNThaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h | ||
| bWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG | ||
| A1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi | ||
| MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfdkeEiCk+5mpXUhJ1FLmOCx6/ | ||
| jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dgpHqds/84pb+3 | ||
| OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1U6zk1iwrbiO3 | ||
| hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf4RhoE6krDdV1 | ||
| JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAPuwXHO5BNw504 | ||
| 3Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3TOhyA1ueXAgMB | ||
| AAGjUzBRMB0GA1UdDgQWBBRHYz8OjqU/4JZMegJaN/jQbdj4MjAfBgNVHSMEGDAW | ||
| gBRHYz8OjqU/4JZMegJaN/jQbdj4MjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 | ||
| DQEBCwUAA4IBAQBr9zqlNx7Mr1ordGfhk+xFrDtyBnk1vXbwVdnog66REqpPLH+K | ||
| MfCKdj6wFoPa8ZjPb4VYFp2DvMxVXtFMzqGfLjYJPqefEzQCleOcA5aiE/ENIaaD | ||
| ybYh99V5CsFAqyKuHLBFEzeYJ028SR3QsCISom0k/Fh6y2IwHJJEHykjqJKvL4bb | ||
| V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds | ||
| HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb | ||
| ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8 | ||
| -----END CERTIFICATE----- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| -----BEGIN PRIVATE KEY----- | ||
| MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfdkeEiCk+5mpX | ||
| UhJ1FLmOCx6/jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dg | ||
| pHqds/84pb+3OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1 | ||
| U6zk1iwrbiO3hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf | ||
| 4RhoE6krDdV1JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAP | ||
| uwXHO5BNw5043Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3T | ||
| OhyA1ueXAgMBAAECggEAPK1LqmULWMlhdoeeyVlQ//lAQn+6X4/MwycG/UsCSJC2 | ||
| BCV4nfgyv853UFRkM0jPBhDQ7h1wz1ohuWbs11xaBcqgKE7ywe3ZQULD5tqnO64y | ||
| BU8V2+rnO4gjpbdMHQLlxdgy5KHxtR3Q4+6Kj+rlFMOMqLWZSmke8na7H+SczzGf | ||
| +dZO4LRTbjGmFdUidehovm2icSM8OdU2w3FHlFRu2NBsTHGeAhRw86Yw24KfJp4R | ||
| GSDQIBdwp1wCs5w7w4zPjxS7Zi+Uwspyq31KDJwyfK2O1WLI05bQ6FLqVRD/xy+Y | ||
| b4WCse1O08SYWze2No915LB07sokgmomr3//bOwuEQKBgQDPBrPQXokn0BoTlgsa | ||
| JohgWzQ5P9u/2WY+u2SG/xgNEx0s+lk/AmAH80wsBJ68FV6z5Non7TzD7xCsf2HJ | ||
| 3cP/EHl2ngTctz/eqpCcS5UPZBHmay60q6WKIkH/3ml7c0UhlqSqS3EDVyEe05hk | ||
| msWAN+fV4ajVlhWgiUZRVdxMpwKBgQDFLyPBOEn6zLOHfkQWcibVf8s2LTe76R/S | ||
| 8Gk3jbk5mimR3vNm0L/rHqGwl75rOuFiFOHVkfuY9Dawaht0QnagjayT5hDqr6aD | ||
| s5Chyoy9qpXnfnqOgk6rQZqj+/ODkjqEkBdRCKWvCVnDIi3Au2kS3QIc4iTsGrBW | ||
| ygZdbxM7kQKBgEuzS7T5nHVuZtqaltytElkJgIMekqAIQpbVtuCWDplZT+XOdSvR | ||
| FoRRtpyx48kql0J4gDzxRrLui85Hld5WtQBjacax6V07tKMbA13jVVIXaWQz9RQj | ||
| X5ivBisljLSTZcfuaa/LfjuWdIntHWBMJ8PGrYNLzIytIKNfDtNW7gMpAoGAIRZQ | ||
| 5JpCZ7Azq9e3KyEKfSbNfZDG2mQ679Vhgm3ol87TjOOhai47FgP008IStMGTkja4 | ||
| 0nKFilvoVV/orXB9oWFEhSjEy+yff1gBO/TV+vmF3+tsOz+IXdpLTZr4eKpv4VCg | ||
| aPuPebiS9Fhm3wFTl1O4iAo2cdvknRuXR9RcoNECgYADksGk1lJGW5kMIMJ+6os+ | ||
| CJdGnJiX7XsnM0VzkagswnqDe03SqkJuFOmIp96eitxLT4EfB+585pYQRSy2fyJX | ||
| WR2AAnC7oqUcQFkgDt9WBZAazI6aLXYO+trRoGKuWynGM8mjetr5C75g0auj4lsN | ||
| rGiie2UnjshJ67FrG4kZoA== | ||
| -----END PRIVATE KEY----- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what this is but you can't add a condition on a private method. What's that supposed to do?