From 8f5f0f0b16a1dfaf33df5fa8a68af1c380b3f691 Mon Sep 17 00:00:00 2001 From: Tamar Weisskopf <98809100+TamarW0@users.noreply.github.com> Date: Tue, 4 Aug 2026 15:58:50 +0300 Subject: [PATCH] fix: Extract username from JWT token claims instead of UserInfo (#291) --------- Co-authored-by: Roni Hartuv Co-authored-by: Tamar Weisskopf Co-authored-by: Zvi Grinberg <75700623+zvigrinberg@users.noreply.github.com> --- .../exploitiq/service/UserService.java | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/redhat/ecosystemappeng/exploitiq/service/UserService.java b/src/main/java/com/redhat/ecosystemappeng/exploitiq/service/UserService.java index 344d6302..bf1b09a0 100644 --- a/src/main/java/com/redhat/ecosystemappeng/exploitiq/service/UserService.java +++ b/src/main/java/com/redhat/ecosystemappeng/exploitiq/service/UserService.java @@ -16,11 +16,13 @@ import io.quarkus.arc.properties.IfBuildProperty; import io.quarkus.oidc.UserInfo; +import io.quarkus.security.identity.SecurityIdentity; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Produces; import jakarta.inject.Inject; import jakarta.json.Json; import jakarta.json.JsonObject; +import org.eclipse.microprofile.jwt.JsonWebToken; import java.util.Objects; @ApplicationScoped @@ -29,6 +31,9 @@ public class UserService { @Inject UserInfo userInfo; + @Inject + SecurityIdentity securityIdentity; + private static final String DEFAULT_USERNAME = "anonymous"; @IfBuildProperty(name = "quarkus.oidc.enabled", stringValue = "false") @@ -42,12 +47,56 @@ public UserInfo getAnonymousUserInfo() { } /** - * Resolves the best available username from UserInfo claims. + * Resolves the best available username from JWT token claims or UserInfo. * - * Checks explicitly for: email, upn, metadata.name, preferred_username, sub. - * Falls back to "anonymous" if UserInfo is missing. + * Priority: + * 1. JWT token claims (email, cognito:username, username, upn, preferred_username, sub) + * 2. UserInfo (if available) + * 3. Falls back to "anonymous" */ public String getUserName() { + // First try to get username from JWT token directly + if (securityIdentity != null && securityIdentity.getPrincipal() instanceof JsonWebToken jwt) { + + + // Try email claim (Cognito ID tokens, common in OIDC) + String name = jwt.getClaim("email"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + + // Try cognito:username (Cognito-specific) + name = jwt.getClaim("cognito:username"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + + // Try username claim + name = jwt.getClaim("username"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + + // Try upn (user principal name - common in enterprise) + name = jwt.getClaim("upn"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + + // Try preferred_username (standard OIDC claim) + name = jwt.getClaim("preferred_username"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + + // Try sub (subject - always present but may be UUID) + name = jwt.getClaim("sub"); + if (Objects.nonNull(name) && !name.isBlank()) { + return name; + } + } + + // Fallback to UserInfo if JWT extraction didn't work if (Objects.nonNull(userInfo)) { var name = userInfo.getString("email"); if (Objects.nonNull(name)) {