From 0d610be3dcbc311941add3f0c3dc14e9b8d916ab Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 10 Apr 2026 12:17:12 +0200 Subject: [PATCH] fix: use OIDC token roles when no claim mapping rules exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OIDC callback extracted roles from the token's Custom JWT claim (e.g. roles: [server:admin]) but never used them. The applyClaimMappings fallback only assigned defaultRoles (VIEWER). Now the fallback priority is: claim mapping rules > OIDC token roles > defaultRoles. This ensures users get their org-mapped roles (owner → server:admin) without requiring manual claim mapping rule configuration. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/security/OidcAuthController.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcAuthController.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcAuthController.java index 2bff1b17..d0dc7e72 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcAuthController.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/OidcAuthController.java @@ -156,7 +156,7 @@ public class OidcAuthController { userId, provider, oidcUser.email(), oidcUser.name(), Instant.now())); // Apply claim mapping rules to assign managed roles/groups from JWT claims - applyClaimMappings(userId, oidcUser.allClaims(), config.get()); + applyClaimMappings(userId, oidcUser.allClaims(), oidcUser.roles(), config.get()); List roles = rbacService.getSystemRoleNames(userId); @@ -180,7 +180,8 @@ public class OidcAuthController { } } - private void applyClaimMappings(String userId, Map claims, OidcConfig oidcConfig) { + private void applyClaimMappings(String userId, Map claims, + List oidcExtractedRoles, OidcConfig oidcConfig) { List rules = claimMappingRepository.findAll(); rbacService.clearManagedAssignments(userId); @@ -214,15 +215,26 @@ public class OidcAuthController { } } - // Fallback: if no mapping rules matched, assign defaultRoles from OIDC config + // Fallback priority: claim mapping rules > OIDC token roles > defaultRoles if (results.isEmpty()) { - List defaultRoles = oidcConfig.defaultRoles(); - if (defaultRoles != null && !defaultRoles.isEmpty()) { - for (String roleName : defaultRoles) { + // Use roles extracted directly from the OIDC token (e.g. Custom JWT 'roles' claim) + if (oidcExtractedRoles != null && !oidcExtractedRoles.isEmpty()) { + for (String roleName : oidcExtractedRoles) { UUID roleId = SystemRole.BY_NAME.get(SystemRole.normalizeScope(roleName)); if (roleId != null) { rbacService.assignRoleToUser(userId, roleId); - log.debug("Default role {} assigned to {} (no claim mapping matched)", roleName, userId); + log.info("OIDC role {} assigned to {} (from token claim)", roleName, userId); + } + } + } else { + List defaultRoles = oidcConfig.defaultRoles(); + if (defaultRoles != null && !defaultRoles.isEmpty()) { + for (String roleName : defaultRoles) { + UUID roleId = SystemRole.BY_NAME.get(SystemRole.normalizeScope(roleName)); + if (roleId != null) { + rbacService.assignRoleToUser(userId, roleId); + log.debug("Default role {} assigned to {} (no claim mapping or OIDC roles)", roleName, userId); + } } } }