Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/main/java/net/staticstudios/audit/AuditLogEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* Represents an entry in the audit log.
*/
public class AuditLogEntry<T extends ActionData> {
private final @NotNull UUID userId;
private final @NotNull AuditUser user;
private final @Nullable UUID sessionId;
private final @NotNull String applicationGroup;
private final @NotNull String applicationId;
Expand All @@ -22,16 +22,16 @@ public class AuditLogEntry<T extends ActionData> {
/**
* Creates a new AuditLogEntry.
*
* @param userId the ID of the user who performed the action
* @param user the ID of the user who performed the action
* @param sessionId the ID of the session in which the action was performed (nullable)
* @param applicationGroup the application group that logged the action
* @param applicationId the application ID that logged the action
* @param timestamp the timestamp when the action was performed
* @param action the action that was performed
* @param data the data associated with the action
*/
public AuditLogEntry(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull String applicationGroup, @NotNull String applicationId, @NotNull Instant timestamp, @NotNull Action<T> action, @NotNull T data) {
this.userId = userId;
public AuditLogEntry(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull String applicationGroup, @NotNull String applicationId, @NotNull Instant timestamp, @NotNull Action<T> action, @NotNull T data) {
this.user = user;
this.sessionId = sessionId;
this.applicationGroup = applicationGroup;
this.applicationId = applicationId;
Expand All @@ -45,8 +45,8 @@ public AuditLogEntry(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull St
*
* @return the user ID
*/
public @NotNull UUID getUserId() {
return userId;
public @NotNull AuditUser getUser() {
return user;
}

/**
Expand Down Expand Up @@ -111,7 +111,7 @@ public AuditLogEntry(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull St
@Override
public String toString() {
return String.format("AuditLogEntry{userId=%s, sessionId=%s, applicationGroup='%s', applicationId='%s', timestamp=%s, action=%s, data=%s}",
userId, sessionId, applicationGroup, applicationId, timestamp, action, data);
user, sessionId, applicationGroup, applicationId, timestamp, action, data);
}

/**
Expand All @@ -126,7 +126,7 @@ public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
AuditLogEntry<?> that = (AuditLogEntry<?>) obj;
return Objects.equals(action, that.action) && Objects.equals(data, that.data) &&
Objects.equals(userId, that.userId) && Objects.equals(sessionId, that.sessionId) &&
Objects.equals(user, that.user) && Objects.equals(sessionId, that.sessionId) &&
Objects.equals(applicationGroup, that.applicationGroup) && Objects.equals(applicationId, that.applicationId)
&& Objects.equals(timestamp, that.timestamp);
}
Expand All @@ -138,6 +138,6 @@ public boolean equals(Object obj) {
*/
@Override
public int hashCode() {
return Objects.hash(action, data, userId, sessionId, applicationGroup, applicationId, timestamp);
return Objects.hash(action, data, user, sessionId, applicationGroup, applicationId, timestamp);
}
}
36 changes: 36 additions & 0 deletions src/main/java/net/staticstudios/audit/AuditUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package net.staticstudios.audit;

import java.util.Objects;
import java.util.UUID;

public class AuditUser {

private final String id;

private AuditUser(String id) {
this.id = id;
}

public static AuditUser of(String id) {
return new AuditUser(id);
}

public static AuditUser of(UUID uuid) {
return new AuditUser(uuid.toString());
}

public String getId() {
return id;
}

@Override
public boolean equals(Object o) {
if (!(o instanceof AuditUser auditUser)) return false;
return Objects.equals(id, auditUser.id);
}

@Override
public int hashCode() {
return Objects.hashCode(id);
}
}
10 changes: 5 additions & 5 deletions src/main/java/net/staticstudios/audit/EncodedAuditLogEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
import java.util.UUID;

public class EncodedAuditLogEntry {
private final @NotNull UUID userId;
private final @NotNull AuditUser user;
private final @Nullable UUID sessionId;
private final @NotNull String applicationGroup;
private final @NotNull String applicationId;
private final @NotNull Instant timestamp;
private final @NotNull String actionId;
private final @NotNull String encodedData;

public EncodedAuditLogEntry(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull String applicationGroup, @NotNull String applicationId, @NotNull Instant timestamp, @NotNull String actionId, @NotNull String encodedData) {
this.userId = userId;
public EncodedAuditLogEntry(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull String applicationGroup, @NotNull String applicationId, @NotNull Instant timestamp, @NotNull String actionId, @NotNull String encodedData) {
this.user = user;
this.sessionId = sessionId;
this.applicationGroup = applicationGroup;
this.applicationId = applicationId;
Expand All @@ -25,8 +25,8 @@ public EncodedAuditLogEntry(@NotNull UUID userId, @Nullable UUID sessionId, @Not
this.encodedData = encodedData;
}

public @NotNull UUID getUserId() {
return userId;
public @NotNull AuditUser getUser() {
return user;
}

public @Nullable UUID getSessionId() {
Expand Down
65 changes: 34 additions & 31 deletions src/main/java/net/staticstudios/audit/StaticAudit.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class StaticAudit {
session_id UUID,
application_group VARCHAR(255) NOT NULL,
application_id VARCHAR(255) NOT NULL,
user_id UUID NOT NULL,
user_id VARCHAR(255) NOT NULL,
action_id VARCHAR(255) NOT NULL,
action_data JSONB
);
Expand All @@ -60,7 +60,9 @@ private StaticAudit(String applicationGroup, String applicationId, String schema

run(connection -> {
logger.info("Creating audit log table... ({}.{})", schemaName, tableName);
String sql = String.format(TABLE_DEF, schemaName, tableName);
String sql = String.format(TABLE_DEF,
schemaName, tableName //CREATE
);
try (Statement statement = connection.createStatement()) {
statement.execute(sql);
logger.trace(sql);
Expand Down Expand Up @@ -159,55 +161,56 @@ public StaticAudit registerAction(Action<?> action) {
/**
* Logs an action to the audit log.
*
* @param userId The ID of the user performing the action.
* @param user The ID of the user performing the action.
* @param sessionId The user's current session ID, if applicable.
* @param timestamp The timestamp of when the action occurred.
* @param action The action being performed.
* @param actionData The data associated with the action.
* @return The StaticAudit instance.
*/
public <T extends ActionData> StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull Instant timestamp, @NotNull Action<T> action, @NotNull T actionData) {
return log(userId, sessionId, timestamp, action.getActionId(), actionData);
public <T extends ActionData> StaticAudit log(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull Instant timestamp, @NotNull Action<T> action, @NotNull T actionData) {
return log(user, sessionId, timestamp, action.getActionId(), actionData);
}

/**
* Logs an action to the audit log.
*
* @param userId The ID of the user performing the action.
* @param user The ID of the user performing the action.
* @param sessionId The user's current session ID, if applicable.
* @param action The action being performed.
* @param actionData The data associated with the action.
* @return The StaticAudit instance.
*/
public <T extends ActionData> StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull Action<T> action, @NotNull T actionData) {
return log(userId, sessionId, Instant.now(), action.getActionId(), actionData);
public <T extends ActionData> StaticAudit log(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull Action<T> action, @NotNull T actionData) {
return log(user, sessionId, Instant.now(), action.getActionId(), actionData);
}

/**
* Logs an action to the audit log.
*
* @param userId The ID of the user performing the action.
* @param user The ID of the user performing the action.
* @param sessionId The user's current session ID, if applicable.
* @param actionId The ID of the action being performed.
* @param actionData The data associated with the action.
* @return The StaticAudit instance.
*/
public StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull String actionId, @NotNull Object actionData) {
return log(userId, sessionId, Instant.now(), actionId, actionData);
public StaticAudit log(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull String actionId, @NotNull Object actionData) {
return log(user, sessionId, Instant.now(), actionId, actionData);
}


/**
* Logs an action to the audit log.
*
* @param userId The ID of the user performing the action.
* @param user The user performing the action.
* @param sessionId The user's current session ID, if applicable.
* @param timestamp The timestamp of when the action occurred.
* @param actionId The ID of the action being performed.
* @param actionData The data associated with the action.
* @return The StaticAudit instance.
*/
public StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull Instant timestamp, @NotNull String actionId, @NotNull Object actionData) {
Preconditions.checkNotNull(userId, "User ID cannot be null");
public StaticAudit log(@NotNull AuditUser user, @Nullable UUID sessionId, @NotNull Instant timestamp, @NotNull String actionId, @NotNull Object actionData) {
Preconditions.checkNotNull(user, "User cannot be null");
Preconditions.checkNotNull(timestamp, "Timestamp cannot be null");
Preconditions.checkNotNull(actionId, "Action ID cannot be null");
Preconditions.checkNotNull(actionData, "Action data cannot be null");
Expand All @@ -224,7 +227,7 @@ public StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull
statement.setObject(3, sessionId);
statement.setString(4, applicationGroup);
statement.setString(5, applicationId);
statement.setObject(6, userId);
statement.setObject(6, user.getId());
statement.setString(7, actionId);
statement.setString(8, actionDataJson);
logger.trace(statement.toString());
Expand All @@ -238,33 +241,33 @@ public StaticAudit log(@NotNull UUID userId, @Nullable UUID sessionId, @NotNull
/**
* Retrieves audit log entries asynchronously for a given user and optional filters.
*
* @param userId The ID of the user whose logs to retrieve.
* @param user The ID of the user whose logs to retrieve.
* @param sessionId The session ID to filter by, or null for any session.
* @param from The start timestamp for filtering, or null for no lower bound.
* @param to The end timestamp for filtering, or null for no upper bound.
* @param actionIds The action IDs to filter by, or null for any action.
* @param limit The maximum number of entries to retrieve.
* @return A CompletableFuture containing the list of matching audit log entries.
*/
public CompletableFuture<List<AuditLogEntry<?>>> retrieveAsync(@NotNull UUID userId, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
public CompletableFuture<List<AuditLogEntry<?>>> retrieveAsync(@NotNull AuditUser user, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
CompletableFuture<List<AuditLogEntry<?>>> future = new CompletableFuture<>();
async(() -> future.complete(retrieve(userId, sessionId, from, to, limit, actionIds)));
async(() -> future.complete(retrieve(user, sessionId, from, to, limit, actionIds)));
return future;
}

/**
* Retrieves audit log entries for a given user and optional filters.
*
* @param userId The ID of the user whose logs to retrieve.
* @param user The ID of the user whose logs to retrieve.
* @param sessionId The session ID to filter by, or null for any session.
* @param from The start timestamp for filtering, or null for no lower bound.
* @param to The end timestamp for filtering, or null for no upper bound.
* @param actionIds The action IDs to filter by, or null for any action.
* @param limit The maximum number of entries to retrieve.
* @return The list of matching audit log entries.
*/
public List<AuditLogEntry<?>> retrieve(@NotNull UUID userId, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
List<EncodedAuditLogEntry> encodedList = retrieveEncoded(userId, sessionId, from, to, limit, actionIds);
public List<AuditLogEntry<?>> retrieve(@NotNull AuditUser user, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
List<EncodedAuditLogEntry> encodedList = retrieveEncoded(user, sessionId, from, to, limit, actionIds);
encodedList.removeIf(encoded -> {
if (!actions.containsKey(encoded.getActionId())) {
logger.warn("Unknown action ID {} in audit log, skipping entry", encoded.getActionId());
Expand All @@ -285,33 +288,33 @@ public List<AuditLogEntry<?>> retrieve(@NotNull UUID userId, @Nullable UUID sess
/**
* Retrieves encoded audit log entries asynchronously for a given user and optional filters.
*
* @param userId The ID of the user whose logs to retrieve.
* @param user The ID of the user whose logs to retrieve.
* @param sessionId The session ID to filter by, or null for any session.
* @param from The start timestamp for filtering, or null for no lower bound.
* @param to The end timestamp for filtering, or null for no upper bound.
* @param actionIds The action IDs to filter by, or null for any action.
* @param limit The maximum number of entries to retrieve.
* @return A CompletableFuture containing the list of matching audit log entries.
*/
public CompletableFuture<List<EncodedAuditLogEntry>> retrieveEncodedAsync(@NotNull UUID userId, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
public CompletableFuture<List<EncodedAuditLogEntry>> retrieveEncodedAsync(@NotNull AuditUser user, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
CompletableFuture<List<EncodedAuditLogEntry>> future = new CompletableFuture<>();
async(() -> future.complete(retrieveEncoded(userId, sessionId, from, to, limit, actionIds)));
async(() -> future.complete(retrieveEncoded(user, sessionId, from, to, limit, actionIds)));
return future;
}

/**
* Retrieves encoded audit log entries for a given user and optional filters.
*
* @param userId The ID of the user whose logs to retrieve.
* @param user The ID of the user whose logs to retrieve.
* @param sessionId The session ID to filter by, or null for any session.
* @param from The start timestamp for filtering, or null for no lower bound.
* @param to The end timestamp for filtering, or null for no upper bound.
* @param actionIds The action IDs to filter by, or null for any action.
* @param limit The maximum number of entries to retrieve.
* @return The list of matching audit log entries.
*/
public List<EncodedAuditLogEntry> retrieveEncoded(@NotNull UUID userId, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
Preconditions.checkNotNull(userId, "User ID cannot be null");
public List<EncodedAuditLogEntry> retrieveEncoded(@NotNull AuditUser user, @Nullable UUID sessionId, @Nullable Instant from, @Nullable Instant to, int limit, String... actionIds) {
Preconditions.checkNotNull(user, "User ID cannot be null");
Preconditions.checkArgument(limit > 0, "Limit must be greater than 0");
List<EncodedAuditLogEntry> entries = new ArrayList<>();

Expand Down Expand Up @@ -340,7 +343,7 @@ public List<EncodedAuditLogEntry> retrieveEncoded(@NotNull UUID userId, @Nullabl
String sql = sqlBuilder.toString().formatted(schemaName, tableName);
try (PreparedStatement statement = connection.prepareStatement(sql)) {
int index = 1;
statement.setObject(index++, userId);
statement.setObject(index++, user.getId());
if (sessionId != null) {
statement.setObject(index++, sessionId);
}
Expand All @@ -359,7 +362,7 @@ public List<EncodedAuditLogEntry> retrieveEncoded(@NotNull UUID userId, @Nullabl
while (rs.next()) {
String _actionId = rs.getString("action_id");
EncodedAuditLogEntry entry = new EncodedAuditLogEntry(
(UUID) rs.getObject("user_id"),
AuditUser.of(rs.getString("user_id")),
(UUID) rs.getObject("session_id"),
rs.getString("application_group"),
rs.getString("application_id"),
Expand All @@ -385,7 +388,7 @@ private <T extends ActionData> T fromJson(Action<T> action, String json) {

private AuditLogEntry<?> createEntry(EncodedAuditLogEntry encoded) {
return createEntry(
encoded.getUserId(),
encoded.getUser(),
encoded.getSessionId(),
encoded.getApplicationGroup(),
encoded.getApplicationId(),
Expand All @@ -396,7 +399,7 @@ private AuditLogEntry<?> createEntry(EncodedAuditLogEntry encoded) {
}

private <T extends ActionData> AuditLogEntry<T> createEntry(
UUID userId, UUID sessionId, String applicationGroup, String applicationId, Instant timestamp,
AuditUser userId, UUID sessionId, String applicationGroup, String applicationId, Instant timestamp,
Action<T> action, String jsonData) {
return new AuditLogEntry<>(userId, sessionId, applicationGroup, applicationId, timestamp,
action, fromJson(action, jsonData));
Expand Down
Loading