Skip to content

Commit

Permalink
Add encrypted audit logging
Browse files Browse the repository at this point in the history
  • Loading branch information
marest94 committed Feb 9, 2024
1 parent b0b866e commit 2c8e2d0
Show file tree
Hide file tree
Showing 10 changed files with 624 additions and 444 deletions.
798 changes: 388 additions & 410 deletions pom.xml

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions src/main/java/it/eng/idsa/businesslogic/entity/AuditLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package it.eng.idsa.businesslogic.entity;

import java.time.LocalDateTime;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonProperty;

@Entity
@Table(name = "AuditLogs")
public class AuditLog {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonProperty("id")
private Long id;
@JsonProperty("timestamp")
private LocalDateTime timestamp;
@JsonProperty("event")
@Column(columnDefinition = "TEXT")
private String event;

public AuditLog() {
}

public AuditLog(String event) {
this.event = event;
this.timestamp = LocalDateTime.now();
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public LocalDateTime getTimestamp() {
return timestamp;
}

public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}

public String getEvent() {
return event;
}

public void setEvent(String event) {
this.event = event;
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package it.eng.idsa.businesslogic.listener;

import static net.logstash.logback.argument.StructuredArguments.keyValue;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
Expand All @@ -20,15 +16,18 @@
import it.eng.idsa.businesslogic.audit.EventTypeHandler;
import it.eng.idsa.businesslogic.audit.TrueConnectorEvent;
import it.eng.idsa.businesslogic.audit.TrueConnectorEventType;
import it.eng.idsa.businesslogic.entity.AuditLog;
import it.eng.idsa.businesslogic.service.AuditEventService;

@Component
public class LoggingAuditEventListener {
private static final Logger LOGGER = LoggerFactory.getLogger("JSON");

private EventTypeHandler eventTypeHandler;
private AuditEventService auditEventService;

public LoggingAuditEventListener(EventTypeHandler eventTypeHandler) {
public LoggingAuditEventListener(EventTypeHandler eventTypeHandler, AuditEventService auditEventService) {
this.eventTypeHandler = eventTypeHandler;
this.auditEventService = auditEventService;
}

// @EventListener
Expand All @@ -39,8 +38,7 @@ public void on(AuditApplicationEvent event) {
return;
}

LOGGER.info("Audit Event: {}", keyValue("event", event.getAuditEvent()));

auditEventService.saveAuditEvent(new AuditLog(event.getAuditEvent().toString()));
}

@EventListener
Expand All @@ -51,8 +49,7 @@ public void on(TrueConnectorEvent event) {
return;
}

LOGGER.info("TrueConnector Audit Event: {}", keyValue("event", event.getAuditEvent()));

auditEventService.saveAuditEvent(new AuditLog(event.getAuditEvent().toString()));
}

@EventListener
Expand All @@ -64,18 +61,18 @@ public void on(AbstractAuthorizationEvent abstractEvent) {
}
if (abstractEvent instanceof AuthorizationFailureEvent) {
AuthorizationFailureEvent event = (AuthorizationFailureEvent) abstractEvent;
LOGGER.error("Failure authorization event: {}", keyValue("event", event.getSource()));

auditEventService.saveAuditEvent(new AuditLog(event.getSource().toString()));
}
if (abstractEvent instanceof AuthorizedEvent) {
AuthorizedEvent event = (AuthorizedEvent) abstractEvent;
LOGGER.info("Succesfull autorization event: {}", keyValue("event", event.getSource()));

auditEventService.saveAuditEvent(new AuditLog(event.getSource().toString()));
}
if (abstractEvent.getSource() instanceof FilterInvocation) {
FilterInvocation filterInvocation = (FilterInvocation) abstractEvent.getSource();
LOGGER.info("Filter invocation event: Filter: {}, Event: {}", filterInvocation.getRequestUrl(),
keyValue("event", abstractEvent.getSource()));
String auditEventDetails = createAuditLogEntryWithFiler(abstractEvent.getSource(), filterInvocation);

auditEventService.saveAuditEvent(new AuditLog(auditEventDetails));
}
}

Expand All @@ -88,18 +85,26 @@ public void on(AbstractAuthenticationEvent abstractEvent) {
}
if (abstractEvent instanceof AuthenticationFailureBadCredentialsEvent) {
AuthenticationFailureBadCredentialsEvent event = (AuthenticationFailureBadCredentialsEvent) abstractEvent;
LOGGER.error("Failure login event: {}", keyValue("event", event.getSource()));

auditEventService.saveAuditEvent(new AuditLog(event.getSource().toString()));
}
if (abstractEvent instanceof AuthenticationSuccessEvent) {
AuthenticationSuccessEvent event = (AuthenticationSuccessEvent) abstractEvent;
LOGGER.info("Succesful login event: {}", keyValue("event", event.getSource()));

auditEventService.saveAuditEvent(new AuditLog(event.getSource().toString()));
}
if (abstractEvent.getSource() instanceof FilterInvocation) {
FilterInvocation filterInvocation = (FilterInvocation) abstractEvent.getSource();
LOGGER.info("Filter invocation event: Filter: {}, Event: {}", filterInvocation.getRequestUrl(),
keyValue("event", abstractEvent.getSource()));
String auditEventDetails = createAuditLogEntryWithFiler(abstractEvent.getSource(), filterInvocation);

auditEventService.saveAuditEvent(new AuditLog(auditEventDetails));
}
}

private String createAuditLogEntryWithFiler(Object eventSource, FilterInvocation filterInvocation) {
String eventDetails = eventSource.toString();
String requestUrl = filterInvocation.getRequestUrl();

return "Event: " + eventDetails + ", Filter: Requested URL=[" + requestUrl + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package it.eng.idsa.businesslogic.repository;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import it.eng.idsa.businesslogic.entity.AuditLog;

public interface AuditEventRepository extends JpaRepository<AuditLog, Long> {
List<AuditLog> findByTimestampBetween(LocalDateTime startOfDay, LocalDateTime endOfDay);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package it.eng.idsa.businesslogic.service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import it.eng.idsa.businesslogic.entity.AuditLog;
import it.eng.idsa.businesslogic.repository.AuditEventRepository;

@Service
public class AuditEventService {
@Autowired
private AuditEventRepository auditRepository;

public AuditLog saveAuditEvent(AuditLog auditEvent) {
return auditRepository.save(auditEvent);
}

public List<AuditLog> getAllAuditEvents() {
return auditRepository.findAll();
}

public List<AuditLog> getAuditEventsForDate(LocalDate date) {
LocalDateTime startOfDay = date.atStartOfDay(); // Start of the day
LocalDateTime endOfDay = date.atTime(LocalTime.MAX); // End of the day

return auditRepository.findByTimestampBetween(startOfDay, endOfDay);
}
}
16 changes: 12 additions & 4 deletions src/main/java/it/eng/idsa/businesslogic/service/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ public class User implements UserDetails {
this.password = requireNonNull(password);
this.role = role;
}

User(final String id, final String username, final String password) {
super();
this.id = requireNonNull(id);
this.username = requireNonNull(username);
this.password = requireNonNull(password);
}

public String getId() {
return id;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
return authorities;
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
return authorities;
}

@Override
Expand Down Expand Up @@ -75,4 +75,12 @@ public boolean isEnabled() {
return true;
}

@Override
public String toString() {
return "User{" + "id='" + id + '\'' + ", username='" + username + '\'' + ", password='"
+ (password != null && !password.isEmpty() ? "[PROTECTED]" : "[NOT SET]") + '\'' + ", role='" + role
+ '\'' + ", accountNonExpired=" + isAccountNonExpired() + ", accountNonLocked=" + isAccountNonLocked()
+ ", credentialsNonExpired=" + isCredentialsNonExpired() + ", enabled=" + isEnabled() + '}';
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package it.eng.idsa.businesslogic.web.rest.resources;

import java.time.LocalDate;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import it.eng.idsa.businesslogic.entity.AuditLog;
import it.eng.idsa.businesslogic.service.AuditEventService;

@Tag(name = "Audit controller", description = "Returns audit logs.")
@RestController
@RequestMapping("/api/audit/")
public class AuditController {

private static final Logger logger = LoggerFactory.getLogger(AuditController.class);

private AuditEventService auditService;

public AuditController(AuditEventService auditService) {
this.auditService = auditService;
}

@Operation(summary = "All audit logs", tags = "Audit controller - all audit logs")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "All audit logs", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = AuditLog.class)) }) })
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<List<AuditLog>> getAuditLogs(
@RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
if (date != null) {
logger.info("Fetching audit logs for date: {}", date);
return ResponseEntity.ok(auditService.getAuditEventsForDate(date));
} else {
logger.info("Fetching all audit logs");
return ResponseEntity.ok(auditService.getAllAuditEvents());
}
}
}
13 changes: 13 additions & 0 deletions src/main/resources/application-RECEIVER.properties
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ application.selfdescription.filelocation=.
application.selfdescription.inboundModelVersion=4.0.0,4.1.0,4.1.2,4.2.0,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7
application.selfdescription.defaultEndpoint=

#H2 properties
spring.datasource.url=jdbc:h2:file:./audit_logs_receiever;CIPHER=AES
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.driver-class-name=org.h2.Driver

spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.h2.console.enabled=true
spring.datasource.username=sa
spring.datasource.password=file_password password

#Springdoc
springdoc.packagesToScan=it.eng.idsa.businesslogic.web.rest
springdoc.pathsToMatch=/**
Expand Down
13 changes: 13 additions & 0 deletions src/main/resources/application-SENDER.properties
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,19 @@ application.selfdescription.filelocation=.
application.selfdescription.inboundModelVersion=4.0.0,4.1.0,4.1.2,4.2.0,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7
application.selfdescription.defaultEndpoint=

#H2 properties
spring.datasource.url=jdbc:h2:file:./audit_logs_sender;CIPHER=AES
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.driver-class-name=org.h2.Driver

spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.h2.console.enabled=true
spring.datasource.username=sa
spring.datasource.password=file_password password

#Springdoc
springdoc.packagesToScan=it.eng.idsa.businesslogic.web.rest
springdoc.pathsToMatch=/**
Expand Down
Loading

0 comments on commit 2c8e2d0

Please sign in to comment.