Merge pull request #5854 from vpavic:audit-repository
* pr/5854: Polish "Improve AuditEventRepository" Improve AuditEventRepository
This commit is contained in:
commit
05b9dd1cb9
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -80,6 +80,7 @@ public class AuditEvent implements Serializable {
|
||||||
public AuditEvent(Date timestamp, String principal, String type,
|
public AuditEvent(Date timestamp, String principal, String type,
|
||||||
Map<String, Object> data) {
|
Map<String, Object> data) {
|
||||||
Assert.notNull(timestamp, "Timestamp must not be null");
|
Assert.notNull(timestamp, "Timestamp must not be null");
|
||||||
|
Assert.notNull(principal, "Principal must not be null");
|
||||||
Assert.notNull(type, "Type must not be null");
|
Assert.notNull(type, "Type must not be null");
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
|
@ -110,8 +111,8 @@ public class AuditEvent implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the user principal responsible for the event or {@code null}.
|
* Returns the user principal responsible for the event.
|
||||||
* @return the principal or {@code null}
|
* @return the principal
|
||||||
*/
|
*/
|
||||||
public String getPrincipal() {
|
public String getPrincipal() {
|
||||||
return this.principal;
|
return this.principal;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2014 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,9 +23,18 @@ import java.util.List;
|
||||||
* Repository for {@link AuditEvent}s.
|
* Repository for {@link AuditEvent}s.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Vedran Pavic
|
||||||
*/
|
*/
|
||||||
public interface AuditEventRepository {
|
public interface AuditEventRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find audit events since the time provided.
|
||||||
|
* @param after timestamp of earliest result required
|
||||||
|
* @return audit events
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
List<AuditEvent> find(Date after);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find audit events relating to the specified principal since the time provided.
|
* Find audit events relating to the specified principal since the time provided.
|
||||||
* @param principal the principal name to search for
|
* @param principal the principal name to search for
|
||||||
|
@ -34,6 +43,17 @@ public interface AuditEventRepository {
|
||||||
*/
|
*/
|
||||||
List<AuditEvent> find(String principal, Date after);
|
List<AuditEvent> find(String principal, Date after);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find audit events of specified type relating to the specified principal since the
|
||||||
|
* time provided.
|
||||||
|
* @param principal the principal name to search for
|
||||||
|
* @param after timestamp of earliest result required
|
||||||
|
* @param type the event type to search for
|
||||||
|
* @return audit events of specified type relating to the principal
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
List<AuditEvent> find(String principal, Date after, String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log an event.
|
* Log an event.
|
||||||
* @param event the audit event to log
|
* @param event the audit event to log
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2015 the original author or authors.
|
* Copyright 2012-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,11 +20,14 @@ import java.util.Date;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In-memory {@link AuditEventRepository} implementation.
|
* In-memory {@link AuditEventRepository} implementation.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Vedran Pavic
|
||||||
*/
|
*/
|
||||||
public class InMemoryAuditEventRepository implements AuditEventRepository {
|
public class InMemoryAuditEventRepository implements AuditEventRepository {
|
||||||
|
|
||||||
|
@ -54,11 +57,26 @@ public class InMemoryAuditEventRepository implements AuditEventRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<AuditEvent> find(String principal, Date after) {
|
public synchronized List<AuditEvent> find(Date after) {
|
||||||
LinkedList<AuditEvent> events = new LinkedList<AuditEvent>();
|
LinkedList<AuditEvent> events = new LinkedList<AuditEvent>();
|
||||||
for (int i = 0; i < this.events.length; i++) {
|
for (int i = 0; i < this.events.length; i++) {
|
||||||
int index = ((this.tail + this.events.length - i) % this.events.length);
|
AuditEvent event = resolveTailEvent(i);
|
||||||
AuditEvent event = this.events[index];
|
if (event == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isMatch(event, after)) {
|
||||||
|
events.addFirst(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized List<AuditEvent> find(String principal, Date after) {
|
||||||
|
Assert.notNull(principal, "Principal must not be null");
|
||||||
|
LinkedList<AuditEvent> events = new LinkedList<AuditEvent>();
|
||||||
|
for (int i = 0; i < this.events.length; i++) {
|
||||||
|
AuditEvent event = resolveTailEvent(i);
|
||||||
if (event == null) {
|
if (event == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -69,15 +87,45 @@ public class InMemoryAuditEventRepository implements AuditEventRepository {
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMatch(AuditEvent auditEvent, String principal, Date after) {
|
@Override
|
||||||
return (principal == null || auditEvent.getPrincipal().equals(principal))
|
public synchronized List<AuditEvent> find(String principal, Date after, String type) {
|
||||||
&& (after == null || auditEvent.getTimestamp().compareTo(after) >= 0);
|
Assert.notNull(principal, "Principal must not be null");
|
||||||
|
Assert.notNull(type, "Type must not be null");
|
||||||
|
LinkedList<AuditEvent> events = new LinkedList<AuditEvent>();
|
||||||
|
for (int i = 0; i < this.events.length; i++) {
|
||||||
|
AuditEvent event = resolveTailEvent(i);
|
||||||
|
if (event == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isMatch(event, principal, type, after)) {
|
||||||
|
events.addFirst(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void add(AuditEvent event) {
|
public synchronized void add(AuditEvent event) {
|
||||||
|
Assert.notNull(event, "AuditEvent must not be null");
|
||||||
this.tail = (this.tail + 1) % this.events.length;
|
this.tail = (this.tail + 1) % this.events.length;
|
||||||
this.events[this.tail] = event;
|
this.events[this.tail] = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuditEvent resolveTailEvent(int offset) {
|
||||||
|
int index = ((this.tail + this.events.length - offset) % this.events.length);
|
||||||
|
return this.events[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMatch(AuditEvent event, Date after) {
|
||||||
|
return (after == null || event.getTimestamp().compareTo(after) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMatch(AuditEvent event, String principal, Date after) {
|
||||||
|
return (event.getPrincipal().equals(principal) && isMatch(event, after));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMatch(AuditEvent event, String principal, String type, Date after) {
|
||||||
|
return (event.getType().equals(type) && isMatch(event, principal, after));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ package org.springframework.boot.actuate.audit;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -26,11 +28,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* Tests for {@link AuditEvent}.
|
* Tests for {@link AuditEvent}.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Vedran Pavic
|
||||||
*/
|
*/
|
||||||
public class AuditEventTests {
|
public class AuditEventTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNowEvent() throws Exception {
|
public void nowEvent() throws Exception {
|
||||||
AuditEvent event = new AuditEvent("phil", "UNKNOWN",
|
AuditEvent event = new AuditEvent("phil", "UNKNOWN",
|
||||||
Collections.singletonMap("a", (Object) "b"));
|
Collections.singletonMap("a", (Object) "b"));
|
||||||
assertThat(event.getData().get("a")).isEqualTo("b");
|
assertThat(event.getData().get("a")).isEqualTo("b");
|
||||||
|
@ -40,10 +46,32 @@ public class AuditEventTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvertStringsToData() throws Exception {
|
public void convertStringsToData() throws Exception {
|
||||||
AuditEvent event = new AuditEvent("phil", "UNKNOWN", "a=b", "c=d");
|
AuditEvent event = new AuditEvent("phil", "UNKNOWN", "a=b", "c=d");
|
||||||
assertThat(event.getData().get("a")).isEqualTo("b");
|
assertThat(event.getData().get("a")).isEqualTo("b");
|
||||||
assertThat(event.getData().get("c")).isEqualTo("d");
|
assertThat(event.getData().get("c")).isEqualTo("d");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nullTimestamp() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Timestamp must not be null");
|
||||||
|
new AuditEvent(null, "phil", "UNKNOWN",
|
||||||
|
Collections.singletonMap("a", (Object) "b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nullPrincipal() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Principal must not be null");
|
||||||
|
new AuditEvent(null, "UNKNOWN", Collections.singletonMap("a", (Object) "b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nullType() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Type must not be null");
|
||||||
|
new AuditEvent("phil", null, Collections.singletonMap("a", (Object) "b"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -31,9 +33,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Vedran Pavic
|
||||||
*/
|
*/
|
||||||
public class InMemoryAuditEventRepositoryTests {
|
public class InMemoryAuditEventRepositoryTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void lessThanCapacity() throws Exception {
|
public void lessThanCapacity() throws Exception {
|
||||||
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
||||||
|
@ -43,7 +49,6 @@ public class InMemoryAuditEventRepositoryTests {
|
||||||
assertThat(events.size()).isEqualTo(2);
|
assertThat(events.size()).isEqualTo(2);
|
||||||
assertThat(events.get(0).getType()).isEqualTo("a");
|
assertThat(events.get(0).getType()).isEqualTo("a");
|
||||||
assertThat(events.get(1).getType()).isEqualTo("b");
|
assertThat(events.get(1).getType()).isEqualTo("b");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -58,6 +63,14 @@ public class InMemoryAuditEventRepositoryTests {
|
||||||
assertThat(events.get(1).getType()).isEqualTo("c");
|
assertThat(events.get(1).getType()).isEqualTo("c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNullAuditEvent() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("AuditEvent must not be null");
|
||||||
|
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
||||||
|
repository.add(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findByPrincipal() throws Exception {
|
public void findByPrincipal() throws Exception {
|
||||||
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
||||||
|
@ -71,6 +84,19 @@ public class InMemoryAuditEventRepositoryTests {
|
||||||
assertThat(events.get(1).getType()).isEqualTo("c");
|
assertThat(events.get(1).getType()).isEqualTo("c");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findByPrincipalAndType() throws Exception {
|
||||||
|
InMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();
|
||||||
|
repository.add(new AuditEvent("dave", "a"));
|
||||||
|
repository.add(new AuditEvent("phil", "b"));
|
||||||
|
repository.add(new AuditEvent("dave", "c"));
|
||||||
|
repository.add(new AuditEvent("phil", "d"));
|
||||||
|
List<AuditEvent> events = repository.find("dave", null, "a");
|
||||||
|
assertThat(events.size()).isEqualTo(1);
|
||||||
|
assertThat(events.get(0).getPrincipal()).isEqualTo("dave");
|
||||||
|
assertThat(events.get(0).getType()).isEqualTo("a");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findByDate() throws Exception {
|
public void findByDate() throws Exception {
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
@ -87,7 +113,7 @@ public class InMemoryAuditEventRepositoryTests {
|
||||||
calendar.add(Calendar.DAY_OF_YEAR, 1);
|
calendar.add(Calendar.DAY_OF_YEAR, 1);
|
||||||
repository.add(new AuditEvent(calendar.getTime(), "phil", "d", data));
|
repository.add(new AuditEvent(calendar.getTime(), "phil", "d", data));
|
||||||
calendar.add(Calendar.DAY_OF_YEAR, 1);
|
calendar.add(Calendar.DAY_OF_YEAR, 1);
|
||||||
List<AuditEvent> events = repository.find(null, after);
|
List<AuditEvent> events = repository.find(after);
|
||||||
assertThat(events.size()).isEqualTo(2);
|
assertThat(events.size()).isEqualTo(2);
|
||||||
assertThat(events.get(0).getType()).isEqualTo("c");
|
assertThat(events.get(0).getType()).isEqualTo("c");
|
||||||
assertThat(events.get(1).getType()).isEqualTo("d");
|
assertThat(events.get(1).getType()).isEqualTo("d");
|
||||||
|
|
Loading…
Reference in New Issue