mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +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.core.AuthCoreProvider;
|
||||
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.AuthProviderDAOResult;
|
||||
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 {
|
||||
AuthCoreProvider provider = context.pair.core;
|
||||
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);
|
||||
if(user == null) {
|
||||
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.UserSession sessionObject;
|
||||
|
||||
public transient Map<String, Object> properties;
|
||||
|
||||
public Map<String, String> serializableProperties;
|
||||
|
|
|
@ -92,6 +92,8 @@ public static void registerResponses() {
|
|||
providers.register("pingServer", PingServerResponse.class);
|
||||
providers.register("currentUser", CurrentUserResponse.class);
|
||||
providers.register("features", FeaturesResponse.class);
|
||||
providers.register("refreshToken", RefreshTokenResponse.class);
|
||||
providers.register("restore", RestoreResponse.class);
|
||||
}
|
||||
|
||||
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import pro.gravit.launcher.events.RequestEvent;
|
||||
import pro.gravit.launcher.events.request.ExitRequestEvent;
|
||||
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.handlers.WebSocketFrameHandler;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
|
@ -38,31 +39,49 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
return;
|
||||
}
|
||||
if (username == null) {
|
||||
if (client.session == null && exitAll) {
|
||||
sendError("Session invalid");
|
||||
return;
|
||||
}
|
||||
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 (client.session != null) server.sessionManager.remove(client.session);
|
||||
if (exitAll) {
|
||||
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
||||
Client client1 = webSocketFrameHandler.getClient();
|
||||
if (client.isAuth && client.username != null) {
|
||||
if (!client1.isAuth || !client.username.equals(client1.username)) return;
|
||||
} else {
|
||||
if (client1.session != client.session) return;
|
||||
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());
|
||||
}
|
||||
exit(server, webSocketFrameHandler, channel, ExitRequestEvent.ExitReason.SERVER);
|
||||
}));
|
||||
}
|
||||
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||
} else {
|
||||
if (client.session == null && exitAll) {
|
||||
sendError("Session invalid");
|
||||
return;
|
||||
}
|
||||
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 (client.session != null) server.sessionManager.remove(client.session);
|
||||
if (exitAll) {
|
||||
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
||||
Client client1 = webSocketFrameHandler.getClient();
|
||||
if (client.isAuth && client.username != null) {
|
||||
if (!client1.isAuth || !client.username.equals(client1.username)) return;
|
||||
} else {
|
||||
if (client1.session != client.session) return;
|
||||
}
|
||||
exit(server, webSocketFrameHandler, channel, ExitRequestEvent.ExitReason.SERVER);
|
||||
}));
|
||||
}
|
||||
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||
}
|
||||
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||
} else {
|
||||
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
||||
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 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 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 WRONG_PASSWORD_ERROR_MESSAGE = "auth.message.wrongpassword";
|
||||
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("currentUser", CurrentUserRequestEvent.class);
|
||||
results.register("features", FeaturesRequestEvent.class);
|
||||
results.register("refreshToken", RefreshTokenRequestEvent.class);
|
||||
results.register("restore", RestoreRequestEvent.class);
|
||||
}
|
||||
|
||||
public void waitIfNotConnected() {
|
||||
|
|
Loading…
Reference in a new issue