From d69f131263e173e8114789acfd68b57370bddc63 Mon Sep 17 00:00:00 2001 From: Romain LABAT Date: Mon, 24 Jun 2024 14:53:45 +0200 Subject: [PATCH 1/2] do not fetchRoles when using client credentials Closes #30444 Signed-off-by: Romain LABAT --- .../policy/provider/role/RolePolicyProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 499acba9a838..1914ef032155 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 @@ -73,7 +73,7 @@ public void evaluate(Evaluation evaluation) { } private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, AuthorizationProvider authorizationProvider, boolean fetchRoles) { - if (fetchRoles) { + if (fetchRoles && !identity.getAttributes().exists("clientId")) { KeycloakSession session = authorizationProvider.getKeycloakSession(); UserModel user = session.users().getUserById(realm, identity.getId()); return user.hasRole(role); @@ -90,4 +90,4 @@ private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, Aut public void close() { } -} \ No newline at end of file +} From ddb0c8e52e325895a55e991c176a638b9ba27bae Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Mon, 24 Jun 2024 11:01:43 -0300 Subject: [PATCH 2/2] Support for service accounts when fetch roles is enabled Signed-off-by: Pedro Igor --- .../provider/role/RolePolicyProvider.java | 28 ++++++++++++++++--- .../testsuite/authz/RolePolicyTest.java | 23 +++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) 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 1914ef032155..43f0eaf91cde 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 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.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; /** @@ -73,10 +76,9 @@ public void evaluate(Evaluation evaluation) { } private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, AuthorizationProvider authorizationProvider, boolean fetchRoles) { - if (fetchRoles && !identity.getAttributes().exists("clientId")) { - KeycloakSession session = authorizationProvider.getKeycloakSession(); - UserModel user = session.users().getUserById(realm, identity.getId()); - return user.hasRole(role); + if (fetchRoles) { + UserModel subject = getSubject(identity, realm, authorizationProvider); + return subject != null && subject.hasRole(role); } String roleName = role.getName(); if (role.isClientRole()) { @@ -86,6 +88,24 @@ private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, Aut 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() { 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 6057c49888fc..0c4c2036b160 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 void testFetchRoles() { 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();