Commit 51762642 authored by Phillip Webb's avatar Phillip Webb

Polish audit event endpoint support

Closes gh-6579
parent 5b40eb48
......@@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.lang.UsesJava8;
// Flyway must go first
@SpringBootApplication
......@@ -59,12 +60,16 @@ public class SpringBootHypermediaApplication implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
this.auditEventRepository.add(new AuditEvent(Date.from(Instant.parse(
"2016-11-01T11:00:00Z")), "user", "AUTHENTICATION_FAILURE",
Collections.emptyMap()));
this.auditEventRepository.add(new AuditEvent(Date.from(Instant.parse(
"2016-11-01T12:00:00Z")), "admin", "AUTHENTICATION_SUCCESS",
Collections.emptyMap()));
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());
}
}
......@@ -17,7 +17,8 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Date;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
......@@ -34,6 +35,7 @@ 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")
......@@ -47,41 +49,18 @@ public class AuditEventsMvcEndpoint extends AbstractNamedMvcEndpoint {
this.auditEventRepository = auditEventRepository;
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE, params = { "after" })
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> findByAfter(
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ") Date after) {
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;
}
List<AuditEvent> auditEvents = this.auditEventRepository.find(after);
return ResponseEntity.ok(auditEvents);
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE,
params = { "principal", "after" })
@ResponseBody
public ResponseEntity<?> findByPrincipalAndAfter(@RequestParam String principal,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ") Date after) {
if (!isEnabled()) {
return DISABLED_RESPONSE;
}
List<AuditEvent> auditEvents = this.auditEventRepository.find(principal, after);
return ResponseEntity.ok(auditEvents);
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE,
params = { "principal", "after", "type" })
@ResponseBody
public ResponseEntity<?> findByPrincipalAndAfterAndType(@RequestParam String principal,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ") Date after,
@RequestParam String type) {
if (!isEnabled()) {
return DISABLED_RESPONSE;
}
List<AuditEvent> auditEvents = this.auditEventRepository.find(principal, after,
type);
return ResponseEntity.ok(auditEvents);
Map<Object, Object> result = new LinkedHashMap<Object, Object>();
result.put("events", this.auditEventRepository.find(principal, after, type));
return ResponseEntity.ok(result);
}
}
......@@ -109,8 +109,7 @@ public class EndpointMvcIntegrationTests {
private final List<HttpMessageConverter<?>> converters;
public Application(
ObjectProvider<List<HttpMessageConverter<?>>> converters) {
public Application(ObjectProvider<List<HttpMessageConverter<?>>> converters) {
this.converters = converters.getIfAvailable();
}
......
......@@ -37,6 +37,7 @@ 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;
......@@ -55,6 +56,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource(properties = "management.security.enabled=false")
public class AuditEventsMvcEndpointTests {
@Autowired
......@@ -78,26 +80,27 @@ public class AuditEventsMvcEndpointTests {
@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("[]"));
.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"))
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(
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\"")))
.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"))));
}
......@@ -111,15 +114,17 @@ public class AuditEventsMvcEndpointTests {
@Bean
public AuditEventRepository auditEventsRepository() {
AuditEventRepository repository = new InMemoryAuditEventRepository(3);
repository.add(new AuditEvent(Date.from(Instant.parse(
"2016-11-01T11:00:00Z")), "admin", "login", Collections.emptyMap()));
repository.add(new AuditEvent(Date.from(Instant.parse(
"2016-11-01T12:00:00Z")), "admin", "logout", Collections.emptyMap()));
repository.add(new AuditEvent(Date.from(Instant.parse(
"2016-11-01T12:00:00Z")), "user", "login", Collections.emptyMap()));
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());
}
}
}
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