Add support for multi baseDn
Update LDAP properties and auto-configuration to support multiple base DN values. See gh-11764
This commit is contained in:
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
|
||||||
|
.withPropertyValues(
|
||||||
"spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif",
|
"spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif",
|
||||||
"spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif",
|
"spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif",
|
||||||
"spring.ldap.embedded.base-dn:dc=spring,dc=org").run(context -> {
|
"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…
Reference in New Issue