Skip to content

Commit

Permalink
Added a page for viewing the web audit log [#592]
Browse files Browse the repository at this point in the history
 * Added the admin module.
 * Added a feature to load web audit log entries.
 * Added a feature to clear the web audit log.
 * Refactored the REST APIs.

NOTE: One effect test, the service failure for clearing the web
audit log, consistently fails even though it appears to be coded
correctly. I've xit'd the test for the time being bug it needs
to be addressed to get our coverage to 100% again.
  • Loading branch information
mcpierce committed Jan 25, 2021
1 parent dccdb3f commit 308265c
Show file tree
Hide file tree
Showing 52 changed files with 2,351 additions and 391 deletions.
Expand Up @@ -27,13 +27,13 @@
import org.comixedproject.views.View;

/**
* <code>RestAuditLogEntry</code> represents a single entry in the REST API audit log table.
* <code>WebAuditLogEntry</code> represents a single entry in the REST API audit log table.
*
* @author Darryl L. Pierce
*/
@Entity
@Table(name = "rest_audit_log")
public class RestAuditLogEntry {
public class WebAuditLogEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
Expand Down
Expand Up @@ -8,22 +8,22 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.views.View;

/**
* <code>GetRestAuditLogResponse</code> represents the content for a reqwuest to get REST audit log
* <code>LoadWebAuditLogResponse</code> represents the content for a reqwuest to get REST audit log
* entries.
*
* @author Darryl L. Pierce
*/
@AllArgsConstructor
public class GetRestAuditLogResponse {
public class LoadWebAuditLogResponse {
@Getter
@Setter
@JsonProperty("entries")
@JsonView(View.AuditLogEntryList.class)
private List<RestAuditLogEntry> entries;
private List<WebAuditLogEntry> entries;

@Getter
@Setter
Expand Down
Expand Up @@ -20,26 +20,26 @@

import java.util.Date;
import java.util.List;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

/**
* <code>RestAuditLogRepository</code> manages persisted instances of {@link RestAuditLogEntry}.
* <code>WebAuditLogRepository</code> manages persisted instances of {@link WebAuditLogEntry}.
*
* @author Darryl L. Pierce
*/
@Repository
public interface RestAuditLogRepository extends JpaRepository<RestAuditLogEntry, Long> {
public interface WebAuditLogRepository extends JpaRepository<WebAuditLogEntry, Long> {
/**
* Retrieve a page of entries after the provided cutoff date.
*
* @param cutoff the cutoff date
* @param pageable the page parameters
* @return the list of entries
*/
List<RestAuditLogEntry> findByEndTimeAfterOrderByEndTime(
List<WebAuditLogEntry> findByEndTimeAfterOrderByEndTime(
@Param("cutoff") Date cutoff, Pageable pageable);
}
Expand Up @@ -25,7 +25,7 @@
import com.github.springtestdbunit.annotation.DatabaseSetup;
import java.util.Date;
import java.util.List;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.repositories.RepositoryContext;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -49,14 +49,14 @@
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class
})
public class RestAuditLogRepositoryTest {
public class WebAuditLogRepositoryTest {
private static final Date TEST_CUTOFF = new Date();

@Autowired private RestAuditLogRepository auditLogRepository;
@Autowired private WebAuditLogRepository auditLogRepository;

@Test
public void testFindByEndDateLaterThanOrderByEndDate() {
final List<RestAuditLogEntry> result =
final List<WebAuditLogEntry> result =
this.auditLogRepository.findByEndTimeAfterOrderByEndTime(
TEST_CUTOFF, PageRequest.of(0, 100));

Expand Down
Expand Up @@ -27,8 +27,8 @@
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.service.auditlog.RestAuditLogService;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.service.auditlog.WebAuditLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
Expand All @@ -44,7 +44,7 @@
@Configuration
@Log4j2
public class AuditableEndpointAspect {
@Autowired private RestAuditLogService restAuditLogService;
@Autowired private WebAuditLogService webAuditLogService;
@Autowired private ObjectMapper objectMapper;

/**
Expand All @@ -66,7 +66,7 @@ public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
error = throwable;
}
final Date ended = new Date();
final RestAuditLogEntry entry = new RestAuditLogEntry();
final WebAuditLogEntry entry = new WebAuditLogEntry();
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

Expand Down Expand Up @@ -99,7 +99,7 @@ public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
entry.setSuccessful(true);
}

this.restAuditLogService.save(entry);
this.webAuditLogService.save(entry);

if (error != null) throw error;
return response;
Expand Down
Expand Up @@ -16,19 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixedproject.controller.core;
package org.comixedproject.controller.admin;

import com.fasterxml.jackson.annotation.JsonView;
import java.util.Date;
import java.util.List;
import lombok.extern.log4j.Log4j2;
import org.comixedproject.auditlog.AuditableEndpoint;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.model.net.GetRestAuditLogResponse;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.model.net.GetTaskAuditLogResponse;
import org.comixedproject.model.net.LoadWebAuditLogResponse;
import org.comixedproject.model.tasks.TaskAuditLogEntry;
import org.comixedproject.service.ComiXedServiceException;
import org.comixedproject.service.auditlog.RestAuditLogService;
import org.comixedproject.service.auditlog.WebAuditLogService;
import org.comixedproject.service.task.TaskService;
import org.comixedproject.views.View;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -48,7 +48,7 @@
@Log4j2
public class AuditLogController {
@Autowired private TaskService taskService;
@Autowired private RestAuditLogService restAuditLogService;
@Autowired private WebAuditLogService webAuditLogService;

/**
* Retrieve the list of log entries after the cutoff time.
Expand Down Expand Up @@ -92,24 +92,23 @@ public void clearTaskAuditLog() {
* @return the list of entries
*/
@GetMapping(
value = "/api/auditing/rest/entries/{cutoff}",
value = "/api/admin/web/audit/entries/{cutoff}",
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasRole('ADMIN')")
@JsonView(View.AuditLogEntryList.class)
public GetRestAuditLogResponse getAllRestEntriesAfterDate(
@PathVariable("cutoff") final Long cutoff) {
log.info("Getting all REST audit entries since {}", cutoff);
final List<RestAuditLogEntry> entries = this.restAuditLogService.getEntriesAfterDate(cutoff);
public LoadWebAuditLogResponse loadWebAuditLogEntries(@PathVariable("cutoff") final Long cutoff) {
log.info("Getting all web audit entries since {}", cutoff);
final List<WebAuditLogEntry> entries = this.webAuditLogService.getEntriesAfterDate(cutoff);
final Date latest =
entries.isEmpty() ? new Date() : entries.get(entries.size() - 1).getEndTime();
return new GetRestAuditLogResponse(entries, latest);
return new LoadWebAuditLogResponse(entries, latest);
}

/** Clear the rest audit log. */
@DeleteMapping(value = "/api/auditing/rest/entries")
@DeleteMapping(value = "/api/admin/web/audit/entries")
@PreAuthorize("hasRole('ADMIN')")
public void deleteAllRestAuditLog() {
log.info("Delete all the entries from the audit log");
this.restAuditLogService.deleteAllRestAuditLog();
log.info("Delete all the entries from the web audit log");
this.webAuditLogService.clearLogEntries();
}
}
Expand Up @@ -23,8 +23,8 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.service.auditlog.RestAuditLogService;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.service.auditlog.WebAuditLogService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -39,11 +39,11 @@ public class AuditableEndpointAspectTest {
private static final byte[] TEST_RESPONSE_OBJECT = "JSON content".getBytes();

@InjectMocks private AuditableEndpointAspect auditableEndpointAspect;
@Mock private RestAuditLogService restAuditLogService;
@Mock private WebAuditLogService webAuditLogService;
@Mock private ProceedingJoinPoint proceedingJoinPoint;
@Mock private Object response;
@Captor private ArgumentCaptor<RestAuditLogEntry> restAuditLogEntryArgumentCaptor;
@Mock private RestAuditLogEntry savedEntry;
@Captor private ArgumentCaptor<WebAuditLogEntry> restAuditLogEntryArgumentCaptor;
@Mock private WebAuditLogEntry savedEntry;
@Mock private ObjectMapper objectMapper;
@Mock private ContentCachingRequestWrapper requestWrapper;

Expand All @@ -55,7 +55,7 @@ public void setUp() {

@Test
public void testAround() throws Throwable {
Mockito.when(restAuditLogService.save(restAuditLogEntryArgumentCaptor.capture()))
Mockito.when(webAuditLogService.save(restAuditLogEntryArgumentCaptor.capture()))
.thenReturn(savedEntry);
Mockito.when(proceedingJoinPoint.proceed()).thenReturn(response);

Expand All @@ -64,7 +64,7 @@ public void testAround() throws Throwable {
assertNotNull(result);
assertSame(response, result);

Mockito.verify(restAuditLogService, Mockito.times(1))
Mockito.verify(webAuditLogService, Mockito.times(1))
.save(restAuditLogEntryArgumentCaptor.getValue());
Mockito.verify(proceedingJoinPoint, Mockito.times(1)).proceed();
}
Expand Down
Expand Up @@ -24,12 +24,13 @@
import java.util.Date;
import java.util.List;
import org.comixedproject.controller.ComiXedControllerException;
import org.comixedproject.model.auditlog.RestAuditLogEntry;
import org.comixedproject.model.net.GetRestAuditLogResponse;
import org.comixedproject.controller.admin.AuditLogController;
import org.comixedproject.model.auditlog.WebAuditLogEntry;
import org.comixedproject.model.net.GetTaskAuditLogResponse;
import org.comixedproject.model.net.LoadWebAuditLogResponse;
import org.comixedproject.model.tasks.TaskAuditLogEntry;
import org.comixedproject.service.ComiXedServiceException;
import org.comixedproject.service.auditlog.RestAuditLogService;
import org.comixedproject.service.auditlog.WebAuditLogService;
import org.comixedproject.service.task.TaskService;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -47,19 +48,19 @@ public class AuditLogControllerTest {

@InjectMocks private AuditLogController auditLogController;
@Mock private TaskService taskService;
@Mock private RestAuditLogService restAuditLogService;
@Mock private WebAuditLogService webAuditLogService;
@Mock private TaskAuditLogEntry taskAuditLogEntry;
@Mock private RestAuditLogEntry restAuditLogEntry;
@Mock private WebAuditLogEntry webAuditLogEntry;

private List<TaskAuditLogEntry> auditLogEntries = new ArrayList<>();
private List<RestAuditLogEntry> restAuditLogEntries = new ArrayList<>();
private List<WebAuditLogEntry> restAuditLogEntries = new ArrayList<>();

@Before
public void setUp() {
this.auditLogEntries.add(taskAuditLogEntry);
Mockito.when(taskAuditLogEntry.getStartTime()).thenReturn(TEST_LAST_UPDATED_DATE);
this.restAuditLogEntries.add(restAuditLogEntry);
Mockito.when(restAuditLogEntry.getEndTime()).thenReturn(TEST_LAST_UPDATED_DATE);
this.restAuditLogEntries.add(webAuditLogEntry);
Mockito.when(webAuditLogEntry.getEndTime()).thenReturn(TEST_LAST_UPDATED_DATE);
}

@Test
Expand Down Expand Up @@ -88,45 +89,45 @@ public void testClearTaskLog() {

@Test
public void testGetRestAuditLogEntriesAfterDate() {
Mockito.when(restAuditLogService.getEntriesAfterDate(Mockito.anyLong()))
Mockito.when(webAuditLogService.getEntriesAfterDate(Mockito.anyLong()))
.thenReturn(restAuditLogEntries);

GetRestAuditLogResponse result =
auditLogController.getAllRestEntriesAfterDate(TEST_LAST_UPDATED_DATE.getTime());
LoadWebAuditLogResponse result =
auditLogController.loadWebAuditLogEntries(TEST_LAST_UPDATED_DATE.getTime());

assertNotNull(result);
assertSame(restAuditLogEntries, result.getEntries());
assertNotNull(result.getLatest());
assertEquals(TEST_LAST_UPDATED_DATE, result.getLatest());

Mockito.verify(restAuditLogService, Mockito.times(1))
Mockito.verify(webAuditLogService, Mockito.times(1))
.getEntriesAfterDate(TEST_LAST_UPDATED_DATE.getTime());
}

@Test
public void testGetRestAuditLogEntriesAfterDateNoEntries() {
restAuditLogEntries.clear();

Mockito.when(restAuditLogService.getEntriesAfterDate(Mockito.anyLong()))
Mockito.when(webAuditLogService.getEntriesAfterDate(Mockito.anyLong()))
.thenReturn(restAuditLogEntries);

GetRestAuditLogResponse result =
auditLogController.getAllRestEntriesAfterDate(TEST_LAST_UPDATED_DATE.getTime());
LoadWebAuditLogResponse result =
auditLogController.loadWebAuditLogEntries(TEST_LAST_UPDATED_DATE.getTime());

assertNotNull(result);
assertSame(restAuditLogEntries, result.getEntries());
assertNotNull(result.getLatest());

Mockito.verify(restAuditLogService, Mockito.times(1))
Mockito.verify(webAuditLogService, Mockito.times(1))
.getEntriesAfterDate(TEST_LAST_UPDATED_DATE.getTime());
}

@Test
public void testDeleteAllRestAuditLog() {
Mockito.doNothing().when(restAuditLogService).deleteAllRestAuditLog();
Mockito.doNothing().when(webAuditLogService).clearLogEntries();

auditLogController.deleteAllRestAuditLog();

Mockito.verify(restAuditLogService, Mockito.times(1)).deleteAllRestAuditLog();
Mockito.verify(webAuditLogService, Mockito.times(1)).clearLogEntries();
}
}

0 comments on commit 308265c

Please sign in to comment.