From 29b5157d426135fe0873c57bac1845482887fbf0 Mon Sep 17 00:00:00 2001 From: Benjamin Elsdon Date: Mon, 2 May 2022 17:25:26 +0800 Subject: [PATCH] Custom Authentication Handler --- .../server/dispatch/DispatchServer.java | 96 ++++++++----------- .../authentication/AuthenticationHandler.java | 16 ++++ .../DefaultAuthenticationHandler.java | 84 ++++++++++++++++ 3 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/dispatch/authentication/AuthenticationHandler.java create mode 100644 src/main/java/emu/grasscutter/server/dispatch/authentication/DefaultAuthenticationHandler.java diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 7b5418e15..5fdda7e87 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -14,6 +14,8 @@ import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegio import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp; import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo; import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo; +import emu.grasscutter.server.dispatch.authentication.AuthenticationHandler; +import emu.grasscutter.server.dispatch.authentication.DefaultAuthenticationHandler; import emu.grasscutter.server.dispatch.json.*; import emu.grasscutter.server.dispatch.json.ComboTokenReqJson.LoginTokenData; import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent; @@ -39,6 +41,7 @@ public final class DispatchServer { public String regionListBase64; public Map regions; + private AuthenticationHandler authHandler; private Express httpServer; public DispatchServer() { @@ -251,6 +254,16 @@ public final class DispatchServer { ctx.result(""); // I'm like 70% sure this won't break anything. }); + // Authentication Handler + // These routes are so that authentication routes are always the same no matter what auth system is used. + httpServer.get("/authentication/type", (req, res) -> { + res.send(this.getAuthHandler().getClass().getName()); + }); + + httpServer.post("/authentication/login", (req, res) -> this.getAuthHandler().handleLogin(req, res)); + httpServer.post("/authentication/register", (req, res) -> this.getAuthHandler().handleRegister(req, res)); + httpServer.post("/authentication/change_password", (req, res) -> this.getAuthHandler().handleChangePassword(req, res)); + // Dispatch httpServer.get("/query_region_list", (req, res) -> { // Log @@ -287,69 +300,15 @@ public final class DispatchServer { try { String body = req.ctx().body(); requestData = getGsonFactory().fromJson(body, LoginAccountRequestJson.class); - } catch (Exception ignored) { - } + } catch (Exception ignored) { } // Create response json if (requestData == null) { return; } - LoginResultJson responseData = new LoginResultJson(); + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s is trying to log in", req.ip())); - Grasscutter.getLogger() - .info(String.format("[Dispatch] Client %s is trying to log in", req.ip())); - - // Login - Account account = DatabaseHelper.getAccountByName(requestData.account); - - // Check if account exists, else create a new one. - if (account == null) { - // Account doesnt exist, so we can either auto create it if the config value is - // set - if (Grasscutter.getConfig().getDispatchOptions().AutomaticallyCreateAccounts) { - // This account has been created AUTOMATICALLY. There will be no permissions - // added. - account = DatabaseHelper.createAccountWithId(requestData.account, 0); - - for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { - account.addPermission(permission); - } - - if (account != null) { - responseData.message = "OK"; - responseData.data.account.uid = account.getId(); - responseData.data.account.token = account.generateSessionKey(); - responseData.data.account.email = account.getEmail(); - - Grasscutter.getLogger() - .info(String.format("[Dispatch] Client %s failed to log in: Account %s created", - req.ip(), responseData.data.account.uid)); - } else { - responseData.retcode = -201; - responseData.message = "Username not found, create failed."; - - Grasscutter.getLogger().info(String.format( - "[Dispatch] Client %s failed to log in: Account create failed", req.ip())); - } - } else { - responseData.retcode = -201; - responseData.message = "Username not found."; - - Grasscutter.getLogger().info(String - .format("[Dispatch] Client %s failed to log in: Account no found", req.ip())); - } - } else { - // Account was found, log the player in - responseData.message = "OK"; - responseData.data.account.uid = account.getId(); - responseData.data.account.token = account.generateSessionKey(); - responseData.data.account.email = account.getEmail(); - - Grasscutter.getLogger().info(String.format("[Dispatch] Client %s logged in as %s", req.ip(), - responseData.data.account.uid)); - } - - res.send(responseData); + res.send(authHandler.handleGameLogin(req, requestData)); }); // Login via token @@ -523,6 +482,29 @@ public final class DispatchServer { return result; } + public AuthenticationHandler getAuthHandler() { + if(authHandler == null) { + return new DefaultAuthenticationHandler(); + } + Grasscutter.getLogger().info(authHandler.getClass().getName()); + + return authHandler; + } + + public boolean registerAuthHandler(AuthenticationHandler authHandler) { + if(this.authHandler != null) { + Grasscutter.getLogger().error(String.format("[Dispatch] Unable to register '%s' authentication handler. \n" + + "The '%s' authentication handler has already been registered", authHandler.getClass().getName(), this.authHandler.getClass().getName())); + return false; + } + this.authHandler = authHandler; + return true; + } + + public void resetAuthHandler() { + this.authHandler = null; + } + public static class RegionData { QueryCurrRegionHttpRsp parsedRegionQuery; String Base64; diff --git a/src/main/java/emu/grasscutter/server/dispatch/authentication/AuthenticationHandler.java b/src/main/java/emu/grasscutter/server/dispatch/authentication/AuthenticationHandler.java new file mode 100644 index 000000000..92a2961ea --- /dev/null +++ b/src/main/java/emu/grasscutter/server/dispatch/authentication/AuthenticationHandler.java @@ -0,0 +1,16 @@ +package emu.grasscutter.server.dispatch.authentication; + +import emu.grasscutter.server.dispatch.json.LoginAccountRequestJson; +import emu.grasscutter.server.dispatch.json.LoginResultJson; +import express.http.Request; +import express.http.Response; + +public interface AuthenticationHandler { + + // This is in case plugins also want some sort of authentication + void handleLogin(Request req, Response res); + void handleRegister(Request req, Response res); + void handleChangePassword(Request req, Response res); + + LoginResultJson handleGameLogin(Request req, LoginAccountRequestJson requestData); +} diff --git a/src/main/java/emu/grasscutter/server/dispatch/authentication/DefaultAuthenticationHandler.java b/src/main/java/emu/grasscutter/server/dispatch/authentication/DefaultAuthenticationHandler.java new file mode 100644 index 000000000..49459f509 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/dispatch/authentication/DefaultAuthenticationHandler.java @@ -0,0 +1,84 @@ +package emu.grasscutter.server.dispatch.authentication; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.Account; +import emu.grasscutter.server.dispatch.json.LoginAccountRequestJson; +import emu.grasscutter.server.dispatch.json.LoginResultJson; +import express.http.Request; +import express.http.Response; + +public class DefaultAuthenticationHandler implements AuthenticationHandler { + + @Override + public void handleLogin(Request req, Response res) { + res.send("Authentication is not available with the default authentication method"); + } + + @Override + public void handleRegister(Request req, Response res) { + res.send("Authentication is not available with the default authentication method"); + } + + @Override + public void handleChangePassword(Request req, Response res) { + res.send("Authentication is not available with the default authentication method"); + } + + @Override + public LoginResultJson handleGameLogin(Request req, LoginAccountRequestJson requestData) { + LoginResultJson responseData = new LoginResultJson(); + + // Login + Account account = DatabaseHelper.getAccountByName(requestData.account); + + // Check if account exists, else create a new one. + if (account == null) { + // Account doesnt exist, so we can either auto create it if the config value is + // set + if (Grasscutter.getConfig().getDispatchOptions().AutomaticallyCreateAccounts) { + // This account has been created AUTOMATICALLY. There will be no permissions + // added. + account = DatabaseHelper.createAccountWithId(requestData.account, 0); + + for (String permission : Grasscutter.getConfig().getDispatchOptions().defaultPermissions) { + account.addPermission(permission); + } + + if (account != null) { + responseData.message = "OK"; + responseData.data.account.uid = account.getId(); + responseData.data.account.token = account.generateSessionKey(); + responseData.data.account.email = account.getEmail(); + + Grasscutter.getLogger() + .info(String.format("[Dispatch] Client %s failed to log in: Account %s created", + req.ip(), responseData.data.account.uid)); + } else { + responseData.retcode = -201; + responseData.message = "Username not found, create failed."; + + Grasscutter.getLogger().info(String.format( + "[Dispatch] Client %s failed to log in: Account create failed", req.ip())); + } + } else { + responseData.retcode = -201; + responseData.message = "Username not found."; + + Grasscutter.getLogger().info(String + .format("[Dispatch] Client %s failed to log in: Account no found", req.ip())); + } + } else { + // Account was found, log the player in + responseData.message = "OK"; + responseData.data.account.uid = account.getId(); + responseData.data.account.token = account.generateSessionKey(); + responseData.data.account.email = account.getEmail(); + + Grasscutter.getLogger().info(String.format("[Dispatch] Client %s logged in as %s", req.ip(), + responseData.data.account.uid)); + } + + return responseData; + } +}