mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 11:39:11 +03:00
[FEATURE] AuthCoreProvider: OAuth Support Part 3
This commit is contained in:
parent
d3751732b0
commit
ea3310b738
12 changed files with 282 additions and 23 deletions
|
@ -11,6 +11,7 @@
|
||||||
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.User;
|
import pro.gravit.launchserver.auth.core.User;
|
||||||
|
import pro.gravit.launchserver.auth.core.UserSession;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProviderDAOResult;
|
import pro.gravit.launchserver.auth.provider.AuthProviderDAOResult;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
|
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
|
||||||
|
@ -138,6 +139,26 @@ private String authWithProviderAndHandler(AuthResponse.AuthContext context, Auth
|
||||||
private AuthReport authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException {
|
private AuthReport authWithCore(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException {
|
||||||
AuthCoreProvider provider = context.pair.core;
|
AuthCoreProvider provider = context.pair.core;
|
||||||
provider.verifyAuth(context);
|
provider.verifyAuth(context);
|
||||||
|
if(password instanceof AuthOAuthPassword) {
|
||||||
|
AuthOAuthPassword password1 = (AuthOAuthPassword) password;
|
||||||
|
UserSession session;
|
||||||
|
try {
|
||||||
|
session = provider.getUserSessionByOAuthAccessToken(password1.accessToken);
|
||||||
|
} catch (AuthCoreProvider.OAuthAccessTokenExpired oAuthAccessTokenExpired) {
|
||||||
|
throw new AuthException(AuthRequestEvent.OAUTH_TOKEN_EXPIRE);
|
||||||
|
}
|
||||||
|
if(session == null) {
|
||||||
|
throw new AuthException(AuthRequestEvent.OAUTH_TOKEN_INVALID);
|
||||||
|
}
|
||||||
|
User user = session.getUser();
|
||||||
|
context.client.coreObject = user;
|
||||||
|
context.client.sessionObject = session;
|
||||||
|
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)) {
|
||||||
|
return AuthReport.ofMinecraftAccessToken(user.getAccessToken());
|
||||||
|
}
|
||||||
|
return AuthReport.ofMinecraftAccessToken(null);
|
||||||
|
}
|
||||||
User user = provider.getUserByUsername(context.login);
|
User user = provider.getUserByUsername(context.login);
|
||||||
if(user == null) {
|
if(user == null) {
|
||||||
throw new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE);
|
throw new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE);
|
||||||
|
|
|
@ -34,6 +34,8 @@ public class Client {
|
||||||
|
|
||||||
public transient pro.gravit.launchserver.auth.core.User coreObject;
|
public transient pro.gravit.launchserver.auth.core.User coreObject;
|
||||||
|
|
||||||
|
public transient pro.gravit.launchserver.auth.core.UserSession sessionObject;
|
||||||
|
|
||||||
public transient Map<String, Object> properties;
|
public transient Map<String, Object> properties;
|
||||||
|
|
||||||
public Map<String, String> serializableProperties;
|
public Map<String, String> serializableProperties;
|
||||||
|
|
|
@ -92,6 +92,8 @@ public static void registerResponses() {
|
||||||
providers.register("pingServer", PingServerResponse.class);
|
providers.register("pingServer", PingServerResponse.class);
|
||||||
providers.register("currentUser", CurrentUserResponse.class);
|
providers.register("currentUser", CurrentUserResponse.class);
|
||||||
providers.register("features", FeaturesResponse.class);
|
providers.register("features", FeaturesResponse.class);
|
||||||
|
providers.register("refreshToken", RefreshTokenResponse.class);
|
||||||
|
providers.register("restore", RestoreResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
|
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import pro.gravit.launcher.events.RequestEvent;
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
import pro.gravit.launcher.events.request.ExitRequestEvent;
|
import pro.gravit.launcher.events.request.ExitRequestEvent;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetSessionsFromUser;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
|
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
@ -38,6 +39,23 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
|
if(client.useOAuth) {
|
||||||
|
WebSocketFrameHandler handler = ctx.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (handler == null) {
|
||||||
|
sendError("Exit internal error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Client newClient = new Client(null);
|
||||||
|
newClient.checkSign = client.checkSign;
|
||||||
|
handler.setClient(newClient);
|
||||||
|
if(exitAll) {
|
||||||
|
if(client.auth instanceof AuthSupportGetSessionsFromUser) {
|
||||||
|
AuthSupportGetSessionsFromUser support = (AuthSupportGetSessionsFromUser) client.auth;
|
||||||
|
support.clearSessionsByUser(client.getUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||||
|
} else {
|
||||||
if (client.session == null && exitAll) {
|
if (client.session == null && exitAll) {
|
||||||
sendError("Session invalid");
|
sendError("Session invalid");
|
||||||
return;
|
return;
|
||||||
|
@ -63,6 +81,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
||||||
Client client1 = webSocketFrameHandler.getClient();
|
Client client1 = webSocketFrameHandler.getClient();
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package pro.gravit.launchserver.socket.response.auth;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.events.request.RefreshTokenRequestEvent;
|
||||||
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
|
import pro.gravit.launchserver.manangers.AuthManager;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
|
||||||
|
public class RefreshTokenResponse extends SimpleResponse {
|
||||||
|
public String authId;
|
||||||
|
public String refreshToken;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "refreshToken";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
|
if(refreshToken == null) {
|
||||||
|
sendError("Invalid request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AuthProviderPair pair;
|
||||||
|
if(!client.isAuth) {
|
||||||
|
if(authId == null || !client.useOAuth) {
|
||||||
|
pair = server.config.getAuthProviderPair();
|
||||||
|
} else {
|
||||||
|
pair = client.auth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pair = server.config.getAuthProviderPair(authId);
|
||||||
|
}
|
||||||
|
if(pair == null || !pair.isUseCore()) {
|
||||||
|
sendError("Invalid request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AuthManager.AuthReport report = pair.core.refreshAccessToken(refreshToken, new AuthResponse.AuthContext(client, null, null, ip, AuthResponse.ConnectTypes.API, pair));
|
||||||
|
if(report == null || !report.isUsingOAuth()) {
|
||||||
|
sendError("Invalid RefreshToken");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendResult(new RefreshTokenRequestEvent(new AuthRequestEvent.OAuthRequestEvent(report.oauthAccessToken, report.oauthRefreshToken, report.oauthExpire)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package pro.gravit.launchserver.socket.response.auth;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.events.request.RestoreRequestEvent;
|
||||||
|
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.core.UserSession;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RestoreResponse extends SimpleResponse {
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ExtendedTokenProvider {
|
||||||
|
void accept(Client client, AuthProviderPair pair, String extendedToken);
|
||||||
|
}
|
||||||
|
public static Map<String, ExtendedTokenProvider> providers = new HashMap<>();
|
||||||
|
public String authId;
|
||||||
|
public String accessToken;
|
||||||
|
public Map<String, String> extended;
|
||||||
|
public boolean needUserInfo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "restore";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
|
if(accessToken == null && !client.isAuth && needUserInfo) {
|
||||||
|
sendError("Invalid request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AuthProviderPair pair;
|
||||||
|
if(!client.isAuth) {
|
||||||
|
if(authId == null || !client.useOAuth) {
|
||||||
|
pair = server.config.getAuthProviderPair();
|
||||||
|
} else {
|
||||||
|
pair = client.auth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pair = server.config.getAuthProviderPair(authId);
|
||||||
|
}
|
||||||
|
if(pair == null || !pair.isUseCore()) {
|
||||||
|
sendError("Invalid request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(accessToken != null) {
|
||||||
|
UserSession session;
|
||||||
|
try {
|
||||||
|
session = pair.core.getUserSessionByOAuthAccessToken(accessToken);
|
||||||
|
} catch (AuthCoreProvider.OAuthAccessTokenExpired e) {
|
||||||
|
sendError(AuthRequestEvent.OAUTH_TOKEN_EXPIRE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(session == null) {
|
||||||
|
sendError(AuthRequestEvent.OAUTH_TOKEN_INVALID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
User user = session.getUser();
|
||||||
|
client.coreObject = user;
|
||||||
|
client.sessionObject = session;
|
||||||
|
server.authManager.internalAuth(client, client.type == null ? AuthResponse.ConnectTypes.API : client.type, pair, user.getUsername(), user.getUUID(), user.getPermissions(), true);
|
||||||
|
}
|
||||||
|
if(extended != null) {
|
||||||
|
extended.forEach((k,v) -> {
|
||||||
|
ExtendedTokenProvider provider = providers.get(k);
|
||||||
|
if(provider == null) return;
|
||||||
|
provider.accept(client, pair, v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(needUserInfo && client.isAuth) {
|
||||||
|
sendResult(new RestoreRequestEvent(CurrentUserResponse.collectUserInfoFromClient(client)));
|
||||||
|
} else {
|
||||||
|
sendResult(new RestoreRequestEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@
|
||||||
public class AuthRequestEvent extends RequestEvent {
|
public class AuthRequestEvent extends RequestEvent {
|
||||||
public static final String TWO_FACTOR_NEED_ERROR_MESSAGE = "auth.require2fa";
|
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 ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX = "auth.require.factor.";
|
||||||
|
public static final String OAUTH_TOKEN_EXPIRE = "auth.expiretoken";
|
||||||
|
public static final String OAUTH_TOKEN_INVALID = "auth.invalidtoken";
|
||||||
public static final String USER_NOT_FOUND_ERROR_MESSAGE = "auth.message.usernotfound";
|
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 WRONG_PASSWORD_ERROR_MESSAGE = "auth.message.wrongpassword";
|
||||||
public static final String ACCOUNT_BLOCKED_ERROR_MESSAGE = "auth.message.blocked";
|
public static final String ACCOUNT_BLOCKED_ERROR_MESSAGE = "auth.message.blocked";
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package pro.gravit.launcher.events.request;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
|
|
||||||
|
public class RefreshTokenRequestEvent extends RequestEvent {
|
||||||
|
public AuthRequestEvent.OAuthRequestEvent oauth;
|
||||||
|
|
||||||
|
public RefreshTokenRequestEvent(AuthRequestEvent.OAuthRequestEvent oauth) {
|
||||||
|
this.oauth = oauth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "refreshToken";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package pro.gravit.launcher.events.request;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
|
|
||||||
|
public class RestoreRequestEvent extends RequestEvent {
|
||||||
|
public CurrentUserRequestEvent.UserInfo userInfo;
|
||||||
|
|
||||||
|
public RestoreRequestEvent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestoreRequestEvent(CurrentUserRequestEvent.UserInfo userInfo) {
|
||||||
|
this.userInfo = userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "restore";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package pro.gravit.launcher.request.auth;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.request.RefreshTokenRequestEvent;
|
||||||
|
import pro.gravit.launcher.request.Request;
|
||||||
|
|
||||||
|
public class RefreshTokenRequest extends Request<RefreshTokenRequestEvent> {
|
||||||
|
public String authId;
|
||||||
|
public String refreshToken;
|
||||||
|
|
||||||
|
public RefreshTokenRequest(String authId, String refreshToken) {
|
||||||
|
this.authId = authId;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "refreshToken";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package pro.gravit.launcher.request.auth;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.request.RestoreRequestEvent;
|
||||||
|
import pro.gravit.launcher.request.Request;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RestoreRequest extends Request<RestoreRequestEvent> {
|
||||||
|
public String authId;
|
||||||
|
public String accessToken;
|
||||||
|
public Map<String, String> extended;
|
||||||
|
public boolean needUserInfo;
|
||||||
|
|
||||||
|
public RestoreRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestoreRequest(String authId, String accessToken, Map<String, String> extended, boolean needUserInfo) {
|
||||||
|
this.authId = authId;
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.extended = extended;
|
||||||
|
this.needUserInfo = needUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "restore";
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,6 +109,8 @@ public void registerResults() {
|
||||||
results.register("pingServer", PingServerRequestEvent.class);
|
results.register("pingServer", PingServerRequestEvent.class);
|
||||||
results.register("currentUser", CurrentUserRequestEvent.class);
|
results.register("currentUser", CurrentUserRequestEvent.class);
|
||||||
results.register("features", FeaturesRequestEvent.class);
|
results.register("features", FeaturesRequestEvent.class);
|
||||||
|
results.register("refreshToken", RefreshTokenRequestEvent.class);
|
||||||
|
results.register("restore", RestoreRequestEvent.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitIfNotConnected() {
|
public void waitIfNotConnected() {
|
||||||
|
|
Loading…
Reference in a new issue