[FEATURE] AuthCoreProvider: OAuth Support Part 1

This commit is contained in:
Gravita 2021-05-23 02:46:31 +07:00
parent f317912de7
commit b919020988
4 changed files with 100 additions and 31 deletions

View file

@ -11,6 +11,7 @@
import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetAllUsers; 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.Client;
import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
@ -41,11 +42,13 @@ public static void registerProviders() {
} }
public abstract User getUserByUsername(String username); public abstract User getUserByUsername(String username);
public abstract User getUserByUUID(UUID uuid); 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 void verifyAuth(AuthResponse.AuthContext context) throws AuthException;
public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password); 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); public abstract void init(LaunchServer server);
// Auth Handler methods // Auth Handler methods
protected abstract boolean updateAuth(User user, String accessToken) throws IOException;
protected abstract boolean updateServerID(User user, String serverID) throws IOException; protected abstract boolean updateServerID(User user, String serverID) throws IOException;
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) { public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
@ -125,7 +128,6 @@ public static class PasswordVerifyReport {
public final boolean success; public final boolean success;
public final boolean needMoreFactor; public final boolean needMoreFactor;
public final List<Integer> factors; public final List<Integer> factors;
public final String accessToken;
public static final PasswordVerifyReport REQUIRED_2FA = new PasswordVerifyReport(-1); public static final PasswordVerifyReport REQUIRED_2FA = new PasswordVerifyReport(-1);
public static final PasswordVerifyReport FAILED = new PasswordVerifyReport(false); public static final PasswordVerifyReport FAILED = new PasswordVerifyReport(false);
@ -133,28 +135,37 @@ public PasswordVerifyReport(boolean success) {
this.success = success; this.success = success;
this.needMoreFactor = false; this.needMoreFactor = false;
this.factors = List.of(); 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) { public PasswordVerifyReport(int nextFactor) {
this.success = false; this.success = false;
this.needMoreFactor = true; this.needMoreFactor = true;
this.factors = List.of(nextFactor); this.factors = List.of(nextFactor);
this.accessToken = null;
} }
public PasswordVerifyReport(List<Integer> factors) { public PasswordVerifyReport(List<Integer> factors) {
this.success = false; this.success = false;
this.needMoreFactor = false; this.needMoreFactor = false;
this.factors = Collections.unmodifiableList(factors); this.factors = Collections.unmodifiableList(factors);
this.accessToken = null; }
private PasswordVerifyReport(boolean success, boolean needMoreFactor, List<Integer> 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);
} }
} }
} }

View file

@ -9,7 +9,9 @@
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.auth.MySQLSourceConfig; import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.launchserver.auth.password.PasswordVerifier; import pro.gravit.launchserver.auth.password.PasswordVerifier;
import pro.gravit.launchserver.manangers.AuthManager;
import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException; import java.io.IOException;
import java.sql.Connection; 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 @Override
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { 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 @Override
public void init(LaunchServer server) { public void init(LaunchServer server) {
if (mySQLHolder == null) logger.error("mySQLHolder cannot be null"); if (mySQLHolder == null) logger.error("mySQLHolder cannot be null");
@ -90,7 +113,6 @@ public void init(LaunchServer server) {
table, serverIDColumn, uuidColumn); table, serverIDColumn, uuidColumn);
} }
@Override
protected boolean updateAuth(User user, String accessToken) throws IOException { protected boolean updateAuth(User user, String accessToken) throws IOException {
try (Connection c = mySQLHolder.getConnection()) { try (Connection c = mySQLHolder.getConnection()) {
PreparedStatement s = c.prepareStatement(updateAuthSQL); PreparedStatement s = c.prepareStatement(updateAuthSQL);

View file

@ -3,6 +3,7 @@
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.manangers.AuthManager;
import pro.gravit.launchserver.socket.response.auth.AuthResponse; import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import java.io.IOException; import java.io.IOException;
@ -19,6 +20,16 @@ public User getUserByUUID(UUID uuid) {
return null; return null;
} }
@Override
public User getUserByOAuthAccessToken(String accessToken) {
return null;
}
@Override
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
return null;
}
@Override @Override
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
throw new AuthException("Please configure AuthCoreProvider"); throw new AuthException("Please configure AuthCoreProvider");
@ -30,13 +41,13 @@ public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordIn
} }
@Override @Override
public void init(LaunchServer server) { public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
return null;
} }
@Override @Override
protected boolean updateAuth(User user, String accessToken) throws IOException { public void init(LaunchServer server) {
return false;
} }
@Override @Override

View file

@ -16,7 +16,6 @@
import pro.gravit.launchserver.auth.provider.AuthProviderResult; import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.auth.AuthResponse; 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.IOHelper;
import pro.gravit.utils.helper.SecurityHelper; 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 * Full client authorization with password verification
* @param context AuthContext * @param context AuthContext
* @param password User password * @param password User password
* @return Access token * @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; AuthProviderPair pair = context.pair;
String accessToken; AuthReport report;
if(pair.core == null) { if(pair.core == null) {
try { try {
accessToken = authWithProviderAndHandler(context, password); report = AuthReport.ofMinecraftAccessToken(authWithProviderAndHandler(context, password));
} catch (Exception e) { } catch (Exception e) {
if(e instanceof AuthException) throw (AuthException) e; if(e instanceof AuthException) throw (AuthException) e;
throw new AuthException("Internal Auth Error. Please contact administrator"); throw new AuthException("Internal Auth Error. Please contact administrator");
} }
} else { } else {
accessToken = authWithCore(context, password); report = authWithCore(context, password);
} }
return accessToken; return report;
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -106,7 +131,7 @@ private String authWithProviderAndHandler(AuthResponse.AuthContext context, Auth
return accessToken; 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; AuthCoreProvider provider = context.pair.core;
provider.verifyAuth(context); provider.verifyAuth(context);
User user = provider.getUserByUsername(context.login); 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); AuthCoreProvider.PasswordVerifyReport report = provider.verifyPassword(user, password);
if(report.success) { if(report.success) {
String accessToken;
UUID uuid = user.getUUID(); UUID uuid = user.getUUID();
if(context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { AuthReport result;
provider.verifyAuth(context); try {
accessToken = report.accessToken; result = provider.createOAuthSession(user, context, report, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context));
} else { } catch (IOException e) {
accessToken = null; logger.error(e);
throw new AuthException("Internal Auth Error");
} }
context.client.coreObject = user; context.client.coreObject = user;
internalAuth(context.client, context.authType, context.pair, user.getUsername(), uuid, user.getPermissions()); internalAuth(context.client, context.authType, context.pair, user.getUsername(), uuid, user.getPermissions());
return accessToken; return result;
} }
else { else {
if(report.needMoreFactor) { if(report.needMoreFactor) {