Support for service accounts when fetch roles is enabled (#30687)

Support for service accounts when fetch roles is enabled

Signed-off-by: Romain LABAT <contact@romainlabat.fr>
Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
Co-authored-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Romain LABAT 2024-06-25 23:00:26 +02:00 committed by GitHub
parent 4be058a3dd
commit 6615691c63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 4 deletions

View file

@ -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,6 +88,24 @@ 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() {

View file

@ -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();