diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index eccdc98acfa1..e55696c6c466 100755
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -220,6 +220,11 @@
sendgrid-java
true
+
+ com.unboundid
+ unboundid-ldapsdk
+ true
+
com.zaxxer
HikariCP-java6
@@ -368,6 +373,11 @@
spring-data-cassandra
true
+
+ org.springframework.data
+ spring-data-ldap
+ true
+
org.springframework.data
spring-data-mongodb
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java
new file mode 100644
index 000000000000..9957ef26032d
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap;
+
+import javax.naming.ldap.LdapContext;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.ldap.repository.LdapRepository;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.LdapOperations;
+import org.springframework.ldap.core.LdapTemplate;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's LDAP support.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@Configuration
+@ConditionalOnClass({ LdapContext.class, LdapRepository.class })
+@AutoConfigureAfter(LdapAutoConfiguration.class)
+public class LdapDataAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(LdapOperations.class)
+ public LdapTemplate ldapTemplate(ContextSource contextSource) {
+ return new LdapTemplate(contextSource);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java
new file mode 100644
index 000000000000..121e719a509d
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap;
+
+import javax.naming.ldap.LdapContext;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.ldap.repository.LdapRepository;
+import org.springframework.data.ldap.repository.support.LdapRepositoryFactoryBean;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase
+ * Repositories.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@Configuration
+@ConditionalOnClass({ LdapContext.class, LdapRepository.class })
+@ConditionalOnProperty(prefix = "spring.data.ldap.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
+@ConditionalOnMissingBean(LdapRepositoryFactoryBean.class)
+@Import(LdapRepositoriesRegistrar.class)
+public class LdapRepositoriesAutoConfiguration {
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java
new file mode 100644
index 000000000000..8070beb9d1d0
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesRegistrar.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap;
+
+import java.lang.annotation.Annotation;
+
+import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
+import org.springframework.data.ldap.repository.config.LdapRepositoryConfigurationExtension;
+import org.springframework.data.repository.config.RepositoryConfigurationExtension;
+
+/**
+ * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data LDAP
+ * Repositories.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+class LdapRepositoriesRegistrar
+ extends AbstractRepositoryConfigurationSourceSupport {
+
+ @Override
+ protected Class extends Annotation> getAnnotation() {
+ return EnableLdapRepositories.class;
+ }
+
+ @Override
+ protected Class> getConfiguration() {
+ return EnableLdapRepositoriesConfiguration.class;
+ }
+
+ @Override
+ protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
+ return new LdapRepositoryConfigurationExtension();
+ }
+
+ @EnableLdapRepositories
+ private static class EnableLdapRepositoriesConfiguration {
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java
new file mode 100644
index 000000000000..aac37e601c8e
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Auto-configuration for Spring Data LDAP.
+ */
+package org.springframework.boot.autoconfigure.data.ldap;
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java
new file mode 100644
index 000000000000..7e5e9447ed03
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap;
+
+import java.util.Collections;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.support.LdapContextSource;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for LDAP.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@Configuration
+@ConditionalOnClass(ContextSource.class)
+@EnableConfigurationProperties(LdapProperties.class)
+public class LdapAutoConfiguration {
+
+ private LdapProperties properties;
+
+ private Environment environment;
+
+ public LdapAutoConfiguration(LdapProperties properties,
+ Environment environment) {
+ this.properties = properties;
+ this.environment = environment;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ContextSource contextSource() {
+ LdapContextSource contextSource = new LdapContextSource();
+ contextSource.setUserDn(this.properties.getUsername());
+ contextSource.setPassword(this.properties.getPassword());
+ contextSource.setBase(this.properties.getBase());
+ contextSource.setUrls(this.properties.determineUrls(this.environment));
+ contextSource.setBaseEnvironmentProperties(Collections
+ .unmodifiableMap(this.properties.getBaseEnvironment()));
+ return contextSource;
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java
new file mode 100644
index 000000000000..018adc9f30f2
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapProperties.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.LdapTemplate;
+/**
+ * Configuration properties to configure {@link LdapTemplate}.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@ConfigurationProperties(prefix = "spring.ldap")
+public class LdapProperties {
+
+ private static final int DEFAULT_PORT = 389;
+
+ /**
+ * LDAP urls.
+ */
+ private String[] urls = new String[0];
+
+ /**
+ * Base suffix from which all operations should originate.
+ */
+ private String base;
+
+ /**
+ * Login user of the LDAP.
+ */
+ private String username;
+
+ /**
+ * Login password of the LDAP.
+ */
+ private String password;
+
+ /**
+ * LDAP custom environment properties.
+ */
+ private Map baseEnvironment = new HashMap();
+
+ public String[] getUrls() {
+ return this.urls;
+ }
+
+ public void setUrls(String[] urls) {
+ this.urls = urls;
+ }
+
+ public String getBase() {
+ return this.base;
+ }
+
+ public void setBase(String base) {
+ this.base = base;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return this.password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Map getBaseEnvironment() {
+ return this.baseEnvironment;
+ }
+
+ public void setBaseEnvironment(Map baseEnvironment) {
+ this.baseEnvironment = baseEnvironment;
+ }
+
+ public String[] determineUrls(Environment environment) {
+ if (this.urls.length == 0) {
+ String protocol = "ldap://";
+ String host = "localhost";
+ int port = determinePort(environment);
+ String[] ldapUrls = new String[1];
+ ldapUrls[0] = protocol + host + ":" + port;
+ return ldapUrls;
+ }
+ return this.urls;
+ }
+
+ private int determinePort(Environment environment) {
+ if (environment != null) {
+ String localPort = environment.getProperty("local.ldap.port");
+ if (localPort != null) {
+ return Integer.valueOf(localPort);
+ }
+ else {
+ return DEFAULT_PORT;
+ }
+ }
+ throw new IllegalStateException(
+ "No local ldap port configuration is available");
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java
new file mode 100644
index 000000000000..a3c4e55acfa2
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap.embedded;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+
+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.ldif.LDIFReader;
+import org.apache.commons.io.IOUtils;
+
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.boot.autoconfigure.ldap.LdapProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.Resource;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.support.LdapContextSource;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Embedded LDAP.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@Configuration
+@EnableConfigurationProperties({ LdapProperties.class, EmbeddedLdapProperties.class })
+@AutoConfigureBefore(LdapAutoConfiguration.class)
+@ConditionalOnClass(InMemoryDirectoryServer.class)
+public class EmbeddedLdapAutoConfiguration {
+
+ private InMemoryDirectoryServer server;
+
+ private EmbeddedLdapProperties embeddedProperties;
+
+ private LdapProperties properties;
+
+ private ConfigurableApplicationContext applicationContext;
+
+ private Environment environment;
+
+ public EmbeddedLdapAutoConfiguration(EmbeddedLdapProperties embeddedProperties,
+ LdapProperties properties,
+ ConfigurableApplicationContext applicationContext,
+ Environment environment) {
+ this.embeddedProperties = embeddedProperties;
+ this.properties = properties;
+ this.applicationContext = applicationContext;
+ this.environment = environment;
+ }
+
+ @Bean
+ @DependsOn("directoryServer")
+ @ConditionalOnMissingBean
+ public ContextSource contextSource() {
+ LdapContextSource contextSource = new LdapContextSource();
+
+ EmbeddedLdapProperties.Credential credential = this.embeddedProperties
+ .getCredential();
+ if (StringUtils.hasText(credential.getUsername()) &&
+ StringUtils.hasText(credential.getPassword())) {
+ contextSource.setUserDn(credential.getUsername());
+ contextSource.setPassword(credential.getPassword());
+ }
+ contextSource.setUrls(this.properties.determineUrls(this.environment));
+ return contextSource;
+ }
+
+ @Bean
+ public InMemoryDirectoryServer directoryServer() throws LDAPException {
+ InMemoryDirectoryServerConfig config =
+ new InMemoryDirectoryServerConfig(this.embeddedProperties
+ .getPartitionSuffix());
+
+ EmbeddedLdapProperties.Credential credential = this.embeddedProperties
+ .getCredential();
+ if (StringUtils.hasText(credential.getUsername()) &&
+ StringUtils.hasText(credential.getPassword())) {
+ config.addAdditionalBindCredentials(credential
+ .getUsername(), credential.getPassword());
+ }
+
+ config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP",
+ this.embeddedProperties.getPort()));
+
+ this.server = new InMemoryDirectoryServer(config);
+
+ populateDirectoryServer();
+
+ this.server.startListening();
+ publishPortInfo(this.server.getListenPort());
+ return this.server;
+ }
+
+ private void publishPortInfo(int port) {
+ setPortProperty(this.applicationContext, port);
+ }
+
+ private void setPortProperty(ApplicationContext currentContext,
+ int port) {
+ if (currentContext instanceof ConfigurableApplicationContext) {
+ MutablePropertySources sources = ((ConfigurableApplicationContext)
+ currentContext).getEnvironment().getPropertySources();
+ getLdapPorts(sources).put("local.ldap.port", port);
+ }
+ if (currentContext.getParent() != null) {
+ setPortProperty(currentContext.getParent(), port);
+ }
+ }
+
+ private Map getLdapPorts(MutablePropertySources sources) {
+ PropertySource> propertySource = sources.get("ldap.ports");
+ if (propertySource == null) {
+ propertySource = new MapPropertySource("ldap.ports",
+ new HashMap());
+ sources.addFirst(propertySource);
+ }
+ return (Map) propertySource.getSource();
+ }
+
+ private void populateDirectoryServer() throws LDAPException {
+ String location = this.embeddedProperties.getLdif();
+ if (StringUtils.hasText(location)) {
+ try {
+ Resource resource = this.applicationContext.getResource(
+ this.embeddedProperties.getLdif());
+ if (resource.exists()) {
+ File tempFile = File.createTempFile("ldap_test_data", ".ldif");
+ try {
+ InputStream inputStream = resource.getInputStream();
+ IOUtils.copy(inputStream, new FileOutputStream(tempFile));
+ this.server.importFromLDIF(true, new LDIFReader(tempFile));
+ }
+ catch (LDAPException e) {
+ e.printStackTrace();
+ }
+ finally {
+ tempFile.delete();
+ }
+ }
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(
+ "Unable to load resource from " + location, ex);
+ }
+ }
+ }
+
+ @PreDestroy
+ public void close() {
+ if (this.server != null) {
+ this.server.shutDown(true);
+ }
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java
new file mode 100644
index 000000000000..0729b03f9cc3
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapProperties.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap.embedded;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for Embedded LDAP.
+ *
+ * @author Eddú Meléndez
+ * @since 1.5.0
+ */
+@ConfigurationProperties(prefix = "spring.ldap.embedded")
+public class EmbeddedLdapProperties {
+
+ /**
+ * Embedded LDAP port.
+ */
+ private int port = 0;
+
+ /**
+ * Embedded LDAP credentials.
+ */
+ private Credential credential = new Credential();
+
+ /**
+ * LDAP partition suffix.
+ */
+ private String partitionSuffix;
+
+ /**
+ * Schema (LDIF) script resource reference.
+ */
+ private String ldif;
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public Credential getCredential() {
+ return this.credential;
+ }
+
+ public void setCredential(Credential credential) {
+ this.credential = credential;
+ }
+
+ public String getPartitionSuffix() {
+ return this.partitionSuffix;
+ }
+
+ public void setPartitionSuffix(String partitionSuffix) {
+ this.partitionSuffix = partitionSuffix;
+ }
+
+ public String getLdif() {
+ return this.ldif;
+ }
+
+ public void setLdif(String ldif) {
+ this.ldif = ldif;
+ }
+
+ static class Credential {
+
+ /**
+ * Embedded LDAP username.
+ */
+ private String username;
+
+ /**
+ * Embedded LDAP password.
+ */
+ private String password;
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return this.password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java
new file mode 100644
index 000000000000..11f9a8a5c4ad
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Auto-configuration for LDAP.
+ */
+package org.springframework.boot.autoconfigure.ldap;
diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index d7d1e0bdf3ce..47120cc19898 100644
--- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -29,6 +29,8 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfi
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
+org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
+org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
@@ -63,6 +65,8 @@ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfigu
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
+org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
+org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java
new file mode 100644
index 000000000000..cffe65943f67
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/ldap/PersonLdapRepository.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.alt.ldap;
+
+import javax.naming.Name;
+
+import org.springframework.boot.autoconfigure.data.ldap.person.Person;
+import org.springframework.data.repository.Repository;
+
+public interface PersonLdapRepository extends Repository {
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java
new file mode 100644
index 000000000000..c907ae0a68da
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap;
+
+import org.junit.After;
+import org.junit.Test;
+
+import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.boot.test.util.EnvironmentTestUtils;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.ldap.core.LdapTemplate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link LdapDataAutoConfiguration}
+ *
+ * @author Eddú Meléndez
+ */
+public class LdapDataAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @After
+ public void close() {
+ this.context.close();
+ }
+
+ @Test
+ public void templateExists() {
+ this.context = new AnnotationConfigApplicationContext();
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "spring.ldap.urls:ldap://localhost:389");
+ this.context.register(PropertyPlaceholderAutoConfiguration.class,
+ LdapAutoConfiguration.class, LdapDataAutoConfiguration.class);
+ this.context.refresh();
+ assertThat(this.context.getBeanNamesForType(LdapTemplate.class).length)
+ .isEqualTo(1);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java
new file mode 100644
index 000000000000..27be0268c348
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap;
+
+import org.junit.After;
+import org.junit.Test;
+
+import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
+import org.springframework.boot.autoconfigure.data.alt.ldap.PersonLdapRepository;
+import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
+import org.springframework.boot.autoconfigure.data.ldap.person.Person;
+import org.springframework.boot.autoconfigure.data.ldap.person.PersonRepository;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.boot.test.util.EnvironmentTestUtils;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link LdapRepositoriesAutoConfiguration}
+ *
+ * @author Eddú Meléndez
+ */
+public class LdapRepositoriesAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @After
+ public void close() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void testDefaultRepositoryConfiguration() throws Exception {
+ load(TestConfiguration.class);
+
+ assertThat(this.context.getBean(PersonRepository.class)).isNotNull();
+ }
+
+ @Test
+ public void testNoRepositoryConfiguration() throws Exception {
+ load(EmptyConfiguration.class);
+
+ assertThat(this.context.getBeanNamesForType(PersonRepository.class).length)
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
+ load(CustomizedConfiguration.class);
+ assertThat(this.context.getBean(PersonLdapRepository.class)).isNotNull();
+ }
+
+ private void load(Class>... configurationClasses) {
+ this.context = new AnnotationConfigApplicationContext();
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "spring.ldap.urls:ldap://localhost:389");
+ this.context.register(configurationClasses);
+ this.context.register(LdapAutoConfiguration.class,
+ LdapDataAutoConfiguration.class,
+ LdapRepositoriesAutoConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class);
+ this.context.refresh();
+ }
+
+ @Configuration
+ @TestAutoConfigurationPackage(Person.class)
+ protected static class TestConfiguration {
+
+ }
+
+ @Configuration
+ @TestAutoConfigurationPackage(EmptyDataPackage.class)
+ protected static class EmptyConfiguration {
+
+ }
+
+ @Configuration
+ @TestAutoConfigurationPackage(LdapRepositoriesAutoConfigurationTests.class)
+ @EnableLdapRepositories(basePackageClasses = PersonLdapRepository.class)
+ protected static class CustomizedConfiguration {
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java
new file mode 100644
index 000000000000..52e4b7bcb4d7
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/Person.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap.person;
+
+import javax.naming.Name;
+
+import org.springframework.ldap.odm.annotations.Attribute;
+import org.springframework.ldap.odm.annotations.DnAttribute;
+import org.springframework.ldap.odm.annotations.Entry;
+import org.springframework.ldap.odm.annotations.Id;
+
+@Entry(objectClasses = {"person", "top"}, base = "ou=someOu")
+public class Person {
+
+ @Id
+ private Name dn;
+
+ @Attribute(name = "cn")
+ @DnAttribute(value = "cn", index = 1)
+ private String fullName;
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java
new file mode 100644
index 000000000000..4f0714ac01c1
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/person/PersonRepository.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.data.ldap.person;
+
+import javax.naming.Name;
+
+import org.springframework.data.repository.Repository;
+
+public interface PersonRepository extends Repository {
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java
new file mode 100644
index 000000000000..2f8653e4d0b0
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.test.util.EnvironmentTestUtils;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link LdapAutoConfiguration}.
+ *
+ * @author Eddú Meléndez
+ */
+public class LdapAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @Before
+ public void setup() {
+ this.context = new AnnotationConfigApplicationContext();
+ }
+
+ @After
+ public void close() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void testDefaultUrl() {
+ load();
+ assertThat(this.context.getBeanNamesForType(ContextSource.class).length)
+ .isEqualTo(1);
+ assertThat(ReflectionTestUtils.getField(this.context.getBean(ContextSource.class),
+ "urls")).isEqualTo(new String[]{"ldap://localhost:389"});
+ }
+
+ @Test
+ public void testContextSourceSetOneUrl() {
+ load("spring.ldap.urls:ldap://localhost:123");
+ assertThat(this.context.getBeanNamesForType(ContextSource.class).length)
+ .isEqualTo(1);
+ assertThat(ReflectionTestUtils.getField(this.context.getBean(ContextSource.class),
+ "urls")).isEqualTo(new String[]{"ldap://localhost:123"});
+ }
+
+ @Test
+ public void testContextSourceSetTwoUrls() {
+ load("spring.ldap.urls:ldap://localhost:123,ldap://mycompany:123");
+ assertThat(this.context.getBeanNamesForType(ContextSource.class).length)
+ .isEqualTo(1);
+ assertThat(this.context.getBean(LdapProperties.class).getUrls().length)
+ .isEqualTo(2);
+ assertThat(ReflectionTestUtils.getField(this.context.getBean(ContextSource.class),
+ "urls"))
+ .isEqualTo(new String[]{"ldap://localhost:123", "ldap://mycompany:123"});
+ }
+
+ @Test
+ public void testContextSourceWithMoreProperties() {
+ load("spring.ldap.urls:ldap://localhost:123",
+ "spring.ldap.username:root",
+ "spring.ldap.password:root",
+ "spring.ldap.base:cn=SpringDevelopers",
+ "spring.ldap.baseEnvironment.java.naming.security" +
+ ".authentication:DIGEST-MD5");
+ assertThat(this.context.getBeanNamesForType(ContextSource.class).length)
+ .isEqualTo(1);
+ assertThat(this.context.getBean(LdapProperties.class).getBaseEnvironment())
+ .containsEntry("java.naming.security.authentication", "DIGEST-MD5");
+ }
+
+ private void load(String... properties) {
+ EnvironmentTestUtils.addEnvironment(this.context, properties);
+ this.context
+ .register(LdapAutoConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class);
+ this.context.refresh();
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java
new file mode 100644
index 000000000000..3cb6c0074343
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.autoconfigure.ldap.embedded;
+
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.sdk.BindResult;
+import com.unboundid.ldap.sdk.DN;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.boot.test.util.EnvironmentTestUtils;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.ldap.core.LdapTemplate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link EmbeddedLdapAutoConfiguration}
+ *
+ * @author Eddú Meléndez
+ */
+public class EmbeddedLdapAutoConfigurationTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @Before
+ public void setup() {
+ this.context = new AnnotationConfigApplicationContext();
+ }
+
+ @After
+ public void close() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void testSetDefaultPort() throws LDAPException {
+ load("spring.ldap.embedded.port:1234",
+ "spring.ldap.embedded.partitionSuffix:dc=spring,dc=org");
+ InMemoryDirectoryServer server = this.context
+ .getBean(InMemoryDirectoryServer.class);
+ assertThat(server.getListenPort()).isEqualTo(1234);
+ }
+
+ @Test
+ public void testRandomPortWithEnvironment() throws LDAPException {
+ load("spring.ldap.embedded.partitionSuffix:dc=spring,dc=org");
+ InMemoryDirectoryServer server = this.context
+ .getBean(InMemoryDirectoryServer.class);
+ assertThat(server.getListenPort()).isEqualTo(this.context.getEnvironment()
+ .getProperty("local.ldap.port", Integer.class));
+ }
+
+ @Test
+ public void testRandomPortWithValueAnnotation() throws LDAPException {
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "spring.ldap.embedded.partitionSuffix:dc=spring,dc=org");
+ this.context.register(EmbeddedLdapAutoConfiguration.class,
+ LdapClientConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class);
+ this.context.refresh();
+ LDAPConnection connection = this.context
+ .getBean(LDAPConnection.class);
+ assertThat(connection.getConnectedPort())
+ .isEqualTo(this.context.getEnvironment()
+ .getProperty("local.ldap.port", Integer.class));
+ }
+
+ @Test
+ public void testSetCredentials() throws LDAPException {
+ load("spring.ldap.embedded.partitionSuffix:dc=spring,dc=org",
+ "spring.ldap.embedded.credential.username:uid=root",
+ "spring.ldap.embedded.credential.password:boot");
+ InMemoryDirectoryServer server = this.context
+ .getBean(InMemoryDirectoryServer.class);
+ BindResult result = server.bind("uid=root", "boot");
+ assertThat(result).isNotNull();
+ }
+
+ @Test
+ public void testSetPartitionSuffix() throws LDAPException {
+ load("spring.ldap.embedded.partitionSuffix:dc=spring,dc=org");
+ InMemoryDirectoryServer server = this.context
+ .getBean(InMemoryDirectoryServer.class);
+ assertThat(server.getBaseDNs()).containsExactly(new DN("dc=spring,dc=org"));
+ }
+
+ @Test
+ public void testSetLdifFile() throws LDAPException {
+ load("spring.ldap.embedded.partitionSuffix:dc=spring,dc=org",
+ "spring.ldap.embedded.ldif:classpath:schema.ldif");
+ InMemoryDirectoryServer server = this.context
+ .getBean(InMemoryDirectoryServer.class);
+ assertThat(server.countEntriesBelow("ou=company1,c=Sweden,dc=spring,dc=org"))
+ .isEqualTo(5);
+ }
+ @Test
+ public void testQueryEmbeddedLdap() throws LDAPException {
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "spring.ldap.embedded.partitionSuffix:dc=spring,dc=org",
+ "spring.ldap.embedded.ldif:classpath:schema.ldif");
+ this.context.register(EmbeddedLdapAutoConfiguration.class,
+ LdapAutoConfiguration.class,
+ LdapDataAutoConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class);
+ this.context.refresh();
+ assertThat(this.context.getBeanNamesForType(LdapTemplate.class).length)
+ .isEqualTo(1);
+ LdapTemplate ldapTemplate = this.context
+ .getBean(LdapTemplate.class);
+ assertThat(ldapTemplate.list("ou=company1,c=Sweden,dc=spring,dc=org").size())
+ .isEqualTo(4);
+ }
+
+ private void load(String... properties) {
+ EnvironmentTestUtils.addEnvironment(this.context, properties);
+ this.context.register(EmbeddedLdapAutoConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class);
+ this.context.refresh();
+ }
+
+ @Configuration
+ static class LdapClientConfiguration {
+
+ @Bean
+ public LDAPConnection ldapConnection(@Value("${local.ldap.port}") int port)
+ throws LDAPException {
+ LDAPConnection con = new LDAPConnection();
+ con.connect("localhost", port);
+ return con;
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/resources/schema.ldif b/spring-boot-autoconfigure/src/test/resources/schema.ldif
new file mode 100644
index 000000000000..df76aace51f9
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/resources/schema.ldif
@@ -0,0 +1,85 @@
+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
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index ff817aed1ad0..7f828a13ed79 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -185,6 +185,7 @@
2.1.0.RELEASE
8.5.6
1.4.8.Final
+ 3.2.0
9f96c74
0.32
1.6.3
@@ -813,6 +814,11 @@
java-statsd-client
${statsd-client.version}
+
+ com.unboundid
+ unboundid-ldapsdk
+ ${unboundid-ldapsdk.version}
+
com.zaxxer
HikariCP
diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index 0c6cf193c3d3..5eb9b7cfdaba 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -315,6 +315,20 @@ content into your application; rather pick only the properties that you need.
spring.jersey.servlet.load-on-startup=-1 # Load on startup priority of the Jersey servlet.
spring.jersey.type=servlet # Jersey integration type.
+ # EMBEDDED LDAP ({sc-spring-boot-autoconfigure}/ldap/embedded/EmbeddedLdapProperties.{sc-ext}[EmbeddedLdapProperties])
+ spring.ldap.embedded.port= # Embedded LDAP port.
+ spring.ldap.embedded.credential.username= # Embedded LDAP username.
+ spring.ldap.embedded.credential.password= # Embedded LDAP password.
+ spring.ldap.embedded.partition-suffix= # LDAP partition suffix.
+ spring.ldap.embedded.ldif= # Schema (LDIF) script resource reference.
+
+ # SPRING LDAP ({sc-spring-boot-autoconfigure}/ldap/LdapProperties.{sc-ext}[LdapProperties])
+ spring.ldap.urls= # LDAP url of the server.
+ spring.ldap.base= # Base suffix from which all operations should originate.
+ spring.ldap.username= # Login user of the server.
+ spring.ldap.password= # Login password of the server.
+ spring.ldap.base-environment.*= # Ldap specification settings.
+
# SPRING MOBILE DEVICE VIEWS ({sc-spring-boot-autoconfigure}/mobile/DeviceDelegatingViewResolverAutoConfiguration.{sc-ext}[DeviceDelegatingViewResolverAutoConfiguration])
spring.mobile.devicedelegatingviewresolver.enable-fallback=false # Enable support for fallback resolution.
spring.mobile.devicedelegatingviewresolver.enabled=false # Enable device view resolver.
diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml
index 9f10942f9fef..de0caf415a92 100644
--- a/spring-boot-starters/pom.xml
+++ b/spring-boot-starters/pom.xml
@@ -33,6 +33,7 @@
spring-boot-starter-data-elasticsearch
spring-boot-starter-data-gemfire
spring-boot-starter-data-jpa
+ spring-boot-starter-data-ldap
spring-boot-starter-data-mongodb
spring-boot-starter-data-neo4j
spring-boot-starter-data-redis
diff --git a/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml b/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml
new file mode 100644
index 000000000000..0f1d8e079d03
--- /dev/null
+++ b/spring-boot-starters/spring-boot-starter-data-ldap/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ spring-boot-starters
+ org.springframework.boot
+ 1.5.0.BUILD-SNAPSHOT
+
+ spring-boot-starter-data-ldap
+ Spring Boot Data LDAP Starter
+ Starter for using Spring Data LDAP
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.data
+ spring-data-ldap
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides b/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides
new file mode 100644
index 000000000000..510e85a80c14
--- /dev/null
+++ b/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides
@@ -0,0 +1 @@
+provides: spring-ldap-core
\ No newline at end of file