diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 2a75a633..c2388814 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -108,6 +108,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab public final LaunchServerModulesManager modulesManager; // Launcher binary public final MirrorManager mirrorManager; + public final AuthManager authManager; public final ReconfigurableManager reconfigurableManager; public final ConfigManager configManager; public final PingServerManager pingServerManager; @@ -169,6 +170,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La configManager = new ConfigManager(); pingServerManager = new PingServerManager(this); featuresManager = new FeaturesManager(this); + authManager = new AuthManager(this); //Generate or set new Certificate API certificateManager.orgName = config.projectName; config.init(ReloadType.FULL); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index 4e73457d..a9aafffc 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -9,6 +9,7 @@ import pro.gravit.launcher.profiles.optional.actions.OptionalAction; import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider; @@ -199,8 +200,9 @@ public static void initGson(LaunchServerModulesManager modulesManager) { Launcher.gsonManager.initGson(); } + @SuppressWarnings("deprecation") public static void registerAll() { - + AuthCoreProvider.registerProviders(); AuthHandler.registerHandlers(); AuthProvider.registerProviders(); TextureProvider.registerProviders(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java index 35a16c7f..cf83bd15 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java @@ -1,6 +1,7 @@ package pro.gravit.launchserver.auth; import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.provider.AuthProvider; import pro.gravit.launchserver.auth.texture.TextureProvider; @@ -13,6 +14,7 @@ public class AuthProviderPair { public AuthProvider provider; public AuthHandler handler; public TextureProvider textureProvider; + public AuthCoreProvider core; public Map links; public transient String name; public String displayName; @@ -26,12 +28,18 @@ public AuthProviderPair(AuthProvider provider, AuthHandler handler, TextureProvi public void init(LaunchServer srv, String name) { this.name = name; if (links != null) link(srv); - if (provider == null) throw new NullPointerException(String.format("Auth %s provider null", name)); - if (handler == null) throw new NullPointerException(String.format("Auth %s handler null", name)); + if(core == null) { + if (provider == null) throw new NullPointerException(String.format("Auth %s provider null", name)); + if (handler == null) throw new NullPointerException(String.format("Auth %s handler null", name)); + provider.init(srv); + handler.init(srv); + } else { + if (provider != null) throw new IllegalArgumentException(String.format("Auth %s provider not null", name)); + if (handler != null) throw new IllegalArgumentException(String.format("Auth %s handler not null", name)); + core.init(srv); + } if (textureProvider == null) throw new NullPointerException(String.format("Auth %s textureProvider null", name)); - provider.init(srv); - handler.init(srv); } public void link(LaunchServer srv) { @@ -57,8 +65,20 @@ public void link(LaunchServer srv) { } public void close() throws IOException { - provider.close(); - handler.close(); + if(core == null) { + provider.close(); + handler.close(); + } else { + core.close(); + } textureProvider.close(); } + + public boolean isUseCore() { + return core != null; + } + + public boolean isUseProviderAndHandler() { + return !isUseCore(); + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java new file mode 100644 index 00000000..0d9b176a --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java @@ -0,0 +1,95 @@ +package pro.gravit.launchserver.auth.core; + +import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.details.AuthPasswordDetails; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.utils.ProviderMap; +import pro.gravit.utils.helper.SecurityHelper; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/* +All-In-One provider + */ +public abstract class AuthCoreProvider implements AutoCloseable { + public static final ProviderMap providers = new ProviderMap<>("AuthCoreProvider"); + private static boolean registredProviders = false; + public static void registerProviders() { + if (!registredProviders) { + registredProviders = true; + } + } + public abstract User getUserByUsername(String username); + public abstract User getUserByUUID(UUID uuid); + public abstract void verifyAuth(AuthResponse.AuthContext context) throws AuthException; + public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password); + public abstract void init(LaunchServer server); + // Auth Handler methods + protected abstract boolean updateAuth(User user) throws IOException; + protected abstract boolean updateServerID(User user, String serverID) throws IOException; + + public List getDetails(Client client) { + return List.of(new AuthPasswordDetails()); + } + + public UUID checkServer(Client client, String username, String serverID) throws IOException { + User user = getUserByUsername(username); + if(user.getUsername().equals(username) && user.getServerId().equals(serverID)) { + return user.getUUID(); + } + return null; + } + + public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { + User user = client.getUser(); + if(user == null) return false; + return user.getUsername().equals(username) && user.getAccessToken().equals(accessToken) && updateServerID(user, serverID); + } + + @Override + public abstract void close() throws IOException; + + public static class PasswordVerifyReport { + public final boolean success; + public final boolean needMoreFactor; + public final List factors; + public final String accessToken; + public static final PasswordVerifyReport REQUIRED_2FA = new PasswordVerifyReport(-1); + public static final PasswordVerifyReport FAILED = new PasswordVerifyReport(false); + + public PasswordVerifyReport(boolean success) { + this.success = success; + this.needMoreFactor = false; + this.factors = List.of(); + this.accessToken = SecurityHelper.randomStringToken(); + } + + public PasswordVerifyReport(String accessToken) { + this.success = true; + this.needMoreFactor = false; + this.factors = List.of(); + this.accessToken = accessToken; + } + + public PasswordVerifyReport(int nextFactor) { + this.success = false; + this.needMoreFactor = true; + this.factors = List.of(nextFactor); + this.accessToken = null; + } + + public PasswordVerifyReport(List factors) { + this.success = false; + this.needMoreFactor = false; + this.factors = Collections.unmodifiableList(factors); + this.accessToken = null; + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java new file mode 100644 index 00000000..adb5357d --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/User.java @@ -0,0 +1,13 @@ +package pro.gravit.launchserver.auth.core; + +import pro.gravit.launcher.ClientPermissions; + +import java.util.UUID; + +public interface User { + String getUsername(); + UUID getUUID(); + String getServerId(); + String getAccessToken(); + ClientPermissions getPermissions(); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRegistration.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRegistration.java new file mode 100644 index 00000000..a9ab2100 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRegistration.java @@ -0,0 +1,10 @@ +package pro.gravit.launchserver.auth.core.interfaces.provider; + +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launchserver.auth.core.User; + +import java.util.Map; + +public interface AuthSupportRegistration { + User registration(String login, AuthRequest.AuthPasswordInterface password, Map properties); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportMoney.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportMoney.java new file mode 100644 index 00000000..f36d101a --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/user/UserSupportMoney.java @@ -0,0 +1,6 @@ +package pro.gravit.launchserver.auth.core.interfaces.user; + +public interface UserSupportMoney { + long getMoney(); + long getDonateMoney(); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/User.java b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/User.java index 90bf2494..eaa193ad 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/User.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/User.java @@ -4,6 +4,7 @@ import java.util.UUID; +@Deprecated public interface User { String getUsername(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserDAO.java b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserDAO.java index aaec8520..38672484 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserDAO.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserDAO.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.UUID; +@Deprecated public interface UserDAO { User findById(int id); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/provider/DaoProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/provider/DaoProvider.java index c4fbdedc..5735f71d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/provider/DaoProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/provider/DaoProvider.java @@ -4,6 +4,7 @@ import pro.gravit.launchserver.dao.UserDAO; import pro.gravit.utils.ProviderMap; +@Deprecated public abstract class DaoProvider { public static final ProviderMap providers = new ProviderMap<>("DaoProvider"); public transient UserDAO userDAO; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java new file mode 100644 index 00000000..83564c93 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -0,0 +1,228 @@ +package pro.gravit.launchserver.manangers; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.password.*; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.auth.AuthProviderPair; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.launchserver.auth.provider.AuthProvider; +import pro.gravit.launchserver.auth.provider.AuthProviderDAOResult; +import pro.gravit.launchserver.auth.provider.AuthProviderResult; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse; +import pro.gravit.utils.helper.IOHelper; +import pro.gravit.utils.helper.SecurityHelper; + +import javax.crypto.Cipher; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +public class AuthManager { + private transient final LaunchServer server; + private transient final Logger logger = LogManager.getLogger(); + + public AuthManager(LaunchServer server) { + this.server = server; + } + + /** + * Create AuthContext + * @return AuthContext instance + */ + public AuthResponse.AuthContext makeAuthContext(Client client, AuthResponse.ConnectTypes authType, AuthProviderPair pair, String login, String profileName, String ip) { + Objects.requireNonNull(client, "Client must be not null"); + Objects.requireNonNull(authType, "authType must be not null"); + Objects.requireNonNull(pair, "AuthProviderPair must be not null"); + return new AuthResponse.AuthContext(client, login, profileName, ip, authType, pair); + } + + /** + * Validate auth params ans state + * @param context Auth context + * @throws AuthException auth not possible + */ + public void check(AuthResponse.AuthContext context) throws AuthException { + if (context.authType == AuthResponse.ConnectTypes.CLIENT && !context.client.checkSign) { + AuthProvider.authError("Don't skip Launcher Update"); + return; + } + if (context.client.isAuth) { + AuthProvider.authError("You are already logged in"); + return; + } + } + + /** + * Full client authorization with password verification + * @param context AuthContext + * @param password User password + * @return Access token + */ + public String auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException { + AuthProviderPair pair = context.pair; + String accessToken; + if(pair.core == null) { + try { + accessToken = authWithProviderAndHandler(context, password); + } catch (Exception e) { + if(e instanceof AuthException) throw (AuthException) e; + throw new AuthException("Internal Auth Error. Please contact administrator"); + } + } else { + accessToken = authWithCore(context, password); + } + return accessToken; + } + + @SuppressWarnings("deprecation") + private String authWithProviderAndHandler(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws Exception { + String accessToken; + context.pair.provider.preAuth(context.login, password, context.ip); + AuthProviderResult aresult = context.pair.provider.auth(context.login, password, context.ip); + UUID uuid; + String username = aresult.username != null ? aresult.username : context.login; + if (aresult instanceof AuthProviderDAOResult) { + context.client.daoObject = ((AuthProviderDAOResult) aresult).daoObject; + } + if(context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { + uuid = context.pair.handler.auth(aresult); + accessToken = aresult.accessToken; + } else { + uuid = context.pair.handler.usernameToUUID(aresult.username); + accessToken = null; + } + internalAuth(context.client, context.authType, context.pair, username, uuid, aresult.permissions); + return accessToken; + } + + private String authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException { + AuthCoreProvider provider = context.pair.core; + provider.verifyAuth(context); + User user = provider.getUserByUsername(context.login); + if(user == null) { + throw new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE); + } + AuthCoreProvider.PasswordVerifyReport report = provider.verifyPassword(user, password); + if(report.success) { + String accessToken; + UUID uuid = user.getUUID(); + if(context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { + provider.verifyAuth(context); + accessToken = report.accessToken; + } else { + accessToken = null; + } + context.client.coreObject = user; + internalAuth(context.client, context.authType, context.pair, user.getUsername(), uuid, user.getPermissions()); + return accessToken; + } + else { + if(report.needMoreFactor) { + if(report.factors.size() == 1 && report.factors.get(0) == -1) { + throw new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE); + } + String message = AuthRequestEvent.ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX + .concat(report.factors.stream().map(String::valueOf).collect(Collectors.joining("."))); + throw new AuthException(message); + } + throw new AuthException(AuthRequestEvent.WRONG_PASSWORD_ERROR_MESSAGE); + } + } + + /** + * Writing authorization information to the Client object + */ + public void internalAuth(Client client, AuthResponse.ConnectTypes authType, AuthProviderPair pair, String username, UUID uuid, ClientPermissions permissions) { + client.isAuth = true; + client.permissions = permissions; + client.auth_id = pair.name; + client.auth = pair; + client.username = username; + client.type = authType; + client.uuid = uuid; + if(pair.isUseCore() && client.coreObject == null) { + client.coreObject = pair.core.getUserByUUID(uuid); + } + } + + public UUID checkServer(Client client, String username, String serverID) throws IOException { + if(client.auth == null) return null; + if(client.auth.isUseCore()) { + return client.auth.core.checkServer(client, username, serverID); + } + else { + return client.auth.handler.checkServer(username, serverID); + } + } + + public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { + if(client.auth == null) return false; + if(client.auth.isUseCore()) { + return client.auth.core.joinServer(client, username, accessToken, serverID); + } else { + return client.auth.handler.joinServer(username, accessToken, serverID); + } + } + + public AuthRequest.AuthPasswordInterface decryptPassword(AuthRequest.AuthPasswordInterface password) throws AuthException { + if(password instanceof Auth2FAPassword) { + Auth2FAPassword auth2FAPassword = (Auth2FAPassword) password; + auth2FAPassword.firstPassword = tryDecryptPasswordPlain(auth2FAPassword.firstPassword); + auth2FAPassword.secondPassword = tryDecryptPasswordPlain(auth2FAPassword.secondPassword); + } + else if(password instanceof AuthMultiPassword) { + AuthMultiPassword multiPassword = (AuthMultiPassword) password; + List list = new ArrayList<>(multiPassword.list.size()); + for(AuthRequest.AuthPasswordInterface p : multiPassword.list) { + list.add(tryDecryptPasswordPlain(p)); + } + multiPassword.list = list; + } + else { + password = tryDecryptPasswordPlain(password); + } + return password; + } + + @SuppressWarnings("deprecation") + private AuthRequest.AuthPasswordInterface tryDecryptPasswordPlain(AuthRequest.AuthPasswordInterface password) throws AuthException { + if (password instanceof AuthECPassword) { + try { + return new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey + , ((AuthECPassword) password).password))); + } catch (Exception ignored) { + throw new AuthException("Password decryption error"); + } + } + if (password instanceof AuthAESPassword) { + try { + return new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey + , ((AuthAESPassword) password).password))); + } catch (Exception ignored) { + throw new AuthException("Password decryption error"); + } + } + if(password instanceof AuthRSAPassword) { + try { + Cipher cipher = SecurityHelper.newRSADecryptCipher(server.keyAgreementManager.rsaPrivateKey); + return new AuthPlainPassword( + IOHelper.decode(cipher.doFinal(((AuthRSAPassword) password).password)) + ); + } catch (Exception ignored) { + throw new AuthException("Password decryption error"); + } + } + return password; + } +} 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 b8c54922..cacdb4f0 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -9,6 +9,7 @@ import pro.gravit.launcher.request.WebSocketEvent; import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider; @@ -31,11 +32,13 @@ public LaunchServerGsonManager(LaunchServerModulesManager modulesManager) { } @Override + @SuppressWarnings("deprecation") public void registerAdapters(GsonBuilder builder) { super.registerAdapters(builder); builder.registerTypeAdapter(AuthProvider.class, new UniversalJsonAdapter<>(AuthProvider.providers)); builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers)); builder.registerTypeAdapter(AuthHandler.class, new UniversalJsonAdapter<>(AuthHandler.providers)); + builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers)); builder.registerTypeAdapter(Component.class, new UniversalJsonAdapter<>(Component.providers)); builder.registerTypeAdapter(ProtectHandler.class, new UniversalJsonAdapter<>(ProtectHandler.providers)); builder.registerTypeAdapter(DaoProvider.class, new UniversalJsonAdapter<>(DaoProvider.providers)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java index b9a7a32a..ba91c284 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/SessionManager.java @@ -53,12 +53,17 @@ private Client decompressClient(byte[] client) { return Launcher.gsonManager.gson.fromJson(new String(client, StandardCharsets.UTF_8), Client.class); //Compress using later } + @SuppressWarnings("deprecation") private Client restoreFromString(byte[] data) { Client result = decompressClient(data); result.updateAuth(server); if (result.auth != null && (result.username != null)) { - if (result.auth.handler instanceof RequiredDAO || result.auth.provider instanceof RequiredDAO || result.auth.textureProvider instanceof RequiredDAO) { - result.daoObject = server.config.dao.userDAO.findByUsername(result.username); + if(result.auth.isUseCore()) { + result.coreObject = result.auth.core.getUserByUUID(result.uuid); + } else { + if (result.auth.handler instanceof RequiredDAO || result.auth.provider instanceof RequiredDAO || result.auth.textureProvider instanceof RequiredDAO) { + result.daoObject = server.config.dao.userDAO.findByUsername(result.username); + } } } if (result.refCount == null) result.refCount = new AtomicInteger(1); 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 776672d3..6d052f94 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -28,8 +28,11 @@ public class Client { public transient AuthProviderPair auth; + @Deprecated public transient User daoObject; + public transient pro.gravit.launchserver.auth.core.User coreObject; + public transient Map properties; public Map serializableProperties; @@ -78,6 +81,14 @@ public void setSerializableProperty(String name, String value) { properties.put(name, value); } + public pro.gravit.launchserver.auth.core.User getUser() { + if(coreObject != null) return coreObject; + if(auth != null && uuid != null && auth.isUseCore()) { + coreObject = auth.core.getUserByUUID(uuid); + } + return coreObject; + } + @Deprecated public enum Type { SERVER, diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java index a65c47ab..a603ce98 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java @@ -221,6 +221,7 @@ public void sendObjectToUUID(UUID userUuid, Object obj, Type type) { } } + @Deprecated public void updateDaoObject(UUID userUuid, User daoObject, Consumer callback) { for (Channel ch : channels) { if (ch == null || ch.pipeline() == null) continue; @@ -252,7 +253,7 @@ public boolean kickByUserUUID(UUID userUuid, boolean isClose) { WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class); if (wsHandler == null) continue; Client client = wsHandler.getClient(); - if (client == null || client.daoObject == null || !userUuid.equals(client.uuid)) continue; + if (client == null || !userUuid.equals(client.uuid)) continue; ExitResponse.exit(server, wsHandler, ch, ExitRequestEvent.ExitReason.SERVER); if (isClose) ch.close(); result = true; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java index 693d573f..160d3a48 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java @@ -48,15 +48,6 @@ public String getType() { public void execute(ChannelHandlerContext ctx, Client clientData) throws Exception { try { AuthRequestEvent result = new AuthRequestEvent(); - if ((authType == null || authType == ConnectTypes.CLIENT) && (clientData == null || !clientData.checkSign)) { - AuthProvider.authError("Don't skip Launcher Update"); - return; - } - - if (clientData.isAuth) { - sendError("You are already logged in"); - return; - } AuthProviderPair pair; if (auth_id == null || auth_id.isEmpty()) pair = server.config.getAuthProviderPair(); else pair = server.config.getAuthProviderPair(auth_id); @@ -64,45 +55,12 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti sendError("auth_id incorrect"); return; } - AuthContext context = new AuthContext(clientData, login, client, ip, authType); - AuthProvider provider = pair.provider; + AuthContext context = server.authManager.makeAuthContext(clientData, authType, pair, login, client, ip); + server.authManager.check(context); + password = server.authManager.decryptPassword(password); server.authHookManager.preHook.hook(context, clientData); - provider.preAuth(login, password, ip); - if(password instanceof Auth2FAPassword) { - AuthPlainPassword first = decryptPassword(server, ((Auth2FAPassword) password).firstPassword); - AuthPlainPassword second = decryptPassword(server, ((Auth2FAPassword) password).secondPassword); - if(first != null) { - ((Auth2FAPassword) password).firstPassword = first; - } - if(second != null) { - ((Auth2FAPassword) password).secondPassword = second; - } - } - else { - AuthPlainPassword passwd = decryptPassword(server, password); - if(passwd != null) { - password = passwd; - } - } - AuthProviderResult aresult = provider.auth(login, password, ip); - if (!VerifyHelper.isValidUsername(aresult.username)) { - AuthProvider.authError(String.format("Illegal result: '%s'", aresult.username)); - return; - } + server.authManager.auth(context, password); server.authHookManager.postHook.hook(context, clientData); - clientData.isAuth = true; - clientData.permissions = aresult.permissions; - clientData.auth_id = auth_id; - clientData.updateAuth(server); - if (aresult.username != null) - clientData.username = aresult.username; - else - clientData.username = login; - if (aresult instanceof AuthProviderDAOResult) { - clientData.daoObject = ((AuthProviderDAOResult) aresult).daoObject; - } - result.accessToken = aresult.accessToken; - result.permissions = clientData.permissions; if (getSession) { if (clientData.session == null) { clientData.session = UUID.randomUUID(); @@ -110,56 +68,13 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti } result.session = clientData.session; } - if (authType == ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { - clientData.uuid = pair.handler.auth(aresult); - if (logger.isDebugEnabled()) { - logger.debug("Auth: {} accessToken {} uuid: {}", login, result.accessToken, clientData.uuid.toString()); - } - } else { - clientData.uuid = pair.handler.usernameToUUID(aresult.username); - result.accessToken = null; - } - - result.playerProfile = ProfileByUUIDResponse.getProfile(clientData.uuid, aresult.username, client, clientData.auth.textureProvider); - - clientData.type = authType; + result.playerProfile = ProfileByUUIDResponse.getProfile(clientData.uuid, clientData.username, client, clientData.auth.textureProvider); sendResult(result); } catch (AuthException | HookException e) { sendError(e.getMessage()); } } - @SuppressWarnings("deprecation") - public static AuthPlainPassword decryptPassword(LaunchServer server, AuthRequest.AuthPasswordInterface password) throws Exception { - if (password instanceof AuthECPassword) { - try { - return new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey - , ((AuthECPassword) password).password))); - } catch (IllegalBlockSizeException | BadPaddingException ignored) { - throw new AuthException("Password decryption error"); - } - } - if (password instanceof AuthAESPassword) { - try { - return new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey - , ((AuthAESPassword) password).password))); - } catch (IllegalBlockSizeException | BadPaddingException ignored) { - throw new AuthException("Password decryption error"); - } - } - if(password instanceof AuthRSAPassword) { - try { - Cipher cipher = SecurityHelper.newRSADecryptCipher(server.keyAgreementManager.rsaPrivateKey); - return new AuthPlainPassword( - IOHelper.decode(cipher.doFinal(((AuthRSAPassword) password).password)) - ); - } catch (IllegalBlockSizeException | BadPaddingException ignored) { - throw new AuthException("Password decryption error"); - } - } - return null; - } - public enum ConnectTypes { @Deprecated SERVER, @@ -173,15 +88,17 @@ public static class AuthContext { public final String ip; public final ConnectTypes authType; public final Client client; + public final AuthProviderPair pair; @Deprecated public int password_length; //Use AuthProvider for get password - public AuthContext(Client client, String login, String profileName, String ip, ConnectTypes authType) { + public AuthContext(Client client, String login, String profileName, String ip, ConnectTypes authType, AuthProviderPair pair) { this.client = client; this.login = login; this.profileName = profileName; this.ip = ip; this.authType = authType; + this.pair = pair; } } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CheckServerResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CheckServerResponse.java index d44667d9..7288c53f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CheckServerResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/CheckServerResponse.java @@ -31,10 +31,11 @@ public void execute(ChannelHandlerContext ctx, Client pClient) { CheckServerRequestEvent result = new CheckServerRequestEvent(); try { server.authHookManager.checkServerHook.hook(this, pClient); - result.uuid = pClient.auth.handler.checkServer(username, serverID); - if (result.uuid != null) + result.uuid = server.authManager.checkServer(pClient, username, serverID); + if (result.uuid != null) { result.playerProfile = ProfileByUUIDResponse.getProfile(result.uuid, username, client, pClient.auth.textureProvider); - logger.debug("checkServer: {} uuid: {} serverID: {}", result.playerProfile.username, result.uuid, serverID); + logger.debug("checkServer: {} uuid: {} serverID: {}", result.playerProfile.username, result.uuid, serverID); + } } catch (AuthException | HookException e) { sendError(e.getMessage()); return; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java index 537083a4..903b4036 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/JoinServerResponse.java @@ -42,11 +42,10 @@ public void execute(ChannelHandlerContext ctx, Client client) { return; } } - if (client.auth == null) { - logger.warn("Client auth is null. Using default."); - success = server.config.getAuthProviderPair().handler.joinServer(username, accessToken, serverID); - } else success = client.auth.handler.joinServer(username, accessToken, serverID); - logger.debug("joinServer: {} accessToken: {} serverID: {}", username, accessToken, serverID); + success = server.authManager.joinServer(client, username, accessToken, serverID); + if(success) { + logger.debug("joinServer: {} accessToken: {} serverID: {}", username, accessToken, serverID); + } } catch (AuthException | HookException | SecurityException e) { sendError(e.getMessage()); return; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AuthRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AuthRequestEvent.java index 08f35b7d..b6f8e926 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AuthRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/AuthRequestEvent.java @@ -9,6 +9,10 @@ public class AuthRequestEvent extends RequestEvent { public static final String TWO_FACTOR_NEED_ERROR_MESSAGE = "auth.require2fa"; + public static final String ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX = "auth.require.factor."; + public static final String USER_NOT_FOUND_ERROR_MESSAGE = "auth.message.usernotfound"; + public static final String WRONG_PASSWORD_ERROR_MESSAGE = "auth.message.wrongpassword"; + public static final String ACCOUNT_BLOCKED_ERROR_MESSAGE = "auth.message.blocked"; @LauncherNetworkAPI public ClientPermissions permissions; @LauncherNetworkAPI