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 2016/06/14 16:22:31 UTC

[08/13] syncope git commit: [SYNCOPE-862] Preliminary work

[SYNCOPE-862] Preliminary work


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/0f738186
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/0f738186
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/0f738186

Branch: refs/heads/master
Commit: 0f738186c95c51e3aa861babc34f28d0627e773a
Parents: 47cdb82
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Tue May 31 17:59:00 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Tue Jun 14 18:21:53 2016 +0200

----------------------------------------------------------------------
 .../AnyObjectDisplayAttributesModalPanel.java   |   2 +-
 .../html/repeater/data/table/AttrColumn.java    |  19 +-
 .../data/table/ConnObjectAttrColumn.java        |  63 +++++
 .../console/wizards/any/AnyObjectDetails.java   |  53 ++++
 .../wizards/any/AnyObjectWizardBuilder.java     |  22 +-
 .../console/wizards/any/AnyWizardBuilder.java   |   3 -
 .../console/wizards/any/ConnObjectPanel.java    |   4 +-
 .../console/wizards/any/GroupDetails.java       |   4 +-
 .../client/console/wizards/any/Groups.java      |   1 -
 .../wizards/resources/ResourceMappingPanel.java |   1 +
 .../console/wizards/any/AnyObjectDetails.html   |  25 ++
 .../syncope/common/lib/AnyOperations.java       |  90 +++++--
 .../common/lib/patch/AnyObjectPatch.java        |  10 +
 .../syncope/common/lib/patch/AnyPatch.java      |  10 +-
 .../common/lib/patch/AttributablePatch.java     |  38 +++
 .../common/lib/patch/MembershipPatch.java       |  33 ++-
 .../syncope/common/lib/to/AnyObjectTO.java      |  10 +
 .../org/apache/syncope/common/lib/to/AnyTO.java |  34 ++-
 .../syncope/common/lib/to/AttributableTO.java   |  53 ++++
 .../syncope/common/lib/to/ConnObjectTO.java     |   9 +-
 .../syncope/common/lib/to/MembershipTO.java     |  75 +++++-
 .../syncope/common/lib/to/RelationshipTO.java   |  26 --
 .../common/lib/types/EntityViolationType.java   |   4 +-
 .../common/lib/types/IntMappingType.java        |   8 +-
 .../persistence/api/dao/AllowedSchemas.java     | 114 +++++++++
 .../core/persistence/api/dao/AnyDAO.java        |   3 +-
 .../core/persistence/api/dao/AnyObjectDAO.java  |   4 +
 .../core/persistence/api/entity/Any.java        |   2 +
 .../core/persistence/api/entity/AnyUtils.java   |   3 +-
 .../api/entity/GroupablePlainAttr.java          |  26 ++
 .../api/entity/GroupableRelatable.java          | 100 ++++++++
 .../api/entity/anyobject/APlainAttr.java        |   4 +-
 .../api/entity/anyobject/AnyObject.java         |  24 +-
 .../persistence/api/entity/user/UPlainAttr.java |   4 +-
 .../core/persistence/api/entity/user/User.java  |  32 +--
 .../persistence/jpa/dao/AbstractAnyDAO.java     |  56 +++--
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    |  34 +++
 .../core/persistence/jpa/dao/JPAConfDAO.java    |  12 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  32 ++-
 .../persistence/jpa/dao/JPAPlainAttrDAO.java    |   2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  28 ---
 .../jpa/entity/AbstractGroupableRelatable.java  | 158 ++++++++++++
 .../persistence/jpa/entity/JPAAnyUtils.java     |  13 +-
 .../jpa/entity/anyobject/JPAAPlainAttr.java     |  22 +-
 .../jpa/entity/anyobject/JPAAnyObject.java      |  95 +++----
 .../persistence/jpa/entity/conf/JPAConf.java    |   8 +-
 .../jpa/entity/group/JPAGPlainAttr.java         |   4 +-
 .../persistence/jpa/entity/group/JPAGroup.java  |  45 +++-
 .../jpa/entity/resource/JPAMappingItem.java     |   4 +
 .../jpa/entity/user/JPAUPlainAttr.java          |  22 +-
 .../persistence/jpa/entity/user/JPAUser.java    |  73 ++----
 .../jpa/validation/entity/AnyValidator.java     |  55 ++--
 .../entity/EntityValidationListener.java        |   5 +-
 .../entity/PlainAttrValueValidator.java         |   2 +-
 .../persistence/jpa/inner/AnyObjectTest.java    |   1 +
 .../persistence/jpa/inner/PlainAttrTest.java    |   2 +-
 .../core/persistence/jpa/outer/ConfTest.java    |  72 ++++++
 .../core/persistence/jpa/outer/GroupTest.java   |   1 +
 .../core/persistence/jpa/outer/UserTest.java    |  91 ++++++-
 .../test/resources/domains/MasterContent.xml    |  11 +-
 .../core/provisioning/api/DerAttrHandler.java   |  23 +-
 .../core/provisioning/api/VirAttrHandler.java   |  28 ++-
 .../provisioning/java/DerAttrHandlerImpl.java   |  32 ++-
 .../provisioning/java/MappingManagerImpl.java   |  20 ++
 .../provisioning/java/VirAttrHandlerImpl.java   |  36 ++-
 .../java/data/AbstractAnyDataBinder.java        | 248 ++++++++++++-------
 .../java/data/AnyObjectDataBinderImpl.java      | 115 +++++++--
 .../java/data/GroupDataBinderImpl.java          |   6 +-
 .../java/data/UserDataBinderImpl.java           |  90 +++++--
 .../java/job/SetUMembershipsJob.java            |   3 +-
 .../provisioning/java/pushpull/PullUtils.java   |   8 +
 .../java/utils/ConnObjectUtils.java             |   2 +-
 .../activiti/ActivitiUserWorkflowAdapter.java   |   2 +-
 fit/build-tools/src/main/resources/testdb.sql   |   1 +
 .../syncope/fit/console/AnyObjectsITCase.java   |   6 +-
 .../syncope/fit/console/BulkActionITCase.java   |   2 +-
 .../fit/console/DisplayAttributesITCase.java    |   4 +-
 .../syncope/fit/core/AnyObjectITCase.java       |   1 +
 .../syncope/fit/core/AuthenticationITCase.java  |   1 +
 .../syncope/fit/core/CamelRouteITCase.java      |   6 +-
 .../syncope/fit/core/MembershipITCase.java      | 206 +++++++++++++++
 .../org/apache/syncope/fit/core/UserITCase.java |  13 +-
 .../apache/syncope/fit/core/UserSelfITCase.java |   3 +-
 .../resources/scriptedsql/CreateScript.groovy   |   3 +-
 .../resources/scriptedsql/SchemaScript.groovy   |   1 +
 .../resources/scriptedsql/SearchScript.groovy   |   2 +-
 .../resources/scriptedsql/SyncScript.groovy     |   3 +-
 .../resources/scriptedsql/TestScript.groovy     |   2 +-
 .../resources/scriptedsql/UpdateScript.groovy   |   7 +-
 89 files changed, 2085 insertions(+), 550 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
index b99a323..39f30ad 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
@@ -35,7 +35,7 @@ public class AnyObjectDisplayAttributesModalPanel<T extends Serializable> extend
 
     private static final long serialVersionUID = 5194630813773543054L;
 
-    public static final String[] DEFAULT_SELECTION = { "key" };
+    public static final String[] DEFAULT_SELECTION = { "key", "name" };
 
     public AnyObjectDisplayAttributesModalPanel(
             final BaseModal<T> modal,

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
index 9a90ef6..b756a05 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
@@ -26,10 +26,9 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.AttributableTO;
 
-public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String> {
+public class AttrColumn<T extends AttributableTO> extends AbstractColumn<T, String> {
 
     private static final long serialVersionUID = 2624734332447371372L;
 
@@ -59,20 +58,14 @@ public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String
                 break;
 
             case DERIVED:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getDerAttrMap().containsKey(name)) {
-                        values = obj.getDerAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getDerAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getDerAttrMap().get(name).getValues();
                 }
                 break;
 
             case VIRTUAL:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getVirAttrMap().containsKey(name)) {
-                        values = obj.getVirAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getVirAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getVirAttrMap().get(name).getValues();
                 }
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
new file mode 100644
index 0000000..56ead58
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+
+public class ConnObjectAttrColumn extends AbstractColumn<ConnObjectTO, String> {
+
+    private static final long serialVersionUID = 2624734332447371372L;
+
+    private final String name;
+
+    public ConnObjectAttrColumn(final String name, final SchemaType schemaType) {
+        // set sortProperty to schematype#name (e.g. derivedSchema#cn, 
+        // for use with SortableUserProviderComparator.AttrModel#getObject)
+        super(new ResourceModel(name, name), schemaType.name() + "#" + name);
+        this.name = name;
+    }
+
+    @Override
+    public void populateItem(
+            final Item<ICellPopulator<ConnObjectTO>> cellItem,
+            final String componentId,
+            final IModel<ConnObjectTO> rowModel) {
+
+        List<String> values = null;
+        if (rowModel.getObject().getPlainAttrMap().containsKey(name)) {
+            values = rowModel.getObject().getPlainAttrMap().get(name).getValues();
+        }
+
+        if (values == null || values.isEmpty()) {
+            cellItem.add(new Label(componentId, ""));
+        } else if (values.size() == 1) {
+            cellItem.add(new Label(componentId, values.get(0)));
+        } else {
+            cellItem.add(new Label(componentId, values.toString()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
new file mode 100644
index 0000000..5d149e7
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wizards.any;
+
+import java.util.List;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+
+public class AnyObjectDetails extends Details<AnyObjectTO> {
+
+    private static final long serialVersionUID = 855618618337931784L;
+
+    public AnyObjectDetails(
+            final AnyWrapper<AnyObjectTO> wrapper,
+            final IModel<List<StatusBean>> statusModel,
+            final boolean templateMode,
+            final boolean includeStatusPanel,
+            final PageReference pageRef) {
+
+        super(wrapper, statusModel, includeStatusPanel, pageRef);
+
+        AnyObjectTO anyObjectTO = wrapper.getInnerObject();
+
+        AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
+                new PropertyModel<String>(anyObjectTO, "name"), false);
+        if (templateMode) {
+            name.enableJexlHelp();
+        } else {
+            name.addRequiredLabel();
+        }
+        this.add(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
index f92bb31..5952017 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
@@ -19,20 +19,27 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.io.Serializable;
-
+import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.layout.AnyObjectForm;
 import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.rest.AnyObjectRestClient;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.model.util.ListModel;
 
 public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implements AnyObjectForm {
 
     private static final long serialVersionUID = -2480279868319546243L;
 
+    private final AnyObjectRestClient anyObjectRestClient = new AnyObjectRestClient();
+
     public AnyObjectWizardBuilder(
             final AnyObjectTO anyObjectTO,
             final List<String> anyTypeClasses,
@@ -48,7 +55,7 @@ public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implem
 
         ProvisioningResult<AnyObjectTO> actual;
         if (inner.getKey() == null) {
-            actual = anyObjectRestClient.create(AnyObjectTO.class.cast(inner));
+            actual = anyObjectRestClient.create(inner);
         } else {
             AnyObjectPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
 
@@ -63,4 +70,15 @@ public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implem
 
         return actual;
     }
+
+    @Override
+    protected AnyObjectWizardBuilder addOptionalDetailsPanel(
+            final AnyWrapper<AnyObjectTO> modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new AnyObjectDetails(
+                modelObject,
+                new ListModel<>(Collections.<StatusBean>emptyList()),
+                mode == AjaxWizard.Mode.TEMPLATE,
+                modelObject.getInnerObject().getKey() != null, pageRef));
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
index a63a757..41fa6bb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
@@ -26,7 +26,6 @@ import org.apache.syncope.client.console.layout.AnyForm;
 import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
 import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
 import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
-import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -40,8 +39,6 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde
 
     private static final long serialVersionUID = -2480279868319546243L;
 
-    protected final AnyObjectRestClient anyObjectRestClient = new AnyObjectRestClient();
-
     protected final List<String> anyTypeClasses;
 
     protected AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo;

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
index 14e3e33..49f6801 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
@@ -57,7 +57,7 @@ public class ConnObjectPanel extends Panel {
             protected List<AttrTO> load() {
                 List<AttrTO> attrs = new ArrayList<>(connObjectTOs == null || connObjectTOs.getRight() == null
                         ? Collections.<AttrTO>emptyList()
-                        : connObjectTOs.getRight().getPlainAttrs());
+                        : connObjectTOs.getRight().getAttrs());
 
                 Collections.sort(attrs, new Comparator<AttrTO>() {
 
@@ -77,7 +77,7 @@ public class ConnObjectPanel extends Panel {
             }
         };
 
-        final Map<String, AttrTO> beforeProfile = connObjectTOs.getLeft() == null
+        final Map<String, AttrTO> beforeProfile = connObjectTOs == null || connObjectTOs.getLeft() == null
                 ? null
                 : connObjectTOs.getLeft().getPlainAttrMap();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
index 7b4f4ce..e61e89c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
@@ -39,9 +39,9 @@ public class GroupDetails extends Details<GroupTO> {
 
         super(wrapper, statusModel, includeStatusPanel, pageRef);
 
-        final GroupTO groupTO = GroupWrapper.class.cast(wrapper).getInnerObject();
+        GroupTO groupTO = GroupWrapper.class.cast(wrapper).getInnerObject();
 
-        final AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
+        AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
                 new PropertyModel<String>(groupTO, "name"), false);
         if (templateMode) {
             name.enableJexlHelp();

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
index 8c84cda..401f8e0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
@@ -105,7 +105,6 @@ public class Groups extends WizardStep {
                     public MembershipTO transform(final GroupTO input) {
                         return new MembershipTO.Builder().
                                 group(input.getKey(), input.getName()).
-                                left(anyTO.getKey(), anyTO.getType()).
                                 build();
                     }
                 }, new ArrayList<MembershipTO>());

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
index 5020bd7..06ea7c8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
@@ -570,6 +570,7 @@ public class ResourceMappingPanel extends Panel {
                 case GroupKey:
                 case GroupName:
                 case AnyObjectKey:
+                case AnyObjectName:
                 default:
                     toBeUpdated.setRequired(false);
                     toBeUpdated.setEnabled(false);

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
new file mode 100644
index 0000000..4d821fe
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
@@ -0,0 +1,25 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div class="form-group">
+      <span wicket:id="name"/>
+    </div>
+  </wicket:extend>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
index 39fbc63..1f985a4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import org.apache.commons.collections4.Closure;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
@@ -173,7 +174,10 @@ public final class AnyOperations {
 
         diff(updated, original, result, incremental);
 
-        // 1. relationships
+        // 1. name
+        result.setName(replacePatchItem(updated.getName(), original.getName(), new StringReplacePatchItem()));
+
+        // 2. relationships
         Map<Pair<String, String>, RelationshipTO> updatedRels = updated.getRelationshipMap();
         Map<Pair<String, String>, RelationshipTO> originalRels = original.getRelationshipMap();
 
@@ -193,21 +197,21 @@ public final class AnyOperations {
             }
         }
 
-        // 2. memberships
+        // 3. memberships
         Map<String, MembershipTO> updatedMembs = updated.getMembershipMap();
         Map<String, MembershipTO> originalMembs = original.getMembershipMap();
 
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -294,14 +298,14 @@ public final class AnyOperations {
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -410,7 +414,7 @@ public final class AnyOperations {
 
         // 2. plain attributes
         result.getPlainAttrs().clear();
-        result.getPlainAttrs().addAll(AnyOperations.patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
+        result.getPlainAttrs().addAll(patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
 
         // 3. virtual attributes
         result.getVirAttrs().clear();
@@ -432,7 +436,7 @@ public final class AnyOperations {
 
     public static GroupTO patch(final GroupTO groupTO, final GroupPatch groupPatch) {
         GroupTO result = SerializationUtils.clone(groupTO);
-        AnyOperations.patch(groupTO, groupPatch, result);
+        patch(groupTO, groupPatch, result);
 
         if (groupPatch.getName() != null) {
             result.setName(groupPatch.getName().getValue());
@@ -454,10 +458,10 @@ public final class AnyOperations {
 
     public static AnyObjectTO patch(final AnyObjectTO anyObjectTO, final AnyObjectPatch anyObjectPatch) {
         AnyObjectTO result = SerializationUtils.clone(anyObjectTO);
-        AnyOperations.patch(anyObjectTO, anyObjectPatch, result);
+        patch(anyObjectTO, anyObjectPatch, result);
 
         // 1. relationships
-        for (final RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -470,12 +474,37 @@ public final class AnyOperations {
 
         // 2. memberships
         for (final MembershipPatch membPatch : anyObjectPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }
@@ -485,7 +514,7 @@ public final class AnyOperations {
 
     public static UserTO patch(final UserTO userTO, final UserPatch userPatch) {
         UserTO result = SerializationUtils.clone(userTO);
-        AnyOperations.patch(userTO, userPatch, result);
+        patch(userTO, userPatch, result);
 
         // 1. password
         if (userPatch.getPassword() != null) {
@@ -498,7 +527,7 @@ public final class AnyOperations {
         }
 
         // 3. relationships
-        for (final RelationshipPatch relPatch : userPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : userPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -511,12 +540,37 @@ public final class AnyOperations {
 
         // 4. memberships
         for (final MembershipPatch membPatch : userPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
index e473e06..ddb4ac3 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
@@ -32,10 +32,20 @@ public class AnyObjectPatch extends AnyPatch {
 
     private static final long serialVersionUID = -1644118942622556097L;
 
+    private StringReplacePatchItem name;
+
     private final Set<RelationshipPatch> relationships = new HashSet<>();
 
     private final Set<MembershipPatch> memberships = new HashSet<>();
 
+    public StringReplacePatchItem getName() {
+        return name;
+    }
+
+    public void setName(final StringReplacePatchItem name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
index 3ec141d..78e61dd 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
@@ -30,7 +30,7 @@ import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlType
-public abstract class AnyPatch extends AbstractBaseBean {
+public abstract class AnyPatch extends AbstractBaseBean implements AttributablePatch {
 
     private static final long serialVersionUID = -7445489774552440544L;
 
@@ -70,16 +70,12 @@ public abstract class AnyPatch extends AbstractBaseBean {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "plainAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
+    @Override
     public Set<AttrPatch> getPlainAttrs() {
         return plainAttrs;
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
new file mode 100644
index 0000000..fa9d189
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.patch;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public interface AttributablePatch {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrPatch> getPlainAttrs();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
index b29a6de..0ed42c1 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
@@ -18,13 +18,15 @@
  */
 package org.apache.syncope.common.lib.patch;
 
+import java.util.HashSet;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlRootElement(name = "membershipPatch")
 @XmlType
-public class MembershipPatch extends AbstractPatch {
+public class MembershipPatch extends AbstractPatch implements AttributablePatch {
 
     private static final long serialVersionUID = -6783121761221554433L;
 
@@ -35,20 +37,33 @@ public class MembershipPatch extends AbstractPatch {
             return new MembershipPatch();
         }
 
-        public Builder membershipTO(final MembershipTO membershipTO) {
-            getInstance().setMembershipTO(membershipTO);
+        public Builder group(final String group) {
+            getInstance().setGroup(group);
             return this;
         }
     }
 
-    private MembershipTO membershipTO;
+    private String group;
 
-    public MembershipTO getMembershipTO() {
-        return membershipTO;
+    private final Set<AttrPatch> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
+    public String getGroup() {
+        return group;
     }
 
-    public void setMembershipTO(final MembershipTO membershipTO) {
-        this.membershipTO = membershipTO;
+    public void setGroup(final String group) {
+        this.group = group;
     }
 
+    @Override
+    public Set<AttrPatch> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
index f652d76..d0bf7d4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
@@ -37,12 +37,22 @@ public class AnyObjectTO extends AnyTO implements RelatableTO, GroupableTO {
 
     private static final long serialVersionUID = 8841697496476959639L;
 
+    private String name;
+
     private final List<RelationshipTO> relationships = new ArrayList<>();
 
     private final List<MembershipTO> memberships = new ArrayList<>();
 
     private final List<String> dynGroups = new ArrayList<>();
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
index 4651835..7732bcc 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.common.lib.to;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import java.util.ArrayList;
@@ -30,15 +29,13 @@ import java.util.Map;
 import java.util.Set;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 
-@XmlRootElement(name = "any")
 @XmlType
 @XmlSeeAlso({ UserTO.class, GroupTO.class, AnyObjectTO.class })
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
-public abstract class AnyTO extends ConnObjectTO implements EntityTO {
+public abstract class AnyTO extends AbstractAnnotatedBean implements EntityTO, AttributableTO {
 
     private static final long serialVersionUID = -754311920679872084L;
 
@@ -52,6 +49,8 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
 
     private final List<String> auxClasses = new ArrayList<>();
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
     private final Set<AttrTO> derAttrs = new HashSet<>();
 
     private final Set<AttrTO> virAttrs = new HashSet<>();
@@ -99,14 +98,27 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "derAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrs")
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
     public Set<AttrTO> getDerAttrs() {
         return derAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getDerAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
         for (AttrTO attributeTO : derAttrs) {
@@ -116,14 +128,12 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return Collections.unmodifiableMap(result);
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getVirAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
         for (AttrTO attributeTO : virAttrs) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
new file mode 100644
index 0000000..51ee0fc
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+public interface AttributableTO {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrTO> getPlainAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getPlainAttrMap();
+
+    @XmlElementWrapper(name = "derAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrs")
+    Set<AttrTO> getDerAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getDerAttrMap();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getVirAttrMap();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
index 82878f8..8f65b70 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
@@ -29,19 +29,20 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
 
 @XmlRootElement(name = "connObject")
 @XmlType
-public class ConnObjectTO extends AbstractAnnotatedBean {
+public class ConnObjectTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = 5139554911265442497L;
 
     private final Set<AttrTO> attrs = new LinkedHashSet<>();
 
-    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElementWrapper(name = "attrs")
     @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
-    public Set<AttrTO> getPlainAttrs() {
+    @JsonProperty("attrs")
+    public Set<AttrTO> getAttrs() {
         return attrs;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
index 6ded46b..58f3d9d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
@@ -18,13 +18,19 @@
  */
 package org.apache.syncope.common.lib.to;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 @XmlRootElement(name = "membership")
 @XmlType
-public class MembershipTO extends RelationshipTO {
+public class MembershipTO extends RelationshipTO implements AttributableTO {
 
     private static final long serialVersionUID = 5992828670273935861L;
 
@@ -32,12 +38,6 @@ public class MembershipTO extends RelationshipTO {
 
         private final MembershipTO instance = new MembershipTO();
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder group(final String groupKey) {
             instance.setRightKey(groupKey);
             return this;
@@ -56,6 +56,12 @@ public class MembershipTO extends RelationshipTO {
 
     private String groupName;
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> derAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
     @Override
     public String getType() {
         return "Membership";
@@ -76,6 +82,15 @@ public class MembershipTO extends RelationshipTO {
         // ignore
     }
 
+    @JsonIgnore
+    public String getGroupKey() {
+        return getRightKey();
+    }
+
+    public void setGroupKey(final String groupKey) {
+        setRightKey(groupKey);
+    }
+
     public String getGroupName() {
         return groupName;
     }
@@ -83,4 +98,50 @@ public class MembershipTO extends RelationshipTO {
     public void setGroupName(final String groupName) {
         this.groupName = groupName;
     }
+
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getDerAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
+        for (AttrTO attributeTO : derAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getVirAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
+        for (AttrTO attributeTO : virAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
index 29326c2..fc5de4f 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
@@ -37,12 +37,6 @@ public class RelationshipTO extends AbstractBaseBean {
             return this;
         }
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder right(final String rightType, final String rightKey) {
             instance.setRightType(rightType);
             instance.setRightKey(rightKey);
@@ -56,10 +50,6 @@ public class RelationshipTO extends AbstractBaseBean {
 
     private String type;
 
-    private String leftType;
-
-    private String leftKey;
-
     private String rightType;
 
     private String rightKey;
@@ -72,22 +62,6 @@ public class RelationshipTO extends AbstractBaseBean {
         this.type = type;
     }
 
-    public String getLeftType() {
-        return leftType;
-    }
-
-    public void setLeftType(final String leftType) {
-        this.leftType = leftType;
-    }
-
-    public String getLeftKey() {
-        return leftKey;
-    }
-
-    public void setLeftKey(final String leftKey) {
-        this.leftKey = leftKey;
-    }
-
     public String getRightType() {
         return rightType;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
index 7532730..db3e329 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
@@ -43,9 +43,7 @@ public enum EntityViolationType {
     InvalidSchemaMultivalueUnique("org.apache.syncope.core.persistence.validation.schema.multivalueUnique"),
     InvalidSchedTask("org.apache.syncope.core.persistence.validation.schedtask"),
     InvalidProvisioningTask("org.apache.syncope.core.persistence.validation.provisioningtask"),
-    InvalidPlainSchema("org.apache.syncope.core.persistence.validation.attrvalue.plainSchema"),
-    InvalidDerSchema("org.apache.syncope.core.persistence.validation.attrvalue.derSchema"),
-    InvalidVirSchema("org.apache.syncope.core.persistence.validation.attrvalue.virSchema"),
+    InvalidPlainAttr("org.apache.syncope.core.persistence.validation.plainattr"),
     InvalidUsername("org.apache.syncope.core.persistence.validation.user.username"),
     InvalidValueList("org.apache.syncope.core.persistence.validation.attr.valueList"),
     MoreThanOneNonNull("org.apache.syncope.core.persistence.validation.attrvalue.moreThanOneNonNull");

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
index eccb89d..8553348 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
@@ -56,7 +56,8 @@ public enum IntMappingType {
     AnyObjectPlainSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectDerivedSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectVirtualSchema(AnyTypeKind.ANY_OBJECT),
-    AnyObjectKey(AnyTypeKind.ANY_OBJECT);
+    AnyObjectKey(AnyTypeKind.ANY_OBJECT),
+    AnyObjectName(AnyTypeKind.ANY_OBJECT);
 
     private final AnyTypeKind anyTypeKind;
 
@@ -119,7 +120,7 @@ public enum IntMappingType {
     public static Set<IntMappingType> getEmbedded() {
         return EnumSet.of(IntMappingType.UserKey, IntMappingType.Username, IntMappingType.Password,
                 IntMappingType.GroupKey, IntMappingType.GroupName, IntMappingType.GroupOwnerSchema,
-                IntMappingType.AnyObjectKey);
+                IntMappingType.AnyObjectKey, IntMappingType.AnyObjectName);
     }
 
     /**
@@ -195,7 +196,8 @@ public enum IntMappingType {
         AnyObjectPlainSchema,
         AnyObjectDerivedSchema,
         AnyObjectVirtualSchema,
-        AnyObjectKey;
+        AnyObjectKey,
+        AnyObjectName;
 
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
new file mode 100644
index 0000000..6c04ac4
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.PredicateUtils;
+import org.apache.commons.collections4.SetUtils;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+
+public class AllowedSchemas<S extends Schema> {
+
+    private final Set<S> forSelf = new HashSet<>();
+
+    private final Map<Group, Set<S>> forMemberships = new HashMap<>();
+
+    public Set<S> getForSelf() {
+        return forSelf;
+    }
+
+    public Set<S> getForMembership(final Group group) {
+        return SetUtils.emptyIfNull(forMemberships.get(group));
+    }
+
+    public Map<Group, Set<S>> getForMemberships() {
+        return forMemberships;
+    }
+
+    public boolean forSelfContains(final S schema) {
+        return forSelf.contains(schema);
+    }
+
+    public boolean forSelfContains(final String schema) {
+        return IterableUtils.matchesAny(forSelf, new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final Group group, final S schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), PredicateUtils.equalPredicate(schema));
+    }
+
+    public boolean forMembershipsContains(final S schema) {
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (entry.getValue().contains(schema)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean forMembershipsContains(final Group group, final String schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final String schema) {
+        KeyMatches keyMatches = new KeyMatches(schema);
+
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (IterableUtils.matchesAny(entry.getValue(), keyMatches)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean contains(final S schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    public boolean contains(final String schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    private class KeyMatches implements Predicate<S> {
+
+        private final String schema;
+
+        KeyMatches(final String schema) {
+            this.schema = schema;
+        }
+
+        @Override
+        public boolean evaluate(final S object) {
+            return object.getKey().equals(schema);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index b6d78fd..6b2fd4e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -72,7 +71,7 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
      */
     List<A> findAll(Set<String> adminRealms, int page, int itemsPerPage, List<OrderByClause> orderBy);
 
-    <S extends Schema> Collection<S> findAllowedSchemas(A any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> findAllowedSchemas(A any, Class<S> reference);
 
     int count(Set<String> adminRealms);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
index bdf9642..c24b37d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
@@ -40,6 +40,10 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {
 
     Map<String, Integer> countByRealm(AnyType anyType);
 
+    AnyObject findByName(String name);
+
+    AnyObject authFindByName(String name);
+
     List<Group> findDynGroupMemberships(AnyObject anyObject);
 
     List<ARelationship> findARelationships(AnyObject anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
index b1580e3..82359e9 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
@@ -41,6 +41,8 @@ public interface Any<P extends PlainAttr<?>> extends AnnotatedEntity {
 
     boolean add(P attr);
 
+    boolean remove(P attr);
+
     P getPlainAttr(String plainSchemaName);
 
     List<? extends P> getPlainAttrs();

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 377f7fe..0e0c8cc 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface AnyUtils {
@@ -52,5 +53,5 @@ public interface AnyUtils {
 
     Set<ExternalResource> getAllResources(Any<?> any);
 
-    <S extends Schema> Set<S> getAllowedSchemas(Any<?> any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> getAllowedSchemas(Any<?> any, Class<S> reference);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
new file mode 100644
index 0000000..7e345a5
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+public interface GroupablePlainAttr<A extends Any<?>, M extends Membership<A>> extends PlainAttr<A> {
+
+    M getMembership();
+
+    void setMembership(M membership);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
new file mode 100644
index 0000000..147f469
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface GroupableRelatable<
+        L extends Any<P>, 
+        M extends Membership<L>, 
+        P extends GroupablePlainAttr<L, M>,
+        R extends Any<?>,
+        REL extends Relationship<L, R>> extends Any<P> {
+
+    @Override
+    boolean add(final P attr);
+
+    @Override
+    boolean remove(final P attr);
+
+    /**
+     * Returns the plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @param plainSchemaName plain schema name
+     * @return plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise
+     */
+    @Override
+    P getPlainAttr(String plainSchemaName);
+
+    /**
+     * Returns the plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise.
+     *
+     * @param plainSchemaName plain schema name
+     * @param membership membership
+     * @return plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise
+     */
+    P getPlainAttr(String plainSchemaName, Membership<?> membership);
+
+    /**
+     * Returns the plain attributes for this instance.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @return plain attribute for this instance
+     */
+    @Override
+    List<? extends P> getPlainAttrs();
+
+    /**
+     * Returns the list of plain attributes for this instance and the given schema name (including membeship attributes,
+     * as opposite to {@link Any#getPlainAttr(java.lang.String)}).
+     *
+     * @param plainSchemaName plain schema name
+     * @return list of plain attributes for this instance and the given schema name (including membeship attributes)
+     */
+    Collection<? extends P> getPlainAttrs(String plainSchemaName);
+
+    /**
+     * Returns the list of plain attributes for this instance and the given membership.
+     *
+     * @param membership membership
+     * @return list of plain attributes for this instance and the given membership
+     */
+    Collection<? extends P> getPlainAttrs(Membership<?> membership);
+
+    boolean add(M membership);
+
+    M getMembership(String groupKey);
+
+    List<? extends M> getMemberships();
+
+    boolean add(REL relationship);
+
+    REL getRelationship(RelationshipType relationshipType, String otherEndKey);
+
+    Collection<? extends REL> getRelationships(String otherEndKey);
+
+    Collection<? extends REL> getRelationships(RelationshipType relationshipType);
+
+    List<? extends REL> getRelationships();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
index 46d2297..64a58ce 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface APlainAttr extends PlainAttr<AnyObject> {
+public interface APlainAttr extends GroupablePlainAttr<AnyObject, AMembership> {
 
     @Override
     List<? extends APlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
index ac5fda0..7b0f434 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
@@ -18,27 +18,13 @@
  */
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
-import java.util.Collection;
-import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface AnyObject extends Any<APlainAttr> {
+public interface AnyObject extends
+        GroupableRelatable<AnyObject, AMembership, APlainAttr, AnyObject, ARelationship> {
 
-    boolean add(ARelationship relationship);
+    String getName();
 
-    ARelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends ARelationship> getRelationships();
-
-    boolean add(AMembership membership);
-
-    AMembership getMembership(String membershipKey);
-
-    List<? extends AMembership> getMemberships();
+    void setName(String name);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
index 5c91acf..503352f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.user;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface UPlainAttr extends PlainAttr<User> {
+public interface UPlainAttr extends GroupablePlainAttr<User, UMembership> {
 
     @Override
     List<? extends UPlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index b7e14bf..fa81fd1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -18,15 +18,15 @@
  */
 package org.apache.syncope.core.persistence.api.entity.user;
 
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface User extends Any<UPlainAttr> {
+public interface User extends
+        GroupableRelatable<User, UMembership, UPlainAttr, AnyObject, URelationship> {
 
     String getUsername();
 
@@ -92,32 +92,8 @@ public interface User extends Any<UPlainAttr> {
 
     void setMustChangePassword(boolean mustChangePassword);
 
-    @Override
-    boolean add(UPlainAttr attr);
-
-    @Override
-    UPlainAttr getPlainAttr(String plainSchemaName);
-
-    @Override
-    List<? extends UPlainAttr> getPlainAttrs();
-
     boolean add(Role role);
 
     List<? extends Role> getRoles();
 
-    boolean add(URelationship relationship);
-
-    URelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends URelationship> getRelationships();
-
-    boolean add(UMembership membership);
-
-    UMembership getMembership(String groupKey);
-
-    List<? extends UMembership> getMemberships();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 379d386..0eb38ac 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -23,8 +23,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 import javax.persistence.NoResultException;
@@ -35,6 +37,7 @@ import org.apache.commons.jexl3.parser.ParserConstants;
 import org.apache.commons.jexl3.parser.Token;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -54,6 +57,7 @@ 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.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
@@ -420,33 +424,55 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     @SuppressWarnings("unchecked")
-    public <S extends Schema> Collection<S> findAllowedSchemas(final A any, final Class<S> reference) {
-        Set<AnyTypeClass> classes = new HashSet<>();
-        classes.addAll(any.getType().getClasses());
-        classes.addAll(any.getAuxClasses());
+    public <S extends Schema> AllowedSchemas<S> findAllowedSchemas(final A any, final Class<S> reference) {
+        AllowedSchemas<S> result = new AllowedSchemas<>();
+
+        // schemas given by type and aux classes
+        Set<AnyTypeClass> typeOwnClasses = new HashSet<>();
+        typeOwnClasses.addAll(any.getType().getClasses());
+        typeOwnClasses.addAll(any.getAuxClasses());
+
+        for (AnyTypeClass typeClass : typeOwnClasses) {
+            if (reference.equals(PlainSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+            } else if (reference.equals(DerSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getDerSchemas());
+            } else if (reference.equals(VirSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getVirSchemas());
+            }
+        }
+
+        // schemas given by type extensions
+        Map<Group, List<? extends AnyTypeClass>> typeExtensionClasses = new HashMap<>();
         if (any instanceof User) {
             for (UMembership memb : ((User) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
                 }
             }
         } else if (any instanceof AnyObject) {
             for (AMembership memb : ((AnyObject) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    if (any.getType().equals(typeExtension.getAnyType())) {
+                        typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
+                    }
                 }
             }
         }
 
-        Set<S> result = new HashSet<>();
-
-        for (AnyTypeClass typeClass : classes) {
-            if (reference.equals(PlainSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getPlainSchemas());
-            } else if (reference.equals(DerSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getDerSchemas());
-            } else if (reference.equals(VirSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getVirSchemas());
+        for (Map.Entry<Group, List<? extends AnyTypeClass>> entry : typeExtensionClasses.entrySet()) {
+            result.getForMemberships().put(entry.getKey(), new HashSet<S>());
+            for (AnyTypeClass typeClass : entry.getValue()) {
+                if (reference.equals(PlainSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+                } else if (reference.equals(DerSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getDerSchemas());
+                } else if (reference.equals(VirSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getVirSchemas());
+                }
             }
         }