feat: support server:-prefixed scopes and case-insensitive role mapping
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:
@@ -105,7 +105,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps OAuth2 scopes to server RBAC roles.
|
* 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) {
|
private List<String> extractRolesFromScopes(Jwt jwt) {
|
||||||
String scopeStr = jwt.getClaimAsString("scope");
|
String scopeStr = jwt.getClaimAsString("scope");
|
||||||
@@ -113,12 +114,17 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
return List.of("VIEWER");
|
return List.of("VIEWER");
|
||||||
}
|
}
|
||||||
List<String> scopes = List.of(scopeStr.split(" "));
|
List<String> scopes = List.of(scopeStr.split(" "));
|
||||||
if (scopes.contains("admin")) return List.of("ADMIN");
|
if (hasScope(scopes, "admin")) return List.of("ADMIN");
|
||||||
if (scopes.contains("operator")) return List.of("OPERATOR");
|
if (hasScope(scopes, "operator")) return List.of("OPERATOR");
|
||||||
if (scopes.contains("viewer")) return List.of("VIEWER");
|
if (hasScope(scopes, "viewer")) return List.of("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) {
|
private List<GrantedAuthority> toAuthorities(List<String> roles) {
|
||||||
return roles.stream()
|
return roles.stream()
|
||||||
.map(role -> (GrantedAuthority) new SimpleGrantedAuthority("ROLE_" + role))
|
.map(role -> (GrantedAuthority) new SimpleGrantedAuthority("ROLE_" + role))
|
||||||
|
|||||||
@@ -170,7 +170,11 @@ public class OidcAuthController {
|
|||||||
private void assignRolesForNewUser(String userId, List<String> oidcRoles, OidcConfig config) {
|
private void assignRolesForNewUser(String userId, List<String> oidcRoles, OidcConfig config) {
|
||||||
List<String> roleNames = !oidcRoles.isEmpty() ? oidcRoles : config.defaultRoles();
|
List<String> roleNames = !oidcRoles.isEmpty() ? oidcRoles : config.defaultRoles();
|
||||||
for (String roleName : roleNames) {
|
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) {
|
if (roleId != null) {
|
||||||
rbacService.assignRoleToUser(userId, roleId);
|
rbacService.assignRoleToUser(userId, roleId);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user