Author: fmartelli Date: Wed Dec 4 11:29:09 2013 New Revision: 1547766 URL: http://svn.apache.org/r1547766 Log: Fixes SYNCOPE-455 on 1.1.X
Modified: syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java syncope/branches/1_1_X/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java Modified: syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java URL: http://svn.apache.org/viewvc/syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java?rev=1547766&r1=1547765&r2=1547766&view=diff ============================================================================== --- syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java (original) +++ syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java Wed Dec 4 11:29:09 2013 @@ -416,7 +416,7 @@ public class PropagationManager { } /** - * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for + * Perform delete on each resource associated to the role. It is possible to ask for a mandatory provisioning for * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if * the creation fails onto a mandatory resource. * Modified: syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java URL: http://svn.apache.org/viewvc/syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java?rev=1547766&r1=1547765&r2=1547766&view=diff ============================================================================== --- syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java (original) +++ syncope/branches/1_1_X/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java Wed Dec 4 11:29:09 2013 @@ -173,7 +173,7 @@ public class RoleController extends Abst @PreAuthorize("hasRole('ROLE_READ')") @RequestMapping(method = RequestMethod.POST, value = "/search") - @Transactional(readOnly = true, rollbackFor = { Throwable.class }) + @Transactional(readOnly = true, rollbackFor = {Throwable.class}) public List<RoleTO> search(@RequestBody final NodeCond searchCondition) throws InvalidSearchConditionException { @@ -182,7 +182,7 @@ public class RoleController extends Abst @PreAuthorize("hasRole('ROLE_READ')") @RequestMapping(method = RequestMethod.POST, value = "/search/{page}/{size}") - @Transactional(readOnly = true, rollbackFor = { Throwable.class }) + @Transactional(readOnly = true, rollbackFor = {Throwable.class}) public List<RoleTO> search(@RequestBody final NodeCond searchCondition, @PathVariable("page") final int page, @PathVariable("size") final int size) throws InvalidSearchConditionException { @@ -206,7 +206,7 @@ public class RoleController extends Abst @PreAuthorize("hasRole('ROLE_READ')") @RequestMapping(method = RequestMethod.POST, value = "/search/count") - @Transactional(readOnly = true, rollbackFor = { Throwable.class }) + @Transactional(readOnly = true, rollbackFor = {Throwable.class}) public ModelAndView searchCount(@RequestBody final NodeCond searchCondition) throws InvalidSearchConditionException { @@ -303,15 +303,31 @@ public class RoleController extends Abst @PreAuthorize("hasRole('ROLE_DELETE')") @RequestMapping(method = RequestMethod.GET, value = "/delete/{roleId}") public RoleTO delete(@PathVariable("roleId") final Long roleId) { - // Generate propagation tasks for deleting users from role resources, if they are on those resources only - // because of the reason being deleted (see SYNCOPE-357) - List<PropagationTask> tasks = new ArrayList<PropagationTask>(); - for (WorkflowResult<Long> wfResult : binder.getUsersOnResourcesOnlyBecauseOfRole(roleId)) { - tasks.addAll(propagationManager.getUserDeleteTaskIds(wfResult)); + final List<SyncopeRole> toBeDeprovisioned = new ArrayList<SyncopeRole>(); + + final SyncopeRole syncopeRole = roleDAO.find(roleId); + + if (syncopeRole != null) { + toBeDeprovisioned.add(syncopeRole); + + final List<SyncopeRole> descendants = roleDAO.findDescendants(toBeDeprovisioned.get(0)); + if (descendants != null) { + toBeDeprovisioned.addAll(descendants); + } } - // Generate propagation tasks for deleting this role from resources - tasks.addAll(propagationManager.getRoleDeleteTaskIds(roleId)); + final List<PropagationTask> tasks = new ArrayList<PropagationTask>(); + + for (SyncopeRole role : toBeDeprovisioned) { + // Generate propagation tasks for deleting users from role resources, if they are on those resources only + // because of the reason being deleted (see SYNCOPE-357) + for (WorkflowResult<Long> wfResult : binder.getUsersOnResourcesOnlyBecauseOfRole(role.getId())) { + tasks.addAll(propagationManager.getUserDeleteTaskIds(wfResult)); + } + + // Generate propagation tasks for deleting this role from resources + tasks.addAll(propagationManager.getRoleDeleteTaskIds(role.getId())); + } RoleTO roleTO = new RoleTO(); roleTO.setId(roleId); Modified: syncope/branches/1_1_X/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java URL: http://svn.apache.org/viewvc/syncope/branches/1_1_X/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java?rev=1547766&r1=1547765&r2=1547766&view=diff ============================================================================== --- syncope/branches/1_1_X/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java (original) +++ syncope/branches/1_1_X/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java Wed Dec 4 11:29:09 2013 @@ -27,17 +27,24 @@ import static org.junit.Assert.fail; import java.security.AccessControlException; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; +import java.util.Map; +import javax.naming.Context; +import javax.naming.directory.InitialDirContext; import org.apache.syncope.common.mod.RoleMod; import org.apache.syncope.common.services.RoleService; import org.apache.syncope.common.to.ConnObjectTO; +import org.apache.syncope.common.to.ResourceTO; import org.apache.syncope.common.to.RoleTO; import org.apache.syncope.common.to.UserTO; import org.apache.syncope.common.types.AttributableType; +import org.apache.syncope.common.types.ConnConfProperty; import org.apache.syncope.common.types.SyncopeClientExceptionType; import org.apache.syncope.common.validation.SyncopeClientCompositeErrorException; import org.apache.syncope.common.validation.SyncopeClientException; +import org.identityconnectors.framework.common.objects.Name; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -370,4 +377,77 @@ public class RoleTestITCase extends Abst assertNotNull(roleTO); assertTrue(roleTO.getEntitlements().isEmpty()); } + + @Test + public void issueSYNCOPE455() { + final String parentName = "issueSYNCOPE455-PRole"; + final String childName = "issueSYNCOPE455-CRole"; + + // 1. create parent role + RoleTO parent = buildBasicRoleTO(parentName); + parent.getResources().add(RESOURCE_NAME_LDAP); + + parent = createRole(roleService, parent); + assertTrue(parent.getResources().contains(RESOURCE_NAME_LDAP)); + + final ConnObjectTO parentRemoteObject = + readConnectorObject(RESOURCE_NAME_LDAP, parent.getId(), AttributableType.ROLE); + assertNotNull(parentRemoteObject); + assertNotNull(getLdapRemoteObject(parentRemoteObject.getAttributeMap().get(Name.NAME).getValues().get(0))); + + // 2. create child role + RoleTO child = buildBasicRoleTO(childName); + child.getResources().add(RESOURCE_NAME_LDAP); + child.setParent(parent.getId()); + + child = createRole(roleService, child); + assertTrue(child.getResources().contains(RESOURCE_NAME_LDAP)); + + final ConnObjectTO childRemoteObject = + readConnectorObject(RESOURCE_NAME_LDAP, child.getId(), AttributableType.ROLE); + assertNotNull(childRemoteObject); + assertNotNull(getLdapRemoteObject(childRemoteObject.getAttributeMap().get(Name.NAME).getValues().get(0))); + + // 3. remove parent role + roleService.delete(parent.getId()); + + // 4. asserts for issue 455 + try { + roleService.read(parent.getId()); + fail(); + } catch (SyncopeClientCompositeErrorException scce) { + // ignore + } + + try { + roleService.read(child.getId()); + fail(); + } catch (SyncopeClientCompositeErrorException scce) { + // ignore + } + + assertNull(getLdapRemoteObject(parentRemoteObject.getAttributeMap().get(Name.NAME).getValues().get(0))); + assertNull(getLdapRemoteObject(childRemoteObject.getAttributeMap().get(Name.NAME).getValues().get(0))); + } + + private Object getLdapRemoteObject(final String name) { + ResourceTO ldapRes = resourceService.read(RESOURCE_NAME_LDAP); + final Map<String, ConnConfProperty> ldapConnConf = + connectorService.read(ldapRes.getConnectorId()).getConfigurationMap(); + + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.PROVIDER_URL, "ldap://" + ldapConnConf.get("host").getValues().get(0) + + ":" + ldapConnConf.get("port").getValues().get(0) + "/"); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, ldapConnConf.get("principal").getValues().get(0)); + env.put(Context.SECURITY_CREDENTIALS, ldapConnConf.get("credentials").getValues().get(0)); + + try { + final InitialDirContext ctx = new InitialDirContext(env); + return ctx.lookup(name); + } catch (Exception e) { + return null; + } + } }