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:
parent
4be058a3dd
commit
6615691c63
2 changed files with 47 additions and 4 deletions
|
@ -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,8 +88,26 @@ 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() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue