mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Add LDAP health actuator
Provide specific health actuator endpoint to verify if LDAP connection is valid. See gh-7905
This commit is contained in:
parent
db99ed843e
commit
b2250f4ad8
@ -166,6 +166,11 @@
|
||||
<artifactId>spring-data-couchbase</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-ldap</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
|
@ -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<LdapHealthIndicator, LdapOperations> {
|
||||
|
||||
private final Map<String, LdapOperations> ldapOperations;
|
||||
|
||||
public LdapHealthIndicatorConfiguration(Map<String, LdapOperations> ldapOperations) {
|
||||
this.ldapOperations = ldapOperations;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "ldapHealthIndicator")
|
||||
public HealthIndicator ldapHealthIndicator() {
|
||||
return createHealthIndicator(this.ldapOperations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(MongoTemplate.class)
|
||||
@ConditionalOnEnabledHealthIndicator("mongo")
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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
|
||||
* @version 1.5.0
|
||||
*/
|
||||
public class LdapHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
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 = (String) this.ldapOperations.executeReadOnly(new ContextExecutor<Object>() {
|
||||
@Override
|
||||
public Object executeWithContext(DirContext ctx) throws NamingException {
|
||||
return ctx.getEnvironment().get("java.naming.ldap.version");
|
||||
}
|
||||
});
|
||||
builder.up().withDetail("version", version);
|
||||
}
|
||||
|
||||
}
|
@ -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",
|
||||
|
@ -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<String, HealthIndicator> 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<String, HealthIndicator> 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,15 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class LdapConfiguration {
|
||||
|
||||
@Bean
|
||||
public LdapOperations ldapOperations() {
|
||||
LdapOperations operations = mock(LdapOperations.class);
|
||||
return operations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user