diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java index 499acba9a8..43f0eaf91c 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java @@ -22,6 +22,7 @@ import java.util.function.BiFunction; import org.jboss.logging.Logger; import org.keycloak.authorization.AuthorizationProvider; +import org.keycloak.authorization.attribute.Attributes.Entry; import org.keycloak.authorization.identity.Identity; import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.policy.evaluation.Evaluation; @@ -31,6 +32,8 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; +import org.keycloak.models.UserProvider; +import org.keycloak.representations.JsonWebToken; import org.keycloak.representations.idm.authorization.RolePolicyRepresentation; /** @@ -74,9 +77,8 @@ public class RolePolicyProvider implements PolicyProvider { private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, AuthorizationProvider authorizationProvider, boolean fetchRoles) { if (fetchRoles) { - KeycloakSession session = authorizationProvider.getKeycloakSession(); - UserModel user = session.users().getUserById(realm, identity.getId()); - return user.hasRole(role); + UserModel subject = getSubject(identity, realm, authorizationProvider); + return subject != null && subject.hasRole(role); } String roleName = role.getName(); if (role.isClientRole()) { @@ -86,8 +88,26 @@ public class RolePolicyProvider implements PolicyProvider { return identity.hasRealmRole(roleName); } + private UserModel getSubject(Identity identity, RealmModel realm, AuthorizationProvider authorizationProvider) { + KeycloakSession session = authorizationProvider.getKeycloakSession(); + UserProvider users = session.users(); + UserModel user = users.getUserById(realm, identity.getId()); + + if (user == null) { + Entry sub = identity.getAttributes().getValue(JsonWebToken.SUBJECT); + + if (sub == null || sub.isEmpty()) { + return null; + } + + return users.getUserById(realm, sub.asString(0)); + } + + return user; + } + @Override public void close() { } -} \ No newline at end of file +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/RolePolicyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/RolePolicyTest.java index 6057c49888..0c4c2036b1 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/RolePolicyTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/RolePolicyTest.java @@ -192,6 +192,29 @@ public class RolePolicyTest extends AbstractAuthzTest { assertNotNull(authzClient.authorization("kolo", "password").authorize(new AuthorizationRequest(ticket))); } + @Test + public void testFetchRolesUsingServiceAccount() { + AuthzClient authzClient = getAuthzClient(); + RealmResource realm = getRealm(); + ClientsResource clients = realm.clients(); + ClientRepresentation client = clients.findByClientId(authzClient.getConfiguration().getResource()).get(0); + ClientScopeRepresentation rolesScope = ApiUtil.findClientScopeByName(realm, OIDCLoginProtocolFactory.ROLES_SCOPE).toRepresentation(); + ClientResource clientResource = clients.get(client.getId()); + clientResource.removeDefaultClientScope(rolesScope.getId()); + UserRepresentation serviceAccountUser = clientResource.getServiceAccountUser(); + RoleRepresentation roleB = realm.roles().get("Role B").toRepresentation(); + realm.users().get(serviceAccountUser.getId()).roles().realmLevel().add(List.of(roleB)); + RolePolicyRepresentation roleRep = clientResource.authorization().policies().role().findByName("Role B Policy"); + roleRep.setFetchRoles(true); + clientResource.authorization().policies().role().findById(roleRep.getId()).update(roleRep); + getCleanup().addCleanup(() -> { + clientResource.addDefaultClientScope(rolesScope.getId()); + roleRep.setFetchRoles(false); + clientResource.authorization().policies().role().findById(roleRep.getId()).update(roleRep); + }); + assertNotNull(authzClient.authorization().authorize(new AuthorizationRequest())); + } + private void createRealmRolePolicy(String name, String... roles) { RolePolicyRepresentation policy = new RolePolicyRepresentation();