mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE] AuthCoreProvider rework
This commit is contained in:
parent
15da924aa6
commit
2a2c2f6b93
19 changed files with 822 additions and 649 deletions
|
@ -0,0 +1,94 @@
|
||||||
|
package pro.gravit.launchserver;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import pro.gravit.launcher.Launcher;
|
||||||
|
import pro.gravit.launchserver.helper.HttpHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
public class HttpRequester {
|
||||||
|
private transient final HttpClient httpClient = HttpClient.newBuilder().build();
|
||||||
|
|
||||||
|
public HttpRequester() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleErrorHandler<T> implements HttpHelper.HttpJsonErrorHandler<T, SimpleError> {
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
private SimpleErrorHandler(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHelper.HttpOptional<T, SimpleError> applyJson(JsonElement response, int statusCode) {
|
||||||
|
if(statusCode < 200 || statusCode >= 300) {
|
||||||
|
return new HttpHelper.HttpOptional<>(null, Launcher.gsonManager.gson.fromJson(response, SimpleError.class), statusCode);
|
||||||
|
}
|
||||||
|
return new HttpHelper.HttpOptional<>(Launcher.gsonManager.gson.fromJson(response, type), null, statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> SimpleErrorHandler<T> makeEH(Class<T> clazz) {
|
||||||
|
return new SimpleErrorHandler<>(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> HttpRequest get(String url, String token) {
|
||||||
|
try {
|
||||||
|
var requestBuilder = HttpRequest.newBuilder()
|
||||||
|
.method("GET", HttpRequest.BodyPublishers.noBody())
|
||||||
|
.uri(new URI(url))
|
||||||
|
.header("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(10000));
|
||||||
|
if(token != null) {
|
||||||
|
requestBuilder.header("Authorization", "Bearer ".concat(token));
|
||||||
|
}
|
||||||
|
return requestBuilder.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> HttpRequest post(String url, T request, String token) {
|
||||||
|
try {
|
||||||
|
var requestBuilder = HttpRequest.newBuilder()
|
||||||
|
.method("POST", HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request)))
|
||||||
|
.uri(new URI(url))
|
||||||
|
.header("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(10000));
|
||||||
|
if(token != null) {
|
||||||
|
requestBuilder.header("Authorization", "Bearer ".concat(token));
|
||||||
|
}
|
||||||
|
return requestBuilder.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> HttpHelper.HttpOptional<T, SimpleError> send(HttpRequest request, Class<T> clazz) throws IOException {
|
||||||
|
return HttpHelper.send(httpClient, request, makeEH(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleError {
|
||||||
|
public String error;
|
||||||
|
public int code;
|
||||||
|
|
||||||
|
public SimpleError(String error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SimpleError{" +
|
||||||
|
"error='" + error + '\'' +
|
||||||
|
", code=" + code +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
package pro.gravit.launchserver.auth;
|
package pro.gravit.launchserver.auth;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public final class AuthException extends IOException {
|
public final class AuthException extends IOException {
|
||||||
private static final long serialVersionUID = -2586107832847245863L;
|
private static final long serialVersionUID = -2586107832847245863L;
|
||||||
|
@ -10,6 +14,24 @@ public AuthException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AuthException need2FA() {
|
||||||
|
return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthException needMFA(List<Integer> factors) {
|
||||||
|
String message = AuthRequestEvent.ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX
|
||||||
|
.concat(factors.stream().map(String::valueOf).collect(Collectors.joining(".")));
|
||||||
|
return new AuthException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthException wrongPassword() {
|
||||||
|
return new AuthException(AuthRequestEvent.WRONG_PASSWORD_ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthException userNotFound() {
|
||||||
|
return new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getMessage();
|
return getMessage();
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.core.AuthSocialProvider;
|
|
||||||
import pro.gravit.launchserver.auth.core.MySQLCoreProvider;
|
import pro.gravit.launchserver.auth.core.MySQLCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
|
|
||||||
|
@ -17,7 +16,6 @@ public final class AuthProviderPair {
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
public boolean isDefault = true;
|
public boolean isDefault = true;
|
||||||
public AuthCoreProvider core;
|
public AuthCoreProvider core;
|
||||||
public AuthSocialProvider social;
|
|
||||||
public TextureProvider textureProvider;
|
public TextureProvider textureProvider;
|
||||||
public Map<String, String> links;
|
public Map<String, String> links;
|
||||||
public transient String name;
|
public transient String name;
|
||||||
|
@ -33,17 +31,6 @@ public AuthProviderPair(AuthCoreProvider core, TextureProvider textureProvider)
|
||||||
this.textureProvider = textureProvider;
|
this.textureProvider = textureProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthProviderPair(AuthCoreProvider core, AuthSocialProvider social) {
|
|
||||||
this.core = core;
|
|
||||||
this.social = social;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthProviderPair(AuthCoreProvider core, AuthSocialProvider social, TextureProvider textureProvider) {
|
|
||||||
this.core = core;
|
|
||||||
this.social = social;
|
|
||||||
this.textureProvider = textureProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<String> getFeatures(Class<?> clazz) {
|
public static Set<String> getFeatures(Class<?> clazz) {
|
||||||
Set<String> list = new HashSet<>();
|
Set<String> list = new HashSet<>();
|
||||||
getFeatures(clazz, list);
|
getFeatures(clazz, list);
|
||||||
|
@ -79,7 +66,6 @@ public static void getFeatures(Class<?> clazz, Set<String> list) {
|
||||||
public final <T> T isSupport(Class<T> clazz) {
|
public final <T> T isSupport(Class<T> clazz) {
|
||||||
if (core == null) return null;
|
if (core == null) return null;
|
||||||
T result = null;
|
T result = null;
|
||||||
if (social != null) result = social.isSupport(clazz);
|
|
||||||
if (result == null) result = core.isSupport(clazz);
|
if (result == null) result = core.isSupport(clazz);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -90,10 +76,6 @@ public final void init(LaunchServer srv, String name) {
|
||||||
core.init(srv);
|
core.init(srv);
|
||||||
features = new HashSet<>();
|
features = new HashSet<>();
|
||||||
getFeatures(core.getClass(), features);
|
getFeatures(core.getClass(), features);
|
||||||
if (social != null) {
|
|
||||||
social.init(srv, core);
|
|
||||||
getFeatures(social.getClass(), features);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void link(LaunchServer srv) {
|
public final void link(LaunchServer srv) {
|
||||||
|
@ -111,16 +93,9 @@ public final void link(LaunchServer srv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void close() throws IOException {
|
public final void close() throws IOException {
|
||||||
if (social != null) {
|
|
||||||
social.close();
|
|
||||||
}
|
|
||||||
core.close();
|
core.close();
|
||||||
if (textureProvider != null) {
|
if (textureProvider != null) {
|
||||||
textureProvider.close();
|
textureProvider.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isUseSocial() {
|
|
||||||
return core != null && social != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ public static void registerProviders() {
|
||||||
if (!registredProviders) {
|
if (!registredProviders) {
|
||||||
providers.register("reject", RejectAuthCoreProvider.class);
|
providers.register("reject", RejectAuthCoreProvider.class);
|
||||||
providers.register("mysql", MySQLCoreProvider.class);
|
providers.register("mysql", MySQLCoreProvider.class);
|
||||||
providers.register("json", JsonCoreProvider.class);
|
providers.register("memory", MemoryAuthCoreProvider.class);
|
||||||
|
providers.register("http", HttpAuthCoreProvider.class);
|
||||||
registredProviders = true;
|
registredProviders = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,16 +63,22 @@ public User getUserByLogin(String login) {
|
||||||
|
|
||||||
public abstract AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context /* may be null */);
|
public abstract AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context /* may be null */);
|
||||||
|
|
||||||
public abstract void verifyAuth(AuthResponse.AuthContext context) throws AuthException;
|
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
|
||||||
|
// None
|
||||||
|
}
|
||||||
|
|
||||||
public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password);
|
public abstract AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context /* may be null */, AuthRequest.AuthPasswordInterface password /* may be null */, boolean minecraftAccess) throws IOException;
|
||||||
|
|
||||||
public abstract AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context /* may be null */, PasswordVerifyReport report /* may be null */, boolean minecraftAccess) throws IOException;
|
public AuthManager.AuthReport authorize(User user, AuthResponse.AuthContext context /* may be null */, AuthRequest.AuthPasswordInterface password /* may be null */, boolean minecraftAccess) throws IOException {
|
||||||
|
return authorize(user.getUsername(), context, password, minecraftAccess);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void init(LaunchServer server);
|
public abstract void init(LaunchServer server);
|
||||||
|
|
||||||
// Auth Handler methods
|
// Auth Handler methods
|
||||||
protected abstract boolean updateServerID(User user, String serverID) throws IOException;
|
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||||
return List.of(new AuthPasswordDetails());
|
return List.of(new AuthPasswordDetails());
|
||||||
|
@ -80,31 +87,27 @@ public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Command> getCommands() {
|
public Map<String, Command> getCommands() {
|
||||||
Map<String, Command> map = defaultCommandsMap();
|
Map<String, Command> map = defaultCommandsMap();
|
||||||
map.put("checkpassword", new SubCommand("[username] [json/plain password data]", "check password") {
|
map.put("auth", new SubCommand("[login] (json/plain password data)", "Test auth") {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 2);
|
verifyArgs(args, 1);
|
||||||
User user = getUserByUsername(args[0]);
|
AuthRequest.AuthPasswordInterface password = null;
|
||||||
if (user == null) throw new CommandException("User not found");
|
if(args.length > 1) {
|
||||||
AuthRequest.AuthPasswordInterface password;
|
|
||||||
if (args[1].startsWith("{")) {
|
if (args[1].startsWith("{")) {
|
||||||
password = Launcher.gsonManager.gson.fromJson(args[1], AuthRequest.AuthPasswordInterface.class);
|
password = Launcher.gsonManager.gson.fromJson(args[1], AuthRequest.AuthPasswordInterface.class);
|
||||||
} else {
|
} else {
|
||||||
password = new AuthPlainPassword(args[1]);
|
password = new AuthPlainPassword(args[1]);
|
||||||
}
|
}
|
||||||
PasswordVerifyReport report = verifyPassword(user, password);
|
}
|
||||||
if (report.success) {
|
var report = authorize(args[0], null, password, false);
|
||||||
logger.info("Password correct");
|
if (report.isUsingOAuth()) {
|
||||||
} else {
|
logger.info("OAuth: AccessToken: {} RefreshToken: {} MinecraftAccessToken: {}", report.oauthAccessToken(), report.oauthRefreshToken(), report.minecraftAccessToken());
|
||||||
if (report.needMoreFactors) {
|
if (report.session() != null) {
|
||||||
if (report.factors.size() == 1 && report.factors.get(0) == -1) {
|
logger.info("UserSession: id {} expire {} user {}", report.session().getID(), report.session().getExpireIn(), report.session().getUser() == null ? "null" : "found");
|
||||||
logger.info("Password not correct: Required 2FA");
|
logger.info(report.session().toString());
|
||||||
} else {
|
|
||||||
logger.info("Password not correct: Required more factors: {}", report.factors.toString());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.info("Password incorrect");
|
logger.info("Basic: MinecraftAccessToken: {}", report.minecraftAccessToken());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -132,32 +135,6 @@ public void invoke(String... args) throws Exception {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
map.put("createsession", new SubCommand("[username] (true/false)", "create user session with/without minecraft access") {
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
User user = getUserByUsername(args[0]);
|
|
||||||
if (user == null) {
|
|
||||||
logger.info("User {} not found", args[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boolean minecraftAccess = args.length > 1 && Boolean.parseBoolean(args[1]);
|
|
||||||
AuthManager.AuthReport report = createOAuthSession(user, null, null, minecraftAccess);
|
|
||||||
if (report == null) {
|
|
||||||
logger.error("Method createOAuthSession return null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (report.isUsingOAuth()) {
|
|
||||||
logger.info("OAuth: AccessToken: {} RefreshToken: {} MinecraftAccessToken: {}", report.oauthAccessToken(), report.oauthRefreshToken(), report.minecraftAccessToken());
|
|
||||||
if (report.session() != null) {
|
|
||||||
logger.info("UserSession: id {} expire {} user {}", report.session().getID(), report.session().getExpireIn(), report.session().getUser() == null ? "null" : "found");
|
|
||||||
logger.info(report.session().toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("Basic: MinecraftAccessToken: {}", report.minecraftAccessToken());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
{
|
{
|
||||||
var instance = isSupport(AuthSupportGetAllUsers.class);
|
var instance = isSupport(AuthSupportGetAllUsers.class);
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
|
@ -355,6 +332,12 @@ public PasswordVerifyReport(boolean success) {
|
||||||
this.factors = List.of();
|
this.factors = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PasswordVerifyReport(AuthManager.AuthReport report) {
|
||||||
|
this.success = true;
|
||||||
|
this.needMoreFactors = false;
|
||||||
|
this.factors = List.of();
|
||||||
|
}
|
||||||
|
|
||||||
public PasswordVerifyReport(int nextFactor) {
|
public PasswordVerifyReport(int nextFactor) {
|
||||||
this.success = false;
|
this.success = false;
|
||||||
this.needMoreFactors = true;
|
this.needMoreFactors = true;
|
||||||
|
@ -372,6 +355,10 @@ private PasswordVerifyReport(boolean success, boolean needMoreFactors, List<Inte
|
||||||
this.needMoreFactors = needMoreFactors;
|
this.needMoreFactors = needMoreFactors;
|
||||||
this.factors = factors;
|
this.factors = factors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OAuthAccessTokenExpired extends Exception {
|
public static class OAuthAccessTokenExpired extends Exception {
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
|
||||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
|
||||||
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 java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class AuthSocialProvider implements AutoCloseable {
|
|
||||||
public static final ProviderMap<AuthSocialProvider> providers = new ProviderMap<>("AuthSocialProvider");
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
|
||||||
private static boolean registredProviders = false;
|
|
||||||
|
|
||||||
public static void registerProviders() {
|
|
||||||
if (!registredProviders) {
|
|
||||||
registredProviders = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void init(LaunchServer server, AuthCoreProvider provider);
|
|
||||||
|
|
||||||
public abstract List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client);
|
|
||||||
|
|
||||||
public abstract SocialResult preAuth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T isSupport(Class<T> clazz) {
|
|
||||||
if (clazz.isAssignableFrom(getClass())) return (T) this;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract void close() throws IOException;
|
|
||||||
|
|
||||||
public static class SocialResult {
|
|
||||||
public String login;
|
|
||||||
public AuthRequest.AuthPasswordInterface password;
|
|
||||||
public User user;
|
|
||||||
|
|
||||||
public SocialResult(String login, AuthRequest.AuthPasswordInterface password, User user) {
|
|
||||||
this.login = login;
|
|
||||||
this.password = password;
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SocialResult ofLoginAndPassword(String login, AuthRequest.AuthPasswordInterface password) {
|
|
||||||
return new SocialResult(login, password, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SocialResult ofUser(User user) {
|
|
||||||
return new SocialResult(null, null, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,333 @@
|
||||||
|
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.events.request.AuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.profiles.Texture;
|
||||||
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
|
import pro.gravit.launchserver.HttpRequester;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures;
|
||||||
|
import pro.gravit.launchserver.helper.HttpHelper;
|
||||||
|
import pro.gravit.launchserver.manangers.AuthManager;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
import pro.gravit.utils.helper.CommonHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class HttpAuthCoreProvider extends AuthCoreProvider {
|
||||||
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
private transient HttpRequester requester;
|
||||||
|
public String bearerToken;
|
||||||
|
public String getUserByUsernameUrl;
|
||||||
|
public String getUserByLoginUrl;
|
||||||
|
public String getUserByUUIDUrl;
|
||||||
|
public String getUserByTokenUrl;
|
||||||
|
public String getAuthDetails;
|
||||||
|
public String refreshTokenUrl;
|
||||||
|
public String authorizeUrl;
|
||||||
|
public String joinServerUrl;
|
||||||
|
public String checkServerUrl;
|
||||||
|
public String updateServerIdUrl;
|
||||||
|
@Override
|
||||||
|
public User getUserByUsername(String username) {
|
||||||
|
try {
|
||||||
|
return requester.send(requester.get(CommonHelper.replace(getUserByUsernameUrl, "username", username), null), HttpUser.class).getOrThrow();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUserByLogin(String login) {
|
||||||
|
if(getUserByLoginUrl != null) {
|
||||||
|
try {
|
||||||
|
return requester.send(requester.get(CommonHelper.replace(getUserByLoginUrl, "login", login), null), HttpUser.class).getOrThrow();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.getUserByLogin(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUserByUUID(UUID uuid) {
|
||||||
|
try {
|
||||||
|
return requester.send(requester.get(CommonHelper.replace(getUserByUUIDUrl, "uuid", uuid.toString()), null), HttpUser.class).getOrThrow();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||||
|
if(getAuthDetails == null) {
|
||||||
|
return super.getDetails(client);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var result = requester.send(requester.get(getAuthDetails, bearerToken), GetAuthDetailsResponse.class).getOrThrow();
|
||||||
|
return result.details;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return super.getDetails(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
|
||||||
|
if(getUserByTokenUrl == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var result = requester.send(requester.get(getUserByTokenUrl, accessToken), HttpUserSession.class);
|
||||||
|
if(!result.isSuccessful()) {
|
||||||
|
var error = result.error().error;
|
||||||
|
if(error.equals(AuthRequestEvent.OAUTH_TOKEN_EXPIRE)) {
|
||||||
|
throw new OAuthAccessTokenExpired();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return result.getOrThrow();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
|
||||||
|
if(refreshTokenUrl == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return requester.send(requester.post(refreshTokenUrl, new RefreshTokenRequest(refreshToken, context),
|
||||||
|
null), AuthManager.AuthReport.class).getOrThrow();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||||
|
var result = requester.send(requester.post(authorizeUrl, new AuthorizeRequest(login, context, password, minecraftAccess),
|
||||||
|
bearerToken), AuthManager.AuthReport.class);
|
||||||
|
if(!result.isSuccessful()) {
|
||||||
|
var error = result.error().error;
|
||||||
|
if(error != null) {
|
||||||
|
throw new AuthException(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||||
|
var result = requester.send(requester.post(updateServerIdUrl, new UpdateServerIdRequest(user.getUsername(), user.getUUID(), serverID),
|
||||||
|
null), Void.class);
|
||||||
|
return result.isSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||||
|
return requester.send(requester.post(checkServerUrl, new CheckServerRequest(username, serverID), null), HttpUser.class).getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
||||||
|
var result = requester.send(requester.post(joinServerUrl, new JoinServerRequest(username, accessToken, serverID), null), Void.class);
|
||||||
|
return result.isSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UpdateServerIdRequest {
|
||||||
|
public String username;
|
||||||
|
public UUID uuid;
|
||||||
|
public String serverId;
|
||||||
|
|
||||||
|
public UpdateServerIdRequest(String username, UUID uuid, String serverId) {
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CheckServerRequest {
|
||||||
|
public String username;
|
||||||
|
public String serverId;
|
||||||
|
|
||||||
|
public CheckServerRequest(String username, String serverId) {
|
||||||
|
this.username = username;
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GetAuthDetailsResponse {
|
||||||
|
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class JoinServerRequest {
|
||||||
|
public String username;
|
||||||
|
public String accessToken;
|
||||||
|
public String serverId;
|
||||||
|
|
||||||
|
public JoinServerRequest(String username, String accessToken, String serverId) {
|
||||||
|
this.username = username;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.serverId = serverId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
requester = new HttpRequester();
|
||||||
|
if(getUserByUsernameUrl == null) {
|
||||||
|
throw new IllegalArgumentException("'getUserByUsernameUrl' can't be null");
|
||||||
|
}
|
||||||
|
if(getUserByUUIDUrl == null) {
|
||||||
|
throw new IllegalArgumentException("'getUserByUUIDUrl' can't be null");
|
||||||
|
}
|
||||||
|
if(authorizeUrl == null) {
|
||||||
|
throw new IllegalArgumentException("'authorizeUrl' can't be null");
|
||||||
|
}
|
||||||
|
if((checkServerUrl == null && joinServerUrl == null) || updateServerIdUrl == null) {
|
||||||
|
throw new IllegalArgumentException("Please set 'checkServerUrl' and 'joinServerUrl' or 'updateServerIdUrl'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AuthorizeRequest {
|
||||||
|
public String login;
|
||||||
|
public AuthResponse.AuthContext context;
|
||||||
|
public AuthRequest.AuthPasswordInterface password;
|
||||||
|
public boolean minecraftAccess;
|
||||||
|
|
||||||
|
public AuthorizeRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthorizeRequest(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) {
|
||||||
|
this.login = login;
|
||||||
|
this.context = context;
|
||||||
|
this.password = password;
|
||||||
|
this.minecraftAccess = minecraftAccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RefreshTokenRequest {
|
||||||
|
public String refreshToken;
|
||||||
|
public AuthResponse.AuthContext context;
|
||||||
|
|
||||||
|
public RefreshTokenRequest(String refreshToken, AuthResponse.AuthContext context) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HttpUser implements User, UserSupportTextures {
|
||||||
|
private String username;
|
||||||
|
private UUID uuid;
|
||||||
|
private String serverId;
|
||||||
|
private String accessToken;
|
||||||
|
private ClientPermissions permissions;
|
||||||
|
private Texture skin;
|
||||||
|
private Texture cloak;
|
||||||
|
|
||||||
|
public HttpUser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions) {
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.serverId = serverId;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak) {
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.serverId = serverId;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.permissions = permissions;
|
||||||
|
this.skin = skin;
|
||||||
|
this.cloak = cloak;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Texture getSkinTexture() {
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Texture getCloakTexture() {
|
||||||
|
return cloak;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HttpUserSession implements UserSession {
|
||||||
|
private String id;
|
||||||
|
private User user;
|
||||||
|
private long expireIn;
|
||||||
|
|
||||||
|
public HttpUserSession() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpUserSession(String id, User user, long expireIn) {
|
||||||
|
this.id = id;
|
||||||
|
this.user = user;
|
||||||
|
this.expireIn = expireIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getExpireIn() {
|
||||||
|
return expireIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,410 +0,0 @@
|
||||||
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.Launcher;
|
|
||||||
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
|
||||||
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.password.PasswordVerifier;
|
|
||||||
import pro.gravit.launchserver.manangers.AuthManager;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.http.HttpClient;
|
|
||||||
import java.net.http.HttpRequest;
|
|
||||||
import java.net.http.HttpResponse;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class JsonCoreProvider extends AuthCoreProvider {
|
|
||||||
private static transient final Logger logger = LogManager.getLogger();
|
|
||||||
public String getUserByUsernameUrl;
|
|
||||||
public String getUserByLoginUrl;
|
|
||||||
public String getUserByUUIDUrl;
|
|
||||||
public String getUserSessionByOAuthAccessTokenUrl;
|
|
||||||
public String getAuthDetailsUrl;
|
|
||||||
public String refreshAccessTokenUrl;
|
|
||||||
public String verifyPasswordUrl;
|
|
||||||
public String createOAuthSessionUrl;
|
|
||||||
public String updateServerIdUrl;
|
|
||||||
public String joinServerUrl;
|
|
||||||
public String checkServerUrl;
|
|
||||||
public String bearerToken;
|
|
||||||
public PasswordVerifier passwordVerifier;
|
|
||||||
private transient HttpClient client;
|
|
||||||
|
|
||||||
public static <T, R> R jsonRequest(T request, String url, String bearerToken, Class<R> clazz, HttpClient client) {
|
|
||||||
HttpRequest.BodyPublisher publisher;
|
|
||||||
if (request != null) {
|
|
||||||
publisher = HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request));
|
|
||||||
} else {
|
|
||||||
publisher = HttpRequest.BodyPublishers.noBody();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
HttpRequest.Builder request1 = HttpRequest.newBuilder()
|
|
||||||
.method("POST", publisher)
|
|
||||||
.uri(new URI(url))
|
|
||||||
.header("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.timeout(Duration.ofMillis(10000));
|
|
||||||
if (bearerToken != null) {
|
|
||||||
request1.header("Authorization", "Bearer ".concat(bearerToken));
|
|
||||||
}
|
|
||||||
HttpResponse<InputStream> response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream());
|
|
||||||
int statusCode = response.statusCode();
|
|
||||||
if (200 > statusCode || statusCode > 300) {
|
|
||||||
if (statusCode >= 500) {
|
|
||||||
logger.error("JsonCoreProvider: {} return {}", url, statusCode);
|
|
||||||
} else if (statusCode >= 300 && statusCode <= 400) {
|
|
||||||
logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown"));
|
|
||||||
} else if (statusCode == 403 || statusCode == 401) {
|
|
||||||
logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try (Reader reader = new InputStreamReader(response.body())) {
|
|
||||||
return Launcher.gsonManager.gson.fromJson(reader, clazz);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getUserByUsername(String username) {
|
|
||||||
return jsonRequest(new JsonGetUserByUsername(username), getUserByUsernameUrl, JsonUser.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getUserByLogin(String login) {
|
|
||||||
if (getUserByLoginUrl != null) {
|
|
||||||
return jsonRequest(new JsonGetUserByUsername(login), getUserByLoginUrl, JsonUser.class);
|
|
||||||
}
|
|
||||||
return super.getUserByLogin(login);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getUserByUUID(UUID uuid) {
|
|
||||||
return jsonRequest(new JsonGetUserByUUID(uuid), getUserByUUIDUrl, JsonUser.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
|
|
||||||
if (getUserSessionByOAuthAccessTokenUrl == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
JsonGetUserSessionByOAuthTokenResponse response = jsonRequest(new JsonGetUserSessionByAccessToken(accessToken), getUserSessionByOAuthAccessTokenUrl, JsonGetUserSessionByOAuthTokenResponse.class);
|
|
||||||
if (response == null) return null;
|
|
||||||
if (!response.expired) throw new OAuthAccessTokenExpired();
|
|
||||||
return response.session;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
|
||||||
if (getAuthDetailsUrl != null) {
|
|
||||||
JsonGetDetailsResponse response = jsonRequest(new JsonGetDetails(), getAuthDetailsUrl, JsonGetDetailsResponse.class);
|
|
||||||
if (response == null) return super.getDetails(client);
|
|
||||||
return response.details;
|
|
||||||
}
|
|
||||||
return super.getDetails(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
|
|
||||||
JsonAuthReportResponse response = jsonRequest(new JsonRefreshToken(refreshToken, context.ip), this.refreshAccessTokenUrl, JsonAuthReportResponse.class);
|
|
||||||
return response == null ? null : response.toAuthReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
|
|
||||||
JsonUser jsonUser = (JsonUser) user;
|
|
||||||
if (password instanceof AuthPlainPassword && jsonUser.password != null && passwordVerifier != null) {
|
|
||||||
if (passwordVerifier.check(jsonUser.password, ((AuthPlainPassword) password).password)) {
|
|
||||||
return PasswordVerifyReport.OK;
|
|
||||||
} else {
|
|
||||||
return PasswordVerifyReport.FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user == null) {
|
|
||||||
return jsonRequest(new JsonPasswordVerify(null, null, password), verifyPasswordUrl, PasswordVerifyReport.class);
|
|
||||||
}
|
|
||||||
return jsonRequest(new JsonPasswordVerify(user.getUsername(), user.getUUID(), password), verifyPasswordUrl, PasswordVerifyReport.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
|
|
||||||
JsonAuthReportResponse response = jsonRequest(new JsonCreateOAuthSession(user == null ? null : user.getUsername(), user == null ? null : user.getUUID(), minecraftAccess), createOAuthSessionUrl, JsonAuthReportResponse.class);
|
|
||||||
if (response == null) return null;
|
|
||||||
if (response.error != null) throw new AuthException(response.error);
|
|
||||||
JsonUser user1 = (JsonUser) user;
|
|
||||||
user1.accessToken = response.minecraftAccessToken;
|
|
||||||
return response.toAuthReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
client = HttpClient.newBuilder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
|
||||||
if (checkServerUrl == null) {
|
|
||||||
return super.checkServer(client, username, serverID);
|
|
||||||
}
|
|
||||||
return jsonRequest(new JsonCheckServer(username, serverID), checkServerUrl, JsonUser.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
|
||||||
if (joinServerUrl == null) {
|
|
||||||
return super.joinServer(client, username, accessToken, serverID);
|
|
||||||
}
|
|
||||||
return jsonRequest(new JsonJoinServer(username, accessToken, serverID), joinServerUrl, JsonSuccessResponse.class).success;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean updateServerID(User user, String serverID) throws IOException {
|
|
||||||
JsonUser jsonUser = (JsonUser) user;
|
|
||||||
if (updateServerIdUrl == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
jsonUser.serverId = serverID;
|
|
||||||
JsonSuccessResponse successResponse = jsonRequest(new JsonUpdateServerId(user.getUsername(), user.getUUID(), serverID), updateServerIdUrl, JsonSuccessResponse.class);
|
|
||||||
if (successResponse == null) return false;
|
|
||||||
return successResponse.success;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T, R> R jsonRequest(T request, String url, Class<R> clazz) {
|
|
||||||
return jsonRequest(request, url, bearerToken, clazz, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetUserByUsername {
|
|
||||||
public String username;
|
|
||||||
|
|
||||||
public JsonGetUserByUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonCheckServer {
|
|
||||||
public String username;
|
|
||||||
public String serverId;
|
|
||||||
|
|
||||||
public JsonCheckServer(String username, String serverId) {
|
|
||||||
this.username = username;
|
|
||||||
this.serverId = serverId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonJoinServer {
|
|
||||||
public String username;
|
|
||||||
public String accessToken;
|
|
||||||
public String serverId;
|
|
||||||
|
|
||||||
public JsonJoinServer(String username, String accessToken, String serverId) {
|
|
||||||
this.username = username;
|
|
||||||
this.accessToken = accessToken;
|
|
||||||
this.serverId = serverId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetUserByUUID {
|
|
||||||
public UUID uuid;
|
|
||||||
|
|
||||||
public JsonGetUserByUUID(UUID uuid) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetUserSessionByAccessToken {
|
|
||||||
public String accessToken;
|
|
||||||
|
|
||||||
public JsonGetUserSessionByAccessToken(String accessToken) {
|
|
||||||
this.accessToken = accessToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonRefreshToken {
|
|
||||||
public String refreshToken;
|
|
||||||
public String ip;
|
|
||||||
|
|
||||||
public JsonRefreshToken(String refreshToken, String ip) {
|
|
||||||
this.refreshToken = refreshToken;
|
|
||||||
this.ip = ip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonAuthReportResponse {
|
|
||||||
public String minecraftAccessToken;
|
|
||||||
public String oauthAccessToken;
|
|
||||||
public String oauthRefreshToken;
|
|
||||||
public long oauthExpire;
|
|
||||||
public JsonUserSession session;
|
|
||||||
public String error;
|
|
||||||
|
|
||||||
public AuthManager.AuthReport toAuthReport() {
|
|
||||||
return new AuthManager.AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonPasswordVerify {
|
|
||||||
public String username;
|
|
||||||
public UUID uuid;
|
|
||||||
public AuthRequest.AuthPasswordInterface password;
|
|
||||||
|
|
||||||
public JsonPasswordVerify(String username, UUID uuid, AuthRequest.AuthPasswordInterface password) {
|
|
||||||
this.username = username;
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonCreateOAuthSession {
|
|
||||||
public String username;
|
|
||||||
public UUID uuid;
|
|
||||||
public boolean minecraftAccess;
|
|
||||||
|
|
||||||
public JsonCreateOAuthSession(String username, UUID uuid, boolean minecraftAccess) {
|
|
||||||
this.username = username;
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.minecraftAccess = minecraftAccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonUpdateServerId {
|
|
||||||
public String username;
|
|
||||||
public UUID uuid;
|
|
||||||
public String serverId;
|
|
||||||
|
|
||||||
public JsonUpdateServerId(String username, UUID uuid, String serverId) {
|
|
||||||
this.username = username;
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.serverId = serverId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonSuccessResponse {
|
|
||||||
public boolean success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetUserSessionByOAuthTokenResponse {
|
|
||||||
public boolean expired;
|
|
||||||
public JsonUserSession session;
|
|
||||||
|
|
||||||
public JsonGetUserSessionByOAuthTokenResponse() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetDetails {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonGetDetailsResponse {
|
|
||||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonUser implements User {
|
|
||||||
private String username;
|
|
||||||
private UUID uuid;
|
|
||||||
private String serverId;
|
|
||||||
private String accessToken;
|
|
||||||
private ClientPermissions permissions;
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
public JsonUser() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, String password) {
|
|
||||||
this.username = username;
|
|
||||||
this.uuid = uuid;
|
|
||||||
this.serverId = serverId;
|
|
||||||
this.accessToken = accessToken;
|
|
||||||
this.permissions = permissions;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "JsonUser{" +
|
|
||||||
"username='" + username + '\'' +
|
|
||||||
", uuid=" + uuid +
|
|
||||||
", permissions=" + permissions +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JsonUserSession implements UserSession {
|
|
||||||
public String id;
|
|
||||||
public JsonUser user;
|
|
||||||
public long expireIn;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getExpireIn() {
|
|
||||||
return expireIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "JsonUserSession{" +
|
|
||||||
"id='" + id + '\'' +
|
|
||||||
"user='" + (user == null ? null : user.getUsername()) + '\'' +
|
|
||||||
", expireIn=" + expireIn +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.ClientPermissions;
|
||||||
|
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
|
import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
|
import pro.gravit.launchserver.manangers.AuthManager;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MemoryAuthCoreProvider extends AuthCoreProvider {
|
||||||
|
private transient final List<MemoryUser> memory = new ArrayList<>(16);
|
||||||
|
@Override
|
||||||
|
public User getUserByUsername(String username) {
|
||||||
|
synchronized (memory) {
|
||||||
|
for(MemoryUser u : memory) {
|
||||||
|
if(u.username.equals(username)) {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var result = new MemoryUser(username);
|
||||||
|
memory.add(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||||
|
return List.of(new AuthLoginOnlyDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUserByUUID(UUID uuid) {
|
||||||
|
synchronized (memory) {
|
||||||
|
for(MemoryUser u : memory) {
|
||||||
|
if(u.uuid.equals(uuid)) {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
|
||||||
|
synchronized (memory) {
|
||||||
|
for(MemoryUser u : memory) {
|
||||||
|
if(u.accessToken.equals(accessToken)) {
|
||||||
|
return new MemoryUserSession(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||||
|
if(login == null) {
|
||||||
|
throw AuthException.userNotFound();
|
||||||
|
}
|
||||||
|
MemoryUser user = null;
|
||||||
|
synchronized (memory) {
|
||||||
|
for(MemoryUser u : memory) {
|
||||||
|
if(u.username.equals(login)) {
|
||||||
|
user = u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(user == null) {
|
||||||
|
user = new MemoryUser(login);
|
||||||
|
memory.add(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(minecraftAccess) {
|
||||||
|
return AuthManager.AuthReport.ofOAuth(user.accessToken, null, 0, new MemoryUserSession(user));
|
||||||
|
} else {
|
||||||
|
return AuthManager.AuthReport.ofOAuthWithMinecraft(user.accessToken, user.accessToken, null, 0, new MemoryUserSession(user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||||
|
MemoryUser memoryUser = (MemoryUser) user;
|
||||||
|
memoryUser.serverId = serverID;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||||
|
synchronized (memory) {
|
||||||
|
for(MemoryUser u : memory) {
|
||||||
|
if(u.username.equals(username)) {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var result = new MemoryUser(username);
|
||||||
|
memory.add(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MemoryUser implements User {
|
||||||
|
private String username;
|
||||||
|
private UUID uuid;
|
||||||
|
private String serverId;
|
||||||
|
private String accessToken;
|
||||||
|
private ClientPermissions permissions;
|
||||||
|
|
||||||
|
public MemoryUser(String username) {
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = makeUuidFromUsername(username);
|
||||||
|
this.accessToken = SecurityHelper.randomStringToken();
|
||||||
|
this.permissions = new ClientPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UUID makeUuidFromUsername(String username) {
|
||||||
|
return UUID.nameUUIDFromBytes(username.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
MemoryUser that = (MemoryUser) o;
|
||||||
|
return uuid.equals(that.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MemoryUserSession implements UserSession {
|
||||||
|
private String id;
|
||||||
|
private MemoryUser user;
|
||||||
|
private long expireIn;
|
||||||
|
|
||||||
|
public MemoryUserSession(MemoryUser user) {
|
||||||
|
this.id = SecurityHelper.randomStringToken();
|
||||||
|
this.user = user;
|
||||||
|
this.expireIn = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getExpireIn() {
|
||||||
|
return expireIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,27 +105,27 @@ public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthRespon
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
|
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||||
|
MySQLUser mySQLUser = (MySQLUser) getUserByLogin(login);
|
||||||
|
if(mySQLUser == null) {
|
||||||
|
throw AuthException.wrongPassword();
|
||||||
}
|
}
|
||||||
|
if(context != null) {
|
||||||
@Override
|
AuthPlainPassword plainPassword = (AuthPlainPassword) password;
|
||||||
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
|
if(plainPassword == null) {
|
||||||
if (passwordVerifier.check(((MySQLUser) user).password, ((AuthPlainPassword) password).password)) {
|
throw AuthException.wrongPassword();
|
||||||
return PasswordVerifyReport.OK;
|
}
|
||||||
} else {
|
if(!passwordVerifier.check(mySQLUser.password, plainPassword.password)) {
|
||||||
return PasswordVerifyReport.FAILED;
|
throw AuthException.wrongPassword();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MySQLUserSession session = new MySQLUserSession(mySQLUser);
|
||||||
@Override
|
|
||||||
public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
|
|
||||||
if (minecraftAccess) {
|
if (minecraftAccess) {
|
||||||
String minecraftAccessToken = SecurityHelper.randomStringToken();
|
String minecraftAccessToken = SecurityHelper.randomStringToken();
|
||||||
updateAuth(user, minecraftAccessToken);
|
updateAuth(mySQLUser, minecraftAccessToken);
|
||||||
return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken);
|
return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken, session);
|
||||||
} else {
|
} else {
|
||||||
return AuthManager.AuthReport.ofMinecraftAccessToken(null);
|
return AuthManager.AuthReport.ofMinecraftAccessToken(null, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,13 +333,14 @@ public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo hardwa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connectUserAndHardware(User user, UserHardware hardware) {
|
public void connectUserAndHardware(UserSession userSession, UserHardware hardware) {
|
||||||
MySQLUser mySQLUser = (MySQLUser) user;
|
MySQLUserSession mySQLUserSession = (MySQLUserSession) userSession;
|
||||||
|
MySQLUser mySQLUser = mySQLUserSession.user;
|
||||||
MySQLUserHardware mySQLUserHardware = (MySQLUserHardware) hardware;
|
MySQLUserHardware mySQLUserHardware = (MySQLUserHardware) hardware;
|
||||||
if (mySQLUser.hwidId == mySQLUserHardware.id) return;
|
if (mySQLUser.hwidId == mySQLUserHardware.id) return;
|
||||||
mySQLUser.hwidId = mySQLUserHardware.id;
|
mySQLUser.hwidId = mySQLUserHardware.id;
|
||||||
try (Connection connection = mySQLHolder.getConnection()) {
|
try (Connection connection = mySQLHolder.getConnection()) {
|
||||||
setUserHardwareId(connection, user.getUUID(), mySQLUserHardware.id);
|
setUserHardwareId(connection, mySQLUser.getUUID(), mySQLUserHardware.id);
|
||||||
} catch (SQLException throwables) {
|
} catch (SQLException throwables) {
|
||||||
logger.error("SQL Error", throwables);
|
logger.error("SQL Error", throwables);
|
||||||
}
|
}
|
||||||
|
@ -513,4 +514,29 @@ public String toString() {
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MySQLUserSession implements UserSession {
|
||||||
|
private final MySQLUser user;
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public MySQLUserSession(MySQLUser user) {
|
||||||
|
this.user = user;
|
||||||
|
this.id = user.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getExpireIn() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,8 @@ public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
|
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||||
return PasswordVerifyReport.FAILED;
|
throw new AuthException("Please configure AuthCoreProvider");
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||||
import pro.gravit.launchserver.auth.core.User;
|
import pro.gravit.launchserver.auth.core.User;
|
||||||
|
import pro.gravit.launchserver.auth.core.UserSession;
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware;
|
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware;
|
||||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||||
|
@ -18,7 +19,7 @@ public interface AuthSupportHardware extends AuthSupport {
|
||||||
|
|
||||||
UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey);
|
UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey);
|
||||||
|
|
||||||
void connectUserAndHardware(User user, UserHardware hardware);
|
void connectUserAndHardware(UserSession userSession, UserHardware hardware);
|
||||||
|
|
||||||
void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey);
|
void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey);
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
package pro.gravit.launchserver.auth.password;
|
package pro.gravit.launchserver.auth.password;
|
||||||
|
|
||||||
import pro.gravit.launchserver.auth.core.JsonCoreProvider;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.Launcher;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.net.URI;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
public class JsonPasswordVerifier extends PasswordVerifier {
|
public class JsonPasswordVerifier extends PasswordVerifier {
|
||||||
|
private static transient final Logger logger = LogManager.getLogger();
|
||||||
private transient final HttpClient client = HttpClient.newBuilder().build();
|
private transient final HttpClient client = HttpClient.newBuilder().build();
|
||||||
public String url;
|
public String url;
|
||||||
public String bearerToken;
|
public String bearerToken;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(String encryptedPassword, String password) {
|
public boolean check(String encryptedPassword, String password) {
|
||||||
JsonPasswordResponse response = JsonCoreProvider.jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client);
|
JsonPasswordResponse response = jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client);
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
return response.success;
|
return response.success;
|
||||||
}
|
}
|
||||||
|
@ -31,4 +41,41 @@ public JsonPasswordRequest(String encryptedPassword, String password) {
|
||||||
public static class JsonPasswordResponse {
|
public static class JsonPasswordResponse {
|
||||||
public boolean success;
|
public boolean success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T, R> R jsonRequest(T request, String url, String bearerToken, Class<R> clazz, HttpClient client) {
|
||||||
|
HttpRequest.BodyPublisher publisher;
|
||||||
|
if (request != null) {
|
||||||
|
publisher = HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request));
|
||||||
|
} else {
|
||||||
|
publisher = HttpRequest.BodyPublishers.noBody();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HttpRequest.Builder request1 = HttpRequest.newBuilder()
|
||||||
|
.method("POST", publisher)
|
||||||
|
.uri(new URI(url))
|
||||||
|
.header("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.timeout(Duration.ofMillis(10000));
|
||||||
|
if (bearerToken != null) {
|
||||||
|
request1.header("Authorization", "Bearer ".concat(bearerToken));
|
||||||
|
}
|
||||||
|
HttpResponse<InputStream> response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream());
|
||||||
|
int statusCode = response.statusCode();
|
||||||
|
if (200 > statusCode || statusCode > 300) {
|
||||||
|
if (statusCode >= 500) {
|
||||||
|
logger.error("JsonCoreProvider: {} return {}", url, statusCode);
|
||||||
|
} else if (statusCode >= 300 && statusCode <= 400) {
|
||||||
|
logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown"));
|
||||||
|
} else if (statusCode == 403 || statusCode == 401) {
|
||||||
|
logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try (Reader reader = new InputStreamReader(response.body())) {
|
||||||
|
return Launcher.gsonManager.gson.fromJson(reader, clazz);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public void onHardwareReport(HardwareReportResponse response, Client client) {
|
||||||
} else {
|
} else {
|
||||||
authSupportHardware.addPublicKeyToHardwareInfo(hardware, client.trustLevel.publicKey);
|
authSupportHardware.addPublicKeyToHardwareInfo(hardware, client.trustLevel.publicKey);
|
||||||
}
|
}
|
||||||
authSupportHardware.connectUserAndHardware(client.getUser(), hardware);
|
authSupportHardware.connectUserAndHardware(client.sessionObject, hardware);
|
||||||
if (hardware.isBanned()) {
|
if (hardware.isBanned()) {
|
||||||
throw new SecurityException("Your hardware banned");
|
throw new SecurityException("Your hardware banned");
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
|
||||||
throw new SecurityException("Your hardware banned");
|
throw new SecurityException("Your hardware banned");
|
||||||
}
|
}
|
||||||
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
||||||
authSupportHardware.connectUserAndHardware(client.getUser(), hardware);
|
authSupportHardware.connectUserAndHardware(client.sessionObject, hardware);
|
||||||
} else if (provider == null) {
|
} else if (provider == null) {
|
||||||
logger.warn("HWIDProvider null. HardwareInfo not checked!");
|
logger.warn("HWIDProvider null. HardwareInfo not checked!");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -192,7 +192,6 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) {
|
if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) {
|
||||||
for (AuthProviderPair pair : auth.values()) {
|
for (AuthProviderPair pair : auth.values()) {
|
||||||
server.registerObject("auth.".concat(pair.name).concat(".core"), pair.core);
|
server.registerObject("auth.".concat(pair.name).concat(".core"), pair.core);
|
||||||
server.registerObject("auth.".concat(pair.name).concat(".social"), pair.social);
|
|
||||||
server.registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
server.registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +202,6 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
try {
|
try {
|
||||||
if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) {
|
if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) {
|
||||||
for (AuthProviderPair pair : auth.values()) {
|
for (AuthProviderPair pair : auth.values()) {
|
||||||
server.unregisterObject("auth.".concat(pair.name).concat(".social"), pair.social);
|
|
||||||
server.unregisterObject("auth.".concat(pair.name).concat(".core"), pair.core);
|
server.unregisterObject("auth.".concat(pair.name).concat(".core"), pair.core);
|
||||||
server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
|
||||||
pair.close();
|
pair.close();
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
import pro.gravit.launchserver.auth.AuthException;
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.core.AuthSocialProvider;
|
|
||||||
import pro.gravit.launchserver.auth.core.User;
|
import pro.gravit.launchserver.auth.core.User;
|
||||||
import pro.gravit.launchserver.auth.core.UserSession;
|
import pro.gravit.launchserver.auth.core.UserSession;
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures;
|
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures;
|
||||||
|
@ -31,7 +30,6 @@
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class AuthManager {
|
public class AuthManager {
|
||||||
private transient final LaunchServer server;
|
private transient final LaunchServer server;
|
||||||
|
@ -143,63 +141,28 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor
|
||||||
context.client.sessionObject = session;
|
context.client.sessionObject = session;
|
||||||
internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), true);
|
internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), true);
|
||||||
if (context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) {
|
if (context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) {
|
||||||
return AuthReport.ofMinecraftAccessToken(user.getAccessToken());
|
return AuthReport.ofMinecraftAccessToken(user.getAccessToken(), session);
|
||||||
}
|
}
|
||||||
return AuthReport.ofMinecraftAccessToken(null);
|
return AuthReport.ofMinecraftAccessToken(null, session);
|
||||||
}
|
}
|
||||||
User user = null;
|
|
||||||
boolean skipPasswordCheck = false;
|
|
||||||
String login = context.login;
|
String login = context.login;
|
||||||
if (context.pair.social != null) {
|
|
||||||
AuthSocialProvider.SocialResult result = context.pair.social.preAuth(context, password);
|
|
||||||
if (result != null) {
|
|
||||||
if (result.user != null) user = result.user;
|
|
||||||
if (result.login != null) login = result.login;
|
|
||||||
if (result.password != null) password = result.password;
|
|
||||||
if (result.user != null && result.password == null) skipPasswordCheck = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user == null && login != null) {
|
|
||||||
user = provider.getUserByLogin(context.login);
|
|
||||||
if (user == null) {
|
|
||||||
throw new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AuthCoreProvider.PasswordVerifyReport report = null;
|
|
||||||
if (!skipPasswordCheck) {
|
|
||||||
report = provider.verifyPassword(user, password);
|
|
||||||
}
|
|
||||||
if (skipPasswordCheck || report.success) {
|
|
||||||
AuthReport result;
|
|
||||||
try {
|
try {
|
||||||
result = provider.createOAuthSession(user, context, report, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context));
|
AuthReport result = provider.authorize(login, context, password, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context));
|
||||||
|
if(result == null || result.session == null || result.session.getUser() == null) {
|
||||||
|
logger.error("AuthCoreProvider {} method 'authorize' return null", context.pair.name);
|
||||||
|
throw new AuthException("Internal Auth Error");
|
||||||
|
}
|
||||||
|
var session = result.session;
|
||||||
|
var user = session.getUser();
|
||||||
|
context.client.coreObject = user;
|
||||||
|
context.client.sessionObject = session;
|
||||||
|
internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), result.isUsingOAuth());
|
||||||
|
return result;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (e instanceof AuthException) throw (AuthException) e;
|
if (e instanceof AuthException) throw (AuthException) e;
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
throw new AuthException("Internal Auth Error");
|
throw new AuthException("Internal Auth Error");
|
||||||
}
|
}
|
||||||
if (user == null) {
|
|
||||||
if (result.session != null) {
|
|
||||||
user = result.session.getUser();
|
|
||||||
} else {
|
|
||||||
logger.error("AuthCoreProvider {} method createOAuthSession returns null session with login null", context.pair.name);
|
|
||||||
throw new AuthException("Internal Auth Error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.client.coreObject = user;
|
|
||||||
internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), result.isUsingOAuth());
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
if (report.needMoreFactors) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,7 +180,6 @@ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, Auth
|
||||||
client.type = authType;
|
client.type = authType;
|
||||||
client.uuid = uuid;
|
client.uuid = uuid;
|
||||||
client.useOAuth = oauth;
|
client.useOAuth = oauth;
|
||||||
client.coreObject = pair.core.getUserByUUID(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException {
|
public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException {
|
||||||
|
@ -374,24 +336,16 @@ public record AuthReport(String minecraftAccessToken, String oauthAccessToken,
|
||||||
String oauthRefreshToken, long oauthExpire,
|
String oauthRefreshToken, long oauthExpire,
|
||||||
UserSession session) {
|
UserSession session) {
|
||||||
|
|
||||||
public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire) {
|
|
||||||
return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) {
|
public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) {
|
||||||
return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire) {
|
|
||||||
return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) {
|
public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) {
|
||||||
return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthReport ofMinecraftAccessToken(String minecraftAccessToken) {
|
public static AuthReport ofMinecraftAccessToken(String minecraftAccessToken, UserSession session) {
|
||||||
return new AuthReport(minecraftAccessToken, null, null, 0, null);
|
return new AuthReport(minecraftAccessToken, null, null, 0, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUsingOAuth() {
|
public boolean isUsingOAuth() {
|
||||||
|
|
|
@ -76,9 +76,9 @@ public static class AuthContext {
|
||||||
public final String profileName;
|
public final String profileName;
|
||||||
public final String ip;
|
public final String ip;
|
||||||
public final ConnectTypes authType;
|
public final ConnectTypes authType;
|
||||||
public final Client client;
|
public transient final Client client;
|
||||||
public final AuthProviderPair pair;
|
public transient final AuthProviderPair pair;
|
||||||
public AuthManager.AuthReport report;
|
public transient AuthManager.AuthReport report;
|
||||||
|
|
||||||
public AuthContext(Client client, String login, String profileName, String ip, ConnectTypes authType, AuthProviderPair pair) {
|
public AuthContext(Client client, String login, String profileName, String ip, ConnectTypes authType, AuthProviderPair pair) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
|
|
@ -20,7 +20,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
List<GetAvailabilityAuthRequestEvent.AuthAvailability> list = new ArrayList<>();
|
List<GetAvailabilityAuthRequestEvent.AuthAvailability> list = new ArrayList<>();
|
||||||
for (AuthProviderPair pair : server.config.auth.values()) {
|
for (AuthProviderPair pair : server.config.auth.values()) {
|
||||||
list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName,
|
list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName,
|
||||||
pair.isUseSocial() ? pair.social.getDetails(client) : pair.core.getDetails(client)));
|
pair.core.getDetails(client)));
|
||||||
}
|
}
|
||||||
sendResult(new GetAvailabilityAuthRequestEvent(list));
|
sendResult(new GetAvailabilityAuthRequestEvent(list));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
|
id 'org.openjfx.javafxplugin' version '0.0.10' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.2.4'
|
version = '5.2.5-SNAPSHOT'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit fd75e8dfa26a3103f03e4e6e6e3eb1c6e6a4ba1a
|
Subproject commit dced154854c59d8b1e816ebfb1f51baaaeafabfb
|
Loading…
Reference in a new issue