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.jboss.logging.Logger;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.attribute.Attributes.Entry;
import org.keycloak.authorization.identity.Identity; import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation; 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.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation; 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) { private boolean hasRole(Identity identity, RoleModel role, RealmModel realm, AuthorizationProvider authorizationProvider, boolean fetchRoles) {
if (fetchRoles) { if (fetchRoles) {
KeycloakSession session = authorizationProvider.getKeycloakSession(); UserModel subject = getSubject(identity, realm, authorizationProvider);
UserModel user = session.users().getUserById(realm, identity.getId()); return subject != null && subject.hasRole(role);
return user.hasRole(role);
} }
String roleName = role.getName(); String roleName = role.getName();
if (role.isClientRole()) { if (role.isClientRole()) {
@ -86,6 +88,24 @@ public class RolePolicyProvider implements PolicyProvider {
return identity.hasRealmRole(roleName); 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 @Override
public void close() { public void close() {

View file

@ -192,6 +192,29 @@ public class RolePolicyTest extends AbstractAuthzTest {
assertNotNull(authzClient.authorization("kolo", "password").authorize(new AuthorizationRequest(ticket))); 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) { private void createRealmRolePolicy(String name, String... roles) {
RolePolicyRepresentation policy = new RolePolicyRepresentation(); RolePolicyRepresentation policy = new RolePolicyRepresentation();