Commit 6adab91f authored by Phillip Webb's avatar Phillip Webb

Merge pull request #6579 from vpavic/audit-endpoint

* pr/6579:
  Polish audit event endpoint support
  Improve MBean without backing Endpoint support
  Add MVC and JMX endpoints to retrieve audit events
  Add JMX without backing `Endpoint` support
parents e1eb48e8 51762642
...@@ -20,6 +20,34 @@ include::{generated}/endpoints.adoc[] ...@@ -20,6 +20,34 @@ include::{generated}/endpoints.adoc[]
=== /auditevents
This endpoint provides information about audit events registered by the application.
Audit events can be filtered using the `after`, `principal` and `type` parameters as
defined by `AuditEventRepository`.
Example cURL request with `after` parameter:
include::{generated}/auditevents/curl-request.adoc[]
Example HTTP request with `after` parameter:
include::{generated}/auditevents/http-request.adoc[]
Example HTTP response:
include::{generated}/auditevents/http-response.adoc[]
Example cURL request with `principal` and `after` parameters:
include::{generated}/auditevents/filter-by-principal/curl-request.adoc[]
Example HTTP request with `principal` and `after` parameters:
include::{generated}/auditevents/filter-by-principal/http-request.adoc[]
Example cURL request with `principal`, `after` and `type` parameters:
include::{generated}/auditevents/filter-by-principal-and-type/curl-request.adoc[]
Example HTTP request with `principal`, `after` and `type` parameters:
include::{generated}/auditevents/filter-by-principal-and-type/http-request.adoc[]
=== /logfile === /logfile
This endpoint (if available) contains the plain text logfile configured by the user This endpoint (if available) contains the plain text logfile configured by the user
using `logging.file` or `logging.path` (by default logs are only emitted on stdout using `logging.file` or `logging.path` (by default logs are only emitted on stdout
......
...@@ -77,7 +77,8 @@ public class EndpointDocumentation { ...@@ -77,7 +77,8 @@ public class EndpointDocumentation {
static final File LOG_FILE = new File("target/logs/spring.log"); static final File LOG_FILE = new File("target/logs/spring.log");
private static final Set<String> SKIPPED = Collections.<String>unmodifiableSet( private static final Set<String> SKIPPED = Collections.<String>unmodifiableSet(
new HashSet<String>(Arrays.asList("/docs", "/logfile", "/heapdump"))); new HashSet<String>(Arrays.asList("/docs", "/logfile", "/heapdump",
"/auditevents")));
@Autowired @Autowired
private MvcEndpoints mvcEndpoints; private MvcEndpoints mvcEndpoints;
...@@ -127,6 +128,33 @@ public class EndpointDocumentation { ...@@ -127,6 +128,33 @@ public class EndpointDocumentation {
.andExpect(status().isOk()).andDo(document("set-logger")); .andExpect(status().isOk()).andDo(document("set-logger"));
} }
@Test
public void auditEvents() throws Exception {
this.mockMvc.perform(get("/auditevents")
.param("after", "2016-11-01T10:00:00+0000")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("auditevents"));
}
@Test
public void auditEventsByPrincipal() throws Exception {
this.mockMvc.perform(get("/auditevents").param("principal", "admin")
.param("after", "2016-11-01T10:00:00+0000")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("auditevents/filter-by-principal"));
}
@Test
public void auditEventsByPrincipalAndType() throws Exception {
this.mockMvc.perform(get("/auditevents").param("principal", "admin")
.param("after", "2016-11-01T10:00:00+0000")
.param("type", "AUTHENTICATION_SUCCESS")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("auditevents/filter-by-principal-and-type"));
}
@Test @Test
public void endpoints() throws Exception { public void endpoints() throws Exception {
final File docs = new File("src/main/asciidoc"); final File docs = new File("src/main/asciidoc");
......
...@@ -16,21 +16,33 @@ ...@@ -16,21 +16,33 @@
package org.springframework.boot.actuate.hypermedia; package org.springframework.boot.actuate.hypermedia;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import groovy.text.GStringTemplateEngine; import groovy.text.GStringTemplateEngine;
import groovy.text.TemplateEngine; import groovy.text.TemplateEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.lang.UsesJava8;
// Flyway must go first // Flyway must go first
@SpringBootApplication @SpringBootApplication
@Import({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class }) @Import({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
public class SpringBootHypermediaApplication { public class SpringBootHypermediaApplication implements CommandLineRunner {
@Autowired
private AuditEventRepository auditEventRepository;
@Bean @Bean
public TemplateEngine groovyTemplateEngine() { public TemplateEngine groovyTemplateEngine() {
...@@ -46,4 +58,18 @@ public class SpringBootHypermediaApplication { ...@@ -46,4 +58,18 @@ public class SpringBootHypermediaApplication {
SpringApplication.run(SpringBootHypermediaApplication.class, args); SpringApplication.run(SpringBootHypermediaApplication.class, args);
} }
@Override
public void run(String... args) throws Exception {
this.auditEventRepository.add(
createEvent("2016-11-01T11:00:00Z", "user", "AUTHENTICATION_FAILURE"));
this.auditEventRepository.add(
createEvent("2016-11-01T12:00:00Z", "admin", "AUTHENTICATION_SUCCESS"));
}
@UsesJava8
private AuditEvent createEvent(String instant, String principal, String type) {
return new AuditEvent(Date.from(Instant.parse(instant)), principal, type,
Collections.<String, Object>emptyMap());
}
} }
...@@ -22,6 +22,11 @@ import java.util.Date; ...@@ -22,6 +22,11 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.Assert; import org.springframework.util.Assert;
...@@ -39,6 +44,7 @@ import org.springframework.util.Assert; ...@@ -39,6 +44,7 @@ import org.springframework.util.Assert;
* @author Dave Syer * @author Dave Syer
* @see AuditEventRepository * @see AuditEventRepository
*/ */
@JsonInclude(Include.NON_EMPTY)
public class AuditEvent implements Serializable { public class AuditEvent implements Serializable {
private final Date timestamp; private final Date timestamp;
...@@ -106,6 +112,7 @@ public class AuditEvent implements Serializable { ...@@ -106,6 +112,7 @@ public class AuditEvent implements Serializable {
* Returns the date/time that the even was logged. * Returns the date/time that the even was logged.
* @return the time stamp * @return the time stamp
*/ */
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
public Date getTimestamp() { public Date getTimestamp() {
return this.timestamp; return this.timestamp;
} }
...@@ -130,6 +137,7 @@ public class AuditEvent implements Serializable { ...@@ -130,6 +137,7 @@ public class AuditEvent implements Serializable {
* Returns the event data. * Returns the event data.
* @return the event data * @return the event data
*/ */
@JsonAnyGetter
public Map<String, Object> getData() { public Map<String, Object> getData() {
return this.data; return this.data;
} }
......
...@@ -21,13 +21,17 @@ import javax.management.MBeanServer; ...@@ -21,13 +21,17 @@ import javax.management.MBeanServer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration.JmxEnabledCondition; import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration.JmxEnabledCondition;
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.jmx.AuditEventsJmxEndpoint;
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter; import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
...@@ -83,6 +87,14 @@ public class EndpointMBeanExportAutoConfiguration { ...@@ -83,6 +87,14 @@ public class EndpointMBeanExportAutoConfiguration {
return new JmxAutoConfiguration().mbeanServer(); return new JmxAutoConfiguration().mbeanServer();
} }
@Bean
@ConditionalOnBean(AuditEventRepository.class)
@ConditionalOnEnabledEndpoint("auditevents")
public AuditEventsJmxEndpoint abstractEndpointMBean(
AuditEventRepository auditEventRepository) {
return new AuditEventsJmxEndpoint(this.objectMapper, auditEventRepository);
}
/** /**
* Condition to check that spring.jmx and endpoints.jmx are enabled. * Condition to check that spring.jmx and endpoints.jmx are enabled.
*/ */
......
...@@ -21,6 +21,7 @@ import java.util.List; ...@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
...@@ -28,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.HealthEndpoint; ...@@ -28,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.HealthEndpoint;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint; import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCustomizer;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
...@@ -62,6 +64,7 @@ import org.springframework.web.cors.CorsConfiguration; ...@@ -62,6 +64,7 @@ import org.springframework.web.cors.CorsConfiguration;
* *
* @author Dave Syer * @author Dave Syer
* @author Ben Hale * @author Ben Hale
* @author Vedran Pavic
* @since 1.3.0 * @since 1.3.0
*/ */
@ManagementContextConfiguration @ManagementContextConfiguration
...@@ -195,6 +198,14 @@ public class EndpointWebMvcManagementContextConfiguration { ...@@ -195,6 +198,14 @@ public class EndpointWebMvcManagementContextConfiguration {
return new ShutdownMvcEndpoint(delegate); return new ShutdownMvcEndpoint(delegate);
} }
@Bean
@ConditionalOnBean(AuditEventRepository.class)
@ConditionalOnEnabledEndpoint("auditevents")
public AuditEventsMvcEndpoint auditEventMvcEndpoint(
AuditEventRepository auditEventRepository) {
return new AuditEventsMvcEndpoint(auditEventRepository);
}
private boolean isHealthSecure() { private boolean isHealthSecure() {
return isSpringSecurityAvailable() return isSpringSecurityAvailable()
&& this.managementServerProperties.getSecurity().isEnabled(); && this.managementServerProperties.getSecurity().isEnabled();
......
/*
* Copyright 2012-2016 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.endpoint.jmx;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EndpointProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.ObjectUtils;
/**
* Abstract base class for {@link JmxEndpoint} implementations without a backing
* {@link Endpoint}.
*
* @author Vedran Pavic
* @author Phillip Webb
* @since 1.5.0
*/
@ManagedResource
public abstract class AbstractJmxEndpoint implements JmxEndpoint, EnvironmentAware {
private final DataConverter dataConverter;
private Environment environment;
/**
* Enable the endpoint.
*/
private Boolean enabled;
public AbstractJmxEndpoint(ObjectMapper objectMapper) {
this.dataConverter = new DataConverter(objectMapper);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected final Environment getEnvironment() {
return this.environment;
}
@Override
public boolean isEnabled() {
return EndpointProperties.isEnabled(this.environment, this.enabled);
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
@Override
public String getIdentity() {
return ObjectUtils.getIdentityHexString(this);
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends Endpoint> getEndpointType() {
return null;
}
/**
* Convert the given data into JSON.
* @param data the source data
* @return the JSON representation
*/
protected Object convert(Object data) {
return this.dataConverter.convert(data);
}
}
/*
* Copyright 2012-2016 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.endpoint.jmx;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.util.Assert;
/**
* {@link JmxEndpoint} for {@link AuditEventRepository}.
*
* @author Vedran Pavic
* @since 1.5.0
*/
@ConfigurationProperties(prefix = "endpoints.auditevents")
public class AuditEventsJmxEndpoint extends AbstractJmxEndpoint {
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
private final AuditEventRepository auditEventRepository;
public AuditEventsJmxEndpoint(ObjectMapper objectMapper,
AuditEventRepository auditEventRepository) {
super(objectMapper);
Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
this.auditEventRepository = auditEventRepository;
}
@ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
public Object getData(String dateAfter) {
List<AuditEvent> auditEvents = this.auditEventRepository
.find(parseDate(dateAfter));
return convert(auditEvents);
}
@ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
public Object getData(String dateAfter, String principal) {
List<AuditEvent> auditEvents = this.auditEventRepository.find(principal,
parseDate(dateAfter));
return convert(auditEvents);
}
@ManagedOperation(description = "Retrieves a list of audit events meeting the given criteria")
public Object getData(String principal, String dateAfter, String type) {
List<AuditEvent> auditEvents = this.auditEventRepository.find(principal,
parseDate(dateAfter), type);
return convert(auditEvents);
}
private Date parseDate(String date) {
try {
return new SimpleDateFormat(DATE_FORMAT).parse(date);
}
catch (ParseException ex) {
throw new IllegalArgumentException(ex);
}
}
}
/*
* Copyright 2012-2016 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.endpoint.jmx;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Internal converter that uses an {@link ObjectMapper} to convert to JSON.
*
* @author Christian Dupuis
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DataConverter {
private final ObjectMapper objectMapper;
private final JavaType listObject;
private final JavaType mapStringObject;
DataConverter(ObjectMapper objectMapper) {
this.objectMapper = (objectMapper == null ? new ObjectMapper() : objectMapper);
this.listObject = this.objectMapper.getTypeFactory()
.constructParametricType(List.class, Object.class);
this.mapStringObject = this.objectMapper.getTypeFactory()
.constructParametricType(Map.class, String.class, Object.class);
}
public Object convert(Object data) {
if (data == null) {
return null;
}
if (data instanceof String) {
return data;
}
if (data.getClass().isArray() || data instanceof List) {
return this.objectMapper.convertValue(data, this.listObject);
}
return this.objectMapper.convertValue(data, this.mapStringObject);
}
}
...@@ -16,10 +16,6 @@ ...@@ -16,10 +16,6 @@
package org.springframework.boot.actuate.endpoint.jmx; package org.springframework.boot.actuate.endpoint.jmx;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
...@@ -27,23 +23,24 @@ import org.springframework.jmx.export.annotation.ManagedAttribute; ...@@ -27,23 +23,24 @@ import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/** /**
* Simple wrapper around {@link Endpoint} implementations to enable JMX export. * Base for adapters that convert {@link Endpoint} implementations to {@link JmxEndpoint}.
* *
* @author Christian Dupuis * @author Christian Dupuis
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Vedran Pavic
* @author Phillip Webb
* @see JmxEndpoint
* @see DataEndpointMBean
*/ */
@ManagedResource @ManagedResource
public class EndpointMBean { public abstract class EndpointMBean implements JmxEndpoint {
private final Endpoint<?> endpoint;
private final ObjectMapper mapper;
private final JavaType listObject; private final DataConverter dataConverter;
private final JavaType mapStringObject; private final Endpoint<?> endpoint;
/** /**
* Create a new {@link EndpointMBean} instance. * Create a new {@link EndpointMBean} instance.
...@@ -53,20 +50,20 @@ public class EndpointMBean { ...@@ -53,20 +50,20 @@ public class EndpointMBean {
*/ */
public EndpointMBean(String beanName, Endpoint<?> endpoint, public EndpointMBean(String beanName, Endpoint<?> endpoint,
ObjectMapper objectMapper) { ObjectMapper objectMapper) {
this.dataConverter = new DataConverter(objectMapper);
Assert.notNull(beanName, "BeanName must not be null"); Assert.notNull(beanName, "BeanName must not be null");
Assert.notNull(endpoint, "Endpoint must not be null"); Assert.notNull(endpoint, "Endpoint must not be null");
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.endpoint = endpoint; this.endpoint = endpoint;
this.mapper = objectMapper;
this.listObject = objectMapper.getTypeFactory()
.constructParametricType(List.class, Object.class);
this.mapStringObject = objectMapper.getTypeFactory()
.constructParametricType(Map.class, String.class, Object.class);
} }
@ManagedAttribute(description = "Returns the class of the underlying endpoint") @ManagedAttribute(description = "Returns the class of the underlying endpoint")
public String getEndpointClass() { public String getEndpointClass() {
return ClassUtils.getQualifiedName(this.endpoint.getClass()); return ClassUtils.getQualifiedName(getEndpointType());
}
@Override
public boolean isEnabled() {
return this.endpoint.isEnabled();
} }
@ManagedAttribute(description = "Indicates whether the underlying endpoint exposes sensitive information") @ManagedAttribute(description = "Indicates whether the underlying endpoint exposes sensitive information")
...@@ -74,21 +71,28 @@ public class EndpointMBean { ...@@ -74,21 +71,28 @@ public class EndpointMBean {
return this.endpoint.isSensitive(); return this.endpoint.isSensitive();
} }
@Override
public String getIdentity() {
return ObjectUtils.getIdentityHexString(getEndpoint());
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends Endpoint> getEndpointType() {
return getEndpoint().getClass();
}
public Endpoint<?> getEndpoint() { public Endpoint<?> getEndpoint() {
return this.endpoint; return this.endpoint;
} }
protected Object convert(Object result) { /**
if (result == null) { * Convert the given data into JSON.
return null; * @param data the source data
} * @return the JSON representation
if (result instanceof String) { */
return result; protected Object convert(Object data) {
} return this.dataConverter.convert(data);
if (result.getClass().isArray() || result instanceof List) {
return this.mapper.convertValue(result, this.listObject);
}
return this.mapper.convertValue(result, this.mapStringObject);
} }
} }
...@@ -39,7 +39,6 @@ import org.springframework.boot.actuate.endpoint.LoggersEndpoint; ...@@ -39,7 +39,6 @@ import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jmx.export.MBeanExportException; import org.springframework.jmx.export.MBeanExportException;
...@@ -53,7 +52,7 @@ import org.springframework.jmx.support.ObjectNameManager; ...@@ -53,7 +52,7 @@ import org.springframework.jmx.support.ObjectNameManager;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
/** /**
* {@link ApplicationListener} that registers all known {@link Endpoint}s with an * {@link SmartLifecycle} bean that registers all known {@link Endpoint}s with an
* {@link MBeanServer} using the {@link MBeanExporter} located from the application * {@link MBeanServer} using the {@link MBeanExporter} located from the application
* context. * context.
* *
...@@ -79,7 +78,7 @@ public class EndpointMBeanExporter extends MBeanExporter ...@@ -79,7 +78,7 @@ public class EndpointMBeanExporter extends MBeanExporter
private final MetadataNamingStrategy defaultNamingStrategy = new MetadataNamingStrategy( private final MetadataNamingStrategy defaultNamingStrategy = new MetadataNamingStrategy(
this.attributeSource); this.attributeSource);
private final Set<Endpoint<?>> registeredEndpoints = new HashSet<Endpoint<?>>(); private final Set<Class<?>> registeredEndpoints = new HashSet<Class<?>>();
private volatile boolean autoStartup = true; private volatile boolean autoStartup = true;
...@@ -156,39 +155,88 @@ public class EndpointMBeanExporter extends MBeanExporter ...@@ -156,39 +155,88 @@ public class EndpointMBeanExporter extends MBeanExporter
locateAndRegisterEndpoints(); locateAndRegisterEndpoints();
} }
@SuppressWarnings({ "rawtypes" })
protected void locateAndRegisterEndpoints() { protected void locateAndRegisterEndpoints() {
Map<String, Endpoint> endpoints = this.beanFactory.getBeansOfType(Endpoint.class); registerJmxEndpoints(this.beanFactory.getBeansOfType(JmxEndpoint.class));
for (Map.Entry<String, Endpoint> endpointEntry : endpoints.entrySet()) { registerEndpoints(this.beanFactory.getBeansOfType(Endpoint.class));
if (!this.registeredEndpoints.contains(endpointEntry.getValue()) }
&& endpointEntry.getValue().isEnabled()) {
registerEndpoint(endpointEntry.getKey(), endpointEntry.getValue()); private void registerJmxEndpoints(Map<String, JmxEndpoint> endpoints) {
this.registeredEndpoints.add(endpointEntry.getValue()); for (Map.Entry<String, JmxEndpoint> entry : endpoints.entrySet()) {
String name = entry.getKey();
JmxEndpoint endpoint = entry.getValue();
Class<?> type = (endpoint.getEndpointType() != null
? endpoint.getEndpointType() : endpoint.getClass());
if (!this.registeredEndpoints.contains(type) && endpoint.isEnabled()) {
try {
registerBeanNameOrInstance(endpoint, name);
}
catch (MBeanExportException ex) {
logger.error("Could not register JmxEndpoint [" + name + "]", ex);
}
this.registeredEndpoints.add(type);
} }
} }
} }
protected void registerEndpoint(String beanName, Endpoint<?> endpoint) { @SuppressWarnings("rawtypes")
@SuppressWarnings("rawtypes") private void registerEndpoints(Map<String, Endpoint> endpoints) {
Class<? extends Endpoint> type = endpoint.getClass(); for (Map.Entry<String, Endpoint> entry : endpoints.entrySet()) {
if (AnnotationUtils.findAnnotation(type, ManagedResource.class) != null) { String name = entry.getKey();
// Already managed Endpoint endpoint = entry.getValue();
return; Class<?> type = endpoint.getClass();
if (!this.registeredEndpoints.contains(type) && endpoint.isEnabled()) {
registerEndpoint(name, endpoint);
this.registeredEndpoints.add(type);
}
} }
if (type.isMemberClass() }
&& AnnotationUtils.findAnnotation(type.getEnclosingClass(),
ManagedResource.class) != null) { /**
// Nested class with @ManagedResource in parent * Register a regular {@link Endpoint} with the {@link MBeanServer}.
* @param beanName the bean name
* @param endpoint the endpoint to register
* @deprecated as of 1.5 in favor of direct {@link JmxEndpoint} registration or
* {@link #adaptEndpoint(String, Endpoint)}
*/
@Deprecated
protected void registerEndpoint(String beanName, Endpoint<?> endpoint) {
Class<?> type = endpoint.getClass();
if (isAnnotatedWithManagedResource(type) || (type.isMemberClass()
&& isAnnotatedWithManagedResource(type.getEnclosingClass()))) {
// Endpoint is directly managed
return; return;
} }
JmxEndpoint jmxEndpoint = adaptEndpoint(beanName, endpoint);
try { try {
registerBeanNameOrInstance(getEndpointMBean(beanName, endpoint), beanName); registerBeanNameOrInstance(jmxEndpoint, beanName);
} }
catch (MBeanExportException ex) { catch (MBeanExportException ex) {
logger.error("Could not register MBean for endpoint [" + beanName + "]", ex); logger.error("Could not register MBean for endpoint [" + beanName + "]", ex);
} }
} }
private boolean isAnnotatedWithManagedResource(Class<?> type) {
return AnnotationUtils.findAnnotation(type, ManagedResource.class) != null;
}
/**
* Adapt the given {@link Endpoint} to a {@link JmxEndpoint}.
* @param beanName the bean name
* @param endpoint the endpoint to adapt
* @return an adapted endpoint
*/
protected JmxEndpoint adaptEndpoint(String beanName, Endpoint<?> endpoint) {
return getEndpointMBean(beanName, endpoint);
}
/**
* Get a {@link EndpointMBean} for the specified {@link Endpoint}.
* @param beanName the bean name
* @param endpoint the endpoint
* @return an {@link EndpointMBean}
* @deprecated as of 1.5 in favor of {@link #adaptEndpoint(String, Endpoint)}
*/
@Deprecated
protected EndpointMBean getEndpointMBean(String beanName, Endpoint<?> endpoint) { protected EndpointMBean getEndpointMBean(String beanName, Endpoint<?> endpoint) {
if (endpoint instanceof ShutdownEndpoint) { if (endpoint instanceof ShutdownEndpoint) {
return new ShutdownEndpointMBean(beanName, endpoint, this.objectMapper); return new ShutdownEndpointMBean(beanName, endpoint, this.objectMapper);
...@@ -205,27 +253,29 @@ public class EndpointMBeanExporter extends MBeanExporter ...@@ -205,27 +253,29 @@ public class EndpointMBeanExporter extends MBeanExporter
if (bean instanceof SelfNaming) { if (bean instanceof SelfNaming) {
return ((SelfNaming) bean).getObjectName(); return ((SelfNaming) bean).getObjectName();
} }
if (bean instanceof EndpointMBean) { if (bean instanceof EndpointMBean) {
StringBuilder builder = new StringBuilder(); return getObjectName((EndpointMBean) bean, beanKey);
builder.append(this.domain);
builder.append(":type=Endpoint");
builder.append(",name=" + beanKey);
if (parentContextContainsSameBean(this.applicationContext, beanKey)) {
builder.append(",context="
+ ObjectUtils.getIdentityHexString(this.applicationContext));
}
if (this.ensureUniqueRuntimeObjectNames) {
builder.append(",identity=" + ObjectUtils
.getIdentityHexString(((EndpointMBean) bean).getEndpoint()));
}
builder.append(getStaticNames());
return ObjectNameManager.getInstance(builder.toString());
} }
return this.defaultNamingStrategy.getObjectName(bean, beanKey); return this.defaultNamingStrategy.getObjectName(bean, beanKey);
} }
private ObjectName getObjectName(JmxEndpoint jmxEndpoint, String beanKey)
throws MalformedObjectNameException {
StringBuilder builder = new StringBuilder();
builder.append(this.domain);
builder.append(":type=Endpoint");
builder.append(",name=" + beanKey);
if (parentContextContainsSameBean(this.applicationContext, beanKey)) {
builder.append(",context="
+ ObjectUtils.getIdentityHexString(this.applicationContext));
}
if (this.ensureUniqueRuntimeObjectNames) {
builder.append(",identity=" + jmxEndpoint.getIdentity());
}
builder.append(getStaticNames());
return ObjectNameManager.getInstance(builder.toString());
}
private boolean parentContextContainsSameBean(ApplicationContext applicationContext, private boolean parentContextContainsSameBean(ApplicationContext applicationContext,
String beanKey) { String beanKey) {
if (applicationContext.getParent() != null) { if (applicationContext.getParent() != null) {
......
/*
* Copyright 2012-2016 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.endpoint.jmx;
import org.springframework.boot.actuate.endpoint.Endpoint;
/**
* A strategy for the JMX layer on top of an {@link Endpoint}. Implementations are allowed
* to use {@code @ManagedAttribute} and the full Spring JMX machinery. Implementations may
* be backed by an actual {@link Endpoint} or may be specifically designed for JMX only.
*
* @author Phillip Webb
* @since 1.5.0
* @see EndpointMBean
* @see AbstractJmxEndpoint
*/
public interface JmxEndpoint {
/**
* Return if the JMX endpoint is enabled.
* @return if the endpoint is enabled
*/
boolean isEnabled();
/**
* Return the MBean identity for this endpoint.
* @return the MBean identity.
*/
String getIdentity();
/**
* Return the type of {@link Endpoint} exposed, or {@code null} if this
* {@link JmxEndpoint} exposes information that cannot be represented as a traditional
* {@link Endpoint}.
* @return the endpoint type
*/
@SuppressWarnings("rawtypes")
Class<? extends Endpoint> getEndpointType();
}
...@@ -26,7 +26,7 @@ import org.springframework.util.Assert; ...@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
* @author Madhura Bhave * @author Madhura Bhave
* @since 1.5.0 * @since 1.5.0
*/ */
public class AbstractNamedMvcEndpoint extends AbstractMvcEndpoint public abstract class AbstractNamedMvcEndpoint extends AbstractMvcEndpoint
implements NamedMvcEndpoint { implements NamedMvcEndpoint {
private final String name; private final String name;
......
/*
* Copyright 2012-2016 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.endpoint.mvc;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* {@link MvcEndpoint} to expose {@link AuditEvent}s.
*
* @author Vedran Pavic
* @author Phillip Webb
* @since 1.5.0
*/
@ConfigurationProperties(prefix = "endpoints.auditevents")
public class AuditEventsMvcEndpoint extends AbstractNamedMvcEndpoint {
private final AuditEventRepository auditEventRepository;
public AuditEventsMvcEndpoint(AuditEventRepository auditEventRepository) {
super("auditevents", "/auditevents", true);
Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
this.auditEventRepository = auditEventRepository;
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> findByPrincipalAndAfterAndType(
@RequestParam(required = false) String principal,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ") Date after,
@RequestParam(required = false) String type) {
if (!isEnabled()) {
return DISABLED_RESPONSE;
}
Map<Object, Object> result = new LinkedHashMap<Object, Object>();
result.put("events", this.auditEventRepository.find(principal, after, type));
return ResponseEntity.ok(result);
}
}
...@@ -103,14 +103,13 @@ public class EndpointMvcIntegrationTests { ...@@ -103,14 +103,13 @@ public class EndpointMvcIntegrationTests {
@MinimalWebConfiguration @MinimalWebConfiguration
@Import({ ManagementServerPropertiesAutoConfiguration.class, @Import({ ManagementServerPropertiesAutoConfiguration.class,
JacksonAutoConfiguration.class, EndpointAutoConfiguration.class, JacksonAutoConfiguration.class, EndpointAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class }) EndpointWebMvcAutoConfiguration.class, AuditAutoConfiguration.class })
@RestController @RestController
protected static class Application { protected static class Application {
private final List<HttpMessageConverter<?>> converters; private final List<HttpMessageConverter<?>> converters;
public Application( public Application(ObjectProvider<List<HttpMessageConverter<?>>> converters) {
ObjectProvider<List<HttpMessageConverter<?>>> converters) {
this.converters = converters.getIfAvailable(); this.converters = converters.getIfAvailable();
} }
......
...@@ -364,7 +364,7 @@ public class EndpointWebMvcAutoConfigurationTests { ...@@ -364,7 +364,7 @@ public class EndpointWebMvcAutoConfigurationTests {
EmbeddedServletContainerAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class); EndpointWebMvcAutoConfiguration.class, AuditAutoConfiguration.class);
this.applicationContext.refresh(); this.applicationContext.refresh();
assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/controller", ports.get().server, "controlleroutput");
assertContent("/test/endpoint", ports.get().server, "endpointoutput"); assertContent("/test/endpoint", ports.get().server, "endpointoutput");
...@@ -381,7 +381,7 @@ public class EndpointWebMvcAutoConfigurationTests { ...@@ -381,7 +381,7 @@ public class EndpointWebMvcAutoConfigurationTests {
EmbeddedServletContainerAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class); EndpointWebMvcAutoConfiguration.class, AuditAutoConfiguration.class);
this.applicationContext.refresh(); this.applicationContext.refresh();
assertContent("/controller", ports.get().server, "controlleroutput"); assertContent("/controller", ports.get().server, "controlleroutput");
ServerProperties serverProperties = this.applicationContext ServerProperties serverProperties = this.applicationContext
...@@ -440,9 +440,9 @@ public class EndpointWebMvcAutoConfigurationTests { ...@@ -440,9 +440,9 @@ public class EndpointWebMvcAutoConfigurationTests {
BaseConfiguration.class, ServerPortConfig.class, BaseConfiguration.class, ServerPortConfig.class,
EndpointWebMvcAutoConfiguration.class); EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh(); this.applicationContext.refresh();
// /health, /metrics, /loggers, /env, /actuator, /heapdump (/shutdown is disabled // /health, /metrics, /loggers, /env, /actuator, /heapdump, /auditevents
// by default) // (/shutdown is disabled by default)
assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class)).hasSize(6); assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class)).hasSize(7);
} }
@Test @Test
...@@ -734,7 +734,7 @@ public class EndpointWebMvcAutoConfigurationTests { ...@@ -734,7 +734,7 @@ public class EndpointWebMvcAutoConfigurationTests {
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class }) ServerPropertiesAutoConfiguration.class, AuditAutoConfiguration.class })
protected static class BaseConfiguration { protected static class BaseConfiguration {
} }
......
...@@ -84,7 +84,7 @@ public class HealthMvcEndpointAutoConfigurationTests { ...@@ -84,7 +84,7 @@ public class HealthMvcEndpointAutoConfigurationTests {
@Configuration @Configuration
@ImportAutoConfiguration({ SecurityAutoConfiguration.class, @ImportAutoConfiguration({ SecurityAutoConfiguration.class,
JacksonAutoConfiguration.class, WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, AuditAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class }) EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class })
static class TestConfiguration { static class TestConfiguration {
......
...@@ -91,7 +91,7 @@ public class ManagementWebSecurityAutoConfigurationTests { ...@@ -91,7 +91,7 @@ public class ManagementWebSecurityAutoConfigurationTests {
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, "security.basic.enabled:false"); EnvironmentTestUtils.addEnvironment(this.context, "security.basic.enabled:false");
this.context.refresh(); this.context.refresh();
assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull(); assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
...@@ -202,8 +202,8 @@ public class ManagementWebSecurityAutoConfigurationTests { ...@@ -202,8 +202,8 @@ public class ManagementWebSecurityAutoConfigurationTests {
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
WebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); AuditAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
Filter filter = this.context.getBean("springSecurityFilterChain", Filter.class); Filter filter = this.context.getBean("springSecurityFilterChain", Filter.class);
...@@ -265,7 +265,7 @@ public class ManagementWebSecurityAutoConfigurationTests { ...@@ -265,7 +265,7 @@ public class ManagementWebSecurityAutoConfigurationTests {
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class,
FallbackWebSecurityAutoConfiguration.class }) FallbackWebSecurityAutoConfiguration.class })
static class WebConfiguration { static class WebConfiguration {
......
...@@ -51,7 +51,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -51,7 +51,7 @@ import org.springframework.context.annotation.Configuration;
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,
HypermediaAutoConfiguration.class, EndpointAutoConfiguration.class, HypermediaAutoConfiguration.class, EndpointAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class }) PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class })
public @interface MinimalActuatorHypermediaApplication { public @interface MinimalActuatorHypermediaApplication {
} }
...@@ -35,6 +35,7 @@ import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint; ...@@ -35,6 +35,7 @@ import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint;
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.AuditEventsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.DocsMvcEndpoint; import org.springframework.boot.actuate.endpoint.mvc.DocsMvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter; import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
...@@ -85,6 +86,7 @@ public class MvcEndpointPathConfigurationTests { ...@@ -85,6 +86,7 @@ public class MvcEndpointPathConfigurationTests {
@Parameters(name = "{0}") @Parameters(name = "{0}")
public static Object[] parameters() { public static Object[] parameters() {
return new Object[] { new Object[] { "actuator", HalJsonMvcEndpoint.class }, return new Object[] { new Object[] { "actuator", HalJsonMvcEndpoint.class },
new Object[] { "auditevents", AuditEventsMvcEndpoint.class },
new Object[] { "autoconfig", AutoConfigurationReportEndpoint.class }, new Object[] { "autoconfig", AutoConfigurationReportEndpoint.class },
new Object[] { "beans", BeansEndpoint.class }, new Object[] { "beans", BeansEndpoint.class },
new Object[] { "configprops", new Object[] { "configprops",
...@@ -143,9 +145,8 @@ public class MvcEndpointPathConfigurationTests { ...@@ -143,9 +145,8 @@ public class MvcEndpointPathConfigurationTests {
@ImportAutoConfiguration({ EndpointAutoConfiguration.class, @ImportAutoConfiguration({ EndpointAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class, ServerPropertiesAutoConfiguration.class, AuditAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class })
EndpointAutoConfiguration.class })
protected static class TestConfiguration { protected static class TestConfiguration {
......
...@@ -128,7 +128,7 @@ public class EndpointMBeanExporterTests { ...@@ -128,7 +128,7 @@ public class EndpointMBeanExporterTests {
this.context.registerBeanDefinition("endpoint1", this.context.registerBeanDefinition("endpoint1",
new RootBeanDefinition(TestEndpoint.class)); new RootBeanDefinition(TestEndpoint.class));
this.context.registerBeanDefinition("endpoint2", this.context.registerBeanDefinition("endpoint2",
new RootBeanDefinition(TestEndpoint.class)); new RootBeanDefinition(TestEndpoint2.class));
this.context.refresh(); this.context.refresh();
MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class);
assertThat(mbeanExporter.getServer() assertThat(mbeanExporter.getServer()
...@@ -329,6 +329,10 @@ public class EndpointMBeanExporterTests { ...@@ -329,6 +329,10 @@ public class EndpointMBeanExporterTests {
} }
public static class TestEndpoint2 extends TestEndpoint {
}
public static class JsonMapConversionEndpoint public static class JsonMapConversionEndpoint
extends AbstractEndpoint<Map<String, Object>> { extends AbstractEndpoint<Map<String, Object>> {
......
/*
* Copyright 2012-2016 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.endpoint.mvc;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link AuditEventsMvcEndpoint}.
*
* @author Vedran Pavic
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource(properties = "management.security.enabled=false")
public class AuditEventsMvcEndpointTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.context.getBean(AuditEventsMvcEndpoint.class).setEnabled(true);
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void invokeWhenDisabledShouldReturnNotFoundStatus() throws Exception {
this.context.getBean(AuditEventsMvcEndpoint.class).setEnabled(false);
this.mvc.perform(get("/auditevents").param("after", "2016-11-01T10:00:00+0000"))
.andExpect(status().isNotFound());
}
@Test
public void invokeFilterByDateAfter() throws Exception {
this.mvc.perform(get("/auditevents").param("after", "2016-11-01T13:00:00+0000"))
.andExpect(status().isOk())
.andExpect(content().string("{\"events\":[]}"));
}
@Test
public void invokeFilterByPrincipalAndDateAfter() throws Exception {
this.mvc.perform(get("/auditevents").param("principal", "user").param("after",
"2016-11-01T10:00:00+0000"))
.andExpect(status().isOk())
.andExpect(content().string(
containsString("\"principal\":\"user\",\"type\":\"login\"")))
.andExpect(content().string(not(containsString("admin"))));
}
@Test
public void invokeFilterByPrincipalAndDateAfterAndType() throws Exception {
this.mvc.perform(get("/auditevents").param("principal", "admin")
.param("after", "2016-11-01T10:00:00+0000").param("type", "logout"))
.andExpect(status().isOk())
.andExpect(content().string(
containsString("\"principal\":\"admin\",\"type\":\"logout\"")))
.andExpect(content().string(not(containsString("login"))));
}
@Import({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class })
@Configuration
protected static class TestConfiguration {
@Bean
public AuditEventRepository auditEventsRepository() {
AuditEventRepository repository = new InMemoryAuditEventRepository(3);
repository.add(createEvent("2016-11-01T11:00:00Z", "admin", "login"));
repository.add(createEvent("2016-11-01T12:00:00Z", "admin", "logout"));
repository.add(createEvent("2016-11-01T12:00:00Z", "user", "login"));
return repository;
}
private AuditEvent createEvent(String instant, String principal, String type) {
return new AuditEvent(Date.from(Instant.parse(instant)), principal, type,
Collections.<String, Object>emptyMap());
}
}
}
...@@ -24,6 +24,7 @@ import org.junit.Test; ...@@ -24,6 +24,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
...@@ -107,7 +108,7 @@ public class EnvironmentMvcEndpointTests { ...@@ -107,7 +108,7 @@ public class EnvironmentMvcEndpointTests {
@Configuration @Configuration
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, AuditAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
public static class TestConfiguration { public static class TestConfiguration {
......
...@@ -31,6 +31,7 @@ import org.springframework.test.annotation.DirtiesContext; ...@@ -31,6 +31,7 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
...@@ -86,7 +87,11 @@ public class HalBrowserMvcEndpointDisabledIntegrationTests { ...@@ -86,7 +87,11 @@ public class HalBrowserMvcEndpointDisabledIntegrationTests {
continue; continue;
} }
path = path.length() > 0 ? path : "/"; path = path.length() > 0 ? path : "/";
this.mockMvc.perform(get(path).accept(MediaType.APPLICATION_JSON)) MockHttpServletRequestBuilder requestBuilder = get(path);
if (endpoint instanceof AuditEventsMvcEndpoint) {
requestBuilder.param("after", "2016-01-01T12:00:00+00:00");
}
this.mockMvc.perform(requestBuilder.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(jsonPath("$._links").doesNotExist()); .andExpect(jsonPath("$._links").doesNotExist());
} }
......
...@@ -119,8 +119,8 @@ public class HalBrowserMvcEndpointVanillaIntegrationTests { ...@@ -119,8 +119,8 @@ public class HalBrowserMvcEndpointVanillaIntegrationTests {
@Test @Test
public void endpointsEachHaveSelf() throws Exception { public void endpointsEachHaveSelf() throws Exception {
Set<String> collections = new HashSet<String>( Set<String> collections = new HashSet<String>(Arrays.asList("/trace", "/beans",
Arrays.asList("/trace", "/beans", "/dump", "/heapdump", "/loggers")); "/dump", "/heapdump", "/loggers", "/auditevents"));
for (MvcEndpoint endpoint : this.mvcEndpoints.getEndpoints()) { for (MvcEndpoint endpoint : this.mvcEndpoints.getEndpoints()) {
String path = endpoint.getPath(); String path = endpoint.getPath();
if (collections.contains(path)) { if (collections.contains(path)) {
......
...@@ -28,6 +28,7 @@ import org.junit.Test; ...@@ -28,6 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
...@@ -114,7 +115,7 @@ public class HeapdumpMvcEndpointTests { ...@@ -114,7 +115,7 @@ public class HeapdumpMvcEndpointTests {
this.mvc.perform(options("/heapdump")).andExpect(status().isOk()); this.mvc.perform(options("/heapdump")).andExpect(status().isOk());
} }
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -25,6 +25,7 @@ import org.junit.Test; ...@@ -25,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.InfoEndpoint;
...@@ -79,7 +80,7 @@ public class InfoMvcEndpointTests { ...@@ -79,7 +80,7 @@ public class InfoMvcEndpointTests {
"\"beanName2\":{\"key21\":\"value21\",\"key22\":\"value22\"}"))); "\"beanName2\":{\"key21\":\"value21\",\"key22\":\"value22\"}")));
} }
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -23,6 +23,7 @@ import org.junit.Test; ...@@ -23,6 +23,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.InfoEndpoint;
...@@ -68,7 +69,7 @@ public class InfoMvcEndpointWithNoInfoContributorsTests { ...@@ -68,7 +69,7 @@ public class InfoMvcEndpointWithNoInfoContributorsTests {
this.mvc.perform(get("/info")).andExpect(status().isOk()); this.mvc.perform(get("/info")).andExpect(status().isOk());
} }
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -21,6 +21,7 @@ import org.junit.Test; ...@@ -21,6 +21,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
...@@ -85,7 +86,7 @@ public class JolokiaMvcEndpointContextPathTests { ...@@ -85,7 +86,7 @@ public class JolokiaMvcEndpointContextPathTests {
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@EnableWebMvc @EnableWebMvc
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -23,6 +23,7 @@ import org.junit.Test; ...@@ -23,6 +23,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
...@@ -100,7 +101,7 @@ public class JolokiaMvcEndpointIntegrationTests { ...@@ -100,7 +101,7 @@ public class JolokiaMvcEndpointIntegrationTests {
@Configuration @Configuration
@EnableConfigurationProperties @EnableConfigurationProperties
@EnableWebMvc @EnableWebMvc
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -25,6 +25,7 @@ import org.junit.Test; ...@@ -25,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
...@@ -129,7 +130,7 @@ public class MetricsMvcEndpointTests { ...@@ -129,7 +130,7 @@ public class MetricsMvcEndpointTests {
.andExpect(content().string(containsString("1"))); .andExpect(content().string(containsString("1")));
} }
@Import({ JacksonAutoConfiguration.class, @Import({ JacksonAutoConfiguration.class, AuditAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class }) ManagementServerPropertiesAutoConfiguration.class })
......
...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc; ...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration;
...@@ -56,7 +57,7 @@ public class MvcEndpointCorsIntegrationTests { ...@@ -56,7 +57,7 @@ public class MvcEndpointCorsIntegrationTests {
HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class,
JolokiaAutoConfiguration.class, WebMvcAutoConfiguration.class); JolokiaAutoConfiguration.class, WebMvcAutoConfiguration.class);
} }
......
...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc; ...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
...@@ -229,9 +230,10 @@ public class MvcEndpointIntegrationTests { ...@@ -229,9 +230,10 @@ public class MvcEndpointIntegrationTests {
@ImportAutoConfiguration({ JacksonAutoConfiguration.class, @ImportAutoConfiguration({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, AuditAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class }) PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,
AuditAutoConfiguration.class })
static class DefaultConfiguration { static class DefaultConfiguration {
} }
......
...@@ -961,6 +961,9 @@ content into your application; rather pick only the properties that you need. ...@@ -961,6 +961,9 @@ content into your application; rather pick only the properties that you need.
endpoints.actuator.enabled=true # Enable the endpoint. endpoints.actuator.enabled=true # Enable the endpoint.
endpoints.actuator.path= # Endpoint URL path. endpoints.actuator.path= # Endpoint URL path.
endpoints.actuator.sensitive=false # Enable security on the endpoint. endpoints.actuator.sensitive=false # Enable security on the endpoint.
endpoints.auditevents.enabled= # Enable the endpoint.
endpoints.auditevents.id= # Endpoint identifier.
endpoints.auditevents.path= # Endpoint path.
endpoints.autoconfig.enabled= # Enable the endpoint. endpoints.autoconfig.enabled= # Enable the endpoint.
endpoints.autoconfig.id= # Endpoint identifier. endpoints.autoconfig.id= # Endpoint identifier.
endpoints.autoconfig.path= # Endpoint path. endpoints.autoconfig.path= # Endpoint path.
......
...@@ -73,6 +73,10 @@ The following technology agnostic endpoints are available: ...@@ -73,6 +73,10 @@ The following technology agnostic endpoints are available:
HATEOAS to be on the classpath. HATEOAS to be on the classpath.
|true |true
|`auditevents`
|Exposes audit events information for the current application.
|true
|`autoconfig` |`autoconfig`
|Displays an auto-configuration report showing all auto-configuration candidates and the |Displays an auto-configuration report showing all auto-configuration candidates and the
reason why they '`were`' or '`were not`' applied. reason why they '`were`' or '`were not`' applied.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment