mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Remove permissions and resources when their corresponding objects are deleted
Closes #37242 Signed-off-by: vramik <vramik@redhat.com>
This commit is contained in:
parent
fde8cc5944
commit
872a691757
@ -16,6 +16,9 @@
|
||||
*/
|
||||
package org.keycloak.authorization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -31,24 +34,32 @@ import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientModel.ClientRemovedEvent;
|
||||
import org.keycloak.models.ClientProvider;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.GroupModel.GroupRemovedEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.ModelValidationException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.UserRemovedEvent;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AuthorizationSchema;
|
||||
import org.keycloak.representations.idm.authorization.GroupPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceType;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
public class AdminPermissionsSchema extends AuthorizationSchema {
|
||||
|
||||
@ -356,18 +367,10 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
|
||||
|
||||
if (supportsAuthorizationSchema(session, resourceServer)) {
|
||||
switch (resourceType) {
|
||||
case CLIENTS_RESOURCE_TYPE -> {
|
||||
return resolveClient(session, resourceName).map(ClientModel::getClientId).orElse(resourceType);
|
||||
}
|
||||
case GROUPS_RESOURCE_TYPE -> {
|
||||
return resolveGroup(session, resourceName).map(GroupModel::getName).orElse(resourceType);
|
||||
}
|
||||
case ROLES_RESOURCE_TYPE -> {
|
||||
return resolveRole(session, resourceName).map(RoleModel::getName).orElse(resourceType);
|
||||
}
|
||||
case USERS_RESOURCE_TYPE -> {
|
||||
return resolveUser(session, resourceName).map(UserModel::getUsername).orElse(resourceType);
|
||||
}
|
||||
case CLIENTS_RESOURCE_TYPE -> resolveClient(session, resourceName).map(ClientModel::getClientId).orElse(resourceType);
|
||||
case GROUPS_RESOURCE_TYPE -> resolveGroup(session, resourceName).map(GroupModel::getName).orElse(resourceType);
|
||||
case ROLES_RESOURCE_TYPE -> resolveRole(session, resourceName).map(RoleModel::getName).orElse(resourceType);
|
||||
case USERS_RESOURCE_TYPE -> resolveUser(session, resourceName).map(UserModel::getUsername).orElse(resourceType);
|
||||
default -> throw new IllegalStateException("Resource type [" + resourceType + "] not found.");
|
||||
}
|
||||
}
|
||||
@ -388,4 +391,39 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeResourceObject(AuthorizationProvider authorization, ProviderEvent event) {
|
||||
if (!isAdminPermissionsEnabled(authorization.getRealm()) || authorization.getRealm().getAdminPermissionsClient() == null) return;
|
||||
|
||||
String id;
|
||||
if (event instanceof UserRemovedEvent userRemovedEvent) {
|
||||
id = userRemovedEvent.getUser().getId();
|
||||
} else if (event instanceof ClientRemovedEvent clientRemovedEvent) {
|
||||
id = clientRemovedEvent.getClient().getId();
|
||||
} else if (event instanceof GroupRemovedEvent groupRemovedEvent) {
|
||||
id = groupRemovedEvent.getGroup().getId();
|
||||
} else if (event instanceof RoleRemovedEvent roleRemovedEvent) {
|
||||
id = roleRemovedEvent.getRole().getId();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceServer server = authorization.getStoreFactory().getResourceServerStore().findByClient(authorization.getRealm().getAdminPermissionsClient());
|
||||
|
||||
Resource resource = authorization.getStoreFactory().getResourceStore().findByName(server, id);
|
||||
if (resource != null) {
|
||||
List<Policy> permissions = authorization.getStoreFactory().getPolicyStore().findByResource(server, resource);
|
||||
//remove object from permission if there is more than one resource, remove the permission if there is only the removed object
|
||||
for (Policy permission : permissions) {
|
||||
if (permission.getResources().size() == 1) {
|
||||
authorization.getStoreFactory().getPolicyStore().delete(permission.getId());
|
||||
} else {
|
||||
permission.removeResource(resource);
|
||||
}
|
||||
}
|
||||
|
||||
//remove the resource associated with the object
|
||||
authorization.getStoreFactory().getResourceStore().delete(resource.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,12 +22,16 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.GroupSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.RoleSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.Synchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.UserSynchronizer;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ClientModel.ClientRemovedEvent;
|
||||
import org.keycloak.models.GroupModel.GroupRemovedEvent;
|
||||
import org.keycloak.models.RealmModel.RealmRemovedEvent;
|
||||
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
|
||||
import org.keycloak.models.UserModel.UserRemovedEvent;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
@ -48,6 +52,8 @@ public interface AuthorizationStoreFactory extends ProviderFactory<StoreFactory>
|
||||
synchronizers.put(ClientRemovedEvent.class, new ClientApplicationSynchronizer());
|
||||
synchronizers.put(RealmRemovedEvent.class, new RealmSynchronizer());
|
||||
synchronizers.put(UserRemovedEvent.class, new UserSynchronizer());
|
||||
synchronizers.put(GroupRemovedEvent.class, new GroupSynchronizer());
|
||||
synchronizers.put(RoleRemovedEvent.class, new RoleSynchronizer());
|
||||
|
||||
factory.register(event -> {
|
||||
try {
|
||||
|
||||
@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
@ -43,6 +44,8 @@ public class ClientApplicationSynchronizer implements Synchronizer<ClientRemoved
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
AdminPermissionsSchema.SCHEMA.removeResourceObject(authorizationProvider, event);
|
||||
|
||||
removeFromClientPolicies(event, authorizationProvider);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package org.keycloak.authorization.store.syncronization;
|
||||
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.models.GroupModel.GroupRemovedEvent;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
public class GroupSynchronizer implements Synchronizer<GroupRemovedEvent> {
|
||||
|
||||
@Override
|
||||
public void synchronize(GroupRemovedEvent event, KeycloakSessionFactory factory) {
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
AdminPermissionsSchema.SCHEMA.removeResourceObject(authorizationProvider, event);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package org.keycloak.authorization.store.syncronization;
|
||||
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
public class RoleSynchronizer implements Synchronizer<RoleRemovedEvent> {
|
||||
|
||||
@Override
|
||||
public void synchronize(RoleRemovedEvent event, KeycloakSessionFactory factory) {
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
AdminPermissionsSchema.SCHEMA.removeResourceObject(authorizationProvider, event);
|
||||
}
|
||||
}
|
||||
@ -18,14 +18,11 @@
|
||||
package org.keycloak.authorization.store.syncronization;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.PermissionTicket;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PermissionTicketStore;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
@ -34,7 +31,6 @@ import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.UserRemovedEvent;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
@ -46,6 +42,8 @@ public class UserSynchronizer implements Synchronizer<UserRemovedEvent> {
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
AdminPermissionsSchema.SCHEMA.removeResourceObject(authorizationProvider, event);
|
||||
|
||||
removeFromUserPermissionTickets(event, authorizationProvider);
|
||||
removeUserResources(event, authorizationProvider);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.keycloak.testframework.realm;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
@ -59,7 +60,9 @@ public class ClientSupplier implements Supplier<ManagedClient, InjectClient> {
|
||||
@Override
|
||||
public void close(InstanceContext<ManagedClient, InjectClient> instanceContext) {
|
||||
if (instanceContext.getNote("managed", Boolean.class)) {
|
||||
instanceContext.getValue().admin().remove();
|
||||
try {
|
||||
instanceContext.getValue().admin().remove();
|
||||
} catch (NotFoundException ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.keycloak.testframework.realm;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
@ -49,7 +50,9 @@ public class UserSupplier implements Supplier<ManagedUser, InjectUser> {
|
||||
|
||||
@Override
|
||||
public void close(InstanceContext<ManagedUser, InjectUser> instanceContext) {
|
||||
instanceContext.getValue().admin().remove();
|
||||
try {
|
||||
instanceContext.getValue().admin().remove();
|
||||
} catch (NotFoundException ex) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -92,10 +92,6 @@ public abstract class AbstractPermissionTest {
|
||||
permission.setLogic(logic);
|
||||
return this;
|
||||
}
|
||||
PermissionBuilder name(String name) {
|
||||
permission.setName(name);
|
||||
return this;
|
||||
}
|
||||
PermissionBuilder resourceType(String resourceType) {
|
||||
permission.setResourceType(resourceType);
|
||||
return this;
|
||||
@ -114,35 +110,43 @@ public abstract class AbstractPermissionTest {
|
||||
}
|
||||
}
|
||||
|
||||
protected static UserPolicyRepresentation createUserPolicy(ManagedRealm realm, ManagedClient client, String name, String userId) {
|
||||
return createUserPolicy(realm, client, name, userId, Logic.POSITIVE);
|
||||
protected static UserPolicyRepresentation createUserPolicy(ManagedRealm realm, ManagedClient client, String name, String... userIds) {
|
||||
return createUserPolicy(Logic.POSITIVE, realm, client, name, userIds);
|
||||
}
|
||||
|
||||
protected static UserPolicyRepresentation createUserPolicy(ManagedRealm realm, ManagedClient client, String name, String userId, Logic logic) {
|
||||
protected static UserPolicyRepresentation createUserPolicy(Logic logic, ManagedRealm realm, ManagedClient client, String name, String... userIds) {
|
||||
UserPolicyRepresentation policy = new UserPolicyRepresentation();
|
||||
policy.setName(name);
|
||||
policy.addUser(userId);
|
||||
for (String userId : userIds) {
|
||||
policy.addUser(userId);
|
||||
}
|
||||
policy.setLogic(logic);
|
||||
try (Response response = client.admin().authorization().policies().user().create(policy)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
realm.cleanup().add(r -> {
|
||||
String policyId = r.clients().get(client.getId()).authorization().policies().user().findByName(name).getId();
|
||||
r.clients().get(client.getId()).authorization().policies().user().findById(policyId).remove();
|
||||
UserPolicyRepresentation userPolicy = r.clients().get(client.getId()).authorization().policies().user().findByName(name);
|
||||
if (userPolicy != null) {
|
||||
r.clients().get(client.getId()).authorization().policies().user().findById(userPolicy.getId()).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
protected static ClientPolicyRepresentation createClientPolicy(ManagedRealm realm, ManagedClient client, String name, String clientId) {
|
||||
protected static ClientPolicyRepresentation createClientPolicy(ManagedRealm realm, ManagedClient client, String name, String... clientIds) {
|
||||
ClientPolicyRepresentation policy = new ClientPolicyRepresentation();
|
||||
policy.setName(name);
|
||||
policy.addClient(clientId);
|
||||
for (String clientId : clientIds) {
|
||||
policy.addClient(clientId);
|
||||
}
|
||||
policy.setLogic(Logic.POSITIVE);
|
||||
try (Response response = client.admin().authorization().policies().client().create(policy)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
realm.cleanup().add(r -> {
|
||||
String policyId = r.clients().get(client.getId()).authorization().policies().client().findByName(name).getId();
|
||||
r.clients().get(client.getId()).authorization().policies().client().findById(policyId).remove();
|
||||
ClientPolicyRepresentation clientPolicy = r.clients().get(client.getId()).authorization().policies().client().findByName(name);
|
||||
if (clientPolicy != null) {
|
||||
r.clients().get(client.getId()).authorization().policies().client().findById(clientPolicy.getId()).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
return policy;
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
package org.keycloak.tests.admin.authz.fgap;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.ScopePermissionsResource;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectClient;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
|
||||
@KeycloakIntegrationTest(config = KeycloakAdminPermissionsServerConfig.class)
|
||||
public class ClientResourceTypePermissionTest extends AbstractPermissionTest {
|
||||
|
||||
@InjectClient(ref = "testClient")
|
||||
ManagedClient testClient;
|
||||
|
||||
@InjectClient(ref = "testClient2", lifecycle = LifeCycle.METHOD)
|
||||
ManagedClient testClient2;
|
||||
|
||||
@BeforeEach
|
||||
public void onBefore() {
|
||||
UserPolicyRepresentation policy = new UserPolicyRepresentation();
|
||||
policy.setName("User Policy");
|
||||
client.admin().authorization().policies().user().create(policy).close();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void onAfter() {
|
||||
ScopePermissionsResource permissions = getScopePermissionsResource(client);
|
||||
|
||||
for (ScopePermissionRepresentation permission : permissions.findAll(null, null, null, -1, -1)) {
|
||||
permissions.findById(permission.getId()).remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveClient() {
|
||||
//create client policies
|
||||
createClientPolicy(realm, client, "Only testClient or testClient2 Client Policy", testClient.getId(), testClient2.getId());
|
||||
createClientPolicy(realm, client, "Only testClient2 Client Policy", testClient2.getId());
|
||||
|
||||
//create client permissions
|
||||
createClientPermission(testClient, testClient2);
|
||||
createClientPermission(testClient2);
|
||||
|
||||
List<PolicyRepresentation> policies = getPolicies().policies(null, "Only", "client", null, null, null, null, null, null, null);
|
||||
assertThat(policies, hasSize(2));
|
||||
assertThat(policies.get(0).getConfig().get("clients"), containsString(testClient2.getId()));
|
||||
assertThat(policies.get(1).getConfig().get("clients"), containsString(testClient2.getId()));
|
||||
|
||||
List<ScopePermissionRepresentation> permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(2));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(testClient2.getId()));
|
||||
assertThat(getPolicies().policy(permissions.get(1).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(testClient2.getId()));
|
||||
|
||||
//remove client
|
||||
realm.admin().clients().get(testClient2.getId()).remove();
|
||||
|
||||
//check the resource was removed from policies
|
||||
ClientPolicyRepresentation clientPolicy = getPolicies().client().findByName("Only testClient or testClient2 Client Policy");
|
||||
assertThat(clientPolicy, notNullValue());
|
||||
assertThat(clientPolicy.getClients(), not(contains(testClient2.getId())));
|
||||
|
||||
ClientPolicyRepresentation clientPolicy1 = getPolicies().client().findByName("Only testClient2 Client Policy");
|
||||
assertThat(clientPolicy1, notNullValue());
|
||||
assertThat(clientPolicy1.getClients(), empty());
|
||||
|
||||
//there should be 1 permission left
|
||||
permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(1));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), not(hasItem(testClient2.getId())));
|
||||
}
|
||||
|
||||
private ScopePermissionRepresentation createClientPermission(ManagedClient... clients) {
|
||||
ScopePermissionRepresentation permission = PermissionBuilder.create()
|
||||
.resourceType(AdminPermissionsSchema.CLIENTS.getType())
|
||||
.resources(Arrays.stream(clients).map(ManagedClient::getClientId).collect(Collectors.toSet()))
|
||||
.scopes(AdminPermissionsSchema.CLIENTS.getScopes())
|
||||
.addPolicies(List.of("User Policy"))
|
||||
.build();
|
||||
|
||||
createPermission(client, permission);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
}
|
||||
@ -65,7 +65,7 @@ public class GroupResourceTypeEvaluationTest extends AbstractPermissionTest {
|
||||
Keycloak realmAdminClient;
|
||||
|
||||
private final String groupName = "top_group";
|
||||
private final GroupRepresentation topGroup = new GroupRepresentation();;
|
||||
private final GroupRepresentation topGroup = new GroupRepresentation();
|
||||
|
||||
@BeforeEach // cannot use @BeforeAll, realm is not initializaed yet
|
||||
public void onBefore() {
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
package org.keycloak.tests.admin.authz.fgap;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.ScopePermissionsResource;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.GroupPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.GroupPolicyRepresentation.GroupDefinition;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.util.ApiUtil;
|
||||
|
||||
@KeycloakIntegrationTest(config = KeycloakAdminPermissionsServerConfig.class)
|
||||
public class GroupResourceTypePermissionTest extends AbstractPermissionTest {
|
||||
|
||||
@BeforeEach
|
||||
public void onBefore() {
|
||||
UserPolicyRepresentation policy = new UserPolicyRepresentation();
|
||||
policy.setName("User Policy");
|
||||
client.admin().authorization().policies().user().create(policy).close();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void onAfter() {
|
||||
ScopePermissionsResource permissions = getScopePermissionsResource(client);
|
||||
|
||||
for (ScopePermissionRepresentation permission : permissions.findAll(null, null, null, -1, -1)) {
|
||||
permissions.findById(permission.getId()).remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveGroup() {
|
||||
//create groups
|
||||
GroupRepresentation topGroup = new GroupRepresentation();
|
||||
topGroup.setName("topGroup");
|
||||
try (Response response = realm.admin().groups().add(topGroup)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
topGroup.setId(ApiUtil.handleCreatedResponse(response));
|
||||
realm.cleanup().add(r -> r.groups().group(topGroup.getId()).remove());
|
||||
}
|
||||
GroupRepresentation topGroup1 = new GroupRepresentation();
|
||||
topGroup1.setName("topGroup1");
|
||||
try (Response response = realm.admin().groups().add(topGroup1)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
topGroup1.setId(ApiUtil.handleCreatedResponse(response));
|
||||
}
|
||||
|
||||
//create group policies
|
||||
createGroupPolicy("Only topGroup or topGroup1 Group Policy", topGroup.getId(), topGroup1.getId());
|
||||
createGroupPolicy("Only topGroup1 Group Policy", topGroup1.getId());
|
||||
|
||||
//create group permissions
|
||||
createGroupPermission(topGroup, topGroup1);
|
||||
createGroupPermission(topGroup1);
|
||||
|
||||
List<PolicyRepresentation> policies = getPolicies().policies(null, "Only", "group", null, null, null, null, null, null, null);
|
||||
assertThat(policies, hasSize(2));
|
||||
assertThat(policies.get(0).getConfig().get("groups"), containsString(topGroup1.getId()));
|
||||
assertThat(policies.get(1).getConfig().get("groups"), containsString(topGroup1.getId()));
|
||||
|
||||
List<ScopePermissionRepresentation> permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(2));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(topGroup1.getId()));
|
||||
assertThat(getPolicies().policy(permissions.get(1).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(topGroup1.getId()));
|
||||
|
||||
//remove group
|
||||
realm.admin().groups().group(topGroup1.getId()).remove();
|
||||
|
||||
//check the resource was removed from policies
|
||||
GroupPolicyRepresentation groupPolicy = getPolicies().group().findByName("Only topGroup or topGroup1 Group Policy");
|
||||
assertThat(groupPolicy, notNullValue());
|
||||
Set<String> groupIds = groupPolicy.getGroups().stream().map(GroupDefinition::getId).collect(Collectors.toSet());
|
||||
assertThat(groupIds, not(contains(topGroup1.getId())));
|
||||
|
||||
GroupPolicyRepresentation groupPolicy1 = getPolicies().group().findByName("Only topGroup1 Group Policy");
|
||||
assertThat(groupPolicy1, notNullValue());
|
||||
assertThat(groupPolicy1.getGroups().stream().map(GroupDefinition::getId).collect(Collectors.toSet()), empty());
|
||||
|
||||
//there should be 1 permission left
|
||||
permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(1));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), not(hasItem(topGroup1.getId())));
|
||||
}
|
||||
|
||||
private ScopePermissionRepresentation createGroupPermission(GroupRepresentation... groups) {
|
||||
ScopePermissionRepresentation permission = PermissionBuilder.create()
|
||||
.resourceType(AdminPermissionsSchema.GROUPS.getType())
|
||||
.resources(Arrays.stream(groups).map(GroupRepresentation::getId).collect(Collectors.toSet()))
|
||||
.scopes(AdminPermissionsSchema.GROUPS.getScopes())
|
||||
.addPolicies(List.of("User Policy"))
|
||||
.build();
|
||||
|
||||
createPermission(client, permission);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
private GroupPolicyRepresentation createGroupPolicy(String name, String... groupIds) {
|
||||
GroupPolicyRepresentation policy = new GroupPolicyRepresentation();
|
||||
policy.setName(name);
|
||||
policy.addGroup(groupIds);
|
||||
policy.setLogic(Logic.POSITIVE);
|
||||
try (Response response = client.admin().authorization().policies().group().create(policy)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
realm.cleanup().add(r -> {
|
||||
GroupPolicyRepresentation groupPolicy = client.admin().authorization().policies().group().findByName(name);
|
||||
if (groupPolicy != null) {
|
||||
client.admin().authorization().policies().group().findById(groupPolicy.getId()).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
package org.keycloak.tests.admin.authz.fgap;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.ScopePermissionsResource;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation.RoleDefinition;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectClient;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
|
||||
@KeycloakIntegrationTest(config = KeycloakAdminPermissionsServerConfig.class)
|
||||
public class RoleResourceTypePermissionTest extends AbstractPermissionTest {
|
||||
|
||||
@InjectClient(ref = "testClient")
|
||||
ManagedClient testClient;
|
||||
|
||||
@BeforeEach
|
||||
public void onBefore() {
|
||||
UserPolicyRepresentation policy = new UserPolicyRepresentation();
|
||||
policy.setName("User Policy");
|
||||
client.admin().authorization().policies().user().create(policy).close();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void onAfter() {
|
||||
ScopePermissionsResource permissions = getScopePermissionsResource(client);
|
||||
|
||||
for (ScopePermissionRepresentation permission : permissions.findAll(null, null, null, -1, -1)) {
|
||||
permissions.findById(permission.getId()).remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveRole() {
|
||||
//create roles
|
||||
RoleRepresentation realmRole = new RoleRepresentation();
|
||||
realmRole.setName("realmRole");
|
||||
try {
|
||||
realm.admin().roles().create(realmRole);
|
||||
realmRole.setId(realm.admin().roles().get(realmRole.getName()).toRepresentation().getId());
|
||||
} finally {
|
||||
realm.cleanup().add(r -> r.roles().deleteRole(realmRole.getName()));
|
||||
}
|
||||
|
||||
RoleRepresentation clientRole = new RoleRepresentation();
|
||||
clientRole.setName("clientRole");
|
||||
clientRole.setClientRole(Boolean.TRUE);
|
||||
clientRole.setContainerId(testClient.getId());
|
||||
realm.admin().roles().create(clientRole);
|
||||
clientRole.setId(realm.admin().roles().get(clientRole.getName()).toRepresentation().getId());
|
||||
|
||||
//create role policies
|
||||
createRolePolicy("Only realmRole or clientRole Role Policy", realmRole.getId(), clientRole.getId());
|
||||
createRolePolicy("Only clientRole Role Policy", clientRole.getId());
|
||||
|
||||
//create role permissions
|
||||
createRolePermission(realmRole, clientRole);
|
||||
createRolePermission(clientRole);
|
||||
|
||||
List<PolicyRepresentation> policies = getPolicies().policies(null, "Only", "role", null, null, null, null, null, null, null);
|
||||
assertThat(policies, hasSize(2));
|
||||
assertThat(policies.get(0).getConfig().get("roles"), containsString(clientRole.getId()));
|
||||
assertThat(policies.get(1).getConfig().get("roles"), containsString(clientRole.getId()));
|
||||
|
||||
List<ScopePermissionRepresentation> permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(2));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(clientRole.getId()));
|
||||
assertThat(getPolicies().policy(permissions.get(1).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(clientRole.getId()));
|
||||
|
||||
//remove role
|
||||
realm.admin().roles().get(clientRole.getName()).remove();
|
||||
|
||||
//check the resource was removed from policies
|
||||
RolePolicyRepresentation rolePolicy = getPolicies().role().findByName("Only realmRole or clientRole Role Policy");
|
||||
assertThat(rolePolicy, notNullValue());
|
||||
Set<String> roleIds = rolePolicy.getRoles().stream().map(RoleDefinition::getId).collect(Collectors.toSet());
|
||||
assertThat(roleIds, not(contains(clientRole.getId())));
|
||||
|
||||
RolePolicyRepresentation rolePolicy1 = getPolicies().role().findByName("Only clientRole Role Policy");
|
||||
assertThat(rolePolicy1, notNullValue());
|
||||
assertThat(rolePolicy1.getRoles().stream().map(RoleDefinition::getId).collect(Collectors.toSet()), empty());
|
||||
|
||||
//there should be 1 permission left
|
||||
permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(1));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), not(hasItem(clientRole.getId())));
|
||||
}
|
||||
|
||||
private ScopePermissionRepresentation createRolePermission(RoleRepresentation... roles) {
|
||||
ScopePermissionRepresentation permission = PermissionBuilder.create()
|
||||
.resourceType(AdminPermissionsSchema.ROLES.getType())
|
||||
.resources(Arrays.stream(roles).map(RoleRepresentation::getId).collect(Collectors.toSet()))
|
||||
.scopes(AdminPermissionsSchema.ROLES.getScopes())
|
||||
.addPolicies(List.of("User Policy"))
|
||||
.build();
|
||||
|
||||
createPermission(client, permission);
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
private RolePolicyRepresentation createRolePolicy(String name, String... roleIds) {
|
||||
RolePolicyRepresentation policy = new RolePolicyRepresentation();
|
||||
policy.setName(name);
|
||||
for (String roleId : roleIds) {
|
||||
policy.addRole(roleId);
|
||||
}
|
||||
policy.setLogic(Logic.POSITIVE);
|
||||
try (Response response = client.admin().authorization().policies().role().create(policy)) {
|
||||
assertThat(response.getStatus(), equalTo(Response.Status.CREATED.getStatusCode()));
|
||||
realm.cleanup().add(r -> {
|
||||
RolePolicyRepresentation rolePolicy = client.admin().authorization().policies().role().findByName(name);
|
||||
if (rolePolicy != null) {
|
||||
client.admin().authorization().policies().role().findById(rolePolicy.getId()).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,7 @@ public class UserResourceTypeEvaluationTest extends AbstractPermissionTest {
|
||||
UserPolicyRepresentation allowMyAdminPermission = createUserPolicy(realm, client,"Only My Admin User Policy", myadmin.getId());
|
||||
createAllPermission(client, usersType, allowMyAdminPermission, Set.of(VIEW));
|
||||
|
||||
UserPolicyRepresentation denyMyAdminAccessingHisAccountPermission = createUserPolicy(realm, client,"Not My Admin User Policy", myadmin.getId(), Logic.NEGATIVE);
|
||||
UserPolicyRepresentation denyMyAdminAccessingHisAccountPermission = createUserPolicy(Logic.NEGATIVE, realm, client,"Not My Admin User Policy", myadmin.getId());
|
||||
createPermission(client, myadmin.getId(), usersType, Set.of(VIEW), denyMyAdminAccessingHisAccountPermission);
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertEquals(1, search.size());
|
||||
@ -235,7 +235,7 @@ public class UserResourceTypeEvaluationTest extends AbstractPermissionTest {
|
||||
@Test
|
||||
public void testViewUserPermissionDenyByDefault() {
|
||||
String myadminId = realm.admin().users().search("myadmin").get(0).getId();
|
||||
UserPolicyRepresentation disallowMyAdmin = createUserPolicy(realm, client,"Not My Admin User Policy", myadminId, Logic.NEGATIVE);
|
||||
UserPolicyRepresentation disallowMyAdmin = createUserPolicy(Logic.NEGATIVE, realm, client,"Not My Admin User Policy", myadminId);
|
||||
createAllPermission(client, usersType, disallowMyAdmin, Set.of(VIEW));
|
||||
|
||||
UserPolicyRepresentation allowAliceOnlyForMyAdmin = createUserPolicy(realm, client,"My Admin User Policy", myadminId);
|
||||
|
||||
@ -18,10 +18,15 @@
|
||||
package org.keycloak.tests.admin.authz.fgap;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@ -39,17 +44,19 @@ import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ScopePermissionResource;
|
||||
import org.keycloak.admin.client.resource.ScopePermissionsResource;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
|
||||
@KeycloakIntegrationTest(config = KeycloakAdminPermissionsServerConfig.class)
|
||||
public class UserResourceTypePermissionTest extends AbstractPermissionTest {
|
||||
|
||||
@InjectUser(ref = "alice")
|
||||
@InjectUser(ref = "alice", lifecycle = LifeCycle.METHOD)
|
||||
ManagedUser userAlice;
|
||||
|
||||
@InjectUser(ref = "bob")
|
||||
@ -227,6 +234,44 @@ public class UserResourceTypePermissionTest extends AbstractPermissionTest {
|
||||
assertThat(permissionResources.get(0).getName(), is(AdminPermissionsSchema.USERS.getType()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUser() {
|
||||
//create user policies
|
||||
createUserPolicy(realm, client, "Only Alice or Bob User Policy", userAlice.getId(), userBob.getId());
|
||||
createUserPolicy(realm, client, "Only Alice User Policy", userAlice.getId());
|
||||
|
||||
//create user permissions
|
||||
createUserPermission(userAlice, userBob);
|
||||
createUserPermission(userAlice);
|
||||
|
||||
List<PolicyRepresentation> policies = getPolicies().policies(null, "Only", "user", null, null, null, null, null, null, null);
|
||||
assertThat(policies, hasSize(2));
|
||||
assertThat(policies.get(0).getConfig().get("users"), containsString(userAlice.getId()));
|
||||
assertThat(policies.get(1).getConfig().get("users"), containsString(userAlice.getId()));
|
||||
|
||||
List<ScopePermissionRepresentation> permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(2));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(userAlice.getId()));
|
||||
assertThat(getPolicies().policy(permissions.get(1).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), hasItem(userAlice.getId()));
|
||||
|
||||
//remove user
|
||||
realm.admin().users().get(userAlice.getId()).remove();
|
||||
|
||||
//check the resource was removed from policies
|
||||
UserPolicyRepresentation userPolicy = getPolicies().user().findByName("Only Alice or Bob User Policy");
|
||||
assertThat(userPolicy, notNullValue());
|
||||
assertThat(userPolicy.getUsers(), not(contains(userAlice.getId())));
|
||||
|
||||
UserPolicyRepresentation userPolicy1 = getPolicies().user().findByName("Only Alice User Policy");
|
||||
assertThat(userPolicy1, notNullValue());
|
||||
assertThat(userPolicy1.getUsers(), empty());
|
||||
|
||||
//there should be 1 permission left
|
||||
permissions = getScopePermissionsResource(client).findAll(null, null, null, null, null);
|
||||
assertThat(permissions, hasSize(1));
|
||||
assertThat(getPolicies().policy(permissions.get(0).getId()).resources().stream().map(ResourceRepresentation::getName).collect(Collectors.toList()), not(hasItem(userAlice.getId())));
|
||||
}
|
||||
|
||||
private ScopePermissionRepresentation createUserPermission(ManagedUser... users) {
|
||||
ScopePermissionRepresentation permission = PermissionBuilder.create()
|
||||
.resourceType(AdminPermissionsSchema.USERS.getType())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user