Add support for multi baseDn

Update LDAP properties and auto-configuration to support multiple
base DN values.

See gh-11764
pull/11910/head
Eddú Meléndez 7 years ago committed by Phillip Webb
parent 44ad630de3
commit 270dc2cd72

@ -20,6 +20,7 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServer;
@ -33,7 +34,6 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
import org.springframework.boot.autoconfigure.ldap.LdapProperties; import org.springframework.boot.autoconfigure.ldap.LdapProperties;
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapProperties.Credential; import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapProperties.Credential;
@ -50,6 +50,7 @@ import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -64,7 +65,6 @@ import org.springframework.util.StringUtils;
@EnableConfigurationProperties({ LdapProperties.class, EmbeddedLdapProperties.class }) @EnableConfigurationProperties({ LdapProperties.class, EmbeddedLdapProperties.class })
@AutoConfigureBefore(LdapAutoConfiguration.class) @AutoConfigureBefore(LdapAutoConfiguration.class)
@ConditionalOnClass(InMemoryDirectoryServer.class) @ConditionalOnClass(InMemoryDirectoryServer.class)
@ConditionalOnProperty(prefix = "spring.ldap.embedded", name = "base-dn")
public class EmbeddedLdapAutoConfiguration { public class EmbeddedLdapAutoConfiguration {
private static final String PROPERTY_SOURCE_NAME = "ldap.ports"; private static final String PROPERTY_SOURCE_NAME = "ldap.ports";
@ -88,6 +88,11 @@ public class EmbeddedLdapAutoConfiguration {
this.environment = environment; this.environment = environment;
} }
@PostConstruct
public void validateBaseDns() {
Assert.notEmpty(this.embeddedProperties.getBaseDn(), "No baseDn found.");
}
@Bean @Bean
@DependsOn("directoryServer") @DependsOn("directoryServer")
@ConditionalOnMissingBean @ConditionalOnMissingBean

@ -40,9 +40,9 @@ public class EmbeddedLdapProperties {
private Credential credential = new Credential(); private Credential credential = new Credential();
/** /**
* The base DN. * List of base DN.
*/ */
private String baseDn; private String[] baseDn = new String[0];
/** /**
* Schema (LDIF) script resource reference. * Schema (LDIF) script resource reference.
@ -70,11 +70,11 @@ public class EmbeddedLdapProperties {
this.credential = credential; this.credential = credential;
} }
public String getBaseDn() { public String[] getBaseDn() {
return this.baseDn; return this.baseDn;
} }
public void setBaseDn(String baseDn) { public void setBaseDn(String[] baseDn) {
this.baseDn = baseDn; this.baseDn = baseDn;
} }

@ -50,8 +50,10 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testSetDefaultPort() { public void testSetDefaultPort() {
this.contextRunner.withPropertyValues("spring.ldap.embedded.port:1234", this.contextRunner
"spring.ldap.embedded.base-dn:dc=spring,dc=org").run(context -> { .withPropertyValues("spring.ldap.embedded.port:1234",
"spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
assertThat(server.getListenPort()).isEqualTo(1234); assertThat(server.getListenPort()).isEqualTo(1234);
@ -61,7 +63,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testRandomPortWithEnvironment() { public void testRandomPortWithEnvironment() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org") .withPropertyValues("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> { .run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
@ -73,7 +75,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testRandomPortWithValueAnnotation() { public void testRandomPortWithValueAnnotation() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
TestPropertyValues.of("spring.ldap.embedded.base-dn:dc=spring,dc=org") TestPropertyValues.of("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.applyTo(context); .applyTo(context);
context.register(EmbeddedLdapAutoConfiguration.class, context.register(EmbeddedLdapAutoConfiguration.class,
LdapClientConfiguration.class, LdapClientConfiguration.class,
@ -87,7 +89,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testSetCredentials() { public void testSetCredentials() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org", .withPropertyValues("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org",
"spring.ldap.embedded.credential.username:uid=root", "spring.ldap.embedded.credential.username:uid=root",
"spring.ldap.embedded.credential.password:boot") "spring.ldap.embedded.credential.password:boot")
.run(context -> { .run(context -> {
@ -101,7 +103,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testSetPartitionSuffix() { public void testSetPartitionSuffix() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org") .withPropertyValues("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> { .run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
@ -113,7 +115,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testSetLdifFile() { public void testSetLdifFile() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org") .withPropertyValues("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> { .run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
@ -126,7 +128,7 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testQueryEmbeddedLdap() { public void testQueryEmbeddedLdap() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org") .withPropertyValues("spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class,
LdapDataAutoConfiguration.class)) LdapDataAutoConfiguration.class))
.run(context -> { .run(context -> {
@ -142,7 +144,7 @@ public class EmbeddedLdapAutoConfigurationTests {
public void testDisableSchemaValidation() { public void testDisableSchemaValidation() {
this.contextRunner this.contextRunner
.withPropertyValues("spring.ldap.embedded.validation.enabled:false", .withPropertyValues("spring.ldap.embedded.validation.enabled:false",
"spring.ldap.embedded.base-dn:dc=spring,dc=org") "spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> { .run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
@ -152,10 +154,12 @@ public class EmbeddedLdapAutoConfigurationTests {
@Test @Test
public void testCustomSchemaValidation() { public void testCustomSchemaValidation() {
this.contextRunner.withPropertyValues( this.contextRunner
"spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif", .withPropertyValues(
"spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif", "spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif",
"spring.ldap.embedded.base-dn:dc=spring,dc=org").run(context -> { "spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif",
"spring.ldap.embedded.base-dn[0]:dc=spring,dc=org")
.run(context -> {
InMemoryDirectoryServer server = context InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class); .getBean(InMemoryDirectoryServer.class);
@ -167,6 +171,24 @@ public class EmbeddedLdapAutoConfigurationTests {
}); });
} }
@Test
public void testMultiBaseDn() {
this.contextRunner
.withPropertyValues(
"spring.ldap.embedded.ldif:classpath:schema-multi-basedn.ldif",
"spring.ldap.embedded.base-dn[0]:dc=spring,dc=org",
"spring.ldap.embedded.base-dn[1]:dc=pivotal,dc=io")
.run(context -> {
InMemoryDirectoryServer server = context
.getBean(InMemoryDirectoryServer.class);
assertThat(server
.countEntriesBelow("ou=company1,c=Sweden,dc=spring,dc=org"))
.isEqualTo(5);
assertThat(server.countEntriesBelow("c=Sweden,dc=pivotal,dc=io"))
.isEqualTo(2);
});
}
@Configuration @Configuration
static class LdapClientConfiguration { static class LdapClientConfiguration {

@ -0,0 +1,114 @@
dn: dc=spring,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: spring
dn: ou=groups,dc=spring,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups
dn: cn=ROLE_USER,ou=groups,dc=spring,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: ROLE_USER
uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org
uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org
uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org
uniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org
dn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: ROLE_ADMIN
uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org
dn: c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: country
c: Sweden
description: The country of Sweden
dn: ou=company1,c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: organizationalUnit
ou: company1
description: First company in Sweden
dn: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person
userPassword: password
cn: Some Person
sn: Person
description: Sweden, Company1, Some Person
telephoneNumber: +46 555-123456
dn: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person2
userPassword: password
cn: Some Person2
sn: Person2
description: Sweden, Company1, Some Person2
telephoneNumber: +46 555-654321
dn: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person3
userPassword: password
cn: Some Person3
sn: Person3
description: Sweden, Company1, Some Person3
telephoneNumber: +46 555-123654
dn: cn=Some Person4,ou=company1,c=Sweden,dc=spring,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person4
userPassword: password
cn: Some Person
sn: Person
description: Sweden, Company1, Some Person
telephoneNumber: +46 555-456321
dn: dc=pivotal,dc=io
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: pivotal
dn: ou=groups,dc=pivotal,dc=io
objectclass: top
objectclass: organizationalUnit
ou: groups
dn: c=Sweden,dc=pivotal,dc=io
objectclass: top
objectclass: country
c: Sweden
description:The country of Sweden
dn: cn=Some Random Person,c=Sweden,dc=pivotal,dc=io
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.random.person
userPassword: password
cn: Some Random Person
sn: Person
description: Sweden, Pivotal, Some Random Person
telephoneNumber: +46 555-123456

@ -4417,6 +4417,8 @@ follows:
spring.ldap.embedded.base-dn=dc=spring,dc=io spring.ldap.embedded.base-dn=dc=spring,dc=io
---- ----
WARNING: `spring.ldap.embedded.base-dn` supports multi base DN, so it must define as follows `spring.ldap.embedded.base-dn[0]=dc=spring,dc=io`
By default, the server starts on a random port and triggers the regular LDAP support. By default, the server starts on a random port and triggers the regular LDAP support.
There is no need to specify a `spring.ldap.urls` property. There is no need to specify a `spring.ldap.urls` property.

Loading…
Cancel
Save