mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] New Core Auth System
This commit is contained in:
parent
97faf5ef79
commit
b647f49390
19 changed files with 429 additions and 109 deletions
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<String, String> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AuthCoreProvider> 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<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> 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<Integer> 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<Integer> factors) {
|
||||
this.success = false;
|
||||
this.needMoreFactor = false;
|
||||
this.factors = Collections.unmodifiableList(factors);
|
||||
this.accessToken = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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<String, String> properties);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.user;
|
||||
|
||||
public interface UserSupportMoney {
|
||||
long getMoney();
|
||||
long getDonateMoney();
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
@Deprecated
|
||||
public interface User {
|
||||
String getUsername();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Deprecated
|
||||
public interface UserDAO {
|
||||
User findById(int id);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import pro.gravit.launchserver.dao.UserDAO;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
|
||||
@Deprecated
|
||||
public abstract class DaoProvider {
|
||||
public static final ProviderMap<DaoProvider> providers = new ProviderMap<>("DaoProvider");
|
||||
public transient UserDAO userDAO;
|
||||
|
|
|
@ -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<AuthRequest.AuthPasswordInterface> 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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<String, Object> properties;
|
||||
|
||||
public Map<String, String> 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,
|
||||
|
|
|
@ -221,6 +221,7 @@ public void sendObjectToUUID(UUID userUuid, Object obj, Type type) {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void updateDaoObject(UUID userUuid, User daoObject, Consumer<Channel> 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue