[FEATURE] Pattern-based permissions system

This commit is contained in:
Gravita 2021-09-22 16:50:05 +07:00
parent d2e222d67d
commit 4c78d00360
6 changed files with 92 additions and 8 deletions

View file

@ -50,7 +50,9 @@ public void invoke(String... args) {
if (client.trustLevel != null) { if (client.trustLevel != null) {
logger.info("trustLevel | key {} | pubkey {}", client.trustLevel.keyChecked ? "checked" : "unchecked", client.trustLevel.publicKey == null ? "null" : new String(Base64.getEncoder().encode(client.trustLevel.publicKey))); logger.info("trustLevel | key {} | pubkey {}", client.trustLevel.keyChecked ? "checked" : "unchecked", client.trustLevel.publicKey == null ? "null" : new String(Base64.getEncoder().encode(client.trustLevel.publicKey)));
} }
logger.info("Permissions: {} (permissions {} | flags {})", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.permissions, client.permissions == null ? 0 : client.permissions.flags); if (client.permissions != null) {
logger.info("Permissions: {}", client.permissions.toString());
}
} }
})); }));
} }

View file

@ -12,6 +12,7 @@
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@SuppressWarnings("deprecation")
public class AdditionalDataResponse extends SimpleResponse { public class AdditionalDataResponse extends SimpleResponse {
public String username; public String username;
public UUID uuid; public UUID uuid;

View file

@ -2,7 +2,6 @@
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.RequestEvent; import pro.gravit.launcher.events.RequestEvent;
import pro.gravit.launcher.events.request.ExitRequestEvent; import pro.gravit.launcher.events.request.ExitRequestEvent;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
@ -35,7 +34,7 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) { public void execute(ChannelHandlerContext ctx, Client client) {
if (username != null && (!client.isAuth || client.permissions == null || !client.permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN))) { if (username != null && (!client.isAuth || client.permissions == null || !client.permissions.hasAction("launchserver\\.management\\.kick"))) {
sendError("Permissions denied"); sendError("Permissions denied");
return; return;
} }

View file

@ -1,7 +1,6 @@
package pro.gravit.launchserver.socket.response.management; package pro.gravit.launchserver.socket.response.management;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.events.request.PingServerReportRequestEvent; import pro.gravit.launcher.events.request.PingServerReportRequestEvent;
import pro.gravit.launcher.request.management.PingServerReportRequest; import pro.gravit.launcher.request.management.PingServerReportRequest;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
@ -18,7 +17,7 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) { public void execute(ChannelHandlerContext ctx, Client client) {
if (!client.isAuth || client.permissions == null || !client.permissions.isPermission(ClientPermissions.PermissionConsts.MANAGEMENT)) { if (!client.isAuth || client.permissions == null || !client.permissions.hasAction("launchserver\\.management\\.pingserver")) {
sendError("Access denied"); sendError("Access denied");
return; return;
} }

View file

@ -11,7 +11,7 @@ public class AuthService {
public static UUID uuid; public static UUID uuid;
public static ClientProfile profile; public static ClientProfile profile;
public static boolean isAdmin() { public static boolean hasPermission(String permission) {
return permissions.isPermission(ClientPermissions.PermissionConsts.ADMIN); return permissions.hasAction(permission);
} }
} }

View file

@ -3,13 +3,25 @@
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
public class ClientPermissions { public class ClientPermissions {
public static final ClientPermissions DEFAULT = new ClientPermissions(); public static final ClientPermissions DEFAULT = new ClientPermissions();
@LauncherNetworkAPI @LauncherNetworkAPI
@Deprecated
public long permissions; public long permissions;
@LauncherNetworkAPI @LauncherNetworkAPI
@Deprecated
public long flags; public long flags;
@LauncherNetworkAPI
private List<String> roles;
@LauncherNetworkAPI
private List<String> actions;
private transient List<Pattern> available;
public ClientPermissions(HInput input) throws IOException { public ClientPermissions(HInput input) throws IOException {
this(input.readLong()); this(input.readLong());
@ -31,6 +43,7 @@ public ClientPermissions(long permissions, long flags) {
public static ClientPermissions getSuperuserAccount() { public static ClientPermissions getSuperuserAccount() {
ClientPermissions perm = new ClientPermissions(); ClientPermissions perm = new ClientPermissions();
perm.setPermission(PermissionConsts.ADMIN, true); perm.setPermission(PermissionConsts.ADMIN, true);
perm.addAction("*");
return perm; return perm;
} }
@ -38,39 +51,102 @@ public long toLong() {
return permissions; return permissions;
} }
public boolean hasRole(String role) {
return roles != null && roles.contains(role);
}
public synchronized void compile() {
if (available != null) {
return;
}
available = new ArrayList<>(actions.size());
for (String a : actions) {
available.add(Pattern.compile(a));
}
if (permissions != 0) {
if (isPermission(PermissionConsts.ADMIN)) {
roles.add("ADMIN");
available.add(Pattern.compile(".*"));
}
}
}
public boolean hasAction(String action) {
if (available == null) {
compile();
}
for (Pattern p : available) {
if (p.matcher(action).matches()) {
return true;
}
}
return false;
}
public void addRole(String role) {
if (roles == null) {
roles = new ArrayList<>(1);
}
roles.add(role);
}
public void addAction(String action) {
if (actions == null) {
actions = new ArrayList<>();
}
actions.add(action);
available.add(Pattern.compile(action));
}
public List<String> getRoles() {
return roles;
}
public List<String> getActions() {
return actions;
}
//Read methods //Read methods
@Deprecated
public final boolean isPermission(PermissionConsts con) { public final boolean isPermission(PermissionConsts con) {
return (permissions & con.mask) != 0; return (permissions & con.mask) != 0;
} }
@Deprecated
public final boolean isPermission(long mask) { public final boolean isPermission(long mask) {
return (permissions & mask) != 0; return (permissions & mask) != 0;
} }
@Deprecated
public final boolean isFlag(FlagConsts con) { public final boolean isFlag(FlagConsts con) {
return (flags & con.mask) != 0; return (flags & con.mask) != 0;
} }
@Deprecated
public final boolean isFlag(long mask) { public final boolean isFlag(long mask) {
return (flags & mask) != 0; return (flags & mask) != 0;
} }
//Write methods //Write methods
@Deprecated
public final void setPermission(PermissionConsts con, boolean value) { public final void setPermission(PermissionConsts con, boolean value) {
if (value) this.permissions |= con.mask; if (value) this.permissions |= con.mask;
else this.permissions &= ~con.mask; else this.permissions &= ~con.mask;
} }
@Deprecated
public final void setPermission(long mask, boolean value) { public final void setPermission(long mask, boolean value) {
if (value) this.permissions |= mask; if (value) this.permissions |= mask;
else this.permissions &= ~mask; else this.permissions &= ~mask;
} }
@Deprecated
public final void setFlag(FlagConsts con, boolean value) { public final void setFlag(FlagConsts con, boolean value) {
if (value) this.flags |= con.mask; if (value) this.flags |= con.mask;
else this.flags &= ~con.mask; else this.flags &= ~con.mask;
} }
@Deprecated
public final void setFlag(long mask, boolean value) { public final void setFlag(long mask, boolean value) {
if (value) this.flags |= mask; if (value) this.flags |= mask;
else this.flags &= ~mask; else this.flags &= ~mask;
@ -78,12 +154,19 @@ public final void setFlag(long mask, boolean value) {
@Override @Override
public String toString() { public String toString() {
if (roles != null || actions != null) {
return "ClientPermissions{" +
"roles=" + String.join(", ", roles == null ? Collections.emptyList() : roles) +
", actions=" + String.join(", ", actions == null ? Collections.emptyList() : actions) +
'}';
}
return "ClientPermissions{" + return "ClientPermissions{" +
"permissions=" + permissions + "permissions=" + permissions +
", flags=" + flags + ", flags=" + flags +
'}'; '}';
} }
@Deprecated
public enum PermissionConsts { public enum PermissionConsts {
ADMIN(0x01), ADMIN(0x01),
MANAGEMENT(0x02); MANAGEMENT(0x02);
@ -94,7 +177,7 @@ public enum PermissionConsts {
} }
} }
@Deprecated
public enum FlagConsts { public enum FlagConsts {
SYSTEM(0x01), SYSTEM(0x01),
BANNED(0x02), BANNED(0x02),