You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by an...@apache.org on 2014/06/10 11:45:55 UTC
svn commit: r1601588 - in /syncope/trunk:
console/src/main/java/org/apache/syncope/console/rest/
core/src/main/java/org/apache/syncope/core/connid/
core/src/main/java/org/apache/syncope/core/persistence/beans/membership/
core/src/main/java/org/apache/s...
Author: andreapatricelli
Date: Tue Jun 10 09:45:54 2014
New Revision: 1601588
URL: http://svn.apache.org/r1601588
Log:
[SYNCOPE-458] improved membership virtual attribute management
Modified:
syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/SchemaRestClient.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/membership/MVirAttr.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/VirAttrTestITCase.java
Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/SchemaRestClient.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/SchemaRestClient.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/SchemaRestClient.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/SchemaRestClient.java Tue Jun 10 09:45:54 2014
@@ -140,16 +140,16 @@ public class SchemaRestClient extends Ba
userDerSchemasNames.add(schemaTO.getName());
}
} catch (SyncopeClientException e) {
- LOG.error("While getting all user derived schema names", e);
+ LOG.error("While getting all {} derived schema names", type, e);
}
return userDerSchemasNames;
}
/**
- * Get derived schemas.
+ * Get virtual schemas.
*
- * @return List of derived schemas.
+ * @return List of virtual schemas.
*/
@SuppressWarnings("unchecked")
public List<VirSchemaTO> getVirSchemas(final AttributableType type) {
@@ -158,7 +158,7 @@ public class SchemaRestClient extends Ba
try {
userVirSchemas = getService(SchemaService.class).list(type, SchemaType.VIRTUAL);
} catch (SyncopeClientException e) {
- LOG.error("While getting all user derived schemas", e);
+ LOG.error("While getting all {} virtual schemas", type, e);
}
return userVirSchemas;
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java Tue Jun 10 09:45:54 2014
@@ -550,7 +550,15 @@ public class ConnObjectUtil {
final VirAttrCacheValue toBeCached = new VirAttrCacheValue();
- for (ExternalResource resource : getTargetResource(virAttr, type, attrUtil)) {
+ // SYNCOPE-458 if virattr owner is a Membership, owner must become user involved in membership because
+ // membership mapping is contained in user mapping
+ final AbstractAttributable realOwner = owner instanceof Membership ? ((Membership) owner).getSyncopeUser()
+ : owner;
+
+ final Set<ExternalResource> targetResources = owner instanceof Membership ? getTargetResource(virAttr, type,
+ attrUtil, realOwner.getResources()) : getTargetResource(virAttr, type, attrUtil);
+
+ for (ExternalResource resource : targetResources) {
LOG.debug("Search values into {}", resource.getName());
try {
final List<AbstractMappingItem> mappings = attrUtil.getMappingItems(resource, MappingPurpose.BOTH);
@@ -564,7 +572,7 @@ public class ConnObjectUtil {
final String accountId = attrUtil.getAccountIdItem(resource) == null
? null
: MappingUtil.getAccountIdValue(
- owner, resource, attrUtil.getAccountIdItem(resource));
+ realOwner, resource, attrUtil.getAccountIdItem(resource));
if (StringUtils.isBlank(accountId)) {
throw new IllegalArgumentException("No AccountId found for " + resource.getName());
@@ -575,7 +583,7 @@ public class ConnObjectUtil {
final OperationOptions oo =
connector.getOperationOptions(MappingUtil.getMatchingMappingItems(mappings, type));
- connectorObject = connector.getObject(fromAttributable(owner), new Uid(accountId), oo);
+ connectorObject = connector.getObject(fromAttributable(realOwner), new Uid(accountId), oo);
externalResources.put(resource.getName(), connectorObject);
}
@@ -617,9 +625,9 @@ public class ConnObjectUtil {
}
}
- virAttrCache.put(attrUtil.getType(), owner.getId(), schemaName, toBeCached);
+ virAttrCache.put(attrUtil.getType(), owner.getId(), schemaName, toBeCached);
+ }
}
- }
private Set<ExternalResource> getTargetResource(
final AbstractVirAttr attr, final IntMappingType type, final AttributableUtil attrUtil) {
@@ -638,6 +646,23 @@ public class ConnObjectUtil {
return resources;
}
+ private Set<ExternalResource> getTargetResource(final AbstractVirAttr attr, final IntMappingType type,
+ final AttributableUtil attrUtil, final Set<ExternalResource> ownerResources) {
+
+ final Set<ExternalResource> resources = new HashSet<ExternalResource>();
+
+ for (ExternalResource res : ownerResources) {
+ if (!MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(res, MappingPurpose.BOTH),
+ attr.getSchema().getName(), type).isEmpty()) {
+
+ resources.add(res);
+ }
+ }
+
+ return resources;
+ }
+
private void fillFromTemplate(final AbstractAttributableTO attributableTO, final AbstractAttributableTO template) {
Map<String, AttributeTO> currentAttrMap = attributableTO.getAttrMap();
for (AttributeTO templateAttr : template.getAttrs()) {
@@ -657,7 +682,7 @@ public class ConnObjectUtil {
}
currentAttrMap = attributableTO.getVirAttrMap();
- for (AttributeTO templateVirAttr : template.getDerAttrs()) {
+ for (AttributeTO templateVirAttr : template.getVirAttrs()) {
if (templateVirAttr.getValues() != null && !templateVirAttr.getValues().isEmpty()
&& (!currentAttrMap.containsKey(templateVirAttr.getSchema())
|| currentAttrMap.get(templateVirAttr.getSchema()).getValues().isEmpty())) {
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/membership/MVirAttr.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/membership/MVirAttr.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/membership/MVirAttr.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/membership/MVirAttr.java Tue Jun 10 09:45:54 2014
@@ -18,8 +18,6 @@
*/
package org.apache.syncope.core.persistence.beans.membership;
-import java.util.Collections;
-import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -69,24 +67,4 @@ public class MVirAttr extends AbstractVi
public <T extends AbstractVirSchema> T getSchema() {
return template == null ? null : (T) template.getSchema();
}
-
- @Override
- public List<String> getValues() {
- return Collections.emptyList();
- }
-
- @Override
- public boolean addValue(final String value) {
- return false;
- }
-
- @Override
- public boolean removeValue(final String value) {
- return false;
- }
-
- @Override
- public void setValues(final List<String> values) {
- // do nothing
- }
}
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java Tue Jun 10 09:45:54 2014
@@ -27,8 +27,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.syncope.common.mod.AttributeMod;
+import org.apache.syncope.common.mod.MembershipMod;
import org.apache.syncope.common.mod.UserMod;
import org.apache.syncope.common.to.AttributeTO;
+import org.apache.syncope.common.to.MembershipTO;
import org.apache.syncope.common.types.AttributableType;
import org.apache.syncope.common.types.MappingPurpose;
import org.apache.syncope.common.types.ResourceOperation;
@@ -38,6 +40,7 @@ import org.apache.syncope.core.persisten
import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
import org.apache.syncope.core.persistence.beans.ExternalResource;
import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.membership.Membership;
import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
import org.apache.syncope.core.persistence.dao.NotFoundException;
@@ -101,15 +104,16 @@ public class PropagationManager {
* @param wfResult user to be propagated (and info associated), as per result from workflow
* @param password to be set
* @param vAttrs virtual attributes to be set
+ * @param membershipTOs user memberships
* @return list of propagation tasks
* @throws NotFoundException if user is not found
* @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
*/
public List<PropagationTask> getUserCreateTaskIds(final WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
- final String password, final List<AttributeTO> vAttrs)
+ final String password, final List<AttributeTO> vAttrs, final List<MembershipTO> membershipTOs)
throws NotFoundException, UnauthorizedRoleException {
- return getUserCreateTaskIds(wfResult, password, vAttrs, null);
+ return getUserCreateTaskIds(wfResult, password, vAttrs, null, membershipTOs);
}
/**
@@ -119,17 +123,30 @@ public class PropagationManager {
* @param password to be set
* @param vAttrs virtual attributes to be set
* @param noPropResourceNames external resources not to be considered for propagation
+ * @param membershipTOs user memberships
* @return list of propagation tasks
* @throws NotFoundException if user is not found
* @throws UnauthorizedRoleException if caller doesn't own enough entitlements to administer the given user
*/
public List<PropagationTask> getUserCreateTaskIds(final WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
- final String password, final Collection<AttributeTO> vAttrs, final Set<String> noPropResourceNames)
+ final String password, final Collection<AttributeTO> vAttrs,
+ final Set<String> noPropResourceNames, final List<MembershipTO> membershipTOs)
throws NotFoundException, UnauthorizedRoleException {
SyncopeUser user = userDataBinder.getUserFromId(wfResult.getResult().getKey());
if (vAttrs != null && !vAttrs.isEmpty()) {
userDataBinder.fillVirtual(user, vAttrs, AttributableUtil.getInstance(AttributableType.USER));
+
+ }
+ for (Membership membership : user.getMemberships()) {
+ MembershipTO membershipTO;
+ if (membership.getVirAttrs() != null && !membership.getVirAttrs().isEmpty()) {
+ membershipTO = findMembershipTO(membership, membershipTOs);
+ if (membershipTO != null) {
+ userDataBinder.fillVirtual(membership, membershipTO.getVirAttrs(), AttributableUtil.getInstance(
+ AttributableType.MEMBERSHIP));
+ }
+ }
}
return getCreateTaskIds(user, password,
wfResult.getResult().getValue(), wfResult.getPropByRes(), noPropResourceNames);
@@ -185,7 +202,7 @@ public class PropagationManager {
propByRes.get(ResourceOperation.CREATE).removeAll(noPropResourceNames);
}
- return createTasks(attributable, password, true, null, null, enable, false, propByRes);
+ return createTasks(attributable, password, true, null, null, null, null, enable, false, propByRes);
}
/**
@@ -209,7 +226,8 @@ public class PropagationManager {
Collections.<String>emptySet(), // no virtual attributes to be managed
Collections.<AttributeMod>emptySet(), // no virtual attributes to be managed
null, // no propagation by resources
- noPropResourceNames);
+ noPropResourceNames,
+ Collections.<MembershipMod>emptySet());
}
/**
@@ -234,7 +252,8 @@ public class PropagationManager {
wfResult.getResult().getKey().getVirAttrsToRemove(),
wfResult.getResult().getKey().getVirAttrsToUpdate(),
wfResult.getPropByRes(),
- noPropResourceNames);
+ noPropResourceNames,
+ wfResult.getResult().getKey().getMembershipsToAdd());
}
public List<PropagationTask> getUserUpdateTaskIds(final WorkflowResult<Map.Entry<UserMod, Boolean>> wfResult) {
@@ -310,13 +329,15 @@ public class PropagationManager {
SyncopeRole role = roleDataBinder.getRoleFromId(wfResult.getResult());
return getUpdateTaskIds(role, null, false, null,
- vAttrsToBeRemoved, vAttrsToBeUpdated, wfResult.getPropByRes(), noPropResourceNames);
+ vAttrsToBeRemoved, vAttrsToBeUpdated, wfResult.getPropByRes(), noPropResourceNames,
+ Collections.<MembershipMod>emptySet());
}
protected List<PropagationTask> getUpdateTaskIds(final AbstractAttributable attributable,
final String password, final boolean changePwd, final Boolean enable,
final Set<String> vAttrsToBeRemoved, final Set<AttributeMod> vAttrsToBeUpdated,
- final PropagationByResource propByRes, final Collection<String> noPropResourceNames)
+ final PropagationByResource propByRes, final Collection<String> noPropResourceNames,
+ final Set<MembershipMod> membershipsToAdd)
throws NotFoundException {
AbstractAttributableDataBinder binder = attributable instanceof SyncopeUser
@@ -328,6 +349,24 @@ public class PropagationManager {
? Collections.<AttributeMod>emptySet()
: vAttrsToBeUpdated, AttributableUtil.getInstance(attributable));
+ // SYNCOPE-458 fill membership virtual attributes
+ if (attributable instanceof SyncopeUser) {
+ final SyncopeUser user = (SyncopeUser) attributable;
+ for (Membership membership : user.getMemberships()) {
+ if (membership.getVirAttrs() != null && !membership.getVirAttrs().isEmpty()) {
+ final MembershipMod membershipMod = findMembershipMod(membership, membershipsToAdd);
+ if (membershipMod != null) {
+ binder.fillVirtual(membership, membershipMod.getVirAttrsToRemove() == null
+ ? Collections.<String>emptySet()
+ : membershipMod.getVirAttrsToRemove(),
+ membershipMod.getVirAttrsToUpdate() == null ? Collections.<AttributeMod>emptySet()
+ : membershipMod.getVirAttrsToUpdate(), AttributableUtil.getInstance(
+ AttributableType.MEMBERSHIP));
+ }
+ }
+ }
+ }
+
if (propByRes == null || propByRes.isEmpty()) {
localPropByRes.addAll(ResourceOperation.UPDATE, attributable.getResourceNames());
} else {
@@ -346,8 +385,23 @@ public class PropagationManager {
}
}
+ // SYNCOPE-458 fill membership virtual attributes to be updated map
+ Map<String, AttributeMod> membVAttrsToBeUpdatedMap = new HashMap<String, AttributeMod>();
+ for (MembershipMod membershipMod : membershipsToAdd) {
+ for (AttributeMod attrMod : membershipMod.getVirAttrsToUpdate()) {
+ membVAttrsToBeUpdatedMap.put(attrMod.getSchema(), attrMod);
+ }
+ }
+
+ // SYNCOPE-458 fill membership virtual attributes to be removed set
+ final Set<String> membVAttrsToBeRemoved = new HashSet<String>();
+ for (MembershipMod membershipMod : membershipsToAdd) {
+ membVAttrsToBeRemoved.addAll(membershipMod.getVirAttrsToRemove());
+ }
+
return createTasks(attributable, password, changePwd,
- vAttrsToBeRemoved, vAttrsToBeUpdatedMap, enable, false, localPropByRes);
+ vAttrsToBeRemoved, vAttrsToBeUpdatedMap, membVAttrsToBeRemoved, membVAttrsToBeUpdatedMap, enable, false,
+ localPropByRes);
}
/**
@@ -429,7 +483,7 @@ public class PropagationManager {
*/
public List<PropagationTask> getUserDeleteTaskIds(final WorkflowResult<Long> wfResult) {
SyncopeUser user = userDataBinder.getUserFromId(wfResult.getResult());
- return createTasks(user, null, false, null, null, false, true, wfResult.getPropByRes());
+ return createTasks(user, null, false, null, null, null, null, false, true, wfResult.getPropByRes());
}
/**
@@ -512,7 +566,7 @@ public class PropagationManager {
if (noPropResourceNames != null && !noPropResourceNames.isEmpty()) {
propByRes.get(ResourceOperation.DELETE).removeAll(noPropResourceNames);
}
- return createTasks(attributable, null, false, null, null, false, true, propByRes);
+ return createTasks(attributable, null, false, null, null, null, null, false, true, propByRes);
}
/**
@@ -524,6 +578,8 @@ public class PropagationManager {
* @param changePwd whether password should be included for propagation attributes or not
* @param vAttrsToBeRemoved virtual attributes to be removed
* @param vAttrsToBeUpdated virtual attributes to be added
+ * @param membVAttrsToBeRemoved membership virtual attributes to be removed
+ * @param membVAttrsToBeUpdatedMap membership virtual attributes to be added
* @param enable whether user must be enabled or not
* @param deleteOnResource whether user / role must be deleted anyway from external resource or not
* @param propByRes operation to be performed per resource
@@ -532,8 +588,8 @@ public class PropagationManager {
protected <T extends AbstractAttributable> List<PropagationTask> createTasks(final T subject,
final String password, final boolean changePwd,
final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
- final Boolean enable, final boolean deleteOnResource,
- final PropagationByResource propByRes) {
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttributeMod> membVAttrsToBeUpdatedMap,
+ final Boolean enable, final boolean deleteOnResource, final PropagationByResource propByRes) {
LOG.debug("Provisioning subject {}:\n{}", subject, propByRes);
@@ -583,7 +639,8 @@ public class PropagationManager {
task.setOldAccountId(propByRes.getOldAccountId(resource.getName()));
Map.Entry<String, Set<Attribute>> preparedAttrs = MappingUtil.prepareAttributes(attrUtil, subject,
- password, changePwd, vAttrsToBeRemoved, vAttrsToBeUpdated, enable, resource);
+ password, changePwd, vAttrsToBeRemoved, vAttrsToBeUpdated, membVAttrsToBeRemoved,
+ membVAttrsToBeUpdatedMap, enable, resource);
task.setAccountId(preparedAttrs.getKey());
// Check if any of mandatory attributes (in the mapping) is missing or not received any value:
@@ -621,4 +678,24 @@ public class PropagationManager {
return tasks;
}
+
+ private MembershipTO findMembershipTO(final Membership membership, final List<MembershipTO> memberships) {
+ for (MembershipTO membershipTO : memberships) {
+ if (membershipTO.getRoleId() == membership.getSyncopeRole().getId()) {
+ return membershipTO;
+ }
+ }
+ LOG.error("No MembershipTO found for membership {}", membership);
+ return null;
+ }
+
+ private MembershipMod findMembershipMod(final Membership membership, final Set<MembershipMod> membershipMods) {
+ for (MembershipMod membershipMod : membershipMods) {
+ if (membershipMod.getRole() == membership.getSyncopeRole().getId()) {
+ return membershipMod;
+ }
+ }
+ LOG.error("No MembershipMod found for membership {}", membership);
+ return null;
+ }
}
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java Tue Jun 10 09:45:54 2014
@@ -38,6 +38,7 @@ import org.apache.syncope.common.to.User
import org.apache.syncope.common.types.AttributableType;
import org.apache.syncope.common.types.ClientExceptionType;
import org.apache.syncope.common.SyncopeClientException;
+import org.apache.syncope.common.mod.MembershipMod;
import org.apache.syncope.core.persistence.beans.PropagationTask;
import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
@@ -207,7 +208,7 @@ public class UserController extends Abst
WorkflowResult<Map.Entry<Long, Boolean>> created = uwfAdapter.create(actual);
List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(
- created, actual.getPassword(), actual.getVirAttrs());
+ created, actual.getPassword(), actual.getVirAttrs(), actual.getMemberships());
PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
getBean(PropagationReporter.class);
try {
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java Tue Jun 10 09:45:54 2014
@@ -104,7 +104,7 @@ public class UserDataBinder extends Abst
return user;
}
-
+
@Transactional(readOnly = true)
public Set<String> getResourceNamesForUserId(final Long userId) {
return getUserFromId(userId).getResourceNames();
@@ -412,6 +412,9 @@ public class UserDataBinder extends Abst
membershipTO.setRoleId(membership.getSyncopeRole().getId());
membershipTO.setRoleName(membership.getSyncopeRole().getName());
+ // SYNCOPE-458 retrieve also membership virtual attributes
+ connObjectUtil.retrieveVirAttrValues(membership, AttributableUtil.getInstance(AttributableType.MEMBERSHIP));
+
fillTO(membershipTO,
membership.getAttrs(), membership.getDerAttrs(), membership.getVirAttrs(),
membership.getResources());
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopePushResultHandler.java Tue Jun 10 09:45:54 2014
@@ -117,6 +117,8 @@ public class SyncopePushResultHandler ex
true, // propagate password (if required)
null, // no vir attrs to be removed
null, // propagate current vir attr values
+ null, // no membership vir attrs to be removed
+ null, // propagate current membership vir attr values
enabled, // propagate status (suspended or not) if required
getSyncTask().getResource()); // target external resource
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/sync/impl/SyncopeSyncResultHandler.java Tue Jun 10 09:45:54 2014
@@ -362,7 +362,7 @@ public class SyncopeSyncResultHandler ex
final List<ConnectorObject> found = connector.search(objectClass,
new EqualsFilter(new Name(name)), connector.getOperationOptions(
- attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)));
+ attrUtil.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)));
if (found.isEmpty()) {
LOG.debug("No {} found on {} with __NAME__ {}", objectClass, syncTask.getResource(), name);
@@ -441,7 +441,7 @@ public class SyncopeSyncResultHandler ex
List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(created,
((UserTO) actual).getPassword(), actual.getVirAttrs(),
- Collections.singleton(syncTask.getResource().getName()));
+ Collections.singleton(syncTask.getResource().getName()), ((UserTO) actual).getMemberships());
taskExecutor.execute(tasks);
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java Tue Jun 10 09:45:54 2014
@@ -190,17 +190,17 @@ public final class AttributableUtil {
if (resource != null) {
switch (type) {
- case USER:
- if (resource.getUmapping() != null) {
- result = resource.getUmapping().getAccountIdItem();
- }
- break;
case ROLE:
if (resource.getRmapping() != null) {
result = resource.getRmapping().getAccountIdItem();
}
break;
case MEMBERSHIP:
+ case USER:
+ if (resource.getUmapping() != null) {
+ result = resource.getUmapping().getAccountIdItem();
+ }
+ break;
default:
}
}
@@ -215,17 +215,17 @@ public final class AttributableUtil {
if (resource != null) {
switch (type) {
- case USER:
- if (resource.getUmapping() != null) {
- items = resource.getUmapping().getItems();
- }
- break;
case ROLE:
if (resource.getRmapping() != null) {
items = resource.getRmapping().getItems();
}
break;
case MEMBERSHIP:
+ case USER:
+ if (resource.getUmapping() != null) {
+ items = resource.getUmapping().getItems();
+ }
+ break;
default:
}
}
@@ -265,6 +265,7 @@ public final class AttributableUtil {
}
break;
default:
+ LOG.error("You requested not existing purpose {}", purpose);
}
return result;
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java Tue Jun 10 09:45:54 2014
@@ -49,6 +49,7 @@ import org.apache.syncope.core.persisten
import org.apache.syncope.core.persistence.beans.membership.MDerSchema;
import org.apache.syncope.core.persistence.beans.membership.MSchema;
import org.apache.syncope.core.persistence.beans.membership.MVirSchema;
+import org.apache.syncope.core.persistence.beans.membership.Membership;
import org.apache.syncope.core.persistence.beans.role.RAttrValue;
import org.apache.syncope.core.persistence.beans.role.RDerSchema;
import org.apache.syncope.core.persistence.beans.role.RSchema;
@@ -130,6 +131,8 @@ public final class MappingUtil {
* @param changePwd whether password should be included for propagation attributes or not
* @param vAttrsToBeRemoved virtual attributes to be removed
* @param vAttrsToBeUpdated virtual attributes to be added
+ * @param membVAttrsToBeRemoved membership virtual attributes to be removed
+ * @param membVAttrsToBeUpdated membership virtual attributes to be added
* @param enable whether user must be enabled or not
* @param resource target resource
* @return account link + prepared attributes
@@ -137,6 +140,7 @@ public final class MappingUtil {
public static <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(
final AttributableUtil attrUtil, final T subject, final String password, final boolean changePwd,
final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttributeMod> membVAttrsToBeUpdated,
final Boolean enable, final ExternalResource resource) {
LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
@@ -162,8 +166,21 @@ public final class MappingUtil {
virAttrCache.expire(attrUtil.getType(), subject.getId(), mapping.getIntAttrName());
}
+ // SYNCOPE-458 expire cache also for membership virtual schemas
+ if (attrUtil.getType() == AttributableType.USER && mapping.getIntMappingType()
+ == IntMappingType.MembershipVirtualSchema && (subject instanceof SyncopeUser)) {
+ final SyncopeUser user = (SyncopeUser) subject;
+ for (Membership membership : user.getMemberships()) {
+ LOG.debug("Expire entry cache {}-{} for membership {}", subject.getId(), mapping.
+ getIntAttrName(), membership);
+ virAttrCache.expire(AttributableType.MEMBERSHIP, membership.getId(), mapping.
+ getIntAttrName());
+ }
+ }
+
Map.Entry<String, Attribute> preparedAttribute = prepareAttribute(
- resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated);
+ resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated,
+ membVAttrsToBeRemoved, membVAttrsToBeUpdated);
if (preparedAttribute != null && preparedAttribute.getKey() != null) {
accountId = preparedAttribute.getKey();
@@ -220,7 +237,8 @@ public final class MappingUtil {
private static <T extends AbstractAttributable> Map.Entry<String, Attribute> prepareAttribute(
final ExternalResource resource, final AbstractMappingItem mapItem,
final T subject, final String password, final PasswordGenerator passwordGenerator,
- final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated) {
+ final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttributeMod> membVAttrsToBeUpdated) {
final List<AbstractAttributable> attributables = new ArrayList<AbstractAttributable>();
@@ -256,7 +274,8 @@ public final class MappingUtil {
}
List<AbstractAttrValue> values = getIntValues(
- resource, mapItem, attributables, vAttrsToBeRemoved, vAttrsToBeUpdated);
+ resource, mapItem, attributables, vAttrsToBeRemoved, vAttrsToBeUpdated, membVAttrsToBeRemoved,
+ membVAttrsToBeUpdated);
AbstractNormalSchema schema = null;
boolean readOnlyVirSchema = false;
@@ -415,7 +434,8 @@ public final class MappingUtil {
Map.Entry<String, Attribute> preparedAttr = prepareAttribute(
resource, attrUtil.getAccountIdItem(resource), subject, null, null,
- Collections.<String>emptySet(), Collections.<String, AttributeMod>emptyMap());
+ Collections.<String>emptySet(), Collections.<String, AttributeMod>emptyMap(), Collections.
+ <String>emptySet(), Collections.<String, AttributeMod>emptyMap());
String accountId = preparedAttr.getKey();
final Name roleOwnerName = evaluateNAME(subject, resource, accountId);
@@ -430,11 +450,14 @@ public final class MappingUtil {
* @param attributables list of attributables
* @param vAttrsToBeRemoved virtual attributes to be removed
* @param vAttrsToBeUpdated virtual attributes to be added
+ * @param membVAttrsToBeRemoved membership virtual attributes to be removed
+ * @param membVAttrsToBeUpdated membership virtual attributes to be added
* @return attribute values.
*/
public static List<AbstractAttrValue> getIntValues(final ExternalResource resource,
final AbstractMappingItem mappingItem, final List<AbstractAttributable> attributables,
- final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated) {
+ final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttributeMod> membVAttrsToBeUpdated) {
LOG.debug("Get attributes for '{}' and mapping type '{}'", attributables, mappingItem.getIntMappingType());
@@ -465,7 +488,6 @@ public final class MappingUtil {
case UserVirtualSchema:
case RoleVirtualSchema:
- case MembershipVirtualSchema:
for (AbstractAttributable attributable : attributables) {
AbstractVirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
if (virAttr != null) {
@@ -489,10 +511,44 @@ public final class MappingUtil {
}
}
- LOG.debug("Retrieved virtual attribute {}"
+ LOG.debug("Retrieved {} virtual attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attributable.getClass().getSimpleName(),
+ virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+ break;
+
+ case MembershipVirtualSchema:
+ for (AbstractAttributable attributable : attributables) {
+ AbstractVirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
+ if (virAttr != null) {
+ if (membVAttrsToBeRemoved != null && membVAttrsToBeUpdated != null) {
+ if (membVAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
+ virAttr.setValues(
+ membVAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
+ } else if (membVAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
+ virAttr.getValues().clear();
+ } else {
+ throw new IllegalArgumentException("Don't need to update membership virtual attribute '"
+ + mappingItem.getIntAttrName() + "'");
+ }
+ }
+ if (virAttr.getValues() != null) {
+ for (String value : virAttr.getValues()) {
+ attrValue = new UAttrValue();
+ attrValue.setStringValue(value);
+ values.add(attrValue);
+ }
+ }
+ }
+
+ LOG.debug("Retrieved {} virtual attribute {}"
+ "\n* IntAttrName {}"
+ "\n* IntMappingType {}"
+ "\n* Attribute values {}",
+ attributable.getClass().getSimpleName(),
virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
}
break;
@@ -580,6 +636,7 @@ public final class MappingUtil {
* Get accountId internal value.
*
* @param attributable attributable
+ * @param resource external resource
* @param accountIdItem accountid mapping item
* @return accountId internal value
*/
@@ -587,7 +644,7 @@ public final class MappingUtil {
final AbstractMappingItem accountIdItem) {
List<AbstractAttrValue> values = getIntValues(resource, accountIdItem,
- Collections.<AbstractAttributable>singletonList(attributable), null, null);
+ Collections.<AbstractAttributable>singletonList(attributable), null, null, null, null);
return values == null || values.isEmpty()
? null
: values.get(0).getValueAsString();
Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/VirAttrTestITCase.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/VirAttrTestITCase.java?rev=1601588&r1=1601587&r2=1601588&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/VirAttrTestITCase.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/VirAttrTestITCase.java Tue Jun 10 09:45:54 2014
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertTru
import org.apache.commons.lang3.SerializationUtils;
import java.util.Map;
import org.apache.syncope.common.mod.AttributeMod;
+import org.apache.syncope.common.mod.MembershipMod;
import org.apache.syncope.common.mod.StatusMod;
import org.apache.syncope.common.mod.UserMod;
import org.apache.syncope.common.services.ResourceService;
@@ -555,4 +556,169 @@ public class VirAttrTestITCase extends A
userTO = updateUser(userMod);
assertNotNull(userTO.getVirAttrMap().get("virtualdata"));
}
+
+ @Test
+ public void issueSYNCOPE458() {
+ // -------------------------------------------
+ // Create a role ad-hoc
+ // -------------------------------------------
+ final String roleName = "issueSYNCOPE458-Role-" + getUUIDString();
+ RoleTO roleTO = new RoleTO();
+ roleTO.setName(roleName);
+ roleTO.setParent(2L);
+ roleTO.setInheritTemplates(true);
+ roleTO = createRole(roleTO);
+ // -------------------------------------------
+
+ // -------------------------------------------
+ // Update resource-db-virattr mapping adding new membership virtual schema mapping
+ // -------------------------------------------
+ ResourceTO resourceDBVirAttr = resourceService.read(RESOURCE_NAME_DBVIRATTR);
+ assertNotNull(resourceDBVirAttr);
+
+ final MappingTO resourceUMapping = resourceDBVirAttr.getUmapping();
+
+ MappingItemTO item = new MappingItemTO();
+ item.setIntAttrName("mvirtualdata");
+ item.setIntMappingType(IntMappingType.MembershipVirtualSchema);
+ item.setExtAttrName("EMAIL");
+ item.setPurpose(MappingPurpose.BOTH);
+
+ resourceUMapping.addItem(item);
+
+ resourceDBVirAttr.setUmapping(resourceUMapping);
+
+ resourceService.update(RESOURCE_NAME_DBVIRATTR, resourceDBVirAttr);
+ // -------------------------------------------
+
+ // -------------------------------------------
+ // Create new user
+ // -------------------------------------------
+ UserTO userTO = getUniqueSampleTO("syncope458@syncope.apache.org");
+ userTO.getResources().clear();
+ userTO.getResources().add(RESOURCE_NAME_DBVIRATTR);
+ userTO.getVirAttrs().clear();
+ userTO.getDerAttrs().clear();
+ userTO.getMemberships().clear();
+
+ // add membership, with virtual attribute populated, to user
+ MembershipTO membership = new MembershipTO();
+ membership.setRoleId(roleTO.getId());
+ membership.getVirAttrs().add(attributeTO("mvirtualdata", "syncope458@syncope.apache.org"));
+ userTO.getMemberships().add(membership);
+
+ //propagate user
+ userTO = createUser(userTO);
+ assertEquals(1, userTO.getPropagationStatusTOs().size());
+ assertTrue(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful());
+ // -------------------------------------------
+
+ // 1. check if membership has virtual attribute populated
+ assertNotNull(userTO.getMemberships().get(0).getVirAttrMap().get("mvirtualdata"));
+ assertEquals("syncope458@syncope.apache.org",
+ userTO.getMemberships().get(0).getVirAttrMap().get("mvirtualdata").getValues().get(0));
+ // -------------------------------------------
+
+ // 2. update membership virtual attribute
+ MembershipMod membershipMod = new MembershipMod();
+ membershipMod.setRole(roleTO.getId());
+ membershipMod.getVirAttrsToUpdate().add(attributeMod("mvirtualdata", "syncope458_NEW@syncope.apache.org"));
+
+ UserMod userMod = new UserMod();
+ userMod.setId(userTO.getId());
+ userMod.getMembershipsToAdd().add(membershipMod);
+ userMod.getMembershipsToRemove().add(userTO.getMemberships().iterator().next().getId());
+
+ userTO = updateUser(userMod);
+ assertNotNull(userTO);
+ // 3. check again after update if membership has virtual attribute populated with new value
+ assertNotNull(userTO.getMemberships().get(0).getVirAttrMap().get("mvirtualdata"));
+ assertEquals("syncope458_NEW@syncope.apache.org", userTO.getMemberships().get(0).getVirAttrMap().get(
+ "mvirtualdata").getValues().get(0));
+
+ // ----------------------------------------
+ // force cache expiring without any modification
+ // ----------------------------------------
+ String jdbcURL = null;
+ ConnInstanceTO connInstanceBean = connectorService.readByResource(RESOURCE_NAME_DBVIRATTR);
+ for (ConnConfProperty prop : connInstanceBean.getConfiguration()) {
+ if ("jdbcUrlTemplate".equals(prop.getSchema().getName())) {
+ jdbcURL = prop.getValues().iterator().next().toString();
+ prop.getValues().clear();
+ prop.getValues().add("jdbc:h2:tcp://localhost:9092/xxx");
+ }
+ }
+
+ connectorService.update(connInstanceBean.getId(), connInstanceBean);
+
+ membershipMod = new MembershipMod();
+ membershipMod.setRole(roleTO.getId());
+ membershipMod.getVirAttrsToUpdate().add(attributeMod("mvirtualdata", "syncope458_updated@syncope.apache.org"));
+
+ userMod = new UserMod();
+ userMod.setId(userTO.getId());
+ userMod.getMembershipsToAdd().add(membershipMod);
+ userMod.getMembershipsToRemove().add(userTO.getMemberships().iterator().next().getId());
+
+ userTO = updateUser(userMod);
+ assertNotNull(userTO);
+ // ----------------------------------
+
+ // change attribute value directly on resource
+ final JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+
+ String value = jdbcTemplate.queryForObject(
+ "SELECT EMAIL FROM testsync WHERE ID=?", String.class, userTO.getId());
+ assertEquals("syncope458_NEW@syncope.apache.org", value);
+
+ jdbcTemplate.update("UPDATE testsync set EMAIL='syncope458_NEW_TWO@syncope.apache.org' WHERE ID=?", userTO.
+ getId());
+
+ value = jdbcTemplate.queryForObject("SELECT EMAIL FROM testsync WHERE ID=?", String.class, userTO.getId());
+ assertEquals("syncope458_NEW_TWO@syncope.apache.org", value);
+ // ----------------------------------------
+
+ // ----------------------------------------
+ // restore connector
+ // ----------------------------------------
+ for (ConnConfProperty prop : connInstanceBean.getConfiguration()) {
+ if ("jdbcUrlTemplate".equals(prop.getSchema().getName())) {
+ prop.getValues().clear();
+ prop.getValues().add(jdbcURL);
+ }
+ }
+ connectorService.update(connInstanceBean.getId(), connInstanceBean);
+ // ----------------------------------------
+
+ userTO = userService.read(userTO.getId());
+ assertNotNull(userTO);
+ // 4. check virtual attribute synchronization after direct update on resource
+ assertEquals("syncope458_NEW_TWO@syncope.apache.org", userTO.getMemberships().get(0).getVirAttrMap().get(
+ "mvirtualdata").getValues().get(0));
+
+ // 5. remove membership virtual attribute
+ membershipMod = new MembershipMod();
+ membershipMod.setRole(roleTO.getId());
+ membershipMod.getVirAttrsToRemove().add("mvirtualdata");
+
+ userMod = new UserMod();
+ userMod.setId(userTO.getId());
+ userMod.getMembershipsToAdd().add(membershipMod);
+ userMod.getMembershipsToRemove().add(userTO.getMemberships().iterator().next().getId());
+
+ userTO = updateUser(userMod);
+ assertNotNull(userTO);
+ // check again after update if membership hasn't any virtual attribute
+ assertTrue(userTO.getMemberships().get(0).getVirAttrMap().isEmpty());
+
+ // -------------------------------------------
+ // Delete role ad-hoc and restore resource mapping
+ // -------------------------------------------
+ roleService.delete(roleTO.getId());
+
+ resourceUMapping.removeItem(item);
+ resourceDBVirAttr.setUmapping(resourceUMapping);
+ resourceService.update(RESOURCE_NAME_DBVIRATTR, resourceDBVirAttr);
+ // -------------------------------------------
+ }
}