diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java index 6179cc7288..78a08bd42a 100644 --- a/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java +++ b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java @@ -21,9 +21,11 @@ package org.keycloak.authorization.store; import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer; import org.keycloak.authorization.store.syncronization.RealmSynchronizer; import org.keycloak.authorization.store.syncronization.Synchronizer; +import org.keycloak.authorization.store.syncronization.UserSynchronizer; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel.ClientRemovedEvent; import org.keycloak.models.RealmModel.RealmRemovedEvent; +import org.keycloak.models.UserModel.UserRemovedEvent; import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.ProviderFactory; @@ -45,6 +47,7 @@ public interface AuthorizationStoreFactory extends ProviderFactory synchronizers.put(ClientRemovedEvent.class, new ClientApplicationSynchronizer()); synchronizers.put(RealmRemovedEvent.class, new RealmSynchronizer()); + synchronizers.put(UserRemovedEvent.class, new UserSynchronizer()); factory.register(event -> { try { diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java new file mode 100644 index 0000000000..01830ff07a --- /dev/null +++ b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.authorization.store.syncronization; + +import org.keycloak.authorization.AuthorizationProvider; +import org.keycloak.authorization.store.PolicyStore; +import org.keycloak.authorization.store.ResourceStore; +import org.keycloak.authorization.store.StoreFactory; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserModel.UserRemovedEvent; +import org.keycloak.provider.ProviderFactory; + +/** + * @author Pedro Igor + */ +public class UserSynchronizer implements Synchronizer { + + @Override + public void synchronize(UserRemovedEvent event, KeycloakSessionFactory factory) { + ProviderFactory providerFactory = factory.getProviderFactory(AuthorizationProvider.class); + AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession()); + StoreFactory storeFactory = authorizationProvider.getStoreFactory(); + UserModel userModel = event.getUser(); + ResourceStore resourceStore = storeFactory.getResourceStore(); + PolicyStore policyStore = storeFactory.getPolicyStore(); + + resourceStore.findByOwner(userModel.getId()).forEach(resource -> { + String resourceId = resource.getId(); + policyStore.findByResource(resourceId).forEach(policy -> { + if (policy.getResources().size() == 1) { + policyStore.delete(policy.getId()); + } else { + policy.removeResource(resource); + } + }); + resourceStore.delete(resourceId); + }); + } +} diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java index 8db12f8a97..49eab24a91 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java @@ -86,17 +86,25 @@ public class ResourceSetService { return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists."); } - String ownerId = owner.getId(); + if (owner != null) { + String ownerId = owner.getId(); - if (ownerId != null) { - if (!resourceServer.getClientId().equals(ownerId)) { - RealmModel realm = authorization.getRealm(); - KeycloakSession keycloakSession = authorization.getKeycloakSession(); - UserFederationManager users = keycloakSession.users(); - UserModel ownerModel = users.getUserByUsername(ownerId, realm); + if (ownerId != null) { + if (!resourceServer.getClientId().equals(ownerId)) { + RealmModel realm = authorization.getRealm(); + KeycloakSession keycloakSession = authorization.getKeycloakSession(); + UserFederationManager users = keycloakSession.users(); + UserModel ownerModel = users.getUserById(ownerId, realm); - if (ownerModel == null) { - return ErrorResponse.error("Owner must be a valid username or, if the resource server, the client id.", Status.BAD_REQUEST); + if (ownerModel == null) { + ownerModel = users.getUserByUsername(ownerId, realm); + } + + if (ownerModel == null) { + return ErrorResponse.error("Owner must be a valid username or user identifier. If the resource server, the client id or null.", Status.BAD_REQUEST); + } + + owner.setId(ownerModel.getId()); } } } @@ -148,7 +156,7 @@ public class ResourceSetService { if (policyModel.getResources().size() == 1) { policyStore.delete(policyModel.getId()); } else { - policyModel.addResource(resource); + policyModel.removeResource(resource); } }