feat: support server:-prefixed scopes and case-insensitive role mapping
Some checks failed
CI / docker (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / deploy-feature (push) Has been cancelled
CI / cleanup-branch (push) Has been cancelled
CI / build (push) Has been cancelled

M2M scope mapping now accepts both 'server:admin' and 'admin' (case-
insensitive). OIDC user login role assignment strips the 'server:'
prefix before looking up SystemRole, so 'server:viewer' from the
id_token maps to VIEWER correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-06 10:05:13 +02:00
parent c757a0ea51
commit 9c2e6aacad
2 changed files with 15 additions and 5 deletions

View File

@@ -105,7 +105,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
/**
* Maps OAuth2 scopes to server RBAC roles.
* Scopes are defined on the Logto API Resource for this server.
* Accepts both prefixed ({@code server:admin}) and bare ({@code admin}) scope names,
* case-insensitive. Scopes are defined on the Logto API Resource for this server.
*/
private List<String> extractRolesFromScopes(Jwt jwt) {
String scopeStr = jwt.getClaimAsString("scope");
@@ -113,12 +114,17 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
return List.of("VIEWER");
}
List<String> scopes = List.of(scopeStr.split(" "));
if (scopes.contains("admin")) return List.of("ADMIN");
if (scopes.contains("operator")) return List.of("OPERATOR");
if (scopes.contains("viewer")) return List.of("VIEWER");
if (hasScope(scopes, "admin")) return List.of("ADMIN");
if (hasScope(scopes, "operator")) return List.of("OPERATOR");
if (hasScope(scopes, "viewer")) return List.of("VIEWER");
return List.of("VIEWER");
}
private boolean hasScope(List<String> scopes, String role) {
return scopes.stream().anyMatch(s ->
s.equalsIgnoreCase(role) || s.equalsIgnoreCase("server:" + role));
}
private List<GrantedAuthority> toAuthorities(List<String> roles) {
return roles.stream()
.map(role -> (GrantedAuthority) new SimpleGrantedAuthority("ROLE_" + role))

View File

@@ -170,7 +170,11 @@ public class OidcAuthController {
private void assignRolesForNewUser(String userId, List<String> oidcRoles, OidcConfig config) {
List<String> roleNames = !oidcRoles.isEmpty() ? oidcRoles : config.defaultRoles();
for (String roleName : roleNames) {
UUID roleId = SystemRole.BY_NAME.get(roleName.toUpperCase());
String normalized = roleName.toUpperCase();
if (normalized.startsWith("SERVER:")) {
normalized = normalized.substring("SERVER:".length());
}
UUID roleId = SystemRole.BY_NAME.get(normalized);
if (roleId != null) {
rbacService.assignRoleToUser(userId, roleId);
}