From de34b620363157424de50ffd12f43d7376ce9adf Mon Sep 17 00:00:00 2001 From: XakepSDK Date: Thu, 14 Mar 2024 17:07:44 +0600 Subject: [PATCH 1/5] [ANY] Update JWT library (#706) Co-authored-by: d3coder (cherry picked from commit 3926f3e5bfb11fc5c382fbed9970dfbb35746cda) --- .../launchserver/auth/protect/AdvancedProtectHandler.java | 4 ++-- .../pro/gravit/launchserver/command/service/TokenCommand.java | 2 +- .../pro/gravit/launchserver/helper/LegacySessionHelper.java | 2 +- .../java/pro/gravit/launchserver/manangers/AuthManager.java | 2 +- .../launchserver/socket/response/update/LauncherResponse.java | 2 +- props.gradle | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java index 83ce07e2..0e3244e3 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java @@ -132,7 +132,7 @@ public static class HardwareInfoTokenVerifier implements RestoreResponse.Extende private final JwtParser parser; public HardwareInfoTokenVerifier(LaunchServer server) { - this.parser = Jwts.parserBuilder() + this.parser = Jwts.parser() .requireIssuer("LaunchServer") .setSigningKey(server.keyAgreementManager.ecdsaPublicKey) .build(); @@ -164,7 +164,7 @@ public static class PublicKeyTokenVerifier implements RestoreResponse.ExtendedTo private final JwtParser parser; public PublicKeyTokenVerifier(LaunchServer server) { - this.parser = Jwts.parserBuilder() + this.parser = Jwts.parser() .requireIssuer("LaunchServer") .setSigningKey(server.keyAgreementManager.ecdsaPublicKey) .build(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java index f6090469..3c0f7c52 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java @@ -18,7 +18,7 @@ public TokenCommand(LaunchServer server) { @Override public void invoke(String... args) throws Exception { verifyArgs(args, 1); - var parser = Jwts.parserBuilder().setSigningKey(server.keyAgreementManager.ecdsaPublicKey).build(); + var parser = Jwts.parser().setSigningKey(server.keyAgreementManager.ecdsaPublicKey).build(); var claims = parser.parseClaimsJws(args[0]); logger.info("Token: {}", claims.getBody()); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java index 9b4acb45..764a7208 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/LegacySessionHelper.java @@ -25,7 +25,7 @@ public static String makeAccessJwtTokenFromString(User user, LocalDateTime expir } public static JwtTokenInfo getJwtInfoFromAccessToken(String token, ECPublicKey publicKey) { - var parser = Jwts.parserBuilder() + var parser = Jwts.parser() .requireIssuer("LaunchServer") .setClock(() -> new Date(Clock.systemUTC().millis())) .setSigningKey(publicKey) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java index 5b7c3c21..e774769a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -38,7 +38,7 @@ public class AuthManager { public AuthManager(LaunchServer server) { this.server = server; - this.checkServerTokenParser = Jwts.parserBuilder() + this.checkServerTokenParser = Jwts.parser() .requireIssuer("LaunchServer") .require("tokenType", "checkServer") .setSigningKey(server.keyAgreementManager.ecdsaPublicKey) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java index 8849c61a..9a771986 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java @@ -89,7 +89,7 @@ public static class LauncherTokenVerifier implements RestoreResponse.ExtendedTok private final Logger logger = LogManager.getLogger(); public LauncherTokenVerifier(LaunchServer server) { - parser = Jwts.parserBuilder() + parser = Jwts.parser() .setSigningKey(server.keyAgreementManager.ecdsaPublicKey) .requireIssuer("LaunchServer") .build(); diff --git a/props.gradle b/props.gradle index 30ea7931..1c40bced 100644 --- a/props.gradle +++ b/props.gradle @@ -6,7 +6,7 @@ verGuavaC = '30.1.1-jre' verJansi = '2.4.1' verJline = '3.25.0' - verJwt = '0.11.5' + verJwt = '0.12.5' verBcprov = '1.70' verGson = '2.10.1' verBcpkix = '1.70' From c18ea096d1268cba08743e9b63f79a8739d5372b Mon Sep 17 00:00:00 2001 From: XakepSDK Date: Mon, 1 Apr 2024 22:09:38 +0500 Subject: [PATCH 2/5] [ANY] Add query helper (#708) * [ANY] Add query helper * [ANY] Rename AuthCodePassword field to the uri --------- Co-authored-by: d3coder (cherry picked from commit 1ebe68f5b874df9ffac2a633d17cbb36618de44e) --- .../auth/password/AuthCodePassword.java | 6 +-- .../pro/gravit/utils/helper/CommonHelper.java | 12 +++-- .../pro/gravit/utils/helper/QueryHelper.java | 47 +++++++++++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 LauncherCore/src/main/java/pro/gravit/utils/helper/QueryHelper.java diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthCodePassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthCodePassword.java index d9595e34..fead6d93 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthCodePassword.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthCodePassword.java @@ -3,10 +3,10 @@ import pro.gravit.launcher.request.auth.AuthRequest; public class AuthCodePassword implements AuthRequest.AuthPasswordInterface { - public final String code; + public final String uri; - public AuthCodePassword(String code) { - this.code = code; + public AuthCodePassword(String uri) { + this.uri = uri; } @Override diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java index ccaeb8ea..dcde9b76 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/CommonHelper.java @@ -5,10 +5,7 @@ import javax.script.ScriptEngine; import java.lang.reflect.Type; -import java.util.Base64; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Locale; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -105,6 +102,13 @@ public static String[] parseCommand(CharSequence line) throws CommandException { return result.toArray(new String[0]); } + public static V multimapFirstOrNullValue(K key, Map> params) { + List list = params.getOrDefault(key, Collections.emptyList()); + if (list.isEmpty()) { + return null; + } + return list.getFirst(); + } public static GsonBuilder newBuilder() { return new GsonBuilder().registerTypeHierarchyAdapter(byte[].class, diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/QueryHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/QueryHelper.java new file mode 100644 index 00000000..03ed93c3 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/QueryHelper.java @@ -0,0 +1,47 @@ +package pro.gravit.utils.helper; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class QueryHelper { + public static Map> splitUriQuery(URI uri) { + String query = uri.getRawQuery(); + if (query == null) { + return Collections.emptyMap(); + } + Map> params = new HashMap<>(); + String[] split = query.split("&"); + for (String qParams : split) { + String[] splitParams = qParams.split("="); + List strings = params.computeIfAbsent(decode(splitParams[0], StandardCharsets.UTF_8), + k -> new ArrayList<>(1)); + strings.add(decode(splitParams[1], StandardCharsets.UTF_8)); + } + return params; + } + + public static String encodeFormPair(String key, String value) { + return encode(key, StandardCharsets.UTF_8) + "=" + encode(value, StandardCharsets.UTF_8); + } + + private static String encode(String value, Charset charset) { + try { + return URLEncoder.encode(value, charset.name()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private static String decode(String value, Charset charset) { + try { + return URLDecoder.decode(value, charset.name()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } +} From bd4ec738a2f73aede7bc509670946f00c4a83d1d Mon Sep 17 00:00:00 2001 From: XakepSDK Date: Wed, 24 Apr 2024 18:21:16 +0500 Subject: [PATCH 3/5] [ANY] Add OpenID auth module (#709) Co-authored-by: d3coder --- LaunchServer/build.gradle | 1 + .../launchserver/auth/AuthException.java | 4 + .../auth/HikariSQLSourceConfig.java | 50 ++++ .../auth/core/AuthCoreProvider.java | 2 + .../auth/core/openid/AccessTokenResponse.java | 14 ++ .../core/openid/OpenIDAuthCoreProvider.java | 178 ++++++++++++++ .../auth/core/openid/OpenIDAuthenticator.java | 229 ++++++++++++++++++ .../auth/core/openid/OpenIDConfig.java | 9 + .../auth/core/openid/QueryBuilder.java | 59 +++++ .../core/openid/SQLServerSessionStore.java | 99 ++++++++ .../auth/core/openid/SQLUserStore.java | 124 ++++++++++ .../auth/core/openid/ServerSessionStore.java | 8 + .../auth/core/openid/TokenResponse.java | 5 + .../auth/core/openid/UserEntity.java | 23 ++ .../auth/core/openid/UserStore.java | 13 + props.gradle | 1 + 16 files changed, 819 insertions(+) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/HikariSQLSourceConfig.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/AccessTokenResponse.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthCoreProvider.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/QueryBuilder.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLServerSessionStore.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLUserStore.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/ServerSessionStore.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/TokenResponse.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserEntity.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserStore.java diff --git a/LaunchServer/build.gradle b/LaunchServer/build.gradle index b522f651..cb88a7ab 100644 --- a/LaunchServer/build.gradle +++ b/LaunchServer/build.gradle @@ -88,6 +88,7 @@ pack project(':LauncherModernCore') bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j'] bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn'] bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn'] + bundle group: 'com.h2database', name: 'h2', version: rootProject['verH2Conn'] bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard'] bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'] bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: rootProject['verLog4j'] diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java index 0fb5c766..11bdadf6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java @@ -16,6 +16,10 @@ public AuthException(String message) { super(message); } + public AuthException(String message, Throwable cause) { + super(message, cause); + } + public static AuthException need2FA() { return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/HikariSQLSourceConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/HikariSQLSourceConfig.java new file mode 100644 index 00000000..974ce17e --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/HikariSQLSourceConfig.java @@ -0,0 +1,50 @@ +package pro.gravit.launchserver.auth; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.function.Consumer; + +public class HikariSQLSourceConfig implements SQLSourceConfig { + private transient HikariDataSource dataSource; + private String dsClass; + private Properties dsProps; + private String driverClass; + private String jdbcUrl; + private String username; + private String password; + + public void init() { + if (dataSource != null) { + return; + } + HikariConfig config = new HikariConfig(); + consumeIfNotNull(config::setDataSourceClassName, dsClass); + consumeIfNotNull(config::setDataSourceProperties, dsProps); + consumeIfNotNull(config::setDriverClassName, driverClass); + consumeIfNotNull(config::setJdbcUrl, jdbcUrl); + consumeIfNotNull(config::setUsername, username); + consumeIfNotNull(config::setPassword, password); + + this.dataSource = new HikariDataSource(config); + } + + @Override + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + @Override + public void close() { + dataSource.close(); + } + + private static void consumeIfNotNull(Consumer consumer, T val) { + if (val != null) { + consumer.accept(val); + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java index f1d8cf7d..64d2b4ca 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java @@ -16,6 +16,7 @@ import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetAllUsers; import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware; import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRegistration; +import pro.gravit.launchserver.auth.core.openid.OpenIDAuthCoreProvider; import pro.gravit.launchserver.manangers.AuthManager; import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.auth.AuthResponse; @@ -45,6 +46,7 @@ public static void registerProviders() { providers.register("postgresql", PostgresSQLCoreProvider.class); providers.register("memory", MemoryAuthCoreProvider.class); providers.register("merge", MergeAuthCoreProvider.class); + providers.register("openid", OpenIDAuthCoreProvider.class); registredProviders = true; } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/AccessTokenResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/AccessTokenResponse.java new file mode 100644 index 00000000..8a1d3f97 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/AccessTokenResponse.java @@ -0,0 +1,14 @@ +package pro.gravit.launchserver.auth.core.openid; + +import com.google.gson.annotations.SerializedName; + +public record AccessTokenResponse(@SerializedName("access_token") String accessToken, + @SerializedName("expires_in") Long expiresIn, + @SerializedName("refresh_expires_in") Long refreshExpiresIn, + @SerializedName("refresh_token") String refreshToken, + @SerializedName("token_type") String tokenType, + @SerializedName("id_token") String idToken, + @SerializedName("not-before-policy") Integer notBeforePolicy, + @SerializedName("session_state") String sessionState, + @SerializedName("scope") String scope) { +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthCoreProvider.java new file mode 100644 index 00000000..6e199a11 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthCoreProvider.java @@ -0,0 +1,178 @@ +package pro.gravit.launchserver.auth.core.openid; + +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +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.password.AuthCodePassword; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.auth.HikariSQLSourceConfig; +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.manangers.AuthManager; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.utils.helper.LogHelper; + +import java.io.IOException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class OpenIDAuthCoreProvider extends AuthCoreProvider { + private transient SQLUserStore sqlUserStore; + private transient SQLServerSessionStore sqlSessionStore; + private transient OpenIDAuthenticator openIDAuthenticator; + private transient LaunchServer server; + + private OpenIDConfig openIDConfig; + private HikariSQLSourceConfig sqlSourceConfig; + + @Override + public List getDetails(Client client) { + return openIDAuthenticator.getDetails(); + } + + @Override + public User getUserByUsername(String username) { + return sqlUserStore.getByUsername(username); + } + + @Override + public User getUserByUUID(UUID uuid) { + return sqlUserStore.getUserByUUID(uuid); + } + + @Override + public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { + return openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken); + } + + @Override + public AuthManager.AuthReport refreshAccessToken(String oldRefreshToken, AuthResponse.AuthContext context) { + var tokens = openIDAuthenticator.refreshAccessToken(oldRefreshToken); + var accessToken = tokens.accessToken(); + var refreshToken = tokens.refreshToken(); + long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn()); + + UserSession session; + try { + session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken); + } catch (OAuthAccessTokenExpired e) { + throw new RuntimeException("invalid token", e); + } + + + return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken, + expiresIn, session); + } + + @Override + public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { + if (password == null) { + throw AuthException.wrongPassword(); + } + var authCodePassword = (AuthCodePassword) password; + + var tokens = openIDAuthenticator.authorize(authCodePassword); + + var accessToken = tokens.accessToken(); + var refreshToken = tokens.refreshToken(); + var user = openIDAuthenticator.createUserFromToken(accessToken); + long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn()); + + sqlUserStore.createOrUpdateUser(user); + + UserSession session; + try { + session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken); + } catch (OAuthAccessTokenExpired e) { + throw new AuthException("invalid token", e); + } + + if (minecraftAccess) { + var minecraftToken = generateMinecraftToken(user); + return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftToken, accessToken, refreshToken, + expiresIn, session); + } else { + return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken, + expiresIn, session); + } + } + + private String generateMinecraftToken(User user) { + return Jwts.builder() + .issuer("LaunchServer") + .subject(user.getUUID().toString()) + .claim("preferred_username", user.getUsername()) + .expiration(Date.from(Instant.now().plus(24, ChronoUnit.HOURS))) + .signWith(server.keyAgreementManager.ecdsaPrivateKey) + .compact(); + } + + private User createUserFromMinecraftToken(String accessToken) throws AuthException { + try { + var parser = Jwts.parser() + .requireIssuer("LaunchServer") + .verifyWith(server.keyAgreementManager.ecdsaPublicKey) + .build(); + var claims = parser.parseSignedClaims(accessToken); + var username = claims.getPayload().get("preferred_username", String.class); + var uuid = UUID.fromString(claims.getPayload().getSubject()); + return new UserEntity(username, uuid, new ClientPermissions()); + } catch (JwtException e) { + throw new AuthException("Bad minecraft token", e); + } + } + + @Override + public void init(LaunchServer server) { + this.server = server; + this.sqlSourceConfig.init(); + this.sqlUserStore = new SQLUserStore(sqlSourceConfig); + this.sqlUserStore.init(); + this.sqlSessionStore = new SQLServerSessionStore(sqlSourceConfig); + this.sqlSessionStore.init(); + this.openIDAuthenticator = new OpenIDAuthenticator(openIDConfig); + } + + @Override + public User checkServer(Client client, String username, String serverID) throws IOException { + var savedServerId = sqlSessionStore.getServerIdByUsername(username); + if (!serverID.equals(savedServerId)) { + return null; + } + + return sqlUserStore.getByUsername(username); + } + + @Override + public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException { + User user; + try { + user = createUserFromMinecraftToken(accessToken); + } catch (AuthException e) { + LogHelper.error(e); + return false; + } + if (!user.getUUID().equals(uuid)) { + return false; + } + + sqlUserStore.createOrUpdateUser(user); + + return sqlSessionStore.joinServer(user.getUUID(), user.getUsername(), serverID); + } + + @Override + public void close() { + sqlSourceConfig.close(); + } + +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java new file mode 100644 index 00000000..3488e1c3 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java @@ -0,0 +1,229 @@ +package pro.gravit.launchserver.auth.core.openid; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.security.Jwk; +import io.jsonwebtoken.security.JwkSet; +import io.jsonwebtoken.security.Jwks; +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.request.auth.details.AuthWebViewDetails; +import pro.gravit.launcher.request.auth.password.AuthCodePassword; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.auth.core.AuthCoreProvider; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.launchserver.auth.core.UserSession; +import pro.gravit.utils.helper.CommonHelper; +import pro.gravit.utils.helper.QueryHelper; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.security.Key; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +public class OpenIDAuthenticator { + private static final HttpClient CLIENT = HttpClient.newBuilder().build(); + private final OpenIDConfig openIDConfig; + private final JwtParser jwtParser; + + public OpenIDAuthenticator(OpenIDConfig openIDConfig) { + this.openIDConfig = openIDConfig; + var keyLocator = loadKeyLocator(openIDConfig); + this.jwtParser = Jwts.parser().keyLocator(keyLocator) + .build(); + } + + public List getDetails() { + var state = UUID.randomUUID().toString(); + var uri = QueryBuilder.get(openIDConfig.authorizationEndpoint()) + .addQuery("response_type", "code") + .addQuery("client_id", openIDConfig.clientId()) + .addQuery("redirect_uri", openIDConfig.redirectUri()) + .addQuery("scope", openIDConfig.scopes()) + .addQuery("state", state) + .toUriString(); + + return List.of(new AuthWebViewDetails(uri, openIDConfig.redirectUri())); + } + + public TokenResponse refreshAccessToken(String oldRefreshToken) { + var postBody = QueryBuilder.post() + .addQuery("grant_type", "refresh_token") + .addQuery("refresh_token", oldRefreshToken) + .addQuery("client_id", openIDConfig.clientId()) + .addQuery("client_secret", openIDConfig.clientSecret()) + .toString(); + + var accessTokenResponse = requestToken(postBody); + var accessToken = accessTokenResponse.accessToken(); + var refreshToken = accessTokenResponse.refreshToken(); + + try { + readAndVerifyToken(accessToken); + } catch (AuthException e) { + throw new RuntimeException(e); + } + + var accessTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.expiresIn(), 0L); + var refreshTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.refreshExpiresIn(), 0L); + + return new TokenResponse(accessToken, accessTokenExpiresIn, + refreshToken, refreshTokenExpiresIn); + } + + public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws AuthCoreProvider.OAuthAccessTokenExpired { + Jws token; + try { + token = readAndVerifyToken(accessToken); + } catch (AuthException e) { + throw new AuthCoreProvider.OAuthAccessTokenExpired("Can't read token", e); + } + var user = createUserFromToken(token); + long expiresIn = 0; + var expDate = token.getPayload().getExpiration(); + if (expDate != null) { + expiresIn = expDate.toInstant().toEpochMilli(); + } + + return new OpenIDUserSession(user, accessToken, expiresIn); + } + + public TokenResponse authorize(AuthCodePassword authCode) throws IOException { + var uri = URI.create(authCode.uri); + var queries = QueryHelper.splitUriQuery(uri); + + String code = CommonHelper.multimapFirstOrNullValue("code", queries); + String error = CommonHelper.multimapFirstOrNullValue("error", queries); + String errorDescription = CommonHelper.multimapFirstOrNullValue("error_description", queries); + + if (error != null && !error.isBlank()) { + throw new AuthException("Auth error. Error: %s, description: %s".formatted(error, errorDescription)); + } + + + var postBody = QueryBuilder.post() + .addQuery("grant_type", "authorization_code") + .addQuery("code", code) + .addQuery("redirect_uri", openIDConfig.redirectUri()) + .addQuery("client_id", openIDConfig.clientId()) + .addQuery("client_secret", openIDConfig.clientSecret()) + .toString(); + + var accessTokenResponse = requestToken(postBody); + var accessToken = accessTokenResponse.accessToken(); + var refreshToken = accessTokenResponse.refreshToken(); + + readAndVerifyToken(accessToken); + + var accessTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.expiresIn(), 0L); + var refreshTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.refreshExpiresIn(), 0L); + + return new TokenResponse(accessToken, accessTokenExpiresIn, + refreshToken, refreshTokenExpiresIn); + } + + public User createUserFromToken(String accessToken) throws AuthException { + return createUserFromToken(readAndVerifyToken(accessToken)); + } + + private Jws readAndVerifyToken(String accessToken) throws AuthException { + if (accessToken == null) { + throw new AuthException("Token is null"); + } + + try { + return jwtParser.parseSignedClaims(accessToken); + } catch (JwtException e) { + throw new AuthException("Bad token", e); + } + } + + private User createUserFromToken(Jws token) { + var username = token.getPayload().get(openIDConfig.extractorConfig().usernameClaim(), String.class); + var uuidStr = token.getPayload().get(openIDConfig.extractorConfig().uuidClaim(), String.class); + var uuid = UUID.fromString(uuidStr); + return new UserEntity(username, uuid, new ClientPermissions()); + } + + private AccessTokenResponse requestToken(String postBody) { + var request = HttpRequest.newBuilder() + .uri(openIDConfig.tokenUri()) + .header("Content-Type", "application/x-www-form-urlencoded") + .header("Accept", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(postBody)) + .build(); + + HttpResponse resp; + try { + resp = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + return Launcher.gsonManager.gson.fromJson(resp.body(), AccessTokenResponse.class); + } + + private static KeyLocator loadKeyLocator(OpenIDConfig openIDConfig) { + var request = HttpRequest.newBuilder(openIDConfig.jwksUri()).GET().build(); + HttpResponse response; + try { + response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + var jwks = Jwks.setParser().build().parse(response.body()); + return new KeyLocator(jwks); + } + + private static class KeyLocator extends LocatorAdapter { + private final Map keys; + + public KeyLocator(JwkSet jwks) { + this.keys = jwks.getKeys().stream().collect( + Collectors.toMap(jwk -> String.valueOf(jwk.get("kid")), Jwk::toKey)); + } + + @Override + protected Key locate(JweHeader header) { + return super.locate(header); + } + + @Override + protected Key locate(JwsHeader header) { + return keys.get(header.getKeyId()); + } + + @Override + protected Key doLocate(Header header) { + return super.doLocate(header); + } + } + + record OpenIDUserSession(User user, String token, long expiresIn) implements UserSession { + @Override + public String getID() { + return user.getUsername(); + } + + @Override + public User getUser() { + return user; + } + + @Override + public String getMinecraftAccessToken() { + return token; + } + + @Override + public long getExpireIn() { + return expiresIn; + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java new file mode 100644 index 00000000..395f2046 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java @@ -0,0 +1,9 @@ +package pro.gravit.launchserver.auth.core.openid; + +import java.net.URI; + +public record OpenIDConfig(URI tokenUri, String authorizationEndpoint, String clientId, String clientSecret, + String redirectUri, URI jwksUri, String scopes, ClaimExtractorConfig extractorConfig) { + + public record ClaimExtractorConfig(String usernameClaim, String uuidClaim) {} +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/QueryBuilder.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/QueryBuilder.java new file mode 100644 index 00000000..c3175ffc --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/QueryBuilder.java @@ -0,0 +1,59 @@ +package pro.gravit.launchserver.auth.core.openid; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @author Xakep_SDK + */ +public class QueryBuilder { + private final String uri; + private final StringBuilder query = new StringBuilder(); + + public QueryBuilder(String uri) { + this.uri = uri; + } + + public static QueryBuilder get(String uri) { + Objects.requireNonNull(uri, "uri"); + if (uri.endsWith("/")) { + uri = uri.substring(0, uri.length() - 1); + } + return new QueryBuilder(uri); + } + + public static QueryBuilder post() { + return new QueryBuilder(null); + } + + public QueryBuilder addQuery(String key, String value) { + if (!query.isEmpty()) { + query.append('&'); + } + query.append(URLEncoder.encode(key, StandardCharsets.UTF_8)) + .append('=') + .append(URLEncoder.encode(value, StandardCharsets.UTF_8)); + return this; + } + + public String toUriString() { + if (uri != null) { + if (query. isEmpty()) { + return uri; + } + return uri + '?' + query; + } + return toQueryString(); + } + + public String toQueryString() { + return query.toString(); + } + + @Override + public String toString() { + return toUriString(); + } +} + diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLServerSessionStore.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLServerSessionStore.java new file mode 100644 index 00000000..6acebc5d --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLServerSessionStore.java @@ -0,0 +1,99 @@ +package pro.gravit.launchserver.auth.core.openid; + +import pro.gravit.launchserver.auth.SQLSourceConfig; +import pro.gravit.utils.helper.LogHelper; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.SQLException; +import java.util.UUID; + +public class SQLServerSessionStore implements ServerSessionStore { + private static final String CREATE_TABLE = """ + create table if not exists `gravit_server_session` ( + id int auto_increment, + uuid varchar(36), + username varchar(255), + server_id varchar(41), + primary key (id), + unique (uuid), + unique (username) + ); + """; + private static final String DELETE_SERVER_ID = """ + delete from `gravit_server_session` where uuid = ? + """; + private static final String INSERT_SERVER_ID = """ + insert into `gravit_server_session` (uuid, username, server_id) values (?, ?, ?) + """; + private static final String SELECT_SERVER_ID_BY_USERNAME = """ + select server_id from `gravit_server_session` where username = ? + """; + + private final SQLSourceConfig sqlSourceConfig; + + public SQLServerSessionStore(SQLSourceConfig sqlSourceConfig) { + this.sqlSourceConfig = sqlSourceConfig; + } + + @Override + public boolean joinServer(UUID uuid, String username, String serverId) { + try (var connection = sqlSourceConfig.getConnection()) { + connection.setAutoCommit(false); + var savepoint = connection.setSavepoint(); + try (var deleteServerIdStmt = connection.prepareStatement(DELETE_SERVER_ID); + var insertServerIdStmt = connection.prepareStatement(INSERT_SERVER_ID)) { + deleteServerIdStmt.setString(1, uuid.toString()); + deleteServerIdStmt.execute(); + insertServerIdStmt.setString(1, uuid.toString()); + insertServerIdStmt.setString(2, username); + insertServerIdStmt.setString(3, serverId); + insertServerIdStmt.execute(); + connection.commit(); + return true; + } catch (Exception e) { + connection.rollback(savepoint); + throw e; + } + } catch (SQLException e) { + LogHelper.debug("Can't join server. Username: %s".formatted(username)); + LogHelper.error(e); + } + + return false; + } + + @Override + public String getServerIdByUsername(String username) { + try (var connection = sqlSourceConfig.getConnection(); + var selectServerId = connection.prepareStatement(SELECT_SERVER_ID_BY_USERNAME)) { + selectServerId.setString(1, username); + try (var rs = selectServerId.executeQuery()) { + if (!rs.next()) { + return null; + } + return rs.getString("server_id"); + } + } catch (SQLException e) { + LogHelper.debug("Can't find server id by username. Username: %s".formatted(username)); + LogHelper.error(e); + } + return null; + } + + public void init() { + try (var connection = sqlSourceConfig.getConnection()) { + connection.setAutoCommit(false); + var savepoint = connection.setSavepoint(); + try (var createTableStmt = connection.prepareStatement(CREATE_TABLE)) { + createTableStmt.execute(); + connection.commit(); + } catch (Exception e) { + connection.rollback(savepoint); + throw e; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLUserStore.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLUserStore.java new file mode 100644 index 00000000..e84c82b7 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/SQLUserStore.java @@ -0,0 +1,124 @@ +package pro.gravit.launchserver.auth.core.openid; + +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launchserver.auth.HikariSQLSourceConfig; +import pro.gravit.launchserver.auth.core.User; +import pro.gravit.utils.helper.LogHelper; + +import java.sql.SQLException; +import java.util.UUID; + +public class SQLUserStore implements UserStore { + private static final String CREATE_USER_TABLE = """ + create table if not exists `gravit_user` ( + id int auto_increment, + uuid varchar(36), + username varchar(255), + primary key (id), + unique (uuid), + unique (username) + ) + """; + private static final String INSERT_USER = """ + insert into `gravit_user` (uuid, username) values (?, ?) + """; + private static final String DELETE_USER_BY_NAME = """ + delete `gravit_user` where username = ? + """; + private static final String SELECT_USER_BY_NAME = """ + select uuid, username from `gravit_user` where username = ? + """; + private static final String SELECT_USER_BY_UUID = """ + select uuid, username from `gravit_user` where uuid = ? + """; + + private final HikariSQLSourceConfig sqlSourceConfig; + + public SQLUserStore(HikariSQLSourceConfig sqlSourceConfig) { + this.sqlSourceConfig = sqlSourceConfig; + } + + @Override + public User getByUsername(String username) { + try (var connection = sqlSourceConfig.getConnection(); + var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_NAME)) { + selectUserStmt.setString(1, username); + try (var rs = selectUserStmt.executeQuery()) { + if (!rs.next()) { + LogHelper.debug("User not found, username: %s".formatted(username)); + return null; + } + return new UserEntity(rs.getString("username"), + UUID.fromString(rs.getString("uuid")), + new ClientPermissions()); + } + } catch (SQLException e) { + LogHelper.error(e); + } + + return null; + } + + @Override + public User getUserByUUID(UUID uuid) { + try (var connection = sqlSourceConfig.getConnection(); + var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_UUID)) { + selectUserStmt.setString(1, uuid.toString()); + try (var rs = selectUserStmt.executeQuery()) { + if (!rs.next()) { + LogHelper.debug("User not found, UUID: %s".formatted(uuid)); + return null; + } + return new UserEntity(rs.getString("username"), + UUID.fromString(rs.getString("uuid")), + new ClientPermissions()); + } + } catch (SQLException e) { + LogHelper.error(e); + } + + return null; + } + + @Override + public void createOrUpdateUser(User user) { + try (var connection = sqlSourceConfig.getConnection()) { + connection.setAutoCommit(false); + var savepoint = connection.setSavepoint(); + try (var deleteUserStmt = connection.prepareStatement(DELETE_USER_BY_NAME); + var insertUserStmt = connection.prepareStatement(INSERT_USER)) { + deleteUserStmt.setString(1, user.getUsername()); + deleteUserStmt.execute(); + insertUserStmt.setString(1, user.getUUID().toString()); + insertUserStmt.setString(2, user.getUsername()); + insertUserStmt.execute(); + connection.commit(); + LogHelper.debug("User saved. UUID: %s, username: %s".formatted(user.getUUID(), user.getUsername())); + } catch (Exception e) { + connection.rollback(savepoint); + throw e; + } + } catch (SQLException e) { + LogHelper.debug("Failed to save user"); + LogHelper.error(e); + throw new RuntimeException("Failed to save user", e); + } + } + + public void init() { + try (var connection = sqlSourceConfig.getConnection()) { + connection.setAutoCommit(false); + var savepoint = connection.setSavepoint(); + try (var createUserTableStmt = connection.prepareStatement(CREATE_USER_TABLE)) { + createUserTableStmt.execute(); + connection.commit(); + } catch (Exception e) { + connection.rollback(savepoint); + throw e; + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/ServerSessionStore.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/ServerSessionStore.java new file mode 100644 index 00000000..cf049951 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/ServerSessionStore.java @@ -0,0 +1,8 @@ +package pro.gravit.launchserver.auth.core.openid; + +import java.util.UUID; + +public interface ServerSessionStore { + boolean joinServer(UUID uuid, String username, String serverId); + String getServerIdByUsername(String username); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/TokenResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/TokenResponse.java new file mode 100644 index 00000000..4775213c --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/TokenResponse.java @@ -0,0 +1,5 @@ +package pro.gravit.launchserver.auth.core.openid; + +public record TokenResponse(String accessToken, long accessTokenExpiresIn, + String refreshToken, long refreshTokenExpiresIn) { +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserEntity.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserEntity.java new file mode 100644 index 00000000..5276acc8 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserEntity.java @@ -0,0 +1,23 @@ +package pro.gravit.launchserver.auth.core.openid; + +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launchserver.auth.core.User; + +import java.util.UUID; + +record UserEntity(String username, UUID uuid, ClientPermissions permissions) implements User { + @Override + public String getUsername() { + return username; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public ClientPermissions getPermissions() { + return permissions; + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserStore.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserStore.java new file mode 100644 index 00000000..55c26e71 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/UserStore.java @@ -0,0 +1,13 @@ +package pro.gravit.launchserver.auth.core.openid; + +import pro.gravit.launchserver.auth.core.User; + +import java.util.UUID; + +public interface UserStore { + User getByUsername(String username); + + User getUserByUUID(UUID uuid); + + void createOrUpdateUser(User user); +} diff --git a/props.gradle b/props.gradle index 1c40bced..68ee1515 100644 --- a/props.gradle +++ b/props.gradle @@ -14,6 +14,7 @@ verLog4j = '2.20.0' verMySQLConn = '8.3.0' verPostgreSQLConn = '42.7.1' + verH2Conn = '2.2.224' verProguard = '7.4.1' verLaunch4j = '3.50' } From 1cbaf4eea32004b2594265a5f698843987e6de39 Mon Sep 17 00:00:00 2001 From: XakepSDK Date: Thu, 25 Apr 2024 20:05:53 +0500 Subject: [PATCH 4/5] [FIX OpenID validate issuer and aud (#710) Co-authored-by: d3coder --- .../launchserver/auth/core/openid/OpenIDAuthenticator.java | 5 ++++- .../gravit/launchserver/auth/core/openid/OpenIDConfig.java | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java index 3488e1c3..29870c32 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java @@ -36,7 +36,10 @@ public class OpenIDAuthenticator { public OpenIDAuthenticator(OpenIDConfig openIDConfig) { this.openIDConfig = openIDConfig; var keyLocator = loadKeyLocator(openIDConfig); - this.jwtParser = Jwts.parser().keyLocator(keyLocator) + this.jwtParser = Jwts.parser() + .keyLocator(keyLocator) + .requireIssuer(openIDConfig.issuer()) + .requireAudience(openIDConfig.clientId()) .build(); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java index 395f2046..2d4f3bae 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDConfig.java @@ -3,7 +3,8 @@ import java.net.URI; public record OpenIDConfig(URI tokenUri, String authorizationEndpoint, String clientId, String clientSecret, - String redirectUri, URI jwksUri, String scopes, ClaimExtractorConfig extractorConfig) { + String redirectUri, URI jwksUri, String scopes, String issuer, + ClaimExtractorConfig extractorConfig) { public record ClaimExtractorConfig(String usernameClaim, String uuidClaim) {} } From ca376e10cb1045cce4c03a7c98a6a460796dc71e Mon Sep 17 00:00:00 2001 From: d3coder Date: Thu, 23 May 2024 22:21:46 +0500 Subject: [PATCH 5/5] [FIX] Fix OpenID access token validation --- .../launchserver/auth/core/openid/OpenIDAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java index 29870c32..03e77f77 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/openid/OpenIDAuthenticator.java @@ -39,7 +39,7 @@ public OpenIDAuthenticator(OpenIDConfig openIDConfig) { this.jwtParser = Jwts.parser() .keyLocator(keyLocator) .requireIssuer(openIDConfig.issuer()) - .requireAudience(openIDConfig.clientId()) + .require("azp", openIDConfig.clientId()) .build(); }