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 index 9903a098..2cb66f72 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java @@ -11,6 +11,7 @@ import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetAllUsers; +import pro.gravit.launchserver.manangers.AuthManager; import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.utils.ProviderMap; @@ -41,11 +42,13 @@ public static void registerProviders() { } public abstract User getUserByUsername(String username); public abstract User getUserByUUID(UUID uuid); + public abstract User getUserByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired; + public abstract AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context /* may be null */); public abstract void verifyAuth(AuthResponse.AuthContext context) throws AuthException; public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password); + public abstract AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context /* may be null */, PasswordVerifyReport report /* may be null */, boolean minecraftAccess) throws IOException; public abstract void init(LaunchServer server); // Auth Handler methods - protected abstract boolean updateAuth(User user, String accessToken) throws IOException; protected abstract boolean updateServerID(User user, String serverID) throws IOException; public List getDetails(Client client) { @@ -125,7 +128,6 @@ 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); @@ -133,28 +135,37 @@ 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; + } + + private PasswordVerifyReport(boolean success, boolean needMoreFactor, List factors) { + this.success = success; + this.needMoreFactor = needMoreFactor; + this.factors = factors; + } + } + + public static class OAuthAccessTokenExpired extends Exception { + public OAuthAccessTokenExpired() { + } + + public OAuthAccessTokenExpired(String message) { + super(message); + } + + public OAuthAccessTokenExpired(String message, Throwable cause) { + super(message, cause); } } } 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 014186e0..5f838918 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 @@ -9,7 +9,9 @@ import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.MySQLSourceConfig; import pro.gravit.launchserver.auth.password.PasswordVerifier; +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.Connection; @@ -56,6 +58,16 @@ public User getUserByUUID(UUID uuid) { } } + @Override + public User getUserByOAuthAccessToken(String accessToken) { + return null; + } + + @Override + public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { + return null; + } + @Override public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { @@ -70,6 +82,17 @@ public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordIn } } + @Override + public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException { + if(minecraftAccess) { + String minecraftAccessToken = SecurityHelper.randomStringToken(); + updateAuth(user, minecraftAccessToken); + return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken); + } else { + return AuthManager.AuthReport.ofMinecraftAccessToken(null); + } + } + @Override public void init(LaunchServer server) { if (mySQLHolder == null) logger.error("mySQLHolder cannot be null"); @@ -90,7 +113,6 @@ public void init(LaunchServer server) { table, serverIDColumn, uuidColumn); } - @Override protected boolean updateAuth(User user, String accessToken) throws IOException { try (Connection c = mySQLHolder.getConnection()) { PreparedStatement s = c.prepareStatement(updateAuthSQL); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java index 7f5afc8b..bbe46169 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java @@ -3,6 +3,7 @@ import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.manangers.AuthManager; import pro.gravit.launchserver.socket.response.auth.AuthResponse; import java.io.IOException; @@ -19,6 +20,16 @@ public User getUserByUUID(UUID uuid) { return null; } + @Override + public User getUserByOAuthAccessToken(String accessToken) { + return null; + } + + @Override + public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { + return null; + } + @Override public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { throw new AuthException("Please configure AuthCoreProvider"); @@ -30,13 +41,13 @@ public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordIn } @Override - public void init(LaunchServer server) { - + public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException { + return null; } @Override - protected boolean updateAuth(User user, String accessToken) throws IOException { - return false; + public void init(LaunchServer server) { + } @Override 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 83564c93..e363bf2a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -16,7 +16,6 @@ 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; @@ -63,26 +62,52 @@ public void check(AuthResponse.AuthContext context) throws AuthException { } } + public static class AuthReport { + public final String minecraftAccessToken; + public final String oauthAccessToken; + public final String oauthRefreshToken; + public final long oauthExpire; + + private AuthReport(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire) { + this.minecraftAccessToken = minecraftAccessToken; + this.oauthAccessToken = oauthAccessToken; + this.oauthRefreshToken = oauthRefreshToken; + this.oauthExpire = oauthExpire; + } + + public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire) { + return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire); + } + + public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire) { + return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire); + } + + public static AuthReport ofMinecraftAccessToken(String minecraftAccessToken) { + return new AuthReport(minecraftAccessToken, null, null, 0); + } + } + /** * 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 { + public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException { AuthProviderPair pair = context.pair; - String accessToken; + AuthReport report; if(pair.core == null) { try { - accessToken = authWithProviderAndHandler(context, password); + report = AuthReport.ofMinecraftAccessToken(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); + report = authWithCore(context, password); } - return accessToken; + return report; } @SuppressWarnings("deprecation") @@ -106,7 +131,7 @@ private String authWithProviderAndHandler(AuthResponse.AuthContext context, Auth return accessToken; } - private String authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException { + private AuthReport authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException { AuthCoreProvider provider = context.pair.core; provider.verifyAuth(context); User user = provider.getUserByUsername(context.login); @@ -115,17 +140,17 @@ private String authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPa } 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; + AuthReport result; + try { + result = provider.createOAuthSession(user, context, report, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)); + } catch (IOException e) { + logger.error(e); + throw new AuthException("Internal Auth Error"); } context.client.coreObject = user; internalAuth(context.client, context.authType, context.pair, user.getUsername(), uuid, user.getPermissions()); - return accessToken; + return result; } else { if(report.needMoreFactor) {