[KEYCLOAK-8281] - Deletion of client with token exchange policy leads to breaking errors
This commit is contained in:
1 parent
0b893d5634
commit
609c521c17
5 files changed
+186
-10
No files matched your search
@@ -137,7 +137,9 @@ public class JPAPolicyStore implements PolicyStore {
|
||||
List<Predicate> predicates = new ArrayList();
|
||||
querybuilder.select(root.get("id"));
|
||||
|
||||
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
|
||||
if (resourceServerId != null) {
|
||||
predicates.add(builder.equal(root.get("resourceServer").get("id"), resourceServerId));
|
||||
}
|
||||
|
||||
attributes.forEach((name, value) -> {
|
||||
if ("permission".equals(name)) {
|
||||
@@ -156,6 +158,9 @@ public class JPAPolicyStore implements PolicyStore {
|
||||
predicates.add(root.join("resources").get("id").in(value));
|
||||
} else if ("scope".equals(name)) {
|
||||
predicates.add(root.join("scopes").get("id").in(value));
|
||||
} else if (name.startsWith("config:")) {
|
||||
predicates.add(root.joinMap("config").key().in(name.substring("config:".length())));
|
||||
predicates.add(builder.like(root.joinMap("config").value().as(String.class), "%" + value[0] + "%"));
|
||||
} else {
|
||||
predicates.add(builder.like(builder.lower(root.get(name)), "%" + value[0].toLowerCase() + "%"));
|
||||
}
|
||||
|
||||
+36
-5
@@ -18,13 +18,21 @@
|
||||
|
||||
package org.keycloak.authorization.store.syncronization;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel.ClientRemovedEvent;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
@@ -35,16 +43,39 @@ public class ClientApplicationSynchronizer implements Synchronizer<ClientRemoved
|
||||
public void synchronize(ClientRemovedEvent event, KeycloakSessionFactory factory) {
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
removeFromClientPolicies(event, authorizationProvider);
|
||||
}
|
||||
|
||||
private void removeFromClientPolicies(ClientRemovedEvent event, AuthorizationProvider authorizationProvider) {
|
||||
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
|
||||
ResourceServerStore store = storeFactory.getResourceServerStore();
|
||||
ResourceServer resourceServer = store.findById(event.getClient().getId());
|
||||
|
||||
if (resourceServer != null) {
|
||||
String id = resourceServer.getId();
|
||||
//storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
|
||||
//storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
|
||||
//storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
|
||||
storeFactory.getResourceServerStore().delete(id);
|
||||
storeFactory.getResourceServerStore().delete(resourceServer.getId());
|
||||
}
|
||||
|
||||
Map<String, String[]> attributes = new HashMap<>();
|
||||
|
||||
attributes.put("type", new String[] {"client"});
|
||||
attributes.put("config:clients", new String[] {event.getClient().getId()});
|
||||
|
||||
List<Policy> search = storeFactory.getPolicyStore().findByResourceServer(attributes, null, -1, -1);
|
||||
|
||||
for (Policy policy : search) {
|
||||
PolicyProviderFactory policyFactory = authorizationProvider.getProviderFactory(policy.getType());
|
||||
ClientPolicyRepresentation representation = ClientPolicyRepresentation.class.cast(policyFactory.toRepresentation(policy, authorizationProvider));
|
||||
Set<String> clients = representation.getClients();
|
||||
|
||||
clients.remove(event.getClient().getId());
|
||||
|
||||
if (clients.isEmpty()) {
|
||||
policyFactory.onRemove(policy, authorizationProvider);
|
||||
authorizationProvider.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||
} else {
|
||||
policyFactory.onUpdate(policy, representation, authorizationProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-2
@@ -17,8 +17,15 @@
|
||||
|
||||
package org.keycloak.authorization.store.syncronization;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
@@ -28,6 +35,7 @@ import org.keycloak.models.RealmModel;
|
||||
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>
|
||||
@@ -38,12 +46,45 @@ public class UserSynchronizer implements Synchronizer<UserRemovedEvent> {
|
||||
public void synchronize(UserRemovedEvent event, KeycloakSessionFactory factory) {
|
||||
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
|
||||
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
|
||||
|
||||
removeUserResources(event, authorizationProvider);
|
||||
removeFromUserPolicies(event, authorizationProvider);
|
||||
}
|
||||
|
||||
private void removeFromUserPolicies(UserRemovedEvent event, AuthorizationProvider authorizationProvider) {
|
||||
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
|
||||
UserModel userModel = event.getUser();
|
||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
UserModel userModel = event.getUser();
|
||||
Map<String, String[]> attributes = new HashMap<>();
|
||||
|
||||
attributes.put("type", new String[] {"user"});
|
||||
attributes.put("config:users", new String[] {userModel.getId()});
|
||||
|
||||
List<Policy> search = policyStore.findByResourceServer(attributes, null, -1, -1);
|
||||
|
||||
for (Policy policy : search) {
|
||||
PolicyProviderFactory policyFactory = authorizationProvider.getProviderFactory(policy.getType());
|
||||
UserPolicyRepresentation representation = UserPolicyRepresentation.class.cast(policyFactory.toRepresentation(policy, authorizationProvider));
|
||||
Set<String> users = representation.getUsers();
|
||||
|
||||
users.remove(userModel.getId());
|
||||
|
||||
if (users.isEmpty()) {
|
||||
policyFactory.onRemove(policy, authorizationProvider);
|
||||
policyStore.delete(policy.getId());
|
||||
} else {
|
||||
policyFactory.onUpdate(policy, representation, authorizationProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeUserResources(UserRemovedEvent event, AuthorizationProvider authorizationProvider) {
|
||||
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||
ResourceServerStore resourceServerStore = storeFactory.getResourceServerStore();
|
||||
RealmModel realm = event.getRealm();
|
||||
UserModel userModel = event.getUser();
|
||||
|
||||
realm.getClients().forEach(clientModel -> {
|
||||
ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId());
|
||||
|
||||
+51
-1
@@ -27,10 +27,12 @@ import java.util.stream.Collectors;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ClientPoliciesResource;
|
||||
import org.keycloak.admin.client.resource.ClientPolicyResource;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import org.keycloak.admin.client.resource.PolicyResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||
@@ -50,7 +52,10 @@ public class ClientPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||
return super.createTestRealm()
|
||||
.client(ClientBuilder.create().clientId("Client A"))
|
||||
.client(ClientBuilder.create().clientId("Client B"))
|
||||
.client(ClientBuilder.create().clientId("Client C"));
|
||||
.client(ClientBuilder.create().clientId("Client C"))
|
||||
.client(ClientBuilder.create().clientId("Client D"))
|
||||
.client(ClientBuilder.create().clientId("Client E"))
|
||||
.client(ClientBuilder.create().clientId("Client F"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -126,6 +131,51 @@ public class ClientPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteClient() {
|
||||
AuthorizationResource authorization = getClient().authorization();
|
||||
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||
|
||||
representation.setName("Update Test Client Policy");
|
||||
representation.setDescription("description");
|
||||
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
|
||||
representation.setLogic(Logic.NEGATIVE);
|
||||
representation.addClient("Client D");
|
||||
representation.addClient("Client E");
|
||||
representation.addClient("Client F");
|
||||
|
||||
assertCreated(authorization, representation);
|
||||
|
||||
ClientsResource clients = getRealm().clients();
|
||||
ClientRepresentation client = clients.findByClientId("Client D").get(0);
|
||||
|
||||
clients.get(client.getId()).remove();
|
||||
|
||||
representation = authorization.policies().client().findById(representation.getId()).toRepresentation();
|
||||
|
||||
Assert.assertEquals(2, representation.getClients().size());
|
||||
Assert.assertFalse(representation.getClients().contains(client.getId()));
|
||||
|
||||
client = clients.findByClientId("Client E").get(0);
|
||||
clients.get(client.getId()).remove();
|
||||
|
||||
representation = authorization.policies().client().findById(representation.getId()).toRepresentation();
|
||||
|
||||
Assert.assertEquals(1, representation.getClients().size());
|
||||
Assert.assertFalse(representation.getClients().contains(client.getId()));
|
||||
|
||||
client = clients.findByClientId("Client F").get(0);
|
||||
clients.get(client.getId()).remove();
|
||||
|
||||
try {
|
||||
authorization.policies().client().findById(representation.getId()).toRepresentation();
|
||||
fail("Client policy should be removed");
|
||||
} catch (NotFoundException nfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericConfig() {
|
||||
AuthorizationResource authorization = getClient().authorization();
|
||||
|
||||
+50
-1
@@ -29,11 +29,13 @@ import java.util.stream.Collectors;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.PolicyResource;
|
||||
import org.keycloak.admin.client.resource.UserPoliciesResource;
|
||||
import org.keycloak.admin.client.resource.UserPolicyResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
@@ -52,7 +54,10 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||
return super.createTestRealm()
|
||||
.user(UserBuilder.create().username("User A"))
|
||||
.user(UserBuilder.create().username("User B"))
|
||||
.user(UserBuilder.create().username("User C"));
|
||||
.user(UserBuilder.create().username("User C"))
|
||||
.user(UserBuilder.create().username("User D"))
|
||||
.user(UserBuilder.create().username("User E"))
|
||||
.user(UserBuilder.create().username("User F"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,6 +132,50 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteUser() {
|
||||
AuthorizationResource authorization = getClient().authorization();
|
||||
UserPolicyRepresentation representation = new UserPolicyRepresentation();
|
||||
|
||||
representation.setName("Realm User Policy");
|
||||
representation.setDescription("description");
|
||||
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
|
||||
representation.setLogic(Logic.NEGATIVE);
|
||||
representation.addUser("User D");
|
||||
representation.addUser("User E");
|
||||
representation.addUser("User F");
|
||||
|
||||
assertCreated(authorization, representation);
|
||||
|
||||
UsersResource users = getRealm().users();
|
||||
UserRepresentation user = users.search("User D").get(0);
|
||||
|
||||
users.get(user.getId()).remove();
|
||||
|
||||
representation = authorization.policies().user().findById(representation.getId()).toRepresentation();
|
||||
|
||||
Assert.assertEquals(2, representation.getUsers().size());
|
||||
Assert.assertFalse(representation.getUsers().contains(user.getId()));
|
||||
|
||||
user = users.search("User E").get(0);
|
||||
users.get(user.getId()).remove();
|
||||
|
||||
representation = authorization.policies().user().findById(representation.getId()).toRepresentation();
|
||||
|
||||
Assert.assertEquals(1, representation.getUsers().size());
|
||||
Assert.assertFalse(representation.getUsers().contains(user.getId()));
|
||||
|
||||
user = users.search("User F").get(0);
|
||||
users.get(user.getId()).remove();
|
||||
|
||||
try {
|
||||
authorization.policies().user().findById(representation.getId()).toRepresentation();
|
||||
fail("User policy should be removed");
|
||||
} catch (NotFoundException nfe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericConfig() {
|
||||
AuthorizationResource authorization = getClient().authorization();
|
||||
|
||||
Reference in new issue
Block a user