From 29a13c1647b2af3c428ab0da2617c9ba8ba9ba77 Mon Sep 17 00:00:00 2001 From: Colin McDonald Date: Mon, 27 Jun 2016 16:55:21 -0400 Subject: [PATCH] Convert authorization to use access tokens. Completes #24 --- apiv3.properties | 4 +- .../net/frozenorb/apiv3/actor/ActorType.java | 2 +- .../frozenorb/apiv3/actor/SimpleActor.java | 13 ++ .../apiv3/actor/actors/BungeeActor.java | 23 ---- .../apiv3/actor/actors/ServerActor.java | 31 ----- .../apiv3/actor/actors/UnknownActor.java | 23 ---- .../apiv3/actor/actors/UserActor.java | 33 ----- .../apiv3/actor/actors/WebsiteActor.java | 23 ---- .../converters/PunishmentConverter.java | 2 +- .../apiv3/handler/ActorAttributeHandler.java | 123 ++++-------------- .../apiv3/handler/AuthorizationHandler.java | 22 +--- .../frozenorb/apiv3/model/AccessToken.java | 77 +++++++++++ .../net/frozenorb/apiv3/model/Server.java | 4 +- .../apiv3/route/servers/DELETEServersId.java | 20 ++- .../apiv3/route/servers/POSTServers.java | 15 ++- .../route/servers/POSTServersHeartbeat.java | 5 +- .../GETUsersIdCompoundedPermissions.java | 3 +- .../apiv3/route/users/POSTUsersIdLeave.java | 3 +- .../apiv3/route/users/POSTUsersIdLogin.java | 3 +- .../frozenorb/apiv3/unsorted/Permissions.java | 1 - .../frozenorb/apiv3/util/PermissionUtils.java | 36 +++-- 21 files changed, 179 insertions(+), 287 deletions(-) create mode 100644 src/main/java/net/frozenorb/apiv3/actor/SimpleActor.java delete mode 100644 src/main/java/net/frozenorb/apiv3/actor/actors/BungeeActor.java delete mode 100644 src/main/java/net/frozenorb/apiv3/actor/actors/ServerActor.java delete mode 100644 src/main/java/net/frozenorb/apiv3/actor/actors/UnknownActor.java delete mode 100644 src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java delete mode 100644 src/main/java/net/frozenorb/apiv3/actor/actors/WebsiteActor.java create mode 100644 src/main/java/net/frozenorb/apiv3/model/AccessToken.java diff --git a/apiv3.properties b/apiv3.properties index 7db7b9f..91d5af4 100644 --- a/apiv3.properties +++ b/apiv3.properties @@ -10,6 +10,4 @@ mandrill.apiKey=0OYtwymqJP6oqvszeJu0vQ maxMind.userId=66817 maxMind.maxMindLicenseKey=8Aw9NsOUeOp7 zang.accountSid=ACf18890845596403e330944d98886440c -zang.authToken=dc70bbd1fbd8411ba133fa93813a461b -auth.websiteApiKey=RVbp4hY6sCFVaf -auth.bungeeApiKey=6d9cf76dc9f0d23 \ No newline at end of file +zang.authToken=dc70bbd1fbd8411ba133fa93813a461b \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/ActorType.java b/src/main/java/net/frozenorb/apiv3/actor/ActorType.java index 84d6771..77e5b80 100644 --- a/src/main/java/net/frozenorb/apiv3/actor/ActorType.java +++ b/src/main/java/net/frozenorb/apiv3/actor/ActorType.java @@ -2,6 +2,6 @@ package net.frozenorb.apiv3.actor; public enum ActorType { - WEBSITE, BUNGEE, SERVER, USER, UNKNOWN + WEBSITE, BUNGEE_CORD, SERVER, UNKNOWN } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/SimpleActor.java b/src/main/java/net/frozenorb/apiv3/actor/SimpleActor.java new file mode 100644 index 0000000..6fbc846 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/actor/SimpleActor.java @@ -0,0 +1,13 @@ +package net.frozenorb.apiv3.actor; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public final class SimpleActor implements Actor { + + @Getter private String name; + @Getter private ActorType type; + @Getter private boolean authorized; + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/BungeeActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/BungeeActor.java deleted file mode 100644 index 9237855..0000000 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/BungeeActor.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.frozenorb.apiv3.actor.actors; - -import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; - -public final class BungeeActor implements Actor { - - @Override - public boolean isAuthorized() { - return true; - } - - @Override - public String getName() { - return "Bungee"; - } - - @Override - public ActorType getType() { - return ActorType.BUNGEE; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/ServerActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/ServerActor.java deleted file mode 100644 index 8e69fe6..0000000 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/ServerActor.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.frozenorb.apiv3.actor.actors; - -import lombok.Getter; -import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.model.Server; - -public final class ServerActor implements Actor { - - @Getter private final Server server; - - public ServerActor(Server server) { - this.server = server; - } - - @Override - public boolean isAuthorized() { - return true; - } - - @Override - public String getName() { - return server.getId(); - } - - @Override - public ActorType getType() { - return ActorType.SERVER; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/UnknownActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/UnknownActor.java deleted file mode 100644 index 39705c1..0000000 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/UnknownActor.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.frozenorb.apiv3.actor.actors; - -import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; - -public final class UnknownActor implements Actor { - - @Override - public boolean isAuthorized() { - return false; - } - - @Override - public String getName() { - return "Unknown"; - } - - @Override - public ActorType getType() { - return ActorType.UNKNOWN; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java deleted file mode 100644 index 9374302..0000000 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/UserActor.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.frozenorb.apiv3.actor.actors; - -import lombok.Getter; -import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.model.User; - -public final class UserActor implements Actor { - - @Getter private final User user; - private final boolean authorized; - - public UserActor(User user, boolean authorized) { - this.user = user; - this.authorized = authorized; - } - - @Override - public boolean isAuthorized() { - return authorized; - } - - @Override - public String getName() { - return user.getLastUsername(); - } - - @Override - public ActorType getType() { - return ActorType.USER; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/actor/actors/WebsiteActor.java b/src/main/java/net/frozenorb/apiv3/actor/actors/WebsiteActor.java deleted file mode 100644 index 9abed7d..0000000 --- a/src/main/java/net/frozenorb/apiv3/actor/actors/WebsiteActor.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.frozenorb.apiv3.actor.actors; - -import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; - -public final class WebsiteActor implements Actor { - - @Override - public boolean isAuthorized() { - return true; - } - - @Override - public String getName() { - return "Website"; - } - - @Override - public ActorType getType() { - return ActorType.WEBSITE; - } - -} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java b/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java index cde80af..aa41514 100644 --- a/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java +++ b/src/main/java/net/frozenorb/apiv3/dataImport/converters/PunishmentConverter.java @@ -46,7 +46,7 @@ public final class PunishmentConverter implements Block { null, punishment.containsKey("addedBy") ? oidToUniqueId.get(((Map) punishment.get("addedBy")).get("$id")) : null, punishment.getDate("created").toInstant(), - punishment.containsKey("createdOn") ? String.valueOf(((Map) punishment.get("createdOn")).get("$id")) : "Website", + punishment.containsKey("createdOn") ? String.valueOf(((Map) punishment.get("createdOn")).get("$id")) : "Old Website", punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE, punishment.containsKey("removedBy") ? (((Map) punishment.get("removedBy")).get("$ref").equals("user") ? oidToUniqueId.get(((Map) punishment.get("removedBy")).get("$id")) : null) : null, punishment.containsKey("removedBy") ? (punishment.containsKey("removedAt") ? punishment.getDate("removedAt") : punishment.getDate("created")).toInstant() : null, diff --git a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java index 20a67f9..57a6950 100644 --- a/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java +++ b/src/main/java/net/frozenorb/apiv3/handler/ActorAttributeHandler.java @@ -1,133 +1,58 @@ package net.frozenorb.apiv3.handler; -import com.google.common.base.Charsets; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; -import net.frozenorb.apiv3.APIv3; -import net.frozenorb.apiv3.actor.actors.*; -import net.frozenorb.apiv3.model.Server; -import net.frozenorb.apiv3.model.User; -import net.frozenorb.apiv3.unsorted.Permissions; +import net.frozenorb.apiv3.actor.ActorType; +import net.frozenorb.apiv3.actor.SimpleActor; +import net.frozenorb.apiv3.model.AccessToken; import net.frozenorb.apiv3.util.ErrorUtils; -import java.util.Base64; - public final class ActorAttributeHandler implements Handler { @Override public void handle(RoutingContext ctx) { - String authorizationHeader = ctx.request().getHeader("Authorization"); String mhqAuthorizationHeader = ctx.request().getHeader("MHQ-Authorization"); - if (authorizationHeader != null) { - processBasicAuthorization(authorizationHeader, ctx); - } else if (mhqAuthorizationHeader != null) { + if (mhqAuthorizationHeader != null) { processMHQAuthorization(mhqAuthorizationHeader, ctx); } else { processNoAuthorization(ctx); } } - private void processBasicAuthorization(String authHeader, RoutingContext ctx) { - String encodedHeader = authHeader.substring("Basic ".length()); - String decodedHeader = new String(Base64.getDecoder().decode(encodedHeader.getBytes(Charsets.UTF_8)), Charsets.UTF_8); - String[] splitHeader = decodedHeader.split(":"); - - if (splitHeader.length != 2) { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize."); + private void processMHQAuthorization(String accessTokenString, RoutingContext ctx) { + if (accessTokenString == null || accessTokenString.isEmpty()) { + ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize: Key not provided"); return; } - String username = splitHeader[0]; - String password = splitHeader[1]; - - User.findByLastUsername(username, (user, error) -> { + AccessToken.findById(accessTokenString, (accessToken, error) -> { if (error != null) { ErrorUtils.respondInternalError(ctx, error); return; } - if (user != null && user.checkPassword(password)) { - user.hasPermissionAnywhere(Permissions.SIGN_API_REQUEST, (hasPermission, error2) -> { - if (error2 != null) { - ErrorUtils.respondInternalError(ctx, error2); - } else { - ctx.put("actor", new UserActor(user, hasPermission)); - ctx.next(); - } - }); - } else { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as " + username + "."); + if (accessToken == null) { + ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize."); + return; } + + if (!accessToken.getLockedIps().isEmpty()) { + boolean allowed = accessToken.getLockedIps().contains(ctx.request().remoteAddress().host()); + + if (!allowed) { + ErrorUtils.respondGeneric(ctx, 401, "Your ip address is not authenticated to use the provided access token."); + return; + } + } + + ctx.put("actor", new SimpleActor(accessToken.getActorName(), accessToken.getActorType(), true)); + ctx.next(); }); } - private void processMHQAuthorization(String authHeader, RoutingContext ctx) { - String[] splitHeader = authHeader.split(" "); - - if (splitHeader.length < 2) { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize."); - return; - } - - String type = splitHeader[0]; - - switch (type.toLowerCase()) { - case "website": - String givenWebsiteKey = splitHeader[1]; - String properWebsiteKey = APIv3.getConfig().getProperty("auth.websiteApiKey"); - - if (givenWebsiteKey.equals(properWebsiteKey)) { - ctx.put("actor", new WebsiteActor()); - ctx.next(); - } else { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as website."); - } - - break; - case "server": - Server server = Server.findById(splitHeader[1]); - - if (server == null) { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize: Server " + splitHeader[1] + " not found"); - return; - } - - if (splitHeader.length != 3) { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize: Key not provided"); - return; - } - - String givenServerKey = splitHeader[2]; - - if (givenServerKey.equals(server.getApiKey())) { - ctx.put("actor", new ServerActor(server)); - ctx.next(); - } else { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as " + server.getId() + "."); - } - - break; - case "bungee": - String givenBungeeKey = splitHeader[1]; - String properBungeeKey = APIv3.getConfig().getProperty("auth.bungeeApiKey"); - - if (givenBungeeKey.equals(properBungeeKey)) { - ctx.put("actor", new BungeeActor()); - ctx.next(); - } else { - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as bungee."); - } - - break; - default: - ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize as " + type + "."); - break; - } - } - private void processNoAuthorization(RoutingContext ctx) { - ctx.put("actor", new UnknownActor()); + ctx.put("actor", new SimpleActor("UNKNOWN", ActorType.UNKNOWN, false)); ctx.next(); } diff --git a/src/main/java/net/frozenorb/apiv3/handler/AuthorizationHandler.java b/src/main/java/net/frozenorb/apiv3/handler/AuthorizationHandler.java index e14a97f..51f6e40 100644 --- a/src/main/java/net/frozenorb/apiv3/handler/AuthorizationHandler.java +++ b/src/main/java/net/frozenorb/apiv3/handler/AuthorizationHandler.java @@ -3,9 +3,6 @@ package net.frozenorb.apiv3.handler; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.actor.Actor; -import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.actor.actors.ServerActor; -import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.util.ErrorUtils; public final class AuthorizationHandler implements Handler { @@ -14,24 +11,11 @@ public final class AuthorizationHandler implements Handler { public void handle(RoutingContext ctx) { Actor actor = ctx.get("actor"); - if (!actor.isAuthorized()) { + if (actor.isAuthorized()) { + ctx.next(); + } else { ErrorUtils.respondGeneric(ctx, 403, "Please authorize as an approved actor. You're currently authorized as " + actor.getName() + " (" + actor.getType() + ")"); - return; } - - if (actor.getType() == ActorType.SERVER) { - Server server = ((ServerActor) actor).getServer(); - String[] serverAddress = server.getServerIp().split(":"); - String expectedHost = serverAddress[0]; - String remoteHost = ctx.request().remoteAddress().host(); - - if (!expectedHost.equals(remoteHost)) { - ErrorUtils.respondGeneric(ctx, 403, "Failed to authorize: Cannot authorize as " + server.getId() + " from given ip."); - return; - } - } - - ctx.next(); } } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/AccessToken.java b/src/main/java/net/frozenorb/apiv3/model/AccessToken.java new file mode 100644 index 0000000..827a254 --- /dev/null +++ b/src/main/java/net/frozenorb/apiv3/model/AccessToken.java @@ -0,0 +1,77 @@ +package net.frozenorb.apiv3.model; + +import com.google.common.collect.ImmutableList; +import com.mongodb.async.SingleResultCallback; +import com.mongodb.async.client.MongoCollection; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import fr.javatic.mongo.jacksonCodec.Entity; +import fr.javatic.mongo.jacksonCodec.objectId.Id; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.actor.Actor; +import net.frozenorb.apiv3.actor.ActorType; +import net.frozenorb.apiv3.maxmind.MaxMindResult; +import net.frozenorb.apiv3.util.MaxMindUtils; +import org.bson.Document; + +import java.time.Instant; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +@Entity +@AllArgsConstructor +public final class AccessToken { + + private static final MongoCollection accessTokensCollection = APIv3.getDatabase().getCollection("accessTokens", AccessToken.class); + + @Getter @Id private String id; + @Getter private String actorName; + @Getter private ActorType actorType; + @Getter private List lockedIps; + @Getter private Instant createdAt; + @Getter private Instant lastUpdatedAt; + + public static void findAll(SingleResultCallback> callback) { + accessTokensCollection.find().into(new LinkedList<>(), callback); + } + + public static void findById(String id, SingleResultCallback callback) { + accessTokensCollection.find(new Document("_id", id)).first(callback); + } + + public static void findByNameAndType(String actorName, ActorType actorType, SingleResultCallback callback) { + accessTokensCollection.find(new Document("actorName", actorName).append("actorType", actorType.name())).first(callback); + } + + private AccessToken() {} // For Jackson + + public AccessToken(Server server) { + // Can't extract server host code to another line because the call to another constructor must be on the first line. + this(UUID.randomUUID().toString().replace("-", ""), server.getId(), ActorType.SERVER, ImmutableList.of(server.getServerIp().split(":")[0])); + } + + public AccessToken(String id, String actorName, ActorType actorType, List lockedIps) { + this.id = id; + this.actorName = actorName; + this.actorType = actorType; + this.lockedIps = lockedIps; + this.createdAt = Instant.now(); + this.lastUpdatedAt = Instant.now(); + } + + public void insert(SingleResultCallback callback) { + accessTokensCollection.insertOne(this, callback); + } + + public void save(SingleResultCallback callback) { + accessTokensCollection.replaceOne(new Document("_id", id), this, callback); + } + + public void delete(SingleResultCallback callback) { + accessTokensCollection.deleteOne(new Document("_id", id), callback); + } + +} \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/model/Server.java b/src/main/java/net/frozenorb/apiv3/model/Server.java index 227f4af..5ac1304 100644 --- a/src/main/java/net/frozenorb/apiv3/model/Server.java +++ b/src/main/java/net/frozenorb/apiv3/model/Server.java @@ -27,7 +27,6 @@ public final class Server { @Getter @Id private String id; @Getter private String displayName; - @Getter @ExcludeFromReplies String apiKey; @Getter private String serverGroup; @Getter private String serverIp; @Getter private Instant lastUpdatedAt; @@ -103,10 +102,9 @@ public final class Server { private Server() {} // For Jackson - public Server(String id, String displayName, String apiKey, ServerGroup serverGroup, String serverIp) { + public Server(String id, String displayName, ServerGroup serverGroup, String serverIp) { this.id = id; this.displayName = displayName; - this.apiKey = apiKey; this.serverGroup = serverGroup.getId(); this.serverIp = serverIp; this.lastUpdatedAt = Instant.now(); diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java b/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java index 2fc3bc6..9cb7094 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/DELETEServersId.java @@ -6,8 +6,10 @@ import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; +import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; +import net.frozenorb.apiv3.model.AccessToken; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.util.ErrorUtils; @@ -24,9 +26,21 @@ public final class DELETEServersId implements Handler { return; } - BlockingCallback callback = new BlockingCallback<>(); - server.delete(callback); - callback.get(); + BlockingCallback deleteServerCallback = new BlockingCallback<>(); + server.delete(deleteServerCallback); + deleteServerCallback.get(); + + BlockingCallback deleteAccessTokenCallback = new BlockingCallback<>(); + AccessToken.findByNameAndType(server.getId(), ActorType.SERVER, (accessToken, error) -> { + if (error != null) { + deleteAccessTokenCallback.onResult(null, error); + } else if (accessToken != null) { + accessToken.delete(deleteServerCallback); + } else { + deleteAccessTokenCallback.onResult(null, new NullPointerException("Access token not found.")); + } + }); + deleteAccessTokenCallback.get(); JsonObject requestBody = ctx.getBodyAsJson(); diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java index 97a29e4..6184f43 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServers.java @@ -7,6 +7,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLogActionType; +import net.frozenorb.apiv3.model.AccessToken; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.ServerGroup; import net.frozenorb.apiv3.unsorted.BlockingCallback; @@ -34,11 +35,15 @@ public final class POSTServers implements Handler { return; } - String generatedApiKey = UUID.randomUUID().toString(); - Server server = new Server(id, displayName, generatedApiKey, group, ip); - BlockingCallback callback = new BlockingCallback<>(); - server.insert(callback); - callback.get(); + Server server = new Server(id, displayName, group, ip); + BlockingCallback insertServerCallback = new BlockingCallback<>(); + server.insert(insertServerCallback); + insertServerCallback.get(); + + AccessToken accessToken = new AccessToken(server); + BlockingCallback insertAccessTokenCallback = new BlockingCallback<>(); + accessToken.insert(insertAccessTokenCallback); + insertAccessTokenCallback.get(); if (requestBody.containsKey("addedBy")) { AuditLog.log(UUID.fromString(requestBody.getString("addedBy")), requestBody.getString("addedByIp"), ctx, AuditLogActionType.SERVER_CREATE, ImmutableMap.of("serverId", id), (ignored, error) -> { diff --git a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java index 135e3df..1f3072f 100644 --- a/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java +++ b/src/main/java/net/frozenorb/apiv3/route/servers/POSTServersHeartbeat.java @@ -12,7 +12,6 @@ import lombok.extern.slf4j.Slf4j; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.actor.actors.ServerActor; import net.frozenorb.apiv3.model.*; import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; import net.frozenorb.apiv3.util.ErrorUtils; @@ -35,7 +34,7 @@ public final class POSTServersHeartbeat implements Handler { return; } - Server actorServer = ((ServerActor) actor).getServer(); + Server actorServer = Server.findById(actor.getName()); ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup()); JsonObject requestBody = ctx.getBodyAsJson(); Map playerNames = extractPlayerNames(requestBody.getJsonObject("players")); @@ -132,7 +131,7 @@ public final class POSTServersHeartbeat implements Handler { serverGroup.calculateScopedPermissions(rank) ); - permissionsResponse.put(rank.getId(), scopedPermissions); + permissionsResponse.put(rank.getId(), PermissionUtils.convertToList(scopedPermissions)); } callback.complete(permissionsResponse); diff --git a/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdCompoundedPermissions.java b/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdCompoundedPermissions.java index dc0bb53..cb1332c 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdCompoundedPermissions.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/GETUsersIdCompoundedPermissions.java @@ -5,6 +5,7 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.util.ErrorUtils; +import net.frozenorb.apiv3.util.PermissionUtils; public final class GETUsersIdCompoundedPermissions implements Handler { @@ -19,7 +20,7 @@ public final class GETUsersIdCompoundedPermissions implements Handler { return; } - Server actorServer = ((ServerActor) actor).getServer(); + Server actorServer = Server.findById(actor.getName()); User.findById(ctx.request().getParam("id"), ((user, error) -> { if (error != null) { diff --git a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java index b59fe64..49f57d5 100644 --- a/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java +++ b/src/main/java/net/frozenorb/apiv3/route/users/POSTUsersIdLogin.java @@ -7,7 +7,6 @@ import io.vertx.ext.web.RoutingContext; import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.ActorType; -import net.frozenorb.apiv3.actor.actors.ServerActor; import net.frozenorb.apiv3.model.IpLogEntry; import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.User; @@ -41,7 +40,7 @@ public final class POSTUsersIdLogin implements Handler { return; } - Server actorServer = ((ServerActor) actor).getServer(); + Server actorServer = Server.findById(actor.getName()); if (!IpUtils.isValidIp(userIp)) { ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); diff --git a/src/main/java/net/frozenorb/apiv3/unsorted/Permissions.java b/src/main/java/net/frozenorb/apiv3/unsorted/Permissions.java index b93774b..2bbe8fc 100644 --- a/src/main/java/net/frozenorb/apiv3/unsorted/Permissions.java +++ b/src/main/java/net/frozenorb/apiv3/unsorted/Permissions.java @@ -6,7 +6,6 @@ import lombok.experimental.UtilityClass; public class Permissions { public static final String PROTECTED_PUNISHMENT = "minehq.punishment.protected"; - public static final String SIGN_API_REQUEST = "apiv3.signRequest"; public static final String BYPASS_VPN_CHECK = "minehq.vpn.bypass"; } \ No newline at end of file diff --git a/src/main/java/net/frozenorb/apiv3/util/PermissionUtils.java b/src/main/java/net/frozenorb/apiv3/util/PermissionUtils.java index 7186b39..3da886f 100644 --- a/src/main/java/net/frozenorb/apiv3/util/PermissionUtils.java +++ b/src/main/java/net/frozenorb/apiv3/util/PermissionUtils.java @@ -1,6 +1,8 @@ package net.frozenorb.apiv3.util; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import io.vertx.core.cli.converters.BooleanConverter; import lombok.experimental.UtilityClass; import net.frozenorb.apiv3.model.Rank; @@ -31,7 +33,7 @@ public class PermissionUtils { } for (Rank rank : mergeQueue) { - Map rankPermissions = convertToMap(raw.get(rank.getId())); + Map rankPermissions = convertFromList(raw.get(rank.getId())); // If there's no permissions defined for this rank just skip it. if (!rankPermissions.isEmpty()) { @@ -47,24 +49,36 @@ public class PermissionUtils { return ImmutableMap.of(); } - private static Map convertToMap(List unconvered) { - if (unconvered == null) { + private static Map convertFromList(List permissionsList) { + if (permissionsList == null) { return ImmutableMap.of(); } - Map result = new HashMap<>(); + Map permissionsMap = new HashMap<>(); - for (String permission : unconvered) { - boolean negate = permission.startsWith("-"); - - if (negate) { - result.put(permission.substring(1), false); + permissionsList.forEach((permission) -> { + if (permission.startsWith("-")) { + permissionsMap.put(permission.substring(1), false); } else { - result.put(permission, true); + permissionsMap.put(permission, true); } + }); + + return permissionsMap; + } + + public static List convertToList(Map permissionsMap) { + if (permissionsMap == null) { + return ImmutableList.of(); } - return result; + List permissionsList = new LinkedList<>(); + + permissionsMap.forEach((permission, granted) -> { + permissionsList.add((granted ? "" : "-") + permission); + }); + + return permissionsList; } } \ No newline at end of file