Convert authorization to use access tokens. Completes #24

This commit is contained in:
Colin McDonald 2016-06-27 16:55:21 -04:00
parent bcae144e8c
commit 29a13c1647
21 changed files with 179 additions and 287 deletions

View File

@ -11,5 +11,3 @@ maxMind.userId=66817
maxMind.maxMindLicenseKey=8Aw9NsOUeOp7 maxMind.maxMindLicenseKey=8Aw9NsOUeOp7
zang.accountSid=ACf18890845596403e330944d98886440c zang.accountSid=ACf18890845596403e330944d98886440c
zang.authToken=dc70bbd1fbd8411ba133fa93813a461b zang.authToken=dc70bbd1fbd8411ba133fa93813a461b
auth.websiteApiKey=RVbp4hY6sCFVaf
auth.bungeeApiKey=6d9cf76dc9f0d23

View File

@ -2,6 +2,6 @@ package net.frozenorb.apiv3.actor;
public enum ActorType { public enum ActorType {
WEBSITE, BUNGEE, SERVER, USER, UNKNOWN WEBSITE, BUNGEE_CORD, SERVER, UNKNOWN
} }

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -46,7 +46,7 @@ public final class PunishmentConverter implements Block<Document> {
null, null,
punishment.containsKey("addedBy") ? oidToUniqueId.get(((Map<String, Object>) punishment.get("addedBy")).get("$id")) : null, punishment.containsKey("addedBy") ? oidToUniqueId.get(((Map<String, Object>) punishment.get("addedBy")).get("$id")) : null,
punishment.getDate("created").toInstant(), punishment.getDate("created").toInstant(),
punishment.containsKey("createdOn") ? String.valueOf(((Map<String, Object>) punishment.get("createdOn")).get("$id")) : "Website", punishment.containsKey("createdOn") ? String.valueOf(((Map<String, Object>) punishment.get("createdOn")).get("$id")) : "Old Website",
punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE, punishment.containsKey("createdOn") ? ActorType.SERVER : ActorType.WEBSITE,
punishment.containsKey("removedBy") ? (((Map<String, Object>) punishment.get("removedBy")).get("$ref").equals("user") ? oidToUniqueId.get(((Map<String, Object>) punishment.get("removedBy")).get("$id")) : null) : null, punishment.containsKey("removedBy") ? (((Map<String, Object>) punishment.get("removedBy")).get("$ref").equals("user") ? oidToUniqueId.get(((Map<String, Object>) punishment.get("removedBy")).get("$id")) : null) : null,
punishment.containsKey("removedBy") ? (punishment.containsKey("removedAt") ? punishment.getDate("removedAt") : punishment.getDate("created")).toInstant() : null, punishment.containsKey("removedBy") ? (punishment.containsKey("removedAt") ? punishment.getDate("removedAt") : punishment.getDate("created")).toInstant() : null,

View File

@ -1,133 +1,58 @@
package net.frozenorb.apiv3.handler; package net.frozenorb.apiv3.handler;
import com.google.common.base.Charsets;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.actor.actors.*; import net.frozenorb.apiv3.actor.SimpleActor;
import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.unsorted.Permissions;
import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.ErrorUtils;
import java.util.Base64;
public final class ActorAttributeHandler implements Handler<RoutingContext> { public final class ActorAttributeHandler implements Handler<RoutingContext> {
@Override @Override
public void handle(RoutingContext ctx) { public void handle(RoutingContext ctx) {
String authorizationHeader = ctx.request().getHeader("Authorization");
String mhqAuthorizationHeader = ctx.request().getHeader("MHQ-Authorization"); String mhqAuthorizationHeader = ctx.request().getHeader("MHQ-Authorization");
if (authorizationHeader != null) { if (mhqAuthorizationHeader != null) {
processBasicAuthorization(authorizationHeader, ctx);
} else if (mhqAuthorizationHeader != null) {
processMHQAuthorization(mhqAuthorizationHeader, ctx); processMHQAuthorization(mhqAuthorizationHeader, ctx);
} else { } else {
processNoAuthorization(ctx); processNoAuthorization(ctx);
} }
} }
private void processBasicAuthorization(String authHeader, RoutingContext ctx) { private void processMHQAuthorization(String accessTokenString, RoutingContext ctx) {
String encodedHeader = authHeader.substring("Basic ".length()); if (accessTokenString == null || accessTokenString.isEmpty()) {
String decodedHeader = new String(Base64.getDecoder().decode(encodedHeader.getBytes(Charsets.UTF_8)), Charsets.UTF_8); ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize: Key not provided");
String[] splitHeader = decodedHeader.split(":");
if (splitHeader.length != 2) {
ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize.");
return; return;
} }
String username = splitHeader[0]; AccessToken.findById(accessTokenString, (accessToken, error) -> {
String password = splitHeader[1];
User.findByLastUsername(username, (user, error) -> {
if (error != null) { if (error != null) {
ErrorUtils.respondInternalError(ctx, error); ErrorUtils.respondInternalError(ctx, error);
return; return;
} }
if (user != null && user.checkPassword(password)) { if (accessToken == null) {
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 + ".");
}
});
}
private void processMHQAuthorization(String authHeader, RoutingContext ctx) {
String[] splitHeader = authHeader.split(" ");
if (splitHeader.length < 2) {
ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize."); ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize.");
return; return;
} }
String type = splitHeader[0]; if (!accessToken.getLockedIps().isEmpty()) {
boolean allowed = accessToken.getLockedIps().contains(ctx.request().remoteAddress().host());
switch (type.toLowerCase()) { if (!allowed) {
case "website": ErrorUtils.respondGeneric(ctx, 401, "Your ip address is not authenticated to use the provided access token.");
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; return;
} }
if (splitHeader.length != 3) {
ErrorUtils.respondGeneric(ctx, 401, "Failed to authorize: Key not provided");
return;
} }
String givenServerKey = splitHeader[2]; ctx.put("actor", new SimpleActor(accessToken.getActorName(), accessToken.getActorType(), true));
if (givenServerKey.equals(server.getApiKey())) {
ctx.put("actor", new ServerActor(server));
ctx.next(); 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) { private void processNoAuthorization(RoutingContext ctx) {
ctx.put("actor", new UnknownActor()); ctx.put("actor", new SimpleActor("UNKNOWN", ActorType.UNKNOWN, false));
ctx.next(); ctx.next();
} }

View File

@ -3,9 +3,6 @@ package net.frozenorb.apiv3.handler;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.actor.Actor; 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; import net.frozenorb.apiv3.util.ErrorUtils;
public final class AuthorizationHandler implements Handler<RoutingContext> { public final class AuthorizationHandler implements Handler<RoutingContext> {
@ -14,24 +11,11 @@ public final class AuthorizationHandler implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) { public void handle(RoutingContext ctx) {
Actor actor = ctx.get("actor"); Actor actor = ctx.get("actor");
if (!actor.isAuthorized()) { if (actor.isAuthorized()) {
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(); ctx.next();
} else {
ErrorUtils.respondGeneric(ctx, 403, "Please authorize as an approved actor. You're currently authorized as " + actor.getName() + " (" + actor.getType() + ")");
}
} }
} }

View File

@ -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<AccessToken> accessTokensCollection = APIv3.getDatabase().getCollection("accessTokens", AccessToken.class);
@Getter @Id private String id;
@Getter private String actorName;
@Getter private ActorType actorType;
@Getter private List<String> lockedIps;
@Getter private Instant createdAt;
@Getter private Instant lastUpdatedAt;
public static void findAll(SingleResultCallback<List<AccessToken>> callback) {
accessTokensCollection.find().into(new LinkedList<>(), callback);
}
public static void findById(String id, SingleResultCallback<AccessToken> callback) {
accessTokensCollection.find(new Document("_id", id)).first(callback);
}
public static void findByNameAndType(String actorName, ActorType actorType, SingleResultCallback<AccessToken> 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<String> 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<Void> callback) {
accessTokensCollection.insertOne(this, callback);
}
public void save(SingleResultCallback<UpdateResult> callback) {
accessTokensCollection.replaceOne(new Document("_id", id), this, callback);
}
public void delete(SingleResultCallback<DeleteResult> callback) {
accessTokensCollection.deleteOne(new Document("_id", id), callback);
}
}

View File

@ -27,7 +27,6 @@ public final class Server {
@Getter @Id private String id; @Getter @Id private String id;
@Getter private String displayName; @Getter private String displayName;
@Getter @ExcludeFromReplies String apiKey;
@Getter private String serverGroup; @Getter private String serverGroup;
@Getter private String serverIp; @Getter private String serverIp;
@Getter private Instant lastUpdatedAt; @Getter private Instant lastUpdatedAt;
@ -103,10 +102,9 @@ public final class Server {
private Server() {} // For Jackson 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.id = id;
this.displayName = displayName; this.displayName = displayName;
this.apiKey = apiKey;
this.serverGroup = serverGroup.getId(); this.serverGroup = serverGroup.getId();
this.serverIp = serverIp; this.serverIp = serverIp;
this.lastUpdatedAt = Instant.now(); this.lastUpdatedAt = Instant.now();

View File

@ -6,8 +6,10 @@ 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.actor.ActorType;
import net.frozenorb.apiv3.auditLog.AuditLog; import net.frozenorb.apiv3.auditLog.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.BlockingCallback;
import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.ErrorUtils;
@ -24,9 +26,21 @@ public final class DELETEServersId implements Handler<RoutingContext> {
return; return;
} }
BlockingCallback<DeleteResult> callback = new BlockingCallback<>(); BlockingCallback<DeleteResult> deleteServerCallback = new BlockingCallback<>();
server.delete(callback); server.delete(deleteServerCallback);
callback.get(); deleteServerCallback.get();
BlockingCallback<DeleteResult> 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(); JsonObject requestBody = ctx.getBodyAsJson();

View File

@ -7,6 +7,7 @@ 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.AuditLog;
import net.frozenorb.apiv3.auditLog.AuditLogActionType; import net.frozenorb.apiv3.auditLog.AuditLogActionType;
import net.frozenorb.apiv3.model.AccessToken;
import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.ServerGroup; import net.frozenorb.apiv3.model.ServerGroup;
import net.frozenorb.apiv3.unsorted.BlockingCallback; import net.frozenorb.apiv3.unsorted.BlockingCallback;
@ -34,11 +35,15 @@ public final class POSTServers implements Handler<RoutingContext> {
return; return;
} }
String generatedApiKey = UUID.randomUUID().toString(); Server server = new Server(id, displayName, group, ip);
Server server = new Server(id, displayName, generatedApiKey, group, ip); BlockingCallback<Void> insertServerCallback = new BlockingCallback<>();
BlockingCallback<Void> callback = new BlockingCallback<>(); server.insert(insertServerCallback);
server.insert(callback); insertServerCallback.get();
callback.get();
AccessToken accessToken = new AccessToken(server);
BlockingCallback<Void> insertAccessTokenCallback = new BlockingCallback<>();
accessToken.insert(insertAccessTokenCallback);
insertAccessTokenCallback.get();
if (requestBody.containsKey("addedBy")) { if (requestBody.containsKey("addedBy")) {
AuditLog.log(UUID.fromString(requestBody.getString("addedBy")), requestBody.getString("addedByIp"), ctx, AuditLogActionType.SERVER_CREATE, ImmutableMap.of("serverId", id), (ignored, error) -> { AuditLog.log(UUID.fromString(requestBody.getString("addedBy")), requestBody.getString("addedByIp"), ctx, AuditLogActionType.SERVER_CREATE, ImmutableMap.of("serverId", id), (ignored, error) -> {

View File

@ -12,7 +12,6 @@ import lombok.extern.slf4j.Slf4j;
import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.actor.actors.ServerActor;
import net.frozenorb.apiv3.model.*; import net.frozenorb.apiv3.model.*;
import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback; import net.frozenorb.apiv3.unsorted.FutureCompatibilityCallback;
import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.ErrorUtils;
@ -35,7 +34,7 @@ public final class POSTServersHeartbeat implements Handler<RoutingContext> {
return; return;
} }
Server actorServer = ((ServerActor) actor).getServer(); Server actorServer = Server.findById(actor.getName());
ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup()); ServerGroup actorServerGroup = ServerGroup.findById(actorServer.getServerGroup());
JsonObject requestBody = ctx.getBodyAsJson(); JsonObject requestBody = ctx.getBodyAsJson();
Map<UUID, String> playerNames = extractPlayerNames(requestBody.getJsonObject("players")); Map<UUID, String> playerNames = extractPlayerNames(requestBody.getJsonObject("players"));
@ -132,7 +131,7 @@ public final class POSTServersHeartbeat implements Handler<RoutingContext> {
serverGroup.calculateScopedPermissions(rank) serverGroup.calculateScopedPermissions(rank)
); );
permissionsResponse.put(rank.getId(), scopedPermissions); permissionsResponse.put(rank.getId(), PermissionUtils.convertToList(scopedPermissions));
} }
callback.complete(permissionsResponse); callback.complete(permissionsResponse);

View File

@ -5,6 +5,7 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.ErrorUtils;
import net.frozenorb.apiv3.util.PermissionUtils;
public final class GETUsersIdCompoundedPermissions implements Handler<RoutingContext> { public final class GETUsersIdCompoundedPermissions implements Handler<RoutingContext> {
@ -19,7 +20,7 @@ public final class GETUsersIdCompoundedPermissions implements Handler<RoutingCon
if (error2 != null) { if (error2 != null) {
ErrorUtils.respondInternalError(ctx, error2); ErrorUtils.respondInternalError(ctx, error2);
} else { } else {
APIv3.respondJson(ctx, permissions); APIv3.respondJson(ctx, PermissionUtils.convertToList(permissions));
} }
}); });
} }

View File

@ -5,7 +5,6 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.actor.actors.ServerActor;
import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.model.User;
import net.frozenorb.apiv3.util.ErrorUtils; import net.frozenorb.apiv3.util.ErrorUtils;
@ -21,7 +20,7 @@ public class POSTUsersIdLeave implements Handler<RoutingContext> {
return; return;
} }
Server actorServer = ((ServerActor) actor).getServer(); Server actorServer = Server.findById(actor.getName());
User.findById(ctx.request().getParam("id"), ((user, error) -> { User.findById(ctx.request().getParam("id"), ((user, error) -> {
if (error != null) { if (error != null) {

View File

@ -7,7 +7,6 @@ import io.vertx.ext.web.RoutingContext;
import net.frozenorb.apiv3.APIv3; import net.frozenorb.apiv3.APIv3;
import net.frozenorb.apiv3.actor.Actor; import net.frozenorb.apiv3.actor.Actor;
import net.frozenorb.apiv3.actor.ActorType; import net.frozenorb.apiv3.actor.ActorType;
import net.frozenorb.apiv3.actor.actors.ServerActor;
import net.frozenorb.apiv3.model.IpLogEntry; import net.frozenorb.apiv3.model.IpLogEntry;
import net.frozenorb.apiv3.model.Server; import net.frozenorb.apiv3.model.Server;
import net.frozenorb.apiv3.model.User; import net.frozenorb.apiv3.model.User;
@ -41,7 +40,7 @@ public final class POSTUsersIdLogin implements Handler<RoutingContext> {
return; return;
} }
Server actorServer = ((ServerActor) actor).getServer(); Server actorServer = Server.findById(actor.getName());
if (!IpUtils.isValidIp(userIp)) { if (!IpUtils.isValidIp(userIp)) {
ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid."); ErrorUtils.respondInvalidInput(ctx, "IP address \"" + userIp + "\" is not valid.");

View File

@ -6,7 +6,6 @@ import lombok.experimental.UtilityClass;
public class Permissions { public class Permissions {
public static final String PROTECTED_PUNISHMENT = "minehq.punishment.protected"; 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"; public static final String BYPASS_VPN_CHECK = "minehq.vpn.bypass";
} }

View File

@ -1,6 +1,8 @@
package net.frozenorb.apiv3.util; package net.frozenorb.apiv3.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import io.vertx.core.cli.converters.BooleanConverter;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import net.frozenorb.apiv3.model.Rank; import net.frozenorb.apiv3.model.Rank;
@ -31,7 +33,7 @@ public class PermissionUtils {
} }
for (Rank rank : mergeQueue) { for (Rank rank : mergeQueue) {
Map<String, Boolean> rankPermissions = convertToMap(raw.get(rank.getId())); Map<String, Boolean> rankPermissions = convertFromList(raw.get(rank.getId()));
// If there's no permissions defined for this rank just skip it. // If there's no permissions defined for this rank just skip it.
if (!rankPermissions.isEmpty()) { if (!rankPermissions.isEmpty()) {
@ -47,24 +49,36 @@ public class PermissionUtils {
return ImmutableMap.of(); return ImmutableMap.of();
} }
private static Map<String, Boolean> convertToMap(List<String> unconvered) { private static Map<String, Boolean> convertFromList(List<String> permissionsList) {
if (unconvered == null) { if (permissionsList == null) {
return ImmutableMap.of(); return ImmutableMap.of();
} }
Map<String, Boolean> result = new HashMap<>(); Map<String, Boolean> permissionsMap = new HashMap<>();
for (String permission : unconvered) { permissionsList.forEach((permission) -> {
boolean negate = permission.startsWith("-"); if (permission.startsWith("-")) {
permissionsMap.put(permission.substring(1), false);
if (negate) {
result.put(permission.substring(1), false);
} else { } else {
result.put(permission, true); permissionsMap.put(permission, true);
} }
});
return permissionsMap;
} }
return result; public static List<String> convertToList(Map<String, Boolean> permissionsMap) {
if (permissionsMap == null) {
return ImmutableList.of();
}
List<String> permissionsList = new LinkedList<>();
permissionsMap.forEach((permission, granted) -> {
permissionsList.add((granted ? "" : "-") + permission);
});
return permissionsList;
} }
} }