diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml
index bcb23ce313..3204b8fc08 100644
--- a/spring-boot-actuator/pom.xml
+++ b/spring-boot-actuator/pom.xml
@@ -166,6 +166,11 @@
spring-data-couchbase
true
+
+ org.springframework.data
+ spring-data-ldap
+ true
+
org.springframework.data
spring-data-mongodb
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
index e838233479..de30335deb 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2016 the original author or authors.
+ * 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.
@@ -39,6 +39,7 @@ import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorPropertie
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
+import org.springframework.boot.actuate.health.LdapHealthIndicator;
import org.springframework.boot.actuate.health.MailHealthIndicator;
import org.springframework.boot.actuate.health.MongoHealthIndicator;
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
@@ -56,6 +57,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration;
@@ -77,6 +79,7 @@ import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+import org.springframework.ldap.core.LdapOperations;
import org.springframework.mail.javamail.JavaMailSenderImpl;
/**
@@ -96,9 +99,10 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
CassandraDataAutoConfiguration.class, CouchbaseDataAutoConfiguration.class,
DataSourceAutoConfiguration.class, ElasticsearchAutoConfiguration.class,
JestAutoConfiguration.class, JmsAutoConfiguration.class,
- MailSenderAutoConfiguration.class, MongoAutoConfiguration.class,
- MongoDataAutoConfiguration.class, RabbitAutoConfiguration.class,
- RedisAutoConfiguration.class, SolrAutoConfiguration.class })
+ LdapDataAutoConfiguration.class, MailSenderAutoConfiguration.class,
+ MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
+ RabbitAutoConfiguration.class, RedisAutoConfiguration.class,
+ SolrAutoConfiguration.class })
@EnableConfigurationProperties({ HealthIndicatorProperties.class })
@Import({
ElasticsearchHealthIndicatorConfiguration.ElasticsearchClientHealthIndicatorConfiguration.class,
@@ -231,6 +235,27 @@ public class HealthIndicatorAutoConfiguration {
}
+ @Configuration
+ @ConditionalOnClass(LdapOperations.class)
+ @ConditionalOnBean(LdapOperations.class)
+ @ConditionalOnEnabledHealthIndicator("ldap")
+ public static class LdapHealthIndicatorConfiguration extends
+ CompositeHealthIndicatorConfiguration {
+
+ private final Map ldapOperations;
+
+ public LdapHealthIndicatorConfiguration(Map ldapOperations) {
+ this.ldapOperations = ldapOperations;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(name = "ldapHealthIndicator")
+ public HealthIndicator ldapHealthIndicator() {
+ return createHealthIndicator(this.ldapOperations);
+ }
+
+ }
+
@Configuration
@ConditionalOnBean(MongoTemplate.class)
@ConditionalOnEnabledHealthIndicator("mongo")
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/LdapHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/LdapHealthIndicator.java
new file mode 100644
index 0000000000..3456b4703b
--- /dev/null
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/LdapHealthIndicator.java
@@ -0,0 +1,62 @@
+/*
+ * 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.actuate.health;
+
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.springframework.ldap.core.ContextExecutor;
+import org.springframework.ldap.core.LdapOperations;
+import org.springframework.util.Assert;
+
+/**
+ * {@link HealthIndicator} for configured LDAP server(s).
+ *
+ * @author Eddú Meléndez
+ * @author Stephane Nicoll
+ * @version 1.5.0
+ */
+public class LdapHealthIndicator extends AbstractHealthIndicator {
+
+ private static final ContextExecutor versionContextExecutor = new VersionContextExecutor();
+
+ private final LdapOperations ldapOperations;
+
+ public LdapHealthIndicator(LdapOperations ldapOperations) {
+ Assert.notNull(ldapOperations, "LdapOperations must not be null");
+ this.ldapOperations = ldapOperations;
+ }
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) throws Exception {
+ String version = this.ldapOperations.executeReadOnly(versionContextExecutor);
+ builder.up().withDetail("version", version);
+ }
+
+ private static class VersionContextExecutor implements ContextExecutor {
+
+ @Override
+ public String executeWithContext(DirContext ctx) throws NamingException {
+ Object version = ctx.getEnvironment().get("java.naming.ldap.version");
+ if (version != null) {
+ return (String) version;
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index bf7b902c6a..0ecc13c01e 100644
--- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -139,6 +139,12 @@
"description": "Enable JMS health check.",
"defaultValue": true
},
+ {
+ "name": "management.health.ldap.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Enable LDAP health check.",
+ "defaultValue": true
+ },
{
"name": "management.health.mongo.enabled",
"type": "java.lang.Boolean",
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
index be0ab02b73..9b3a33831d 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2016 the original author or authors.
+ * 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.
@@ -35,6 +35,7 @@ import org.springframework.boot.actuate.health.ElasticsearchJestHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
+import org.springframework.boot.actuate.health.LdapHealthIndicator;
import org.springframework.boot.actuate.health.MailHealthIndicator;
import org.springframework.boot.actuate.health.MongoHealthIndicator;
import org.springframework.boot.actuate.health.RabbitHealthIndicator;
@@ -63,6 +64,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+import org.springframework.ldap.core.LdapOperations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -535,6 +537,35 @@ public class HealthIndicatorAutoConfigurationTests {
.isEqualTo(ApplicationHealthIndicator.class);
}
+ @Test
+ public void ldapHealthIndicator() throws Exception {
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "management.health.diskspace.enabled:false");
+ this.context.register(LdapConfiguration.class,
+ ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+ Map beans = this.context
+ .getBeansOfType(HealthIndicator.class);
+ assertThat(beans.size()).isEqualTo(1);
+ assertThat(beans.values().iterator().next().getClass())
+ .isEqualTo(LdapHealthIndicator.class);
+ }
+
+ @Test
+ public void notLdapHealthIndicator() throws Exception {
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "management.health.diskspace.enabled:false",
+ "management.health.ldap.enabled:false");
+ this.context.register(LdapConfiguration.class,
+ ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+ Map beans = this.context
+ .getBeansOfType(HealthIndicator.class);
+ assertThat(beans.size()).isEqualTo(1);
+ assertThat(beans.values().iterator().next().getClass())
+ .isEqualTo(ApplicationHealthIndicator.class);
+ }
+
@Configuration
@EnableConfigurationProperties
protected static class DataSourceConfig {
@@ -605,4 +636,14 @@ public class HealthIndicatorAutoConfigurationTests {
}
+ @Configuration
+ protected static class LdapConfiguration {
+
+ @Bean
+ public LdapOperations ldapOperations() {
+ return mock(LdapOperations.class);
+ }
+
+ }
+
}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/LdapHealthIndicatorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/LdapHealthIndicatorTests.java
new file mode 100644
index 0000000000..5a03f2b003
--- /dev/null
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/LdapHealthIndicatorTests.java
@@ -0,0 +1,100 @@
+/*
+ * 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.actuate.health;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration;
+import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration;
+import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.ldap.CommunicationException;
+import org.springframework.ldap.core.ContextExecutor;
+import org.springframework.ldap.core.LdapTemplate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link LdapHealthIndicator}
+ *
+ * @author Eddú Meléndez
+ */
+public class LdapHealthIndicatorTests {
+
+ 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 indicatorExist() {
+ this.context.register(LdapAutoConfiguration.class,
+ LdapDataAutoConfiguration.class,
+ PropertyPlaceholderAutoConfiguration.class,
+ EndpointAutoConfiguration.class,
+ HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+ LdapTemplate ldapTemplate = this.context.getBean(LdapTemplate.class);
+ assertThat(ldapTemplate).isNotNull();
+ LdapHealthIndicator healthIndicator = this.context.getBean(
+ LdapHealthIndicator.class);
+ assertThat(healthIndicator).isNotNull();
+ }
+
+ @Test
+ public void ldapIsUp() {
+ LdapTemplate ldapTemplate = mock(LdapTemplate.class);
+ given(ldapTemplate.executeReadOnly(any(ContextExecutor.class))).willReturn("3");
+ LdapHealthIndicator healthIndicator = new LdapHealthIndicator(ldapTemplate);
+ Health health = healthIndicator.health();
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ assertThat(health.getDetails().get("version")).isEqualTo("3");
+ verify(ldapTemplate).executeReadOnly(any(ContextExecutor.class));
+ }
+
+ @Test
+ public void ldapIsDown() {
+ LdapTemplate ldapTemplate = mock(LdapTemplate.class);
+ given(ldapTemplate.executeReadOnly(any(ContextExecutor.class)))
+ .willThrow(new CommunicationException(
+ new javax.naming.CommunicationException("Connection failed")));
+ LdapHealthIndicator healthIndicator = new LdapHealthIndicator(ldapTemplate);
+ Health health = healthIndicator.health();
+ assertThat(health.getStatus()).isEqualTo(Status.DOWN);
+ assertThat((String) health.getDetails().get("error"))
+ .contains("Connection failed");
+ verify(ldapTemplate).executeReadOnly(any(ContextExecutor.class));
+ }
+
+}
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 38c4a77945..fb0af799b2 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -1114,6 +1114,7 @@ content into your application; rather pick only the properties that you need.
management.health.elasticsearch.indices= # Comma-separated index names.
management.health.elasticsearch.response-timeout=100 # The time, in milliseconds, to wait for a response from the cluster.
management.health.jms.enabled=true # Enable JMS health check.
+ management.health.ldap.enabled=true # Enable LDAP health check.
management.health.mail.enabled=true # Enable Mail health check.
management.health.mongo.enabled=true # Enable MongoDB health check.
management.health.rabbit.enabled=true # Enable RabbitMQ health check.