You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2013/11/12 09:55:32 UTC
svn commit: r1540975 - in /syncope/trunk:
common/src/main/java/org/apache/syncope/common/types/
core/src/main/java/org/apache/syncope/core/connid/
core/src/main/java/org/apache/syncope/core/persistence/beans/
core/src/main/java/org/apache/syncope/core/...
Author: ilgrosso
Date: Tue Nov 12 08:55:31 2013
New Revision: 1540975
URL: http://svn.apache.org/r1540975
Log:
[SYNCOPE-435] Merge from 1_1_X
Modified:
syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.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/AbstractDerAttr.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.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/data/AbstractAttributableDataBinder.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.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/util/AttributableUtil.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java
syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
syncope/trunk/core/src/main/resources/syncopeContext.xml
syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java
syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java Tue Nov 12 08:55:31 2013
@@ -18,16 +18,10 @@
*/
package org.apache.syncope.common.types;
-import javax.xml.bind.annotation.XmlEnum;
-
-@XmlEnum
public enum ResourceOperation {
CREATE,
UPDATE,
- DELETE;
+ DELETE
- public static ResourceOperation fromString(final String value) {
- return ResourceOperation.valueOf(value.toUpperCase());
- }
}
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=1540975&r1=1540974&r2=1540975&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 Nov 12 08:55:31 2013
@@ -86,12 +86,6 @@ public class ConnObjectUtil {
private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtil.class);
/**
- * JEXL engine for evaluating connector's account link.
- */
- @Autowired
- private JexlUtil jexlUtil;
-
- /**
* User data binder.
*/
@Autowired
@@ -350,14 +344,14 @@ public class ConnObjectUtil {
if (template != null) {
if (template instanceof UserTO) {
if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
- String evaluated = jexlUtil.evaluate(((UserTO) template).getUsername(), attributableTO);
+ String evaluated = JexlUtil.evaluate(((UserTO) template).getUsername(), attributableTO);
if (StringUtils.isNotBlank(evaluated)) {
((UserTO) attributableTO).setUsername(evaluated);
}
}
if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
- String evaluated = jexlUtil.evaluate(((UserTO) template).getPassword(), attributableTO);
+ String evaluated = JexlUtil.evaluate(((UserTO) template).getPassword(), attributableTO);
if (StringUtils.isNotBlank(evaluated)) {
((UserTO) attributableTO).setPassword(evaluated);
}
@@ -378,7 +372,7 @@ public class ConnObjectUtil {
}
if (template instanceof RoleTO) {
if (StringUtils.isNotBlank(((RoleTO) template).getName())) {
- String evaluated = jexlUtil.evaluate(((RoleTO) template).getName(), attributableTO);
+ String evaluated = JexlUtil.evaluate(((RoleTO) template).getName(), attributableTO);
if (StringUtils.isNotBlank(evaluated)) {
((RoleTO) attributableTO).setName(evaluated);
}
@@ -543,7 +537,7 @@ public class ConnObjectUtil {
final String accountId = attrUtil.getAccountIdItem(resource) == null
? null
: MappingUtil.getAccountIdValue(
- owner, resource, attrUtil.getAccountIdItem(resource));
+ owner, resource, attrUtil.getAccountIdItem(resource));
if (StringUtils.isBlank(accountId)) {
throw new IllegalArgumentException("No AccountId found for " + resource.getName());
@@ -643,7 +637,7 @@ public class ConnObjectUtil {
if (template.getValues() != null && !template.getValues().isEmpty()) {
for (String value : template.getValues()) {
- String evaluated = jexlUtil.evaluate(value, attributableTO);
+ String evaluated = JexlUtil.evaluate(value, attributableTO);
if (StringUtils.isNotBlank(evaluated)) {
result.getValues().add(evaluated);
}
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java Tue Nov 12 08:55:31 2013
@@ -25,9 +25,7 @@ import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.MapContext;
-import org.apache.syncope.core.util.ApplicationContextProvider;
import org.apache.syncope.core.util.JexlUtil;
-import org.springframework.context.ConfigurableApplicationContext;
@MappedSuperclass
public abstract class AbstractDerAttr extends AbstractBaseBean {
@@ -48,16 +46,13 @@ public abstract class AbstractDerAttr ex
* @return the value of this derived attribute
*/
public String getValue(final Collection<? extends AbstractAttr> attributes) {
- final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
- final JexlUtil jexlUtil = context.getBean(JexlUtil.class);
-
// Prepare context using user attributes
final JexlContext jexlContext = new MapContext();
- jexlUtil.addAttrsToContext(attributes, jexlContext);
- jexlUtil.addFieldsToContext(getOwner(), jexlContext);
+ JexlUtil.addAttrsToContext(attributes, jexlContext);
+ JexlUtil.addFieldsToContext(getOwner(), jexlContext);
// Evaluate expression using the context prepared before
- return jexlUtil.evaluate(getSchema().getExpression(), jexlContext);
+ return JexlUtil.evaluate(getSchema().getExpression(), jexlContext);
}
public abstract <T extends AbstractAttributable> T getOwner();
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java Tue Nov 12 08:55:31 2013
@@ -72,7 +72,7 @@ public class SyncopeUser extends Abstrac
@Id
private Long id;
- @NotNull
+ @NotNull(message = "Blank password")
private String password;
@Transient
@@ -122,7 +122,7 @@ public class SyncopeUser extends Abstrac
* Username/Login.
*/
@Column(unique = true)
- @NotNull
+ @NotNull(message = "Blank username")
private String username;
/**
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java Tue Nov 12 08:55:31 2013
@@ -31,6 +31,18 @@ import org.apache.syncope.core.persisten
public interface PropagationTaskExecutor {
/**
+ * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+ * mapping but not to be propagated.
+ */
+ String MANDATORY_MISSING_ATTR_NAME = "__MANDATORY_MISSING__";
+
+ /**
+ * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+ * mapping but about to be propagated as null or empty.
+ */
+ String MANDATORY_NULL_OR_EMPTY_ATTR_NAME = "__MANDATORY_NULL_OR_EMPTY__";
+
+ /**
* Execute the given PropagationTask and returns the generated TaskExec.
*
* @param task to be executed
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java Tue Nov 12 08:55:31 2013
@@ -18,10 +18,12 @@
*/
package org.apache.syncope.core.propagation.impl;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
@@ -125,6 +127,27 @@ public abstract class AbstractPropagatio
// set of attributes to be propagated
final Set<Attribute> attributes = new HashSet<Attribute>(task.getAttributes());
+ // check if there is any missing or null / empty mandatory attribute
+ List<Object> mandatoryAttrNames = new ArrayList<Object>();
+ Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
+ if (mandatoryMissing != null) {
+ attributes.remove(mandatoryMissing);
+
+ if (beforeObj == null) {
+ mandatoryAttrNames.addAll(mandatoryMissing.getValue());
+ }
+ }
+ Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
+ if (mandatoryNullOrEmpty != null) {
+ attributes.remove(mandatoryNullOrEmpty);
+
+ mandatoryAttrNames.addAll(mandatoryNullOrEmpty.getValue());
+ }
+ if (!mandatoryAttrNames.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Not attempted because there are mandatory attributes without value(s): " + mandatoryAttrNames);
+ }
+
if (beforeObj == null) {
// 1. get accountId
final String accountId = task.getAccountId();
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java Tue Nov 12 08:55:31 2013
@@ -55,9 +55,6 @@ public class LDAPMembershipPropagationAc
@Autowired
protected UserDAO userDAO;
- @Autowired
- protected JexlUtil jexlUtil;
-
/**
* Allows easy subclassing for the ConnId AD connector bundle.
*
@@ -83,11 +80,11 @@ public class LDAPMembershipPropagationAc
LOG.debug("Evaluating accountLink for {}", role);
final JexlContext jexlContext = new MapContext();
- jexlUtil.addFieldsToContext(role, jexlContext);
- jexlUtil.addAttrsToContext(role.getAttrs(), jexlContext);
- jexlUtil.addDerAttrsToContext(role.getDerAttrs(), role.getAttrs(), jexlContext);
+ JexlUtil.addFieldsToContext(role, jexlContext);
+ JexlUtil.addAttrsToContext(role.getAttrs(), jexlContext);
+ JexlUtil.addDerAttrsToContext(role.getDerAttrs(), role.getAttrs(), jexlContext);
final String roleAccountLink =
- jexlUtil.evaluate(task.getResource().getRmapping().getAccountLink(), jexlContext);
+ JexlUtil.evaluate(task.getResource().getRmapping().getAccountLink(), jexlContext);
LOG.debug("AccountLink for {} is '{}'", role, roleAccountLink);
if (StringUtils.isNotBlank(roleAccountLink)) {
roleAccountLinks.add(roleAccountLink);
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=1540975&r1=1540974&r2=1540975&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 Nov 12 08:55:31 2013
@@ -46,11 +46,13 @@ import org.apache.syncope.core.persisten
import org.apache.syncope.core.persistence.dao.NotFoundException;
import org.apache.syncope.core.persistence.dao.ResourceDAO;
import org.apache.syncope.core.propagation.PropagationByResource;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
import org.apache.syncope.core.rest.data.AbstractAttributableDataBinder;
import org.apache.syncope.core.rest.data.RoleDataBinder;
import org.apache.syncope.core.rest.data.UserDataBinder;
import org.apache.syncope.core.util.AttributableUtil;
+import org.apache.syncope.core.util.JexlUtil;
import org.apache.syncope.core.util.MappingUtil;
import org.apache.syncope.core.util.VirAttrCache;
import org.apache.syncope.core.workflow.WorkflowResult;
@@ -488,6 +490,7 @@ public class PropagationManager {
* Prepare attributes for sending to a connector instance.
*
* @param <T> user / role
+ * @param attrUtil user / role
* @param subject given user / role
* @param password clear-text password
* @param vAttrsToBeRemoved virtual attributes to be removed
@@ -496,9 +499,10 @@ public class PropagationManager {
* @param resource target resource
* @return account link + prepared attributes
*/
- protected <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(final T subject,
- final String password, final Set<String> vAttrsToBeRemoved,
- final Map<String, AttributeMod> vAttrsToBeUpdated, final Boolean enable, final ExternalResource resource) {
+ protected <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(
+ final AttributableUtil attrUtil, final T subject, final String password,
+ final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+ final Boolean enable, final ExternalResource resource) {
LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
subject, resource, subject.getAttrs());
@@ -506,7 +510,6 @@ public class PropagationManager {
Set<Attribute> attributes = new HashSet<Attribute>();
String accountId = null;
- final AttributableUtil attrUtil = AttributableUtil.getInstance(subject);
for (AbstractMappingItem mapping : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
LOG.debug("Processing schema {}", mapping.getIntAttrName());
@@ -515,6 +518,7 @@ public class PropagationManager {
&& mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
|| (attrUtil.getType() == AttributableType.ROLE
&& mapping.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+
LOG.debug("Expire entry cache {}-{}", subject.getId(), mapping.getIntAttrName());
virAttrCache.expire(attrUtil.getType(), subject.getId(), mapping.getIntAttrName());
}
@@ -527,8 +531,7 @@ public class PropagationManager {
}
if (preparedAttribute.getValue() != null) {
- final Attribute alreadyAdded = AttributeUtil.find(preparedAttribute.getValue().getName(),
- attributes);
+ Attribute alreadyAdded = AttributeUtil.find(preparedAttribute.getValue().getName(), attributes);
if (alreadyAdded == null) {
attributes.add(preparedAttribute.getValue());
@@ -620,9 +623,35 @@ public class PropagationManager {
task.setPropagationMode(resource.getPropagationMode());
task.setOldAccountId(propByRes.getOldAccountId(resource.getName()));
- Map.Entry<String, Set<Attribute>> preparedAttrs = prepareAttributes(subject, password,
+ Map.Entry<String, Set<Attribute>> preparedAttrs = prepareAttributes(attrUtil, subject, password,
vAttrsToBeRemoved, vAttrsToBeUpdated, enable, resource);
task.setAccountId(preparedAttrs.getKey());
+
+ // Check if any of mandatory attributes (in the mapping) is missing or not received any value:
+ // if so, add special attributes that will be evaluated by PropagationTaskExecutor
+ List<String> mandatoryMissing = new ArrayList<String>();
+ List<String> mandatoryNullOrEmpty = new ArrayList<String>();
+ for (AbstractMappingItem item : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (!item.isAccountid()
+ && JexlUtil.evaluateMandatoryCondition(item.getMandatoryCondition(), subject)) {
+
+ Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
+ if (attr == null) {
+ mandatoryMissing.add(item.getExtAttrName());
+ } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
+ mandatoryNullOrEmpty.add(item.getExtAttrName());
+ }
+ }
+ }
+ if (!mandatoryMissing.isEmpty()) {
+ preparedAttrs.getValue().add(AttributeBuilder.build(
+ PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
+ }
+ if (!mandatoryNullOrEmpty.isEmpty()) {
+ preparedAttrs.getValue().add(AttributeBuilder.build(
+ PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
+ }
+
task.setAttributes(preparedAttrs.getValue());
tasks.add(task);
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java Tue Nov 12 08:55:31 2013
@@ -25,8 +25,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import org.apache.commons.jexl2.JexlContext;
-import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.mod.AbstractAttributableMod;
import org.apache.syncope.common.mod.AttributeMod;
@@ -138,9 +136,6 @@ public abstract class AbstractAttributab
@Autowired
protected PolicyDAO policyDAO;
- @Autowired
- private JexlUtil jexlUtil;
-
@SuppressWarnings("unchecked")
protected <T extends AbstractSchema> T getSchema(final String schemaName, final Class<T> reference) {
T result = null;
@@ -239,17 +234,6 @@ public abstract class AbstractAttributab
}
}
- private boolean evaluateMandatoryCondition(final String mandatoryCondition,
- final AbstractAttributable attributable) {
-
- JexlContext jexlContext = new MapContext();
- jexlUtil.addAttrsToContext(attributable.getAttrs(), jexlContext);
- jexlUtil.addDerAttrsToContext(attributable.getDerAttrs(), attributable.getAttrs(), jexlContext);
- jexlUtil.addVirAttrsToContext(attributable.getVirAttrs(), jexlContext);
-
- return Boolean.parseBoolean(jexlUtil.evaluate(mandatoryCondition, jexlContext));
- }
-
private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil, final ExternalResource resource,
final AbstractAttributable attributable, final String intAttrName, final IntMappingType intMappingType) {
@@ -259,7 +243,7 @@ public abstract class AbstractAttributab
attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
for (Iterator<AbstractMappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
final AbstractMappingItem mapping = itor.next();
- result |= evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
+ result |= JexlUtil.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
}
return result;
@@ -307,9 +291,9 @@ public abstract class AbstractAttributab
for (AbstractNormalSchema schema : normalSchemas) {
if (attributable.getAttr(schema.getName()) == null
&& !schema.isReadonly()
- && (evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
+ && (JexlUtil.evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
|| evaluateMandatoryCondition(attrUtil, attributable, schema.getName(),
- attrUtil.intMappingType()))) {
+ attrUtil.intMappingType()))) {
LOG.error("Mandatory schema " + schema.getName() + " not provided with values");
@@ -335,7 +319,7 @@ public abstract class AbstractAttributab
for (AbstractDerSchema derSchema : derSchemas) {
if (attributable.getDerAttr(derSchema.getName()) == null
&& evaluateMandatoryCondition(attrUtil, attributable, derSchema.getName(),
- attrUtil.derIntMappingType())) {
+ attrUtil.derIntMappingType())) {
LOG.error("Mandatory derived schema " + derSchema.getName() + " does not evaluate to any value");
@@ -362,7 +346,7 @@ public abstract class AbstractAttributab
if (attributable.getVirAttr(virSchema.getName()) == null
&& !virSchema.isReadonly()
&& evaluateMandatoryCondition(attrUtil, attributable, virSchema.getName(),
- attrUtil.virIntMappingType())) {
+ attrUtil.virIntMappingType())) {
LOG.error("Mandatory virtual schema " + virSchema.getName() + " not provided with values");
@@ -622,7 +606,6 @@ public abstract class AbstractAttributab
}
}
-
// 1.1 remove values
Set<Long> valuesToBeRemoved = new HashSet<Long>();
for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java Tue Nov 12 08:55:31 2013
@@ -63,15 +63,12 @@ public class ResourceDataBinder {
*/
private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
- private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = {"id", "mapping"};
+ private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = { "id", "mapping" };
@Autowired
private ConnInstanceDAO connInstanceDAO;
@Autowired
- private JexlUtil jexlUtil;
-
- @Autowired
private PolicyDAO policyDAO;
public ExternalResource create(final ResourceTO resourceTO) {
@@ -203,7 +200,7 @@ public class ResourceDataBinder {
}
// no mandatory condition implies mandatory condition false
- if (!jexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
+ if (!JexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
? "false" : itemTO.getMandatoryCondition())) {
SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java Tue Nov 12 08:55:31 2013
@@ -43,12 +43,9 @@ public class SchemaDataBinder {
@Autowired
private SchemaDAO schemaDAO;
- @Autowired
- private JexlUtil jexlUtil;
-
// --------------- NORMAL -----------------
private <T extends AbstractNormalSchema> void fill(final T schema, final SchemaTO schemaTO) {
- if (!jexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
+ if (!JexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
sce.getElements().add(schemaTO.getMandatoryCondition());
throw sce;
@@ -108,7 +105,7 @@ public class SchemaDataBinder {
requiredValuesMissing.getElements().add("expression");
scce.addException(requiredValuesMissing);
- } else if (!jexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
+ } else if (!JexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
ClientExceptionType.InvalidValues);
invalidMandatoryCondition.getElements().add(derSchemaTO.getExpression());
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java Tue Nov 12 08:55:31 2013
@@ -64,9 +64,9 @@ public class TaskDataBinder {
*/
private static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
- private static final String[] IGNORE_TASK_PROPERTIES = {"executions", "resource",};
+ private static final String[] IGNORE_TASK_PROPERTIES = { "executions", "resource", };
- private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = {"id", "task"};
+ private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = { "id", "task" };
@Autowired
private ResourceDAO resourceDAO;
@@ -77,17 +77,14 @@ public class TaskDataBinder {
@Autowired
private SchedulerFactoryBean scheduler;
- @Autowired
- private JexlUtil jexlUtil;
-
private void checkJexl(final AbstractAttributableTO attributableTO, final SyncopeClientException sce) {
for (AttributeTO attrTO : attributableTO.getAttrs()) {
- if (!attrTO.getValues().isEmpty() && !jexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
}
}
for (AttributeTO attrTO : attributableTO.getVirAttrs()) {
- if (!attrTO.getValues().isEmpty() && !jexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
}
}
@@ -100,10 +97,10 @@ public class TaskDataBinder {
if (taskTO.getUserTemplate() != null) {
UserTO template = taskTO.getUserTemplate();
- if (StringUtils.isNotBlank(template.getUsername()) && !jexlUtil.isExpressionValid(template.getUsername())) {
+ if (StringUtils.isNotBlank(template.getUsername()) && !JexlUtil.isExpressionValid(template.getUsername())) {
sce.getElements().add("Invalid JEXL: " + template.getUsername());
}
- if (StringUtils.isNotBlank(template.getPassword()) && !jexlUtil.isExpressionValid(template.getPassword())) {
+ if (StringUtils.isNotBlank(template.getPassword()) && !JexlUtil.isExpressionValid(template.getPassword())) {
sce.getElements().add("Invalid JEXL: " + template.getPassword());
}
@@ -116,7 +113,7 @@ public class TaskDataBinder {
if (taskTO.getRoleTemplate() != null) {
RoleTO template = taskTO.getRoleTemplate();
- if (StringUtils.isNotBlank(template.getName()) && !jexlUtil.isExpressionValid(template.getName())) {
+ if (StringUtils.isNotBlank(template.getName()) && !JexlUtil.isExpressionValid(template.getName())) {
sce.getElements().add("Invalid JEXL: " + template.getName());
}
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=1540975&r1=1540974&r2=1540975&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 Nov 12 08:55:31 2013
@@ -304,7 +304,6 @@ public class UserDataBinder extends Abst
if (membership == null) {
LOG.debug("Invalid membership id specified to be removed: {}", membershipId);
} else {
-
if (!membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
toBeDeprovisioned.addAll(membership.getSyncopeRole().getResourceNames());
}
@@ -315,7 +314,6 @@ public class UserDataBinder extends Abst
// some modifications compared to the one stored in the DB
membership = user.getMembership(membership.getSyncopeRole().getId());
if (membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
-
Set<Long> attributeIds = new HashSet<Long>(membership.getAttrs().size());
for (AbstractAttr attribute : membership.getAttrs()) {
attributeIds.add(attribute.getId());
@@ -327,7 +325,6 @@ public class UserDataBinder extends Abst
// remove derived attributes
for (AbstractDerAttr derAttr : membership.getDerAttrs()) {
-
attributeIds.add(derAttr.getId());
}
for (Long derAttrId : attributeIds) {
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=1540975&r1=1540974&r2=1540975&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 Nov 12 08:55:31 2013
@@ -240,6 +240,7 @@ public final class AttributableUtil {
}
}
break;
+
case PROPAGATION:
for (T item : items) {
if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()) {
@@ -247,7 +248,9 @@ public final class AttributableUtil {
}
}
break;
+
case BOTH:
+ default:
result.addAll(items);
}
Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java Tue Nov 12 08:55:31 2013
@@ -37,16 +37,16 @@ import org.apache.commons.lang3.StringUt
import org.apache.syncope.common.to.AbstractAttributableTO;
import org.apache.syncope.common.to.AttributeTO;
import org.apache.syncope.core.persistence.beans.AbstractAttr;
+import org.apache.syncope.core.persistence.beans.AbstractAttributable;
import org.apache.syncope.core.persistence.beans.AbstractDerAttr;
import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
/**
* @see http://commons.apache.org/jexl/reference/index.html
*/
-public class JexlUtil {
+public final class JexlUtil {
/**
* Logger.
@@ -54,15 +54,24 @@ public class JexlUtil {
*/
private static final Logger LOG = LoggerFactory.getLogger(JexlUtil.class);
- private static final String[] IGNORE_FIELDS = {"password", "clearPassword", "serialVersionUID", "class"};
+ private static final String[] IGNORE_FIELDS = { "password", "clearPassword", "serialVersionUID", "class" };
- @Autowired
- private JexlEngine jexlEngine;
+ private static JexlEngine jexlEngine;
- public boolean isExpressionValid(final String expression) {
+ private static JexlEngine getEngine() {
+ synchronized (LOG) {
+ if (jexlEngine == null) {
+ jexlEngine = ApplicationContextProvider.getApplicationContext().getBean(JexlEngine.class);
+ }
+ }
+
+ return jexlEngine;
+ }
+
+ public static boolean isExpressionValid(final String expression) {
boolean result;
try {
- jexlEngine.createExpression(expression);
+ getEngine().createExpression(expression);
result = true;
} catch (JexlException e) {
LOG.error("Invalid jexl expression: " + expression, e);
@@ -72,12 +81,12 @@ public class JexlUtil {
return result;
}
- public String evaluate(final String expression, final JexlContext jexlContext) {
+ public static String evaluate(final String expression, final JexlContext jexlContext) {
String result = "";
if (StringUtils.isNotBlank(expression) && jexlContext != null) {
try {
- Expression jexlExpression = jexlEngine.createExpression(expression);
+ Expression jexlExpression = getEngine().createExpression(expression);
Object evaluated = jexlExpression.evaluate(jexlContext);
if (evaluated != null) {
result = evaluated.toString();
@@ -92,7 +101,7 @@ public class JexlUtil {
return result;
}
- public JexlContext addFieldsToContext(final Object attributable, final JexlContext jexlContext) {
+ public static JexlContext addFieldsToContext(final Object attributable, final JexlContext jexlContext) {
JexlContext context = jexlContext == null ? new MapContext() : jexlContext;
try {
@@ -137,7 +146,7 @@ public class JexlUtil {
return context;
}
- public JexlContext addAttrsToContext(final Collection<? extends AbstractAttr> attrs,
+ public static JexlContext addAttrsToContext(final Collection<? extends AbstractAttr> attrs,
final JexlContext jexlContext) {
JexlContext context = jexlContext == null
@@ -160,7 +169,7 @@ public class JexlUtil {
return context;
}
- public JexlContext addDerAttrsToContext(final Collection<? extends AbstractDerAttr> derAttrs,
+ public static JexlContext addDerAttrsToContext(final Collection<? extends AbstractDerAttr> derAttrs,
final Collection<? extends AbstractAttr> attrs, final JexlContext jexlContext) {
JexlContext context = jexlContext == null
@@ -183,7 +192,7 @@ public class JexlUtil {
return context;
}
- public JexlContext addVirAttrsToContext(final Collection<? extends AbstractVirAttr> virAttrs,
+ public static JexlContext addVirAttrsToContext(final Collection<? extends AbstractVirAttr> virAttrs,
final JexlContext jexlContext) {
JexlContext context = jexlContext == null
@@ -206,7 +215,7 @@ public class JexlUtil {
return context;
}
- public String evaluate(final String expression, final AbstractAttributableTO attributableTO) {
+ public static String evaluate(final String expression, final AbstractAttributableTO attributableTO) {
final JexlContext context = new MapContext();
addFieldsToContext(attributableTO, context);
@@ -245,4 +254,22 @@ public class JexlUtil {
// Evaluate expression using the context prepared before
return evaluate(expression, context);
}
+
+ public static boolean evaluateMandatoryCondition(final String mandatoryCondition,
+ final AbstractAttributable attributable) {
+
+ JexlContext jexlContext = new MapContext();
+ addAttrsToContext(attributable.getAttrs(), jexlContext);
+ addDerAttrsToContext(attributable.getDerAttrs(), attributable.getAttrs(), jexlContext);
+ addVirAttrsToContext(attributable.getVirAttrs(), jexlContext);
+
+ return Boolean.parseBoolean(evaluate(mandatoryCondition, jexlContext));
+ }
+
+ /**
+ * Private default constructor, for static-only classes.
+ */
+ private JexlUtil() {
+ }
+
}
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=1540975&r1=1540974&r2=1540975&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 Nov 12 08:55:31 2013
@@ -124,7 +124,6 @@ public final class MappingUtil {
* @param vAttrsToBeRemoved virtual attributes to be removed
* @param vAttrsToBeUpdated virtual attributes to be added
* @return account link + prepared attribute
- * @throws ClassNotFoundException if schema type for given mapping does not exists in current class loader
*/
@SuppressWarnings("unchecked")
public static <T extends AbstractAttributable> Map.Entry<String, Attribute> prepareAttribute(
@@ -266,14 +265,11 @@ public final class MappingUtil {
// Evaluate AccountLink expression
String evalAccountLink = null;
if (StringUtils.isNotBlank(attrUtil.getAccountLink(resource))) {
- final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
- final JexlUtil jexlUtil = context.getBean(JexlUtil.class);
-
final JexlContext jexlContext = new MapContext();
- jexlUtil.addFieldsToContext(subject, jexlContext);
- jexlUtil.addAttrsToContext(subject.getAttrs(), jexlContext);
- jexlUtil.addDerAttrsToContext(subject.getDerAttrs(), subject.getAttrs(), jexlContext);
- evalAccountLink = jexlUtil.evaluate(attrUtil.getAccountLink(resource), jexlContext);
+ JexlUtil.addFieldsToContext(subject, jexlContext);
+ JexlUtil.addAttrsToContext(subject.getAttrs(), jexlContext);
+ JexlUtil.addDerAttrsToContext(subject.getDerAttrs(), subject.getAttrs(), jexlContext);
+ evalAccountLink = JexlUtil.evaluate(attrUtil.getAccountLink(resource), jexlContext);
}
// If AccountLink evaluates to an empty string, just use the provided AccountId as Name(),
Modified: syncope/trunk/core/src/main/resources/syncopeContext.xml
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/resources/syncopeContext.xml?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/resources/syncopeContext.xml (original)
+++ syncope/trunk/core/src/main/resources/syncopeContext.xml Tue Nov 12 08:55:31 2013
@@ -96,8 +96,6 @@ under the License.
<property name="silent" value="false"/>
</bean>
- <bean id="jexlUtil" class="org.apache.syncope.core.util.JexlUtil"/>
-
<bean id="virAttrCache" class="org.apache.syncope.core.util.VirAttrCache" scope="singleton">
<constructor-arg value="60"/>
<constructor-arg value="5000"/>
Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java Tue Nov 12 08:55:31 2013
@@ -33,7 +33,7 @@ import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.search.MembershipCond;
import org.apache.syncope.common.search.NodeCond;
import org.apache.syncope.common.to.MembershipTO;
Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java Tue Nov 12 08:55:31 2013
@@ -34,6 +34,7 @@ import java.util.Date;
import java.util.List;
import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.SerializationUtils;
import org.apache.syncope.common.mod.AttributeMod;
import org.apache.syncope.common.mod.MembershipMod;
@@ -49,6 +50,7 @@ import org.apache.syncope.common.to.Bulk
import org.apache.syncope.common.to.ConfigurationTO;
import org.apache.syncope.common.to.ConnObjectTO;
import org.apache.syncope.common.to.MappingItemTO;
+import org.apache.syncope.common.to.MappingTO;
import org.apache.syncope.common.to.MembershipTO;
import org.apache.syncope.common.to.PasswordPolicyTO;
import org.apache.syncope.common.to.PropagationStatusTO;
@@ -1990,7 +1992,7 @@ public class UserTestITCase extends Abst
@Test
public void issueSYNCOPE383() {
- // 1. create user on testdb and testdb2
+ // 1. create user without resources
UserTO userTO = getUniqueSampleTO("syncope383@apache.org");
userTO.getResources().clear();
userTO = createUser(userTO);
@@ -2022,6 +2024,8 @@ public class UserTestITCase extends Abst
public void issueSYNCOPE397() {
ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);
// change mapping of resource-csv
+ MappingTO origMapping = SerializationUtils.clone(csv.getUmapping());
+ assertNotNull(origMapping);
for (MappingItemTO item : csv.getUmapping().getItems()) {
if ("email".equals(item.getIntAttrName())) {
// unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
@@ -2072,20 +2076,22 @@ public class UserTestITCase extends Abst
//modify virtual attribute
userMod.getVirAttrsToRemove().add("virtualdata");
userMod.getVirAttrsToUpdate().add(attributeMod("virtualdata", "test@testoneone.com"));
- // check Syncope change password
+ // check Syncope change password
StatusMod pwdPropRequest = new StatusMod();
- //change pwd on external resource
- pwdPropRequest.getResourceNames().add("ws-target-resource-2");
- //change pwd on Syncope
pwdPropRequest.setOnSyncope(true);
+ pwdPropRequest.getResourceNames().add("ws-target-resource-2");
userMod.setPwdPropRequest(pwdPropRequest);
+
toBeUpdated = updateUser(userMod);
assertNotNull(toBeUpdated);
assertEquals("test@testoneone.com", toBeUpdated.getVirAttrs().get(0).getValues().get(0));
// check if propagates correctly with assertEquals on size of tasks list
-
assertEquals(2, toBeUpdated.getPropagationStatusTOs().size());
+
+ // restore mapping of resource-csv
+ csv.setUmapping(origMapping);
+ resourceService.update(csv.getName(), csv);
}
@Test
@@ -2252,4 +2258,32 @@ public class UserTestITCase extends Abst
assertNotNull(userTO);
}
+ @Test
+ public void issueSYNCOPE435() {
+ // 1. try to create user without password - fail
+ UserTO userTO = getUniqueSampleTO("syncope435@syncope.apache.org");
+ userTO.setPassword(null);
+
+ try {
+ createUser(userTO);
+ fail();
+ } catch (SyncopeClientException e) {
+ assertEquals(ClientExceptionType.InvalidSyncopeUser, e.getType());
+ }
+
+ userTO.setPassword("password123");
+ userTO = createUser(userTO);
+ assertNotNull(userTO);
+
+ // 2. try to update user by subscribing a resource - works but propagation is not even attempted
+ UserMod userMod = new UserMod();
+ userMod.getResourcesToAdd().add("ws-target-resource-1");
+
+ userTO = userService.update(userTO.getId(), userMod).readEntity(UserTO.class);
+ assertEquals(Collections.singleton("ws-target-resource-1"), userTO.getResources());
+ assertFalse(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful());
+ assertTrue(userTO.getPropagationStatusTOs().get(0).getFailureReason().
+ startsWith("Not attempted because there are mandatory attributes without value(s): [__PASSWORD__]"));
+ }
+
}