diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index fe7be0da..902c846e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -8,7 +8,6 @@ import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider; -import pro.gravit.launchserver.auth.session.MemorySessionStorage; import pro.gravit.launchserver.binary.EXEL4JLauncherBinary; import pro.gravit.launchserver.binary.EXELauncherBinary; import pro.gravit.launchserver.binary.JARLauncherBinary; @@ -94,7 +93,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab //public static LaunchServer server = null; public final Class launcherEXEBinaryClass; // Server config - public final SessionManager sessionManager; public final AuthHookManager authHookManager; public final LaunchServerModulesManager modulesManager; // Launcher binary @@ -149,10 +147,8 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La runtime.verify(); config.verify(); - if (config.sessions == null) config.sessions = new MemorySessionStorage(); // build hooks, anti-brutforce and other - sessionManager = new SessionManager(this); mirrorManager = new MirrorManager(); reconfigurableManager = new ReconfigurableManager(); authHookManager = new AuthHookManager(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index 8bde3ffc..cab9413e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -13,7 +13,6 @@ import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.auth.protect.ProtectHandler; -import pro.gravit.launchserver.auth.session.SessionStorage; import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.config.LaunchServerConfig; @@ -205,7 +204,6 @@ public static void registerAll() { GetAvailabilityAuthRequest.registerProviders(); OptionalAction.registerProviders(); OptionalTrigger.registerProviders(); - SessionStorage.registerProviders(); } public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java index c87f769c..11a72699 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java @@ -1,5 +1,7 @@ package pro.gravit.launchserver.auth.core; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import pro.gravit.launcher.ClientPermissions; @@ -13,6 +15,7 @@ import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware; import pro.gravit.launchserver.auth.password.PasswordVerifier; +import pro.gravit.launchserver.helper.LegacySessionHelper; import pro.gravit.launchserver.manangers.AuthManager; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.utils.helper.IOHelper; @@ -21,6 +24,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.sql.*; +import java.time.Duration; +import java.time.LocalDateTime; import java.util.Base64; import java.util.LinkedList; import java.util.List; @@ -30,6 +35,7 @@ public class MySQLCoreProvider extends AuthCoreProvider implements AuthSupportHa private transient final Logger logger = LogManager.getLogger(); public MySQLSourceConfig mySQLHolder; + public int expireSeconds = 3600; public String uuidColumn; public String usernameColumn; public String accessTokenColumn; @@ -63,6 +69,8 @@ public class MySQLCoreProvider extends AuthCoreProvider implements AuthSupportHa private transient String updateAuthSQL; private transient String updateServerIDSQL; + private transient LaunchServer server; + @Override public User getUserByUsername(String username) { try { @@ -95,12 +103,38 @@ public User getUserByLogin(String login) { @Override public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { - return null; + try { + var info = LegacySessionHelper.getJwtInfoFromAccessToken(accessToken, server.keyAgreementManager.ecdsaPublicKey); + var user = (MySQLUser) getUserByUUID(info.uuid()); + if(user == null) { + return null; + } + return new MySQLUserSession(user); + } catch (ExpiredJwtException e) { + throw new OAuthAccessTokenExpired(); + } catch (JwtException e) { + return null; + } } @Override public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { - return null; + String[] parts = refreshToken.split("\\."); + if(parts.length != 2) { + return null; + } + String username = parts[0]; + String token = parts[1]; + var user = (MySQLUser) getUserByUsername(username); + if(user == null || user.password == null) { + return null; + } + var realToken = LegacySessionHelper.makeRefreshTokenFromPassword(username, user.password, server.keyAgreementManager.legacySalt); + if(!token.equals(realToken)) { + return null; + } + var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(user, LocalDateTime.now().plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey); + return new AuthManager.AuthReport(null, accessToken, refreshToken, expireSeconds * 1000L, new MySQLUserSession(user)); } @Override @@ -119,17 +153,20 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c } } MySQLUserSession session = new MySQLUserSession(mySQLUser); + var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(mySQLUser, LocalDateTime.now().plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey); + var refreshToken = LegacySessionHelper.makeRefreshTokenFromPassword(mySQLUser.username, mySQLUser.password, server.keyAgreementManager.legacySalt); if (minecraftAccess) { String minecraftAccessToken = SecurityHelper.randomStringToken(); updateAuth(mySQLUser, minecraftAccessToken); - return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken, session); + return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftAccessToken, accessToken, refreshToken, expireSeconds * 1000L, session); } else { - return AuthManager.AuthReport.ofMinecraftAccessToken(null, session); + return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken, expireSeconds * 1000L, session); } } @Override public void init(LaunchServer server) { + this.server = server; if (mySQLHolder == null) logger.error("mySQLHolder cannot be null"); if (uuidColumn == null) logger.error("uuidColumn cannot be null"); if (usernameColumn == null) logger.error("usernameColumn cannot be null"); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/PostgresSQLCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/PostgresSQLCoreProvider.java index 747f089e..e1f99ac9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/PostgresSQLCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/PostgresSQLCoreProvider.java @@ -1,5 +1,7 @@ package pro.gravit.launchserver.auth.core; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import pro.gravit.launcher.ClientPermissions; @@ -10,18 +12,21 @@ import pro.gravit.launchserver.auth.MySQLSourceConfig; import pro.gravit.launchserver.auth.PostgreSQLSourceConfig; import pro.gravit.launchserver.auth.password.PasswordVerifier; +import pro.gravit.launchserver.helper.LegacySessionHelper; import pro.gravit.launchserver.manangers.AuthManager; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.utils.helper.SecurityHelper; import java.io.IOException; import java.sql.*; +import java.time.LocalDateTime; import java.util.UUID; public class PostgresSQLCoreProvider extends AuthCoreProvider { private transient final Logger logger = LogManager.getLogger(); public PostgreSQLSourceConfig postgresSQLHolder; + public int expireSeconds = 3600; public String uuidColumn; public String usernameColumn; public String accessTokenColumn; @@ -42,6 +47,8 @@ public class PostgresSQLCoreProvider extends AuthCoreProvider { private transient String updateAuthSQL; private transient String updateServerIDSQL; + private transient LaunchServer server; + @Override public User getUserByUsername(String username) { try { @@ -74,12 +81,38 @@ public User getUserByLogin(String login) { @Override public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { - return null; + try { + var info = LegacySessionHelper.getJwtInfoFromAccessToken(accessToken, server.keyAgreementManager.ecdsaPublicKey); + var user = (MySQLCoreProvider.MySQLUser) getUserByUUID(info.uuid()); + if(user == null) { + return null; + } + return new MySQLCoreProvider.MySQLUserSession(user); + } catch (ExpiredJwtException e) { + throw new OAuthAccessTokenExpired(); + } catch (JwtException e) { + return null; + } } @Override public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { - return null; + String[] parts = refreshToken.split("\\."); + if(parts.length != 2) { + return null; + } + String username = parts[0]; + String token = parts[1]; + var user = (MySQLCoreProvider.MySQLUser) getUserByUsername(username); + if(user == null || user.password == null) { + return null; + } + var realToken = LegacySessionHelper.makeRefreshTokenFromPassword(username, user.password, server.keyAgreementManager.legacySalt); + if(!token.equals(realToken)) { + return null; + } + var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(user, LocalDateTime.now().plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey); + return new AuthManager.AuthReport(null, accessToken, refreshToken, expireSeconds * 1000L, new MySQLCoreProvider.MySQLUserSession(user)); } @Override @@ -98,17 +131,20 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c } } MySQLUserSession session = new MySQLUserSession(postgresSQLUser); + var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(postgresSQLUser, LocalDateTime.now().plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey); + var refreshToken = LegacySessionHelper.makeRefreshTokenFromPassword(postgresSQLUser.username, postgresSQLUser.password, server.keyAgreementManager.legacySalt); if (minecraftAccess) { String minecraftAccessToken = SecurityHelper.randomStringToken(); updateAuth(postgresSQLUser, minecraftAccessToken); - return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken, session); + return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftAccessToken, accessToken, refreshToken, expireSeconds * 1000L, session); } else { - return AuthManager.AuthReport.ofMinecraftAccessToken(null, session); + return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken, expireSeconds * 1000L, session); } } @Override public void init(LaunchServer server) { + this.server = server; if (postgresSQLHolder == null) logger.error("postgresSQLHolder cannot be null"); if (uuidColumn == null) logger.error("uuidColumn cannot be null"); if (usernameColumn == null) logger.error("usernameColumn cannot be null"); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java deleted file mode 100644 index a341c13f..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/MemorySessionStorage.java +++ /dev/null @@ -1,172 +0,0 @@ -package pro.gravit.launchserver.auth.session; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.Launcher; -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.utils.helper.IOHelper; - -import java.io.Reader; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; - -public class MemorySessionStorage extends SessionStorage implements AutoCloseable { - - private transient final Map clientSet = new ConcurrentHashMap<>(128); - private transient final Map> uuidIndex = new ConcurrentHashMap<>(32); - private transient final Logger logger = LogManager.getLogger(); - public boolean autoDump = false; - public String dumpFile = "sessions.json"; - - @Override - public void init(LaunchServer server) { - super.init(server); - if (autoDump) { - loadSessionsData(); - } - } - - @Override - public byte[] getSessionData(UUID session) { - - Entry e = clientSet.get(session); - if (e == null) return null; - return e.data; - } - - @Override - public Stream getSessionsFromUserUUID(UUID userUUID) { - Set set = uuidIndex.get(userUUID); - if (set != null) return set.stream().map((e) -> e.sessionUuid); - return null; - } - - @Override - public boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data) { - deleteSession(sessionUUID); - Entry e = new Entry(data, sessionUUID); - clientSet.put(sessionUUID, e); - if (userUUID != null) { - Set uuidSet = uuidIndex.computeIfAbsent(userUUID, k -> ConcurrentHashMap.newKeySet()); - uuidSet.add(e); - } - return false; - } - - @Override - public boolean deleteSession(UUID sessionUUID) { - Entry e = clientSet.remove(sessionUUID); - if (e != null) { - Set set = uuidIndex.get(sessionUUID); - if (set != null) { - removeUuidFromIndexSet(set, e, sessionUUID); - } - return true; - } - return false; - } - - @Override - public boolean deleteSessionsByUserUUID(UUID userUUID) { - Set set = uuidIndex.get(userUUID); - if (set != null) { - for (Entry e : set) { - clientSet.remove(e.sessionUuid); - } - set.clear(); - uuidIndex.remove(userUUID); - } - return true; - } - - @Override - public void clear() { - clientSet.clear(); - uuidIndex.clear(); - } - - public void dumpSessionsData() { - DumpedData dumpedData = new DumpedData(clientSet, uuidIndex); - Path path = Paths.get(dumpFile); - try (Writer writer = IOHelper.newWriter(path)) { - Launcher.gsonManager.gson.toJson(dumpedData, writer); - } catch (Throwable e) { - logger.error("Sessions can't be saved", e); - } - } - - public void loadSessionsData() { - Path path = Paths.get(dumpFile); - if (!Files.exists(path)) return; - try (Reader reader = IOHelper.newReader(path)) { - DumpedData data = Launcher.gsonManager.gson.fromJson(reader, DumpedData.class); - clientSet.putAll(data.clientSet); - uuidIndex.putAll(data.uuidIndex); - } catch (Throwable e) { - logger.error("Sessions can't be loaded", e); - } - } - - @Override - public void lockSession(UUID sessionUUID) { - - } - - @Override - public void lockUser(UUID userUUID) { - - } - - @Override - public void unlockSession(UUID sessionUUID) { - - } - - @Override - public void unlockUser(UUID userUUID) { - - } - - private void removeUuidFromIndexSet(Set set, Entry e, UUID session) { - set.remove(e); - if (set.isEmpty()) { - uuidIndex.remove(session); - } - } - - @Override - public void close() { - if (autoDump) { - dumpSessionsData(); - } - } - - private static class Entry { - public byte[] data; - public UUID sessionUuid; - public long timestamp; - - public Entry(byte[] data, UUID sessionUuid) { - this.data = data; - this.sessionUuid = sessionUuid; - this.timestamp = System.currentTimeMillis(); - } - } - - private static class DumpedData { - private final Map clientSet; - private final Map> uuidIndex; - - private DumpedData(Map clientSet, Map> uuidIndex) { - this.clientSet = clientSet; - this.uuidIndex = uuidIndex; - } - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java deleted file mode 100644 index 4a2387e3..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/session/SessionStorage.java +++ /dev/null @@ -1,47 +0,0 @@ -package pro.gravit.launchserver.auth.session; - -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.utils.ProviderMap; - -import java.util.UUID; -import java.util.stream.Stream; - -public abstract class SessionStorage { - public static ProviderMap providers = new ProviderMap<>(); - private static boolean registeredProviders = false; - protected transient LaunchServer server; - - public static void registerProviders() { - if (!registeredProviders) { - providers.register("memory", MemorySessionStorage.class); - registeredProviders = true; - } - } - - public abstract byte[] getSessionData(UUID session); - - public abstract Stream getSessionsFromUserUUID(UUID userUUID); - - public abstract boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data); - - public abstract boolean deleteSession(UUID sessionUUID); - - public boolean deleteSessionsByUserUUID(UUID userUUID) { - getSessionsFromUserUUID(userUUID).forEach(this::deleteSession); - return true; - } - - public abstract void clear(); - - public abstract void lockSession(UUID sessionUUID); - - public abstract void lockUser(UUID userUUID); - - public abstract void unlockSession(UUID sessionUUID); - - public abstract void unlockUser(UUID userUUID); - - public void init(LaunchServer server) { - this.server = server; - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index d7fb793c..15cd985a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -11,8 +11,6 @@ import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.StdProtectHandler; -import pro.gravit.launchserver.auth.session.MemorySessionStorage; -import pro.gravit.launchserver.auth.session.SessionStorage; import pro.gravit.launchserver.auth.texture.RequestTextureProvider; import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask; import pro.gravit.launchserver.components.AuthLimiterComponent; @@ -34,7 +32,6 @@ public final class LaunchServerConfig { public boolean cacheUpdates = true; public LauncherConfig.LauncherEnvironment env; public Map auth; - public SessionStorage sessions; // Handlers & Providers public ProtectHandler protectHandler; public Map components; @@ -70,7 +67,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { a.displayName = "Default"; newConfig.auth.put("std", a); newConfig.protectHandler = new StdProtectHandler(); - newConfig.sessions = new MemorySessionStorage(); newConfig.binaryName = "Launcher"; newConfig.netty = new NettyConfig(); @@ -191,10 +187,6 @@ public void init(LaunchServer.ReloadType type) { protectHandler.init(server); protectHandler.checkLaunchServerLicense(); } - if (sessions != null) { - sessions.init(server); - server.registerObject("sessions", sessions); - } if (components != null) { components.forEach((k, v) -> server.registerObject("component.".concat(k), v)); } @@ -235,16 +227,6 @@ public void close(LaunchServer.ReloadType type) { server.unregisterObject("protectHandler", protectHandler); protectHandler.close(); } - if (sessions != null) { - server.unregisterObject("sessions", sessions); - if (sessions instanceof AutoCloseable) { - try { - ((AutoCloseable) sessions).close(); - } catch (Exception e) { - logger.error(e); - } - } - } } public static class ExeConf { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java new file mode 100644 index 00000000..092cf99f --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java @@ -0,0 +1,48 @@ +package pro.gravit.launchserver.helper; + +import io.jsonwebtoken.Jwts; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.utils.helper.SecurityHelper; + +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; +import java.util.UUID; + +public class LegacySessionHelper { + public static String makeAccessJwtTokenFromString(User user, LocalDateTime expirationTime, ECPrivateKey privateKey) { + return Jwts.builder() + .setIssuer("LaunchServer") + .setSubject(user.getUsername()) + .claim("uuid", user.getUUID().toString()) + .setExpiration(Date.from(expirationTime + .toInstant(ZoneOffset.UTC))) + .signWith(privateKey) + .compact(); + } + + public static JwtTokenInfo getJwtInfoFromAccessToken(String token, ECPublicKey publicKey) { + var parser = Jwts.parserBuilder() + .requireIssuer("LaunchServer") + .setSigningKey(publicKey) + .build(); + var claims = parser.parseClaimsJws(token); + var uuid = UUID.fromString(claims.getBody().get("uuid", String.class)); + var username = claims.getBody().getSubject(); + return new JwtTokenInfo(username, uuid); + } + + public static String makeRefreshTokenFromPassword(String username, String rawPassword, String secretSalt) { + if(rawPassword == null) { + rawPassword = ""; + } + return SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, + String.format("%s.%s.%s.%s", secretSalt, username, rawPassword, secretSalt))); + } + + public record JwtTokenInfo(String username, UUID uuid) { + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java index eaa75f7a..f494f990 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -169,7 +169,7 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor */ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, AuthProviderPair pair, String username, UUID uuid, ClientPermissions permissions, boolean oauth) { if(!oauth) { - pair.internalShowOAuthWarnMessage(); + throw new UnsupportedOperationException("Unsupported legacy session system"); } client.isAuth = true; client.permissions = permissions; @@ -178,7 +178,7 @@ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, Auth client.username = username; client.type = authType; client.uuid = uuid; - client.useOAuth = oauth; + client.useOAuth = true; } public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/KeyAgreementManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/KeyAgreementManager.java index cdb33947..8658b907 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/KeyAgreementManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/KeyAgreementManager.java @@ -6,6 +6,7 @@ import pro.gravit.utils.helper.SecurityHelper; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.security.KeyPair; import java.security.SecureRandom; @@ -20,13 +21,15 @@ public class KeyAgreementManager { public final ECPrivateKey ecdsaPrivateKey; public final RSAPublicKey rsaPublicKey; public final RSAPrivateKey rsaPrivateKey; + public final String legacySalt; private transient final Logger logger = LogManager.getLogger(); - public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey) { + public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey, String legacySalt) { this.ecdsaPublicKey = ecdsaPublicKey; this.ecdsaPrivateKey = ecdsaPrivateKey; this.rsaPublicKey = rsaPublicKey; this.rsaPrivateKey = rsaPrivateKey; + this.legacySalt = legacySalt; } public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpecException { @@ -62,5 +65,12 @@ public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpec IOHelper.write(rsaPublicKeyPath, rsaPublicKey.getEncoded()); IOHelper.write(rsaPrivateKeyPath, rsaPrivateKey.getEncoded()); } + Path legacySaltPath = keyDirectory.resolve("legacySalt"); + if(IOHelper.isFile(legacySaltPath)) { + legacySalt = new String(IOHelper.read(legacySaltPath), StandardCharsets.UTF_8); + } else { + legacySalt = SecurityHelper.randomStringToken(); + IOHelper.write(legacySaltPath, legacySalt.getBytes(StandardCharsets.UTF_8)); + } } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java index a33d5755..131dacf4 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -14,7 +14,6 @@ import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.auth.protect.ProtectHandler; -import pro.gravit.launchserver.auth.session.SessionStorage; import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; @@ -47,7 +46,6 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails.class, new UniversalJsonAdapter<>(GetAvailabilityAuthRequest.providers)); builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers)); builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers)); - builder.registerTypeAdapter(SessionStorage.class, new UniversalJsonAdapter<>(SessionStorage.providers)); modulesManager.invokeEvent(new PreGsonPhase(builder)); //ClientWebSocketService.appendTypeAdapters(builder); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java deleted file mode 100644 index 7be2f9ef..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java +++ /dev/null @@ -1,76 +0,0 @@ -package pro.gravit.launchserver.manangers; - -import pro.gravit.launcher.Launcher; -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.utils.HookSet; -import pro.gravit.utils.helper.IOHelper; - -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; - -public class SessionManager { - - private final LaunchServer server; - public HookSet clientRestoreHook = new HookSet<>(); - - public SessionManager(LaunchServer server) { - this.server = server; - } - - - public boolean addClient(Client client) { - if (client == null || client.session == null) return false; - return server.config.sessions.writeSession(client.uuid, client.session, compressClient(client)); - } - - public Stream findSessionsByUUID(UUID uuid) { - return server.config.sessions.getSessionsFromUserUUID(uuid); - } - - public boolean removeByUUID(UUID uuid) { - return server.config.sessions.deleteSessionsByUserUUID(uuid); - } - - public void clear() { - server.config.sessions.clear(); - } - - private byte[] compressClient(Client client) { - return IOHelper.encode(Launcher.gsonManager.gson.toJson(client)); //Compress using later - } - - private Client decompressClient(byte[] client) { - return Launcher.gsonManager.gson.fromJson(IOHelper.decode(client), Client.class); //Compress using later - } - - private Client restoreFromString(byte[] data) { - Client result = decompressClient(data); - result.updateAuth(server); - if (result.auth != null && (result.username != null)) { - result.coreObject = result.auth.core.getUserByUUID(result.uuid); - } - if (result.refCount == null) result.refCount = new AtomicInteger(1); - clientRestoreHook.hook(result); - return result; - } - - - public Client getClient(UUID session) { - if (session == null) return null; - byte[] data = server.config.sessions.getSessionData(session); - if (data == null) return null; - return restoreFromString(data); - } - - - public Client getOrNewClient(UUID session) { - Client client = getClient(session); - return client == null ? new Client(session) : client; - } - - public boolean remove(UUID session) { - return server.config.sessions.deleteSession(session); - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java index 382496c8..b15a6c43 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -13,8 +13,10 @@ import java.util.concurrent.atomic.AtomicInteger; public class Client { + @Deprecated public UUID session; - public boolean useOAuth; + @Deprecated + public boolean useOAuth; // Always true public String auth_id; public long timestamp; public AuthResponse.ConnectTypes type; @@ -36,6 +38,7 @@ public class Client { public Map serializableProperties; + @Deprecated public transient AtomicInteger refCount; public Client(UUID session) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java index 8af37ca0..17d4e723 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/handlers/WebSocketFrameHandler.java @@ -97,14 +97,6 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Client {} disconnected", IOHelper.getIP(ctx.channel().remoteAddress())); } - int refCount = client.refCount.decrementAndGet(); - if (client.session != null) { - if (refCount == 0) { - srv.sessionManager.addClient(client); - } else if (refCount < 0) { - logger.warn("Client session {} reference counter invalid - {}", client.session, refCount); - } - } super.channelInactive(ctx); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java index 82e17f7f..3ee1e1ed 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java @@ -21,7 +21,9 @@ public static void exit(LaunchServer server, WebSocketFrameHandler wsHandler, Ch Client newCusClient = new Client(null); newCusClient.checkSign = chClient.checkSign; wsHandler.setClient(newCusClient); - if (chClient.session != null) server.sessionManager.remove(chClient.session); + if (chClient.session != null) { + throw new UnsupportedOperationException("Legacy session system removed"); + } ExitRequestEvent event = new ExitRequestEvent(reason); event.requestUUID = RequestEvent.eventUUID; wsHandler.service.sendObject(channel, event); @@ -73,7 +75,9 @@ public void execute(ChannelHandlerContext ctx, Client client) { Client newClient = new Client(null); newClient.checkSign = client.checkSign; handler.setClient(newClient); - if (client.session != null) server.sessionManager.remove(client.session); + if (client.session != null) { + throw new UnsupportedOperationException("Legacy session system removed"); + } if (exitAll) { service.forEachActiveChannels(((channel, webSocketFrameHandler) -> { Client client1 = webSocketFrameHandler.getClient(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java index 6d3530c4..d7978c2d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/RestoreSessionResponse.java @@ -21,34 +21,6 @@ public String getType() { @Override public void execute(ChannelHandlerContext ctx, Client client) throws Exception { - if (session == null) { - sendError("Session invalid"); - return; - } - final Client[] rClient = {null}; - service.forEachActiveChannels((channel, handler) -> { - Client c = handler.getClient(); - if (c != null && session.equals(c.session)) { - rClient[0] = c; - } - }); - if (rClient[0] == null) { - rClient[0] = server.sessionManager.getClient(session); - } - if (rClient[0] == null) { - sendError("Session invalid"); - return; - } - if (rClient[0].useOAuth) { - sendError("This session using OAuth. Session restoration not safety"); - return; - } - WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class); - frameHandler.setClient(rClient[0]); - if (needUserInfo) { - sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(server, rClient[0]))); - } else { - sendResult(new RestoreSessionRequestEvent()); - } + sendError("Legacy session system removed"); } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/RestoreSessionRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/RestoreSessionRequestEvent.java index c3a4297c..70016c56 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/RestoreSessionRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/RestoreSessionRequestEvent.java @@ -2,6 +2,7 @@ import pro.gravit.launcher.events.RequestEvent; +@Deprecated public class RestoreSessionRequestEvent extends RequestEvent { public CurrentUserRequestEvent.UserInfo userInfo; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/RestoreSessionRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/RestoreSessionRequest.java index b1642b5f..4e256b6e 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/RestoreSessionRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/RestoreSessionRequest.java @@ -7,6 +7,7 @@ import java.util.UUID; +@Deprecated public class RestoreSessionRequest extends Request implements WebSocketRequest { @LauncherNetworkAPI public final UUID session;