Work on audit log redux
This commit is contained in:
parent
f8bf433953
commit
2a5118ee3f
@ -2,22 +2,31 @@ package net.frozenorb.apiv3.auditLog;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.mongodb.async.SingleResultCallback;
|
import com.mongodb.async.SingleResultCallback;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import net.frozenorb.apiv3.actor.Actor;
|
import net.frozenorb.apiv3.actor.Actor;
|
||||||
import net.frozenorb.apiv3.model.AuditLogEntry;
|
import net.frozenorb.apiv3.model.AuditLogEntry;
|
||||||
import net.frozenorb.apiv3.model.User;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class AuditLog {
|
public class AuditLog {
|
||||||
|
|
||||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, SingleResultCallback<AuditLogEntry> callback) {
|
public static void log(UUID performedBy, String performedByIp, RoutingContext ctx, AuditLogActionType actionType, SingleResultCallback<AuditLogEntry> callback) {
|
||||||
log(performedBy, performedByIp, actor, actionType, ImmutableMap.of(), callback);
|
log(performedBy, performedByIp, ctx.get("actor"), ctx.request().remoteAddress().host(), actionType, ImmutableMap.of(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void log(User performedBy, String performedByIp, Actor actor, AuditLogActionType actionType, Map<String, Object> actionData, SingleResultCallback<AuditLogEntry> callback) {
|
public static void log(UUID performedBy, String performedByIp, RoutingContext ctx, AuditLogActionType actionType, Map<String, Object> actionData, SingleResultCallback<AuditLogEntry> callback) {
|
||||||
AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor, actionType, actionData);
|
log(performedBy, performedByIp, ctx.get("actor"), ctx.request().remoteAddress().host(), actionType, actionData, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(UUID performedBy, String performedByIp, Actor actor, String actorIp, AuditLogActionType actionType, SingleResultCallback<AuditLogEntry> callback) {
|
||||||
|
log(performedBy, performedByIp, actor, actorIp, actionType, ImmutableMap.of(), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(UUID performedBy, String performedByIp, Actor actor, String actorIp, AuditLogActionType actionType, Map<String, Object> actionData, SingleResultCallback<AuditLogEntry> callback) {
|
||||||
|
AuditLogEntry entry = new AuditLogEntry(performedBy, performedByIp, actor,actorIp, actionType, actionData);
|
||||||
entry.insert((ignored, error) -> {
|
entry.insert((ignored, error) -> {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
callback.onResult(null, error);
|
callback.onResult(null, error);
|
||||||
|
@ -1,26 +1,49 @@
|
|||||||
package net.frozenorb.apiv3.auditLog;
|
package net.frozenorb.apiv3.auditLog;
|
||||||
|
|
||||||
import com.mongodb.async.SingleResultCallback;
|
import com.mongodb.async.SingleResultCallback;
|
||||||
|
import lombok.Getter;
|
||||||
import net.frozenorb.apiv3.model.AuditLogEntry;
|
import net.frozenorb.apiv3.model.AuditLogEntry;
|
||||||
|
|
||||||
public enum AuditLogActionType {
|
public enum AuditLogActionType {
|
||||||
|
|
||||||
DELETE_PUNISHMENT {
|
BANNED_ASN_CREATE(false),
|
||||||
|
BANNED_ASN_UPDATE(false),
|
||||||
|
BANNED_ASN_DELETE(false),
|
||||||
|
BANNED_CALL_CARRIER_CREATE(false),
|
||||||
|
BANNED_CALL_CARRIER_UPDATE(false),
|
||||||
|
BANNED_CALL_CARRIER_DELETE(false),
|
||||||
|
GRANT_CREATE(false),
|
||||||
|
GRANT_UPDATE(false),
|
||||||
|
GRANT_DELETE(false),
|
||||||
|
IP_BAN_CREATE(false),
|
||||||
|
IP_BAN_UPDATE(false),
|
||||||
|
IP_BAN_DELETE(false),
|
||||||
|
NOTIFICATION_TEMPLATE_CREATE(false),
|
||||||
|
NOTIFICATION_TEMPLATE_UPDATE(false),
|
||||||
|
NOTIFICATION_TEMPLATE_DELETE(false),
|
||||||
|
PUNISHMENT_CREATE(false),
|
||||||
|
PUNISHMENT_UPDATE(false),
|
||||||
|
PUNISHMENT_DELETE(false),
|
||||||
|
RANK_CREATE(false),
|
||||||
|
RANK_UPDATE(false),
|
||||||
|
RANK_DELETE(false),
|
||||||
|
SERVER_GROUP_CREATE(false),
|
||||||
|
SERVER_GROUP_UPDATE(false),
|
||||||
|
SERVER_GROUP_DELETE(false),
|
||||||
|
SERVER_CREATE(false),
|
||||||
|
SERVER_UPDATE(false),
|
||||||
|
SERVER_DELETE(false),
|
||||||
|
USER_CHANGE_PASSWORD(false),
|
||||||
|
USER_PASSWORD_RESET(false),
|
||||||
|
USER_REGISTER(false),
|
||||||
|
USER_SETUP_TOTP(false),
|
||||||
|
USER_VERIFY_TOTP(false);
|
||||||
|
|
||||||
@Override
|
@Getter private boolean reversible;
|
||||||
public void revert(AuditLogEntry entry, SingleResultCallback<Boolean> callback) {
|
|
||||||
callback.onResult(false, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
AuditLogActionType(boolean reversible) {
|
||||||
DELETE_GRANT {
|
this.reversible = reversible;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void revert(AuditLogEntry entry, SingleResultCallback<Boolean> callback) {
|
|
||||||
callback.onResult(false, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
public void revert(AuditLogEntry entry, SingleResultCallback<Boolean> callback) {
|
public void revert(AuditLogEntry entry, SingleResultCallback<Boolean> callback) {
|
||||||
callback.onResult(null, new UnsupportedOperationException());
|
callback.onResult(null, new UnsupportedOperationException());
|
||||||
|
@ -30,6 +30,10 @@ public final class AuditLogEntry {
|
|||||||
@Getter private Instant performedAt;
|
@Getter private Instant performedAt;
|
||||||
@Getter private String actorName;
|
@Getter private String actorName;
|
||||||
@Getter private ActorType actorType;
|
@Getter private ActorType actorType;
|
||||||
|
@Getter private String actorIp;
|
||||||
|
// We store 'reversible' in each object in case later on we go back and
|
||||||
|
// make something reversible (by storing more meta or such)
|
||||||
|
@Getter private boolean reversible;
|
||||||
@Getter private AuditLogActionType type;
|
@Getter private AuditLogActionType type;
|
||||||
@Getter private Map<String, Object> metadata;
|
@Getter private Map<String, Object> metadata;
|
||||||
|
|
||||||
@ -43,13 +47,15 @@ public final class AuditLogEntry {
|
|||||||
|
|
||||||
private AuditLogEntry() {} // For Jackson
|
private AuditLogEntry() {} // For Jackson
|
||||||
|
|
||||||
public AuditLogEntry(User user, String userIp, Actor actor, AuditLogActionType type, Map<String, Object> metadata) {
|
public AuditLogEntry(UUID user, String userIp, Actor actor, String actorIp, AuditLogActionType type, Map<String, Object> metadata) {
|
||||||
this.id = new ObjectId().toString();
|
this.id = new ObjectId().toString();
|
||||||
this.user = user.getId();
|
this.user = user;
|
||||||
this.userIp = userIp;
|
this.userIp = userIp;
|
||||||
this.performedAt = Instant.now();
|
this.performedAt = Instant.now();
|
||||||
this.actorName = actor.getName();
|
this.actorName = actor.getName();
|
||||||
this.actorType = actor.getType();
|
this.actorType = actor.getType();
|
||||||
|
this.actorIp = actorIp;
|
||||||
|
this.reversible = type.isReversible();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.metadata = ImmutableMap.copyOf(metadata);
|
this.metadata = ImmutableMap.copyOf(metadata);
|
||||||
}
|
}
|
||||||
|
@ -18,33 +18,37 @@ public final class POSTAuditLog implements Handler<RoutingContext> {
|
|||||||
User.findById(requestBody.getString("user"), (user, error) -> {
|
User.findById(requestBody.getString("user"), (user, error) -> {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
ErrorUtils.respondInternalError(ctx, error);
|
ErrorUtils.respondInternalError(ctx, error);
|
||||||
} else if (user == null) {
|
return;
|
||||||
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user"));
|
|
||||||
} else {
|
|
||||||
String userIp = requestBody.getString("userIp");
|
|
||||||
|
|
||||||
if (!IpUtils.isValidIp(userIp)) {
|
|
||||||
ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AuditLogActionType type;
|
|
||||||
|
|
||||||
try {
|
|
||||||
type = AuditLogActionType.valueOf(requestBody.getString("type"));
|
|
||||||
} catch (IllegalArgumentException ignored) {
|
|
||||||
ErrorUtils.respondNotFound(ctx, "Audit log action type", requestBody.getString("type"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AuditLog.log(user, userIp, ctx.get("actor"), type, ctx.getBodyAsJson().getMap(), (auditLogEntry, error2) -> {
|
|
||||||
if (error2 != null) {
|
|
||||||
ErrorUtils.respondInternalError(ctx, error2);
|
|
||||||
} else {
|
|
||||||
APIv3.respondJson(ctx, auditLogEntry);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
ErrorUtils.respondNotFound(ctx, "User", requestBody.getString("user"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String userIp = requestBody.getString("userIp");
|
||||||
|
|
||||||
|
if (!IpUtils.isValidIp(userIp)) {
|
||||||
|
ErrorUtils.respondInvalidInput(ctx, "Ip address \"" + userIp + "\" is not valid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuditLogActionType type;
|
||||||
|
|
||||||
|
try {
|
||||||
|
type = AuditLogActionType.valueOf(requestBody.getString("type"));
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
ErrorUtils.respondNotFound(ctx, "Audit log action type", requestBody.getString("type"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuditLog.log(user.getId(), userIp, ctx, type, requestBody.getJsonObject("metadata").getMap(), (auditLogEntry, error2) -> {
|
||||||
|
if (error2 != null) {
|
||||||
|
ErrorUtils.respondInternalError(ctx, error2);
|
||||||
|
} else {
|
||||||
|
APIv3.respondJson(ctx, auditLogEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,10 +49,14 @@ public final class DELETEGrantsId implements Handler<RoutingContext> {
|
|||||||
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
BlockingCallback<UpdateResult> callback = new BlockingCallback<>();
|
||||||
grant.delete(removedBy, reason, callback);
|
grant.delete(removedBy, reason, callback);
|
||||||
callback.get();
|
callback.get();
|
||||||
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_GRANT, ImmutableMap.of(), blockingCallback);
|
AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.GRANT_DELETE,ImmutableMap.of("grantId", grant.getId()), (ignored, error) -> {
|
||||||
blockingCallback.get();
|
if (error != null) {
|
||||||
APIv3.respondJson(ctx, grant);
|
ErrorUtils.respondInternalError(ctx, error);
|
||||||
|
} else {
|
||||||
|
APIv3.respondJson(ctx, grant);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,12 @@
|
|||||||
package net.frozenorb.apiv3.route.grants;
|
package net.frozenorb.apiv3.route.grants;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import net.frozenorb.apiv3.APIv3;
|
import net.frozenorb.apiv3.APIv3;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLog;
|
||||||
|
import net.frozenorb.apiv3.auditLog.AuditLogActionType;
|
||||||
import net.frozenorb.apiv3.model.Grant;
|
import net.frozenorb.apiv3.model.Grant;
|
||||||
import net.frozenorb.apiv3.model.Rank;
|
import net.frozenorb.apiv3.model.Rank;
|
||||||
import net.frozenorb.apiv3.model.ServerGroup;
|
import net.frozenorb.apiv3.model.ServerGroup;
|
||||||
@ -79,7 +82,18 @@ public final class POSTGrants implements Handler<RoutingContext> {
|
|||||||
BlockingCallback<Void> callback = new BlockingCallback<>();
|
BlockingCallback<Void> callback = new BlockingCallback<>();
|
||||||
grant.insert(callback);
|
grant.insert(callback);
|
||||||
callback.get();
|
callback.get();
|
||||||
APIv3.respondJson(ctx, grant);
|
|
||||||
|
if (addedBy != null) {
|
||||||
|
AuditLog.log(addedBy.getId(), requestBody.getString("addedByIp"), ctx, AuditLogActionType.GRANT_CREATE, ImmutableMap.of("grantId", grant.getId()), (ignored, error) -> {
|
||||||
|
if (error != null) {
|
||||||
|
ErrorUtils.respondInternalError(ctx, error);
|
||||||
|
} else {
|
||||||
|
APIv3.respondJson(ctx, grant);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
APIv3.respondJson(ctx, grant);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -50,7 +50,7 @@ public final class DELETEIpBansId implements Handler<RoutingContext> {
|
|||||||
ipBan.delete(removedBy, reason, callback);
|
ipBan.delete(removedBy, reason, callback);
|
||||||
callback.get();
|
callback.get();
|
||||||
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
|
AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.IP_BAN_DELETE, ImmutableMap.of("punishmentId", ipBan.getId()), blockingCallback);
|
||||||
blockingCallback.get();
|
blockingCallback.get();
|
||||||
APIv3.respondJson(ctx, ipBan);
|
APIv3.respondJson(ctx, ipBan);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ public final class DELETEPunishmentsId implements Handler<RoutingContext> {
|
|||||||
punishment.delete(removedBy, reason, removeCallback);
|
punishment.delete(removedBy, reason, removeCallback);
|
||||||
removeCallback.get();
|
removeCallback.get();
|
||||||
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
|
AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.PUNISHMENT_DELETE, ImmutableMap.of("punishmentId", punishment.getId()), blockingCallback);
|
||||||
blockingCallback.get();
|
blockingCallback.get();
|
||||||
APIv3.respondJson(ctx, punishment);
|
APIv3.respondJson(ctx, punishment);
|
||||||
}
|
}
|
||||||
|
@ -50,21 +50,29 @@ public final class DELETEUsersIdActivePunishment implements Handler<RoutingConte
|
|||||||
|
|
||||||
BlockingCallback<List<Punishment>> callback = new BlockingCallback<>();
|
BlockingCallback<List<Punishment>> callback = new BlockingCallback<>();
|
||||||
Punishment.findByUserAndType(target, ImmutableSet.of(type), callback);
|
Punishment.findByUserAndType(target, ImmutableSet.of(type), callback);
|
||||||
|
Punishment activePunishment = null;
|
||||||
|
|
||||||
for (Punishment punishment : callback.get()) {
|
for (Punishment punishment : callback.get()) {
|
||||||
if (punishment.isActive()) {
|
if (punishment.isActive()) {
|
||||||
BlockingCallback<UpdateResult> punishmentCallback = new BlockingCallback<>();
|
activePunishment = punishment;
|
||||||
punishment.delete(removedBy, reason, punishmentCallback);
|
break;
|
||||||
punishmentCallback.get();
|
|
||||||
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
|
||||||
AuditLog.log(removedBy, "", ctx.get("actor"), AuditLogActionType.DELETE_PUNISHMENT, ImmutableMap.of(), blockingCallback);
|
|
||||||
blockingCallback.get();
|
|
||||||
APIv3.respondJson(ctx, punishment);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorUtils.respondGeneric(ctx, 404, "User provided has no active punishments");
|
if (activePunishment == null) {
|
||||||
|
ErrorUtils.respondGeneric(ctx, 404, "User provided has no active punishments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockingCallback<UpdateResult> punishmentCallback = new BlockingCallback<>();
|
||||||
|
activePunishment.delete(removedBy, reason, punishmentCallback);
|
||||||
|
punishmentCallback.get();
|
||||||
|
|
||||||
|
BlockingCallback<AuditLogEntry> blockingCallback = new BlockingCallback<>();
|
||||||
|
AuditLog.log(removedBy.getId(), requestBody.getString("removedByIp"), ctx, AuditLogActionType.PUNISHMENT_DELETE, ImmutableMap.of("punishmentId", activePunishment.getId()), blockingCallback);
|
||||||
|
blockingCallback.get();
|
||||||
|
|
||||||
|
APIv3.respondJson(ctx, activePunishment);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user