[SYNCOPE-1099] Adding checks to ensure that all resources (including the ones coming from dynamic groups) are considered for propagation
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/ca0fcf1b Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/ca0fcf1b Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/ca0fcf1b Branch: refs/heads/master Commit: ca0fcf1b728c9c6937b55fd0a8bead1d91d3edb4 Parents: 3088b03 Author: Francesco Chicchiriccò <ilgro...@apache.org> Authored: Fri May 26 14:37:45 2017 +0200 Committer: Francesco Chicchiriccò <ilgro...@apache.org> Committed: Fri May 26 14:38:15 2017 +0200 ---------------------------------------------------------------------- .../persistence/jpa/dao/JPAAnyObjectDAO.java | 2 +- .../core/persistence/jpa/dao/JPAUserDAO.java | 2 +- .../provisioning/api/PropagationByResource.java | 6 ++++ .../DefaultAnyObjectProvisioningManager.java | 17 +++++++-- .../provisioning/java/VirAttrHandlerImpl.java | 5 ++- .../java/data/AbstractAnyDataBinder.java | 17 ++++++++- .../java/data/AnyObjectDataBinderImpl.java | 36 ++++++++++++++++---- .../java/data/UserDataBinderImpl.java | 35 +++++++++++++++---- .../activiti/ActivitiUserWorkflowAdapter.java | 4 +-- .../java/DefaultAnyObjectWorkflowAdapter.java | 2 +- .../java/DefaultUserWorkflowAdapter.java | 4 +-- .../org/apache/syncope/fit/core/UserITCase.java | 5 ++- .../syncope/fit/core/UserIssuesITCase.java | 28 +++++++++++++++ 13 files changed, 131 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java index f882ad7..1521749 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java @@ -311,7 +311,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj return result; } - @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true) + @Transactional(readOnly = true) @Override public Collection<String> findAllResourceKeys(final String key) { return CollectionUtils.collect(findAllResources(authFind(key)), EntityUtils.<ExternalResource>keyTransformer()); http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java index 28af7e2..47d6f30 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java @@ -562,7 +562,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { return result; } - @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true) + @Transactional(readOnly = true) @Override public Collection<String> findAllResourceKeys(final String key) { return CollectionUtils.collect(findAllResources(authFind(key)), EntityUtils.keyTransformer()); http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/PropagationByResource.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/PropagationByResource.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/PropagationByResource.java index e7b8bfc..b02c34a 100644 --- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/PropagationByResource.java +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/PropagationByResource.java @@ -236,6 +236,12 @@ public class PropagationByResource implements Serializable { return result; } + public boolean contains(final String resourceKey) { + return toBeCreated.contains(resourceKey) + || toBeUpdated.contains(resourceKey) + || toBeDeleted.contains(resourceKey); + } + /** * Get resources for a given resource operation type. * http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java index ad966de..9b23633 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java @@ -39,6 +39,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationManager; import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter; import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; import org.apache.syncope.core.provisioning.api.VirAttrHandler; +import org.apache.syncope.core.provisioning.api.propagation.PropagationException; import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Propagation; @@ -123,14 +124,26 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin public List<PropagationStatus> delete( final String key, final Set<String> excludedResources, final boolean nullPriorityAsync) { + PropagationByResource propByRes = new PropagationByResource(); + propByRes.set(ResourceOperation.DELETE, anyObjectDAO.findAllResourceKeys(key)); + + // Note here that we can only notify about "delete", not any other + // task defined in workflow process definition: this because this + // information could only be available after awfAdapter.delete(), which + // will also effectively remove user from db, thus making virtually + // impossible by NotificationManager to fetch required user information List<PropagationTask> tasks = propagationManager.getDeleteTasks( AnyTypeKind.ANY_OBJECT, key, - null, + propByRes, excludedResources); PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync); - awfAdapter.delete(key); + try { + awfAdapter.delete(key); + } catch (PropagationException e) { + throw e; + } return propagationReporter.getStatuses(); } http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java index 85e6522..b4090d8 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java @@ -18,7 +18,6 @@ */ package org.apache.syncope.core.provisioning.java; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -69,7 +68,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler { private AnyUtilsFactory anyUtilsFactory; private Map<VirSchema, List<String>> getValues(final Any<?> any, final Set<VirSchema> schemas) { - Collection<? extends ExternalResource> ownedResources = anyUtilsFactory.getInstance(any).getAllResources(any); + Set<ExternalResource> ownedResources = anyUtilsFactory.getInstance(any).getAllResources(any); Map<VirSchema, List<String>> result = new HashMap<>(); @@ -179,7 +178,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler { return getValues( any, anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class). - getForMembership(membership.getRightEnd())); + getForMembership(membership.getRightEnd())); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java index 160c702..b25712b 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeClientCompositeException; import org.apache.syncope.common.lib.SyncopeClientException; @@ -93,6 +94,20 @@ abstract class AbstractAnyDataBinder { protected static final Logger LOG = LoggerFactory.getLogger(AbstractAnyDataBinder.class); + protected static class PropByResContains implements Predicate<String> { + + private final PropagationByResource propByRes; + + PropByResContains(final PropagationByResource propByRes) { + this.propByRes = propByRes; + } + + @Override + public boolean evaluate(final String resourceKey) { + return !propByRes.contains(resourceKey); + } + } + @Autowired protected SchemaDataBinder schemaDataBinder; @@ -287,7 +302,7 @@ abstract class AbstractAnyDataBinder { final PlainSchema schema, final PlainAttr<?> attr, final AnyUtils anyUtils, - final Set<ExternalResource> resources, + final Collection<ExternalResource> resources, final PropagationByResource propByRes, final SyncopeClientException invalidValues) { http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java index dc944b5..5428f5f 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.Transformer; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeClientCompositeException; @@ -231,10 +232,10 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An } else { LOG.error("{} cannot be assigned to {}", group, anyObject); - SyncopeClientException unassignabled = + SyncopeClientException unassignable = SyncopeClientException.build(ClientExceptionType.InvalidMembership); - unassignabled.getElements().add("Cannot be assigned: " + group); - scce.addException(unassignabled); + unassignable.getElements().add("Cannot be assigned: " + group); + scce.addException(unassignable); } } } @@ -326,10 +327,10 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An } else { LOG.error("{} cannot be assigned to {}", otherEnd, anyObject); - SyncopeClientException unassignabled = + SyncopeClientException unassignable = SyncopeClientException.build(ClientExceptionType.InvalidRelationship); - unassignabled.getElements().add("Cannot be assigned: " + otherEnd); - scce.addException(unassignabled); + unassignable.getElements().add("Cannot be assigned: " + otherEnd); + scce.addException(unassignable); } } } @@ -337,7 +338,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An } } - Set<ExternalResource> resources = anyUtils.getAllResources(anyObject); + Collection<ExternalResource> resources = anyObjectDAO.findAllResources(anyObject); SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues); // memberships @@ -437,6 +438,27 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An } } + // finally double-check that there are no resources owned (after all changes above) that remain + // not considered for provisioning + anyObject = anyObjectDAO.save(anyObject); + PropByResContains propByResContains = new PropByResContains(propByRes); + Collection<String> prospectResources = anyObjectDAO.findAllResourceKeys(anyObject.getKey()); + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(currentResources, prospectResources), propByResContains)) { + + propByRes.add(ResourceOperation.DELETE, resourceKey); + } + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(prospectResources, currentResources), propByResContains)) { + + propByRes.add(ResourceOperation.CREATE, resourceKey); + } + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(prospectResources, currentResources), propByResContains)) { + + propByRes.add(ResourceOperation.UPDATE, resourceKey); + } + // Throw composite exception if there is at least one element set in the composing exceptions if (scce.hasExceptions()) { throw scce; http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java index 0140de3..3cd52c3 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java @@ -272,10 +272,10 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat } else { LOG.error("{} cannot be assigned to {}", group, user); - SyncopeClientException unassignabled = + SyncopeClientException unassignable = SyncopeClientException.build(ClientExceptionType.InvalidMembership); - unassignabled.getElements().add("Cannot be assigned: " + group); - scce.addException(unassignabled); + unassignable.getElements().add("Cannot be assigned: " + group); + scce.addException(unassignable); } } } @@ -432,17 +432,17 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat } else { LOG.error("{} cannot be assigned to {}", otherEnd, user); - SyncopeClientException unassignabled = + SyncopeClientException unassignable = SyncopeClientException.build(ClientExceptionType.InvalidRelationship); - unassignabled.getElements().add("Cannot be assigned: " + otherEnd); - scce.addException(unassignabled); + unassignable.getElements().add("Cannot be assigned: " + otherEnd); + scce.addException(unassignable); } } } } } - Set<ExternalResource> resources = anyUtils.getAllResources(user); + Collection<ExternalResource> resources = userDAO.findAllResources(user); SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues); // memberships @@ -554,6 +554,27 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat } } + // finally double-check that there are no resources owned (after all changes above) that remain + // not considered for provisioning + user = userDAO.save(user); + PropByResContains propByResContains = new PropByResContains(propByRes); + Collection<String> prospectResources = userDAO.findAllResourceKeys(user.getKey()); + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(currentResources, prospectResources), propByResContains)) { + + propByRes.add(ResourceOperation.DELETE, resourceKey); + } + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(prospectResources, currentResources), propByResContains)) { + + propByRes.add(ResourceOperation.CREATE, resourceKey); + } + for (String resourceKey : IterableUtils.filteredIterable( + CollectionUtils.intersection(prospectResources, currentResources), propByResContains)) { + + propByRes.add(ResourceOperation.UPDATE, resourceKey); + } + // Throw composite exception if there is at least one element set in the composing exceptions if (scce.hasExceptions()) { throw scce; http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java index 66dd5e2..21727fd 100644 --- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java +++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java @@ -258,9 +258,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { } PropagationByResource propByRes = new PropagationByResource(); - propByRes.set( - ResourceOperation.CREATE, - CollectionUtils.collect(userDAO.findAllResources(user), EntityUtils.keyTransformer())); + propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceKeys(user.getKey())); saveForFormSubmit(user, userTO.getPassword(), propByRes); http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java index 8852aa0..ada196f 100644 --- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java +++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java @@ -44,7 +44,7 @@ public class DefaultAnyObjectWorkflowAdapter extends AbstractAnyObjectWorkflowAd anyObject = anyObjectDAO.save(anyObject); PropagationByResource propByRes = new PropagationByResource(); - propByRes.set(ResourceOperation.CREATE, anyObject.getResourceKeys()); + propByRes.set(ResourceOperation.CREATE, anyObjectDAO.findAllResourceKeys(anyObject.getKey())); return new WorkflowResult<>(anyObject.getKey(), propByRes, "create"); } http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java index b94930b..e3b87ba 100644 --- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java +++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java @@ -79,9 +79,7 @@ public class DefaultUserWorkflowAdapter extends AbstractUserWorkflowAdapter { user = userDAO.save(user); PropagationByResource propByRes = new PropagationByResource(); - propByRes.set( - ResourceOperation.CREATE, - CollectionUtils.collect(userDAO.findAllResources(user), EntityUtils.keyTransformer())); + propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceKeys(user.getKey())); return new WorkflowResult<Pair<String, Boolean>>( new ImmutablePair<>(user.getKey(), propagateEnable), propByRes, "create"); http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java index 21e9fe6..69dd12e 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java @@ -599,8 +599,7 @@ public class UserITCase extends AbstractITCase { assertFalse(beforeTasks <= 0); UserTO userTO = getUniqueSampleTO("pwdo...@t.com"); - userTO.getMemberships().add(new MembershipTO.Builder(). - group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build()); + userTO.getMemberships().add(new MembershipTO.Builder().group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build()); userTO = createUser(userTO).getEntity(); @@ -615,7 +614,7 @@ public class UserITCase extends AbstractITCase { int afterTasks = taskService.list( new TaskQuery.Builder(TaskType.PROPAGATION).page(1).size(1).build()).getTotalCount(); - assertFalse(beforeTasks <= 0); + assertFalse(afterTasks <= 0); assertTrue(beforeTasks < afterTasks); } http://git-wip-us.apache.org/repos/asf/syncope/blob/ca0fcf1b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java index a831dd0..df32cad 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java @@ -1344,4 +1344,32 @@ public class UserIssuesITCase extends AbstractITCase { // 5. verify that user is not in LDAP anynmore assertNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, userDn.getValues().get(0))); } + + @Test + public void issueSYNCOPE1099() { + // 1. create group with dynamic condition and resource + GroupTO group = GroupITCase.getSampleTO("syncope1099G"); + group.getResources().clear(); + group.getResources().add(RESOURCE_NAME_TESTDB); + group.setUDynMembershipCond("firstname==issueSYNCOPE1099"); + + group = createGroup(group).getEntity(); + assertNotNull(group); + + // 2. create user matching the condition above + UserTO user = UserITCase.getUniqueSampleTO("syncope10...@apache.org"); + user.getPlainAttrMap().get("firstname").getValues().set(0, "issueSYNCOPE1099"); + + ProvisioningResult<UserTO> created = createUser(user); + assertNotNull(created); + + // 3. verify that dynamic membership is set and that resource is consequently assigned + user = created.getEntity(); + assertTrue(user.getDynGroups().contains(group.getKey())); + assertTrue(user.getResources().contains(RESOURCE_NAME_TESTDB)); + + // 4. verify that propagation happened towards the resource of the dynamic group + assertFalse(created.getPropagationStatuses().isEmpty()); + assertEquals(RESOURCE_NAME_TESTDB, created.getPropagationStatuses().get(0).getResource()); + } }