mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-31 20:59:54 +03:00
[FEATURE] PasswordVerifier and MySQLCoreProvider
This commit is contained in:
parent
9da0ca8604
commit
d9f8b20a71
9 changed files with 271 additions and 2 deletions
|
@ -11,6 +11,7 @@
|
||||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
||||||
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||||
|
@ -203,6 +204,7 @@ public static void initGson(LaunchServerModulesManager modulesManager) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void registerAll() {
|
public static void registerAll() {
|
||||||
AuthCoreProvider.registerProviders();
|
AuthCoreProvider.registerProviders();
|
||||||
|
PasswordVerifier.registerProviders();
|
||||||
AuthHandler.registerHandlers();
|
AuthHandler.registerHandlers();
|
||||||
AuthProvider.registerProviders();
|
AuthProvider.registerProviders();
|
||||||
TextureProvider.registerProviders();
|
TextureProvider.registerProviders();
|
||||||
|
|
|
@ -24,6 +24,7 @@ public abstract class AuthCoreProvider implements AutoCloseable {
|
||||||
public static void registerProviders() {
|
public static void registerProviders() {
|
||||||
if (!registredProviders) {
|
if (!registredProviders) {
|
||||||
providers.register("reject", RejectAuthCoreProvider.class);
|
providers.register("reject", RejectAuthCoreProvider.class);
|
||||||
|
providers.register("mysql", MySQLCoreProvider.class);
|
||||||
registredProviders = true;
|
registredProviders = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +34,7 @@ public static void registerProviders() {
|
||||||
public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password);
|
public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password);
|
||||||
public abstract void init(LaunchServer server);
|
public abstract void init(LaunchServer server);
|
||||||
// Auth Handler methods
|
// Auth Handler methods
|
||||||
protected abstract boolean updateAuth(User user) throws IOException;
|
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) {
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.ClientPermissions;
|
||||||
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
|
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
|
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
||||||
|
import pro.gravit.launchserver.auth.handler.CachedAuthHandler;
|
||||||
|
import pro.gravit.launchserver.auth.password.DigestPasswordVerifier;
|
||||||
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class MySQLCoreProvider extends AuthCoreProvider {
|
||||||
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
public MySQLSourceConfig mySQLHolder;
|
||||||
|
|
||||||
|
public String uuidColumn;
|
||||||
|
public String usernameColumn;
|
||||||
|
public String accessTokenColumn;
|
||||||
|
public String passwordColumn;
|
||||||
|
public String serverIDColumn;
|
||||||
|
public String table;
|
||||||
|
public DigestPasswordVerifier passwordVerifier;
|
||||||
|
|
||||||
|
// Prepared SQL queries
|
||||||
|
private transient String queryByUUIDSQL;
|
||||||
|
private transient String queryByUsernameSQL;
|
||||||
|
private transient String updateAuthSQL;
|
||||||
|
private transient String updateServerIDSQL;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUserByUsername(String username) {
|
||||||
|
try {
|
||||||
|
return query(queryByUsernameSQL, username);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("SQL error", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUserByUUID(UUID uuid) {
|
||||||
|
try {
|
||||||
|
return query(queryByUUIDSQL, uuid.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("SQL error", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
|
||||||
|
if(passwordVerifier.check(((MySQLUser)user).password, ((AuthPlainPassword)password).password)) {
|
||||||
|
return new PasswordVerifyReport(true);
|
||||||
|
} else {
|
||||||
|
return PasswordVerifyReport.FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer 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");
|
||||||
|
if (accessTokenColumn == null) logger.error("accessTokenColumn cannot be null");
|
||||||
|
if (serverIDColumn == null) logger.error("serverIDColumn cannot be null");
|
||||||
|
if (table == null) logger.error("table cannot be null");
|
||||||
|
// Prepare SQL queries
|
||||||
|
queryByUUIDSQL = String.format("SELECT %s, %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
|
||||||
|
uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, passwordColumn, table, uuidColumn);
|
||||||
|
queryByUsernameSQL = String.format("SELECT %s, %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
|
||||||
|
uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, passwordColumn, table, usernameColumn);
|
||||||
|
|
||||||
|
updateAuthSQL = String.format("UPDATE %s SET %s=?, %s=NULL WHERE %s=? LIMIT 1",
|
||||||
|
table, accessTokenColumn, serverIDColumn, uuidColumn);
|
||||||
|
updateServerIDSQL = String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
|
||||||
|
table, serverIDColumn, uuidColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean updateAuth(User user, String accessToken) throws IOException {
|
||||||
|
try (Connection c = mySQLHolder.getConnection()) {
|
||||||
|
PreparedStatement s = c.prepareStatement(updateAuthSQL);
|
||||||
|
s.setString(1, accessToken);
|
||||||
|
s.setString(2, user.getUUID().toString());
|
||||||
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
|
return s.executeUpdate() > 0;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||||
|
try (Connection c = mySQLHolder.getConnection()) {
|
||||||
|
PreparedStatement s = c.prepareStatement(updateServerIDSQL);
|
||||||
|
s.setString(1, serverID);
|
||||||
|
s.setString(2, user.getUUID().toString());
|
||||||
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
|
return s.executeUpdate() > 0;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
mySQLHolder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MySQLUser constructUser(ResultSet set) throws SQLException {
|
||||||
|
return set.next() ? new MySQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||||
|
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), new ClientPermissions()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private User query(String sql, String value) throws IOException {
|
||||||
|
try (Connection c = mySQLHolder.getConnection()) {
|
||||||
|
PreparedStatement s = c.prepareStatement(sql);
|
||||||
|
s.setString(1, value);
|
||||||
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
|
try (ResultSet set = s.executeQuery()) {
|
||||||
|
return constructUser(set);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MySQLUser implements User {
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String username;
|
||||||
|
private final String accessToken;
|
||||||
|
private final String serverId;
|
||||||
|
private final String password;
|
||||||
|
private final ClientPermissions permissions;
|
||||||
|
|
||||||
|
public MySQLUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.username = username;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.serverId = serverId;
|
||||||
|
this.password = password;
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServerId() {
|
||||||
|
return serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPermissions getPermissions() {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ public void init(LaunchServer server) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean updateAuth(User user) throws IOException {
|
protected boolean updateAuth(User user, String accessToken) throws IOException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pro.gravit.launchserver.auth.password;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class DigestPasswordVerifier extends PasswordVerifier {
|
||||||
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
public String algo;
|
||||||
|
@Override
|
||||||
|
public boolean check(String encryptedPassword, String password) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(algo);
|
||||||
|
byte[] bytes = SecurityHelper.fromHex(encryptedPassword);
|
||||||
|
return Arrays.equals(password.getBytes(StandardCharsets.UTF_8), digest.digest(bytes));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
logger.error("Digest algorithm {} not supported", algo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package pro.gravit.launchserver.auth.password;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class DoubleDigestPasswordVerifier extends PasswordVerifier {
|
||||||
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
public String algo;
|
||||||
|
public boolean toHexMode;
|
||||||
|
@Override
|
||||||
|
public boolean check(String encryptedPassword, String password) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(algo);
|
||||||
|
byte[] bytes = SecurityHelper.fromHex(encryptedPassword);
|
||||||
|
byte[] firstDigest = digest.digest(bytes);
|
||||||
|
return Arrays.equals(password.getBytes(StandardCharsets.UTF_8), toHexMode ? digest.digest(SecurityHelper.toHex(firstDigest).getBytes(StandardCharsets.UTF_8)) : digest.digest(firstDigest));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
logger.error("Digest algorithm {} not supported", algo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package pro.gravit.launchserver.auth.password;
|
||||||
|
|
||||||
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
|
||||||
|
public abstract class PasswordVerifier {
|
||||||
|
public static final ProviderMap<PasswordVerifier> providers = new ProviderMap<>("PasswordVerifier");
|
||||||
|
private static boolean registeredProviders = false;
|
||||||
|
public static void registerProviders() {
|
||||||
|
if(!registeredProviders) {
|
||||||
|
providers.register("plain", PlainPasswordVerifier.class);
|
||||||
|
providers.register("digest", DigestPasswordVerifier.class);
|
||||||
|
providers.register("doubleDigest", DoubleDigestPasswordVerifier.class);
|
||||||
|
registeredProviders = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public abstract boolean check(String encryptedPassword, String password);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package pro.gravit.launchserver.auth.password;
|
||||||
|
|
||||||
|
public class PlainPasswordVerifier extends PasswordVerifier {
|
||||||
|
@Override
|
||||||
|
public boolean check(String encryptedPassword, String password) {
|
||||||
|
return encryptedPassword.equals(password);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
||||||
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||||
|
@ -39,6 +40,7 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
||||||
builder.registerTypeAdapter(AuthHandler.class, new UniversalJsonAdapter<>(AuthHandler.providers));
|
builder.registerTypeAdapter(AuthHandler.class, new UniversalJsonAdapter<>(AuthHandler.providers));
|
||||||
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
||||||
|
builder.registerTypeAdapter(PasswordVerifier.class, new UniversalJsonAdapter<>(PasswordVerifier.providers));
|
||||||
builder.registerTypeAdapter(Component.class, new UniversalJsonAdapter<>(Component.providers));
|
builder.registerTypeAdapter(Component.class, new UniversalJsonAdapter<>(Component.providers));
|
||||||
builder.registerTypeAdapter(ProtectHandler.class, new UniversalJsonAdapter<>(ProtectHandler.providers));
|
builder.registerTypeAdapter(ProtectHandler.class, new UniversalJsonAdapter<>(ProtectHandler.providers));
|
||||||
builder.registerTypeAdapter(DaoProvider.class, new UniversalJsonAdapter<>(DaoProvider.providers));
|
builder.registerTypeAdapter(DaoProvider.class, new UniversalJsonAdapter<>(DaoProvider.providers));
|
||||||
|
|
Loading…
Reference in a new issue