diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java index 727d74df21..b91b7542a0 100755 --- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java +++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java @@ -3,6 +3,7 @@ package org.keycloak.protocol; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserModel; +import org.keycloak.representations.AccessToken; import java.lang.reflect.Method; import java.util.List; @@ -41,4 +42,18 @@ public class ProtocolMapperUtils { } return null; } + + public static String[] parseRole(String role) { + int scopeIndex = role.indexOf('.'); + if (scopeIndex > -1) { + String appName = role.substring(0, scopeIndex); + role = role.substring(scopeIndex + 1); + String[] rtn = {appName, role}; + return rtn; + } else { + String[] rtn = {null, role}; + return rtn; + + } + } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java index ec0f720c03..26075e46bb 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java @@ -4,6 +4,7 @@ import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.AccessToken; @@ -65,12 +66,11 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { String role = mappingModel.getConfig().get(ROLE_CONFIG); - String appName = null; - int scopeIndex = role.indexOf('.'); - if (scopeIndex > -1) { - appName = role.substring(0, scopeIndex); - role = role.substring(scopeIndex + 1); - token.addAccess(appName).addRole(role); + String[] scopedRole = ProtocolMapperUtils.parseRole(role); + String appName = scopedRole[0]; + String roleName = scopedRole[1]; + if (appName != null) { + token.addAccess(appName).addRole(roleName); } else { AccessToken.Access access = token.getRealmAccess(); if (access == null) { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java index f60246caa1..eaee955b6d 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java @@ -76,29 +76,35 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc UserSessionModel userSession, ClientSessionModel clientSession) { String role = mappingModel.getConfig().get(ROLE_CONFIG); String newName = mappingModel.getConfig().get(NEW_ROLE_NAME); - String appName = null; - int scopeIndex = role.indexOf('.'); - if (scopeIndex > -1) { - appName = role.substring(0, scopeIndex); + + String[] scopedRole = ProtocolMapperUtils.parseRole(role); + String[] newScopedRole = ProtocolMapperUtils.parseRole(newName); + String appName = scopedRole[0]; + String roleName = scopedRole[1]; + if (appName != null) { AccessToken.Access access = token.getResourceAccess(appName); if (access == null) return token; - - role = role.substring(scopeIndex + 1); - if (!access.getRoles().contains(role)) return token; - access.getRoles().remove(role); + if (!access.getRoles().contains(roleName)) return token; + access.getRoles().remove(roleName); } else { AccessToken.Access access = token.getRealmAccess(); if (access == null) return token; - access.getRoles().remove(role); + access.getRoles().remove(roleName); } - String newAppName = null; - scopeIndex = newName.indexOf('.'); - if (scopeIndex > -1) { - newAppName = role.substring(0, scopeIndex); - newName = role.substring(scopeIndex + 1); - token.addAccess(newAppName).addRole(newName); + String newAppName = newScopedRole[0]; + String newRoleName = newScopedRole[1]; + AccessToken.Access access = null; + if (newAppName == null) { + access = token.getRealmAccess(); + if (access == null) { + access = new AccessToken.Access(); + token.setRealmAccess(access); + } + } else { + access = token.addAccess(newAppName); } + access.addRole(newRoleName); return token; } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java index 0091e337c6..b6f45bd294 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java @@ -607,6 +607,7 @@ public class AccessTokenTest { app.addProtocolMapper(UserAttributeMapper.createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true)); app.addProtocolMapper(HardcodedRole.create("hard-realm", "hardcoded")); app.addProtocolMapper(HardcodedRole.create("hard-app", "app.hardcoded")); + app.addProtocolMapper(RoleNameMapper.create("rename-app-role", "test-app.customer-user", "realm-user")); session.getTransaction().commit(); session.close(); } @@ -647,6 +648,8 @@ public class AccessTokenTest { nested = (Map)accessToken.getOtherClaims().get("home"); Assert.assertEquals("617-777-6666", nested.get("phone")); Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded")); + Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("realm-user")); + Assert.assertFalse(accessToken.getResourceAccess("test-app").getRoles().contains("customer-user")); Assert.assertTrue(accessToken.getResourceAccess("app").getRoles().contains("hardcoded")); @@ -665,6 +668,7 @@ public class AccessTokenTest { || model.getName().equals("hard-nested") || model.getName().equals("custom phone") || model.getName().equals("nested phone") + || model.getName().equals("rename-app-role") || model.getName().equals("hard-realm") || model.getName().equals("hard-app") ) {