[FEATURE] Permissions

This commit is contained in:
Gravita 2021-10-12 16:55:32 +07:00
parent e782f0409d
commit 9841ef3157
11 changed files with 166 additions and 23 deletions

View file

@ -121,6 +121,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
// Updates and profiles
private volatile Set<ClientProfile> profilesList;
@SuppressWarnings("deprecation")
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager) throws IOException {
this.dir = directories.dir;
this.tmpDir = directories.tmpDir;
@ -405,6 +406,7 @@ public void restart() {
}
}
@SuppressWarnings("deprecation")
public void registerObject(String name, Object object) {
if (object instanceof Reconfigurable) {
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
@ -414,6 +416,7 @@ public void registerObject(String name, Object object) {
}
}
@SuppressWarnings("deprecation")
public void unregisterObject(String name, Object object) {
if (object instanceof Reconfigurable) {
reconfigurableManager.unregisterReconfigurable(name);

View file

@ -1,8 +1,11 @@
package pro.gravit.launchserver.auth;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
import pro.gravit.launchserver.auth.core.AuthSocialProvider;
import pro.gravit.launchserver.auth.core.MySQLCoreProvider;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import java.io.IOException;
@ -11,6 +14,7 @@
import java.util.Set;
public final class AuthProviderPair {
private transient final Logger logger = LogManager.getLogger();
public boolean isDefault = true;
public AuthCoreProvider core;
public AuthSocialProvider social;
@ -19,6 +23,7 @@ public final class AuthProviderPair {
public transient String name;
public transient Set<String> features;
public String displayName;
private transient boolean warnOAuthShow = false;
public AuthProviderPair(AuthCoreProvider core, TextureProvider textureProvider) {
this.core = core;
@ -42,6 +47,15 @@ public static Set<String> getFeatures(Class<?> clazz) {
return list;
}
public void internalShowOAuthWarnMessage() {
if(!warnOAuthShow) {
if(!(core instanceof MySQLCoreProvider)) { // MySQL upgraded later
logger.warn("AuthCoreProvider {} ({}) not supported OAuth. Legacy session system may be removed in next release", name, core.getClass().getName());
}
warnOAuthShow = true;
}
}
public static void getFeatures(Class<?> clazz, Set<String> list) {
Features features = clazz.getAnnotation(Features.class);
if (features != null) {

View file

@ -141,8 +141,10 @@ public boolean onJoinServer(String serverID, String username, Client client) {
@Override
public void init(LaunchServer server) {
if (provider != null)
if (provider != null) {
provider.init(server);
logger.warn("HWIDProvider deprecated. Please use 'AuthSupportHardware' in AuthCoreProvider");
}
this.server = server;
}

View file

@ -1,16 +1,17 @@
package pro.gravit.launchserver.auth.protect;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class StdProtectHandler extends ProtectHandler implements ProfilesProtectHandler {
private transient final Logger logger = LogManager.getLogger();
public Map<String, List<String>> profileWhitelist = new HashMap<>();
public List<String> allowUpdates = new ArrayList<>();
@ -24,14 +25,21 @@ public void checkLaunchServerLicense() {
}
@Override
public void init(LaunchServer server) {
if(profileWhitelist != null && profileWhitelist.size() > 0) {
logger.warn("profileWhitelist deprecated. Please use permission 'launchserver.profile.PROFILE_UUID.show' and 'launchserver.profile.PROFILE_UUID.enter'");
}
}
@Override
public boolean canGetProfile(ClientProfile profile, Client client) {
return canChangeProfile(profile, client);
return client.isAuth && client.username != null && (!profile.isLimited() || isWhitelisted("launchserver.profile.%s.show", profile, client) );
}
@Override
public boolean canChangeProfile(ClientProfile profile, Client client) {
return client.isAuth && client.username != null && isWhitelisted(profile.getTitle(), client.username);
return client.isAuth && client.username != null && (!profile.isLimited() || isWhitelisted("launchserver.profile.%s.enter", profile, client) );
}
@Override
@ -39,9 +47,19 @@ public boolean canGetUpdates(String updatesDirName, Client client) {
return client.profile != null && (client.profile.getDir().equals(updatesDirName) || client.profile.getAssetDir().equals(updatesDirName) || allowUpdates.contains(updatesDirName));
}
public boolean isWhitelisted(String profileTitle, String username) {
List<String> allowedUsername = profileWhitelist.get(profileTitle);
if (allowedUsername == null) return true;
return allowedUsername.contains(username);
private boolean isWhitelisted(String property, ClientProfile profile, Client client) {
if(client.permissions != null) {
String permByUUID = String.format(property, profile.getUUID());
if(client.permissions.hasAction(permByUUID)) {
return true;
}
String permByTitle = String.format(property, profile.getTitle().toLowerCase(Locale.ROOT));
if(client.permissions.hasAction(permByTitle)) {
return true;
}
}
List<String> allowedUsername = profileWhitelist.get(profile.getTitle());
if (allowedUsername != null && allowedUsername.contains(client.username)) return true;
return false;
}
}

View file

@ -205,6 +205,9 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor
* Writing authorization information to the Client object
*/
public void internalAuth(Client client, AuthResponse.ConnectTypes authType, AuthProviderPair pair, String username, UUID uuid, ClientPermissions permissions, boolean oauth) {
if(!oauth) {
pair.internalShowOAuthWarnMessage();
}
client.isAuth = true;
client.permissions = permissions;
client.auth_id = pair.name;

View file

@ -3,10 +3,7 @@
import pro.gravit.launcher.serialize.HInput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import java.util.*;
public class ClientPermissions {
public static final ClientPermissions DEFAULT = new ClientPermissions();
@ -21,7 +18,7 @@ public class ClientPermissions {
@LauncherNetworkAPI
private List<String> actions;
private transient List<Pattern> available;
private transient List<PermissionPattern> available;
public ClientPermissions(HInput input) throws IOException {
this(input.readLong());
@ -61,12 +58,12 @@ public synchronized void compile() {
}
available = new ArrayList<>(actions.size());
for (String a : actions) {
available.add(Pattern.compile(a));
available.add(new PermissionPattern(a));
}
if (permissions != 0) {
if (isPermission(PermissionConsts.ADMIN)) {
roles.add("ADMIN");
available.add(Pattern.compile(".*"));
available.add(new PermissionPattern("*"));
}
}
}
@ -75,8 +72,8 @@ public boolean hasAction(String action) {
if (available == null) {
compile();
}
for (Pattern p : available) {
if (p.matcher(action).matches()) {
for (PermissionPattern p : available) {
if (p.match(action)) {
return true;
}
}
@ -98,7 +95,7 @@ public void addAction(String action) {
if(available == null) {
available = new ArrayList<>(1);
}
available.add(Pattern.compile(action));
available.add(new PermissionPattern(action));
}
public List<String> getRoles() {
@ -186,4 +183,54 @@ public enum FlagConsts {
this.mask = mask;
}
}
public static class PermissionPattern {
private final String[] parts;
private final int priority;
public PermissionPattern(String pattern) {
List<String> prepare = new ArrayList<>();
for(int i=0;true;) {
int pos = pattern.indexOf("*", i);
if(pos >= 0) {
prepare.add(pattern.substring(i, pos));
i = pos+1;
} else {
prepare.add(pattern.substring(i));
break;
}
}
priority = prepare.size() - 1;
parts = prepare.toArray(new String[0]);
}
public int getPriority() {
return priority;
}
public boolean match(String str) {
if(parts.length == 0) {
return true;
}
if(parts.length == 1) {
return parts[0].equals(str);
}
int offset = 0;
if(!str.startsWith(parts[0])) {
return false;
}
if(!str.endsWith(parts[parts.length-1])) {
return false;
}
for(int i=1;i<parts.length-1;++i) {
int pos = str.indexOf(parts[i], offset);
if(pos >= 0) {
offset = pos+1;
} else {
return false;
}
}
return true;
}
}
}

View file

@ -77,6 +77,8 @@ public final class ClientProfile implements Comparable<ClientProfile> {
private ProfileDefaultSettings settings = new ProfileDefaultSettings();
@LauncherNetworkAPI
private boolean updateFastCheck;
@LauncherNetworkAPI
private boolean limited;
// Client launcher
@LauncherNetworkAPI
private String mainClass;
@ -441,6 +443,10 @@ public void setRuntimeInClientConfig(RuntimeInClientConfig runtimeInClientConfig
this.runtimeInClientConfig = runtimeInClientConfig;
}
public boolean isLimited() {
return limited;
}
public enum Version {
MC125("1.2.5", 29),
MC147("1.4.7", 51),

View file

@ -0,0 +1,50 @@
package pro.gravit.launcher;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class PermissionTest {
@Test
public void testPermission() {
{
ClientPermissions permissions = new ClientPermissions();
permissions.addAction("*");
Assertions.assertTrue(permissions.hasAction("abcd"));
Assertions.assertTrue(permissions.hasAction("t.a.c.d.f.*"));
Assertions.assertTrue(permissions.hasAction("*"));
}
{
ClientPermissions permissions = new ClientPermissions();
permissions.addAction("launchserver.*");
Assertions.assertTrue(permissions.hasAction("launchserver.*"));
Assertions.assertTrue(permissions.hasAction("launchserver.abcd"));
Assertions.assertFalse(permissions.hasAction("default.abcd"));
Assertions.assertFalse(permissions.hasAction("nolaunchserver.abcd"));
}
{
ClientPermissions permissions = new ClientPermissions();
permissions.addAction("launchserver.*.prop");
Assertions.assertTrue(permissions.hasAction("launchserver.ii.prop"));
Assertions.assertTrue(permissions.hasAction("launchserver.ia.prop"));
Assertions.assertFalse(permissions.hasAction("default.abcd"));
Assertions.assertFalse(permissions.hasAction("launchserver.ia"));
Assertions.assertFalse(permissions.hasAction("launchserver.ia.prop2"));
}
{
ClientPermissions permissions = new ClientPermissions();
permissions.addAction("launchserver.*.def.*.prop");
Assertions.assertTrue(permissions.hasAction("launchserver.1.def.2.prop"));
Assertions.assertTrue(permissions.hasAction("launchserver.none.def.none.prop"));
Assertions.assertTrue(permissions.hasAction("launchserver.def.def.def.prop"));
Assertions.assertFalse(permissions.hasAction("launchserver.*.*.prop"));
Assertions.assertFalse(permissions.hasAction("launchserver.*.undef.*.prop"));
}
{
ClientPermissions permissions = new ClientPermissions();
permissions.addAction("launchserver.*.e.*.i.*.prop");
Assertions.assertTrue(permissions.hasAction("launchserver.2.e.3.i.4.prop"));
Assertions.assertTrue(permissions.hasAction("launchserver.12212.e.233455.i.2356436346346345345345345.prop"));
Assertions.assertFalse(permissions.hasAction("launchserver.prop"));
}
}
}

View file

@ -7,6 +7,7 @@
import java.util.Timer;
import java.util.TimerTask;
@Deprecated
public class GarbageManager {
private static final Timer timer = new Timer("GarbageTimer");
private static final Set<Entry> NEED_GARBARE_COLLECTION = new HashSet<>();

View file

@ -8,7 +8,7 @@ public final class Version implements Comparable<Version> {
public static final int MINOR = 2;
public static final int PATCH = 3;
public static final int BUILD = 1;
public static final Version.Type RELEASE = Type.DEV;
public static final Version.Type RELEASE = Type.BETA;
public final int major;
public final int minor;
public final int patch;

View file

@ -20,7 +20,6 @@ public String getUsageDescription() {
public void invoke(String... args) {
LogHelper.subInfo("Performing full GC");
JVMHelper.fullGC();
GarbageManager.gc();
// Print memory usage
long max = JVMHelper.RUNTIME.maxMemory() >> 20;
long free = JVMHelper.RUNTIME.freeMemory() >> 20;