[SYNCOPE-1302] Added new expression model in mapping for internal attributes to acces...
authorskylark17 <matteo.alessandroni@tirasa.net>
Thu, 12 Apr 2018 13:21:30 +0000 (15:21 +0200)
committerskylark17 <matteo.alessandroni@tirasa.net>
Thu, 12 Apr 2018 15:00:39 +0000 (17:00 +0200)
client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationWizardBuilder.java
client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrName.java
core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/IntAttrNameParser.java
core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/IntAttrNameParserTest.java
src/main/asciidoc/reference-guide/concepts/externalresources.adoc

index 471e549..83f948f 100644 (file)
@@ -353,7 +353,9 @@ public class NotificationWizardBuilder extends AjaxWizardBuilder<NotificationWra
             recipientAttrName.addRequiredLabel();
             recipientAttrName.setTitle(getString("intAttrNameInfo.help")
                     + "<code>groups[groupName].attribute</code>, "
+                    + "<code>users[userName].attribute</code>, "
                     + "<code>anyObjects[anyObjectName].attribute</code>, "
+                    + "<code>relationships[relationshipType][anyType].attribute</code> or "
                     + "<code>memberships[groupName].attribute</code> or "
                     + "<code>privileges[applicationKey]</code>", true);
             add(recipientAttrName);
index c35be6a..ad63013 100644 (file)
@@ -152,7 +152,9 @@ public abstract class AbstractMappingPanel extends Panel {
                 Model.<String>of(),
                 Model.of(getString("intAttrNameInfo.help")
                         + "<code>groups[groupName].attribute</code>, "
+                        + "<code>users[userName].attribute</code>, "
                         + "<code>anyObjects[anyObjectName].attribute</code>, "
+                        + "<code>relationships[relationshipType][anyType].attribute</code> or "
                         + "<code>memberships[groupName].attribute</code> or "
                         + "<code>privileges[applicationKey]</code>"),
                 new PopoverConfig().withHtml(true).withPlacement(TooltipConfig.Placement.right)) {
index 1c42ec9..c504fd2 100644 (file)
@@ -35,12 +35,18 @@ public class IntAttrName {
 
     private String enclosingGroup;
 
+    private String relatedUser;
+
     private String relatedAnyObject;
 
     private String membershipOfGroup;
 
     private String privilegesOfApplication;
 
+    private String relationshipType;
+
+    private String relationshipAnyType;
+
     public AnyTypeKind getAnyTypeKind() {
         return anyTypeKind;
     }
@@ -81,6 +87,14 @@ public class IntAttrName {
         this.enclosingGroup = enclosingGroup;
     }
 
+    public String getRelatedUser() {
+        return relatedUser;
+    }
+
+    public void setRelatedUser(final String relatedUser) {
+        this.relatedUser = relatedUser;
+    }
+
     public String getRelatedAnyObject() {
         return relatedAnyObject;
     }
@@ -105,6 +119,22 @@ public class IntAttrName {
         this.privilegesOfApplication = privilegesOfApplication;
     }
 
+    public String getRelationshipType() {
+        return relationshipType;
+    }
+
+    public void setRelationshipType(final String relationshipType) {
+        this.relationshipType = relationshipType;
+    }
+
+    public String getRelationshipAnyType() {
+        return relationshipAnyType;
+    }
+
+    public void setRelationshipAnyType(final String relationshipAnyType) {
+        this.relationshipAnyType = relationshipAnyType;
+    }
+
     @Override
     public String toString() {
         return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
index 2d42609..914d248 100644 (file)
@@ -41,12 +41,19 @@ public class IntAttrNameParser {
     private static final Pattern ENCLOSING_GROUP_PATTERN = Pattern.compile(
             "^groups\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]\\.(.+)");
 
+    private static final Pattern RELATED_USER_PATTERN = Pattern.compile(
+            "^users\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]\\.(.+)");
+
     private static final Pattern RELATED_ANY_OBJECT_PATTERN = Pattern.compile(
             "^anyObjects\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]\\.(.+)");
 
     private static final Pattern MEMBERSHIP_PATTERN = Pattern.compile(
             "^memberships\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]\\.(.+)");
 
+    private static final Pattern RELATIONSHIP_PATTERN = Pattern.compile(
+            "^relationships\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]"
+            + "\\[(" + SyncopeConstants.NAME_PATTERN + ")\\]\\.(.+)");
+
     @Autowired
     private PlainSchemaDAO plainSchemaDAO;
 
@@ -124,7 +131,22 @@ public class IntAttrNameParser {
                         result.setMembershipOfGroup(matcher.group(1));
                         setFieldOrSchemaName(matcher.group(2), result.getAnyTypeKind(), result);
                     } else {
-                        throw new ParseException("Unparsable expression: " + intAttrName, 0);
+                        matcher = RELATED_USER_PATTERN.matcher(intAttrName);
+                        if (matcher.matches()) {
+                            result.setAnyTypeKind(AnyTypeKind.USER);
+                            result.setRelatedUser(matcher.group(1));
+                            setFieldOrSchemaName(matcher.group(2), result.getAnyTypeKind(), result);
+                        } else {
+                            matcher = RELATIONSHIP_PATTERN.matcher(intAttrName);
+                            if (matcher.matches()) {
+                                result.setAnyTypeKind(AnyTypeKind.ANY_OBJECT);
+                                result.setRelationshipType(matcher.group(1));
+                                result.setRelationshipAnyType(matcher.group(2));
+                                setFieldOrSchemaName(matcher.group(3), result.getAnyTypeKind(), result);
+                            } else {
+                                throw new ParseException("Unparsable expression: " + intAttrName, 0);
+                            }
+                        }
                     }
                 }
             }
index 83d8e76..23af3cc 100644 (file)
@@ -26,6 +26,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
@@ -39,6 +40,7 @@ import org.apache.syncope.common.lib.to.GroupableRelatableTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -48,9 +50,11 @@ import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.dao.RelationshipTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Application;
@@ -61,6 +65,8 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -124,6 +130,9 @@ public class MappingManagerImpl implements MappingManager {
     private GroupDAO groupDAO;
 
     @Autowired
+    private RelationshipTypeDAO relationshipTypeDAO;
+
+    @Autowired
     private RealmDAO realmDAO;
 
     @Autowired
@@ -409,10 +418,14 @@ public class MappingManagerImpl implements MappingManager {
 
         LOG.debug("Get internal values for {} as '{}' on {}", any, mapItem.getIntAttrName(), provision.getResource());
 
-        Any<?> reference = null;
+        List<Any<?>> references = new ArrayList<>();
         Membership<?> membership = null;
-        if (intAttrName.getEnclosingGroup() == null && intAttrName.getRelatedAnyObject() == null) {
-            reference = any;
+        if (intAttrName.getEnclosingGroup() == null
+                && intAttrName.getRelatedAnyObject() == null
+                && intAttrName.getRelationshipAnyType() == null
+                && intAttrName.getRelationshipType() == null
+                && intAttrName.getRelatedUser() == null) {
+            references.add(any);
         }
         if (any instanceof GroupableRelatable) {
             GroupableRelatable<?, ?, ?, ?, ?> groupableRelatable = (GroupableRelatable<?, ?, ?, ?, ?>) any;
@@ -423,7 +436,17 @@ public class MappingManagerImpl implements MappingManager {
                     LOG.warn("No membership for {} in {}, ignoring",
                             intAttrName.getEnclosingGroup(), groupableRelatable);
                 } else {
-                    reference = group;
+                    references.add(group);
+                }
+            } else if (intAttrName.getRelatedUser() != null) {
+                User user = userDAO.findByUsername(intAttrName.getRelatedUser());
+                if (user == null || user.getRelationships(groupableRelatable.getKey()).isEmpty()) {
+                    LOG.warn("No relationship for {} in {}, ignoring",
+                            intAttrName.getRelatedUser(), groupableRelatable);
+                } else if (groupableRelatable.getType().getKind() == AnyTypeKind.USER) {
+                    LOG.warn("Users cannot have relationship with other users, ignoring");
+                } else {
+                    references.add(user);
                 }
             } else if (intAttrName.getRelatedAnyObject() != null) {
                 AnyObject anyObject = anyObjectDAO.findByName(intAttrName.getRelatedAnyObject());
@@ -431,14 +454,28 @@ public class MappingManagerImpl implements MappingManager {
                     LOG.warn("No relationship for {} in {}, ignoring",
                             intAttrName.getRelatedAnyObject(), groupableRelatable);
                 } else {
-                    reference = anyObject;
+                    references.add(anyObject);
+                }
+            } else if (intAttrName.getRelationshipAnyType() != null && intAttrName.getRelationshipType() != null) {
+                RelationshipType relationshipType = relationshipTypeDAO.find(intAttrName.getRelationshipType());
+                final AnyType anyType = anyTypeDAO.find(intAttrName.getRelationshipAnyType());
+                if (relationshipType == null || groupableRelatable.getRelationships(relationshipType).isEmpty()) {
+                    LOG.warn("No relationship for type {} in {}, ignoring",
+                            intAttrName.getRelationshipType(), groupableRelatable);
+                } else if (anyType == null) {
+                    LOG.warn("No anyType {}, ignoring", intAttrName.getRelationshipAnyType());
+                } else {
+                    references.addAll(groupableRelatable.getRelationships(relationshipType).stream().
+                            filter(relationship -> anyType.equals(relationship.getRightEnd().getType())).
+                            map(Relationship::getRightEnd).
+                            collect(Collectors.toList()));
                 }
             } else if (intAttrName.getMembershipOfGroup() != null) {
                 Group group = groupDAO.findByName(intAttrName.getMembershipOfGroup());
                 membership = groupableRelatable.getMembership(group.getKey()).orElse(null);
             }
         }
-        if (reference == null) {
+        if (references.isEmpty()) {
             LOG.warn("Could not determine the reference instance for {}", mapItem.getIntAttrName());
             return Collections.emptyList();
         }
@@ -446,161 +483,163 @@ public class MappingManagerImpl implements MappingManager {
         List<PlainAttrValue> values = new ArrayList<>();
         boolean transform = true;
 
-        AnyUtils anyUtils = anyUtilsFactory.getInstance(reference);
-        if (intAttrName.getField() != null) {
-            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-
-            switch (intAttrName.getField()) {
-                case "key":
-                    attrValue.setStringValue(reference.getKey());
-                    values.add(attrValue);
-                    break;
+        for (Any<?> reference : references) {
+            AnyUtils anyUtils = anyUtilsFactory.getInstance(reference);
+            if (intAttrName.getField() != null) {
+                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
 
-                case "realm":
-                    attrValue.setStringValue(reference.getRealm().getFullPath());
-                    values.add(attrValue);
-                    break;
+                switch (intAttrName.getField()) {
+                    case "key":
+                        attrValue.setStringValue(reference.getKey());
+                        values.add(attrValue);
+                        break;
 
-                case "password":
-                    // ignore
-                    break;
+                    case "realm":
+                        attrValue.setStringValue(reference.getRealm().getFullPath());
+                        values.add(attrValue);
+                        break;
+
+                    case "password":
+                        // ignore
+                        break;
+
+                    case "userOwner":
+                    case "groupOwner":
+                        Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
+                                ? provision.getMapping()
+                                : null;
+                        Mapping gMapping = provision.getAnyType().equals(anyTypeDAO.findGroup())
+                                ? provision.getMapping()
+                                : null;
+
+                        if (reference instanceof Group) {
+                            Group group = (Group) reference;
+                            String groupOwnerValue = null;
+                            if (group.getUserOwner() != null && uMapping != null) {
+                                groupOwnerValue = getGroupOwnerValue(provision, group.getUserOwner());
+                            }
+                            if (group.getGroupOwner() != null && gMapping != null) {
+                                groupOwnerValue = getGroupOwnerValue(provision, group.getGroupOwner());
+                            }
 
-                case "userOwner":
-                case "groupOwner":
-                    Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
-                            ? provision.getMapping()
-                            : null;
-                    Mapping gMapping = provision.getAnyType().equals(anyTypeDAO.findGroup())
-                            ? provision.getMapping()
-                            : null;
-
-                    if (reference instanceof Group) {
-                        Group group = (Group) reference;
-                        String groupOwnerValue = null;
-                        if (group.getUserOwner() != null && uMapping != null) {
-                            groupOwnerValue = getGroupOwnerValue(provision, group.getUserOwner());
-                        }
-                        if (group.getGroupOwner() != null && gMapping != null) {
-                            groupOwnerValue = getGroupOwnerValue(provision, group.getGroupOwner());
+                            if (StringUtils.isNotBlank(groupOwnerValue)) {
+                                attrValue.setStringValue(groupOwnerValue);
+                                values.add(attrValue);
+                            }
                         }
+                        break;
 
-                        if (StringUtils.isNotBlank(groupOwnerValue)) {
-                            attrValue.setStringValue(groupOwnerValue);
+                    case "suspended":
+                        if (reference instanceof User) {
+                            attrValue.setBooleanValue(((User) reference).isSuspended());
                             values.add(attrValue);
                         }
-                    }
-                    break;
-
-                case "suspended":
-                    if (reference instanceof User) {
-                        attrValue.setBooleanValue(((User) reference).isSuspended());
-                        values.add(attrValue);
-                    }
-                    break;
+                        break;
 
-                case "mustChangePassword":
-                    if (reference instanceof User) {
-                        attrValue.setBooleanValue(((User) reference).isMustChangePassword());
-                        values.add(attrValue);
-                    }
-                    break;
+                    case "mustChangePassword":
+                        if (reference instanceof User) {
+                            attrValue.setBooleanValue(((User) reference).isMustChangePassword());
+                            values.add(attrValue);
+                        }
+                        break;
 
-                default:
-                    try {
-                        Object fieldValue = FieldUtils.readField(reference, intAttrName.getField(), true);
-                        if (fieldValue instanceof Date) {
-                            // needed because ConnId does not natively supports the Date type
-                            attrValue.setStringValue(DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.
-                                    format((Date) fieldValue));
-                        } else if (Boolean.TYPE.isInstance(fieldValue)) {
-                            attrValue.setBooleanValue((Boolean) fieldValue);
-                        } else if (Double.TYPE.isInstance(fieldValue) || Float.TYPE.isInstance(fieldValue)) {
-                            attrValue.setDoubleValue((Double) fieldValue);
-                        } else if (Long.TYPE.isInstance(fieldValue) || Integer.TYPE.isInstance(fieldValue)) {
-                            attrValue.setLongValue((Long) fieldValue);
+                    default:
+                        try {
+                            Object fieldValue = FieldUtils.readField(reference, intAttrName.getField(), true);
+                            if (fieldValue instanceof Date) {
+                                // needed because ConnId does not natively supports the Date type
+                                attrValue.setStringValue(DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.
+                                        format((Date) fieldValue));
+                            } else if (Boolean.TYPE.isInstance(fieldValue)) {
+                                attrValue.setBooleanValue((Boolean) fieldValue);
+                            } else if (Double.TYPE.isInstance(fieldValue) || Float.TYPE.isInstance(fieldValue)) {
+                                attrValue.setDoubleValue((Double) fieldValue);
+                            } else if (Long.TYPE.isInstance(fieldValue) || Integer.TYPE.isInstance(fieldValue)) {
+                                attrValue.setLongValue((Long) fieldValue);
+                            } else {
+                                attrValue.setStringValue(fieldValue.toString());
+                            }
+                            values.add(attrValue);
+                        } catch (Exception e) {
+                            LOG.error("Could not read value of '{}' from {}", intAttrName.getField(), reference, e);
+                        }
+                }
+            } else if (intAttrName.getSchemaType() != null) {
+                switch (intAttrName.getSchemaType()) {
+                    case PLAIN:
+                        PlainAttr<?> attr;
+                        if (membership == null) {
+                            attr = reference.getPlainAttr(intAttrName.getSchemaName()).orElse(null);
                         } else {
-                            attrValue.setStringValue(fieldValue.toString());
+                            attr = ((GroupableRelatable<?, ?, ?, ?, ?>) reference).getPlainAttr(
+                                    intAttrName.getSchemaName(), membership).orElse(null);
                         }
-                        values.add(attrValue);
-                    } catch (Exception e) {
-                        LOG.error("Could not read value of '{}' from {}", intAttrName.getField(), reference, e);
-                    }
-            }
-        } else if (intAttrName.getSchemaType() != null) {
-            switch (intAttrName.getSchemaType()) {
-                case PLAIN:
-                    PlainAttr<?> attr;
-                    if (membership == null) {
-                        attr = reference.getPlainAttr(intAttrName.getSchemaName()).orElse(null);
-                    } else {
-                        attr = ((GroupableRelatable<?, ?, ?, ?, ?>) reference).getPlainAttr(
-                                intAttrName.getSchemaName(), membership).orElse(null);
-                    }
-                    if (attr == null) {
-                        LOG.warn("Invalid PlainSchema {} or PlainAttr not found for {}",
-                                intAttrName.getSchemaName(), reference);
-                    } else {
-                        if (attr.getUniqueValue() != null) {
-                            values.add(anyUtils.clonePlainAttrValue(attr.getUniqueValue()));
-                        } else if (attr.getValues() != null) {
-                            attr.getValues().forEach(value -> values.add(anyUtils.clonePlainAttrValue(value)));
+                        if (attr == null) {
+                            LOG.warn("Invalid PlainSchema {} or PlainAttr not found for {}",
+                                    intAttrName.getSchemaName(), reference);
+                        } else {
+                            if (attr.getUniqueValue() != null) {
+                                values.add(anyUtils.clonePlainAttrValue(attr.getUniqueValue()));
+                            } else if (attr.getValues() != null) {
+                                attr.getValues().forEach(value -> values.add(anyUtils.clonePlainAttrValue(value)));
+                            }
                         }
-                    }
-                    break;
+                        break;
 
-                case DERIVED:
-                    DerSchema derSchema = derSchemaDAO.find(intAttrName.getSchemaName());
-                    if (derSchema == null) {
-                        LOG.warn("Invalid DerSchema: {}", intAttrName.getSchemaName());
-                    } else {
-                        String derValue = membership == null
-                                ? derAttrHandler.getValue(reference, derSchema)
-                                : derAttrHandler.getValue(reference, membership, derSchema);
-                        if (derValue != null) {
-                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                            attrValue.setStringValue(derValue);
-                            values.add(attrValue);
+                    case DERIVED:
+                        DerSchema derSchema = derSchemaDAO.find(intAttrName.getSchemaName());
+                        if (derSchema == null) {
+                            LOG.warn("Invalid DerSchema: {}", intAttrName.getSchemaName());
+                        } else {
+                            String derValue = membership == null
+                                    ? derAttrHandler.getValue(reference, derSchema)
+                                    : derAttrHandler.getValue(reference, membership, derSchema);
+                            if (derValue != null) {
+                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                                attrValue.setStringValue(derValue);
+                                values.add(attrValue);
+                            }
                         }
-                    }
-                    break;
+                        break;
 
-                case VIRTUAL:
-                    // virtual attributes don't get transformed
-                    transform = false;
+                    case VIRTUAL:
+                        // virtual attributes don't get transformed
+                        transform = false;
 
-                    VirSchema virSchema = virSchemaDAO.find(intAttrName.getSchemaName());
-                    if (virSchema == null) {
-                        LOG.warn("Invalid VirSchema: {}", intAttrName.getSchemaName());
-                    } else {
-                        LOG.debug("Expire entry cache {}-{}", reference, intAttrName.getSchemaName());
-                        virAttrCache.expire(
-                                reference.getType().getKey(), reference.getKey(), intAttrName.getSchemaName());
-
-                        List<String> virValues = membership == null
-                                ? virAttrHandler.getValues(reference, virSchema)
-                                : virAttrHandler.getValues(reference, membership, virSchema);
-                        virValues.forEach(virValue -> {
-                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                            attrValue.setStringValue(virValue);
-                            values.add(attrValue);
-                        });
-                    }
-                    break;
+                        VirSchema virSchema = virSchemaDAO.find(intAttrName.getSchemaName());
+                        if (virSchema == null) {
+                            LOG.warn("Invalid VirSchema: {}", intAttrName.getSchemaName());
+                        } else {
+                            LOG.debug("Expire entry cache {}-{}", reference, intAttrName.getSchemaName());
+                            virAttrCache.expire(
+                                    reference.getType().getKey(), reference.getKey(), intAttrName.getSchemaName());
+
+                            List<String> virValues = membership == null
+                                    ? virAttrHandler.getValues(reference, virSchema)
+                                    : virAttrHandler.getValues(reference, membership, virSchema);
+                            virValues.forEach(virValue -> {
+                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                                attrValue.setStringValue(virValue);
+                                values.add(attrValue);
+                            });
+                        }
+                        break;
 
-                default:
-            }
-        } else if (intAttrName.getPrivilegesOfApplication() != null && reference instanceof User) {
-            Application application = applicationDAO.find(intAttrName.getPrivilegesOfApplication());
-            if (application == null) {
-                LOG.warn("Invalid application: {}", intAttrName.getPrivilegesOfApplication());
-            } else {
-                userDAO.findAllRoles((User) reference).stream().
-                        flatMap(role -> role.getPrivileges(application).stream()).
-                        forEach(privilege -> {
-                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                            attrValue.setStringValue(privilege.getKey());
-                            values.add(attrValue);
-                        });
+                    default:
+                }
+            } else if (intAttrName.getPrivilegesOfApplication() != null && reference instanceof User) {
+                Application application = applicationDAO.find(intAttrName.getPrivilegesOfApplication());
+                if (application == null) {
+                    LOG.warn("Invalid application: {}", intAttrName.getPrivilegesOfApplication());
+                } else {
+                    userDAO.findAllRoles((User) reference).stream().
+                            flatMap(role -> role.getPrivileges(application).stream()).
+                            forEach(privilege -> {
+                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                                attrValue.setStringValue(privilege.getKey());
+                                values.add(attrValue);
+                            });
+                }
             }
         }
 
index 681743e..6154658 100644 (file)
@@ -523,6 +523,21 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                                         "No need to map virtual schema on linking resource");
                             }
                         }
+                        if (intAttrName.getRelatedUser() != null
+                                && item.getPurpose() != MappingPurpose.PROPAGATION) {
+
+                            invalidMapping.getElements().add(
+                                    "Only " + MappingPurpose.PROPAGATION.name()
+                                    + " allowed when referring to users");
+                        }
+                        if ((intAttrName.getRelationshipType() != null
+                                || intAttrName.getRelationshipAnyType() != null)
+                                && item.getPurpose() != MappingPurpose.PROPAGATION) {
+
+                            invalidMapping.getElements().add(
+                                    "Only " + MappingPurpose.PROPAGATION.name()
+                                    + " allowed when referring to relationships");
+                        }
                     } else {
                         LOG.error("'{}' not allowed", itemTO.getIntAttrName());
                         invalidMapping.getElements().add("'" + itemTO.getIntAttrName() + "' not allowed");
index 0316a12..205300f 100644 (file)
@@ -50,6 +50,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
 
         intAttrName = intAttrNameParser.parse("name", AnyTypeKind.GROUP);
         assertNotNull(intAttrName);
@@ -62,6 +65,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
 
         intAttrName = intAttrNameParser.parse("userOwner", AnyTypeKind.GROUP);
         assertNotNull(intAttrName);
@@ -74,6 +80,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
 
         intAttrName = intAttrNameParser.parse("name", AnyTypeKind.USER);
         assertNotNull(intAttrName);
@@ -93,6 +102,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
 
         intAttrName = intAttrNameParser.parse("cn", AnyTypeKind.ANY_OBJECT);
         assertNotNull(intAttrName);
@@ -104,6 +116,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
 
         intAttrName = intAttrNameParser.parse("rvirtualdata", AnyTypeKind.ANY_OBJECT);
         assertNotNull(intAttrName);
@@ -115,6 +130,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
     }
 
     @Test
@@ -129,6 +147,26 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
+    }
+
+    @Test
+    public void relatedUser() throws ParseException {
+        IntAttrName intAttrName = intAttrNameParser.parse("users[bellini].firstname", AnyTypeKind.USER);
+        assertNotNull(intAttrName);
+        assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
+        assertNull(intAttrName.getField());
+        assertEquals("firstname", intAttrName.getSchemaName());
+        assertEquals(SchemaType.PLAIN, intAttrName.getSchemaType());
+        assertEquals("bellini", intAttrName.getRelatedUser());
+        assertNull(intAttrName.getEnclosingGroup());
+        assertNull(intAttrName.getMembershipOfGroup());
+        assertNull(intAttrName.getRelatedAnyObject());
+        assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
     }
 
     @Test
@@ -143,6 +181,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertEquals("hp", intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
     }
 
     @Test
@@ -157,6 +198,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertEquals("top", intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
     }
 
     @Test
@@ -170,6 +214,26 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getRelatedAnyObject());
         assertEquals("mightyApp", intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getRelationshipType());
+        assertNull(intAttrName.getRelatedUser());
+    }
+
+    @Test
+    public void relationship() throws ParseException {
+        IntAttrName intAttrName = intAttrNameParser.parse("relationships[inclusion][PRINTER].location",
+                AnyTypeKind.USER);
+        assertNotNull(intAttrName);
+        assertEquals(AnyTypeKind.ANY_OBJECT, intAttrName.getAnyTypeKind());
+        assertNull(intAttrName.getField());
+        assertEquals("location", intAttrName.getSchemaName());
+        assertEquals(SchemaType.PLAIN, intAttrName.getSchemaType());
+        assertEquals("inclusion", intAttrName.getRelationshipType());
+        assertEquals("PRINTER", intAttrName.getRelationshipAnyType());
+        assertNull(intAttrName.getEnclosingGroup());
+        assertNull(intAttrName.getRelatedAnyObject());
+        assertNull(intAttrName.getPrivilegesOfApplication());
+        assertNull(intAttrName.getRelatedUser());
     }
 
     @Test
index 946fbc4..a4c83d2 100644 (file)
@@ -122,8 +122,12 @@ specified by an expression matching one of the following models:
 ** `schema` - resolves to the attribute for the given `schema`, owned by the mapped entity (user, group, any object)
 ** `groups[groupName].schema` - resolves to the attribute for the given `schema`, owned by the group with name
 `groupName`, if a membership for the mapped entity exists
+** `users[userName].schema` - resolves to the attribute for the given `schema`, owned by the user with name
+`userName`, if a relationship with the mapped entity exists
 ** `anyObjects[anyObjectName].schema` - resolves to the attribute for the given `schema`, owned by the any object with
 name `anyObjectName`, if a relationship with the mapped entity exists
+** `relationships[relationshipType][relationshipAnyType].schema` - resolves to the attribute for the given `schema`, 
+owned by the any object of type `relationshipAnyType`, if a relationship with the mapped entity and type `relationshipType` exists
 ** `memberships[groupName].schema` - resolves to the attribute for the given `schema`, owned by the membership for group
 `groupName` of the mapped entity (user, any object), if such a membership exists
 ** `privileges[applicationKey]` - resolves to the list of <<privileges,privileges>> related to the given application,