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 2017/07/10 16:35:58 UTC

[1/4] syncope git commit: [SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 699b3c62c -> b5d6dc4aa
  refs/heads/master f1eaaa263 -> 9779e13e0


http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index f3ada03..5b7ec8e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -191,7 +191,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
             }
             if (authRealms == null || authRealms.isEmpty() || !authorized) {
                 throw new DelegatedAdministrationException(
-                        user.getRealm().getFullPath(), AnyTypeKind.USER, user.getKey());
+                        user.getRealm().getFullPath(), AnyTypeKind.USER.name(), user.getKey());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
index 449b0f3..bd5a108 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
@@ -38,7 +38,7 @@ public abstract class AbstractAny<P extends PlainAttr<?>> extends AbstractAnnota
 
     private static final long serialVersionUID = -2666540708092702810L;
 
-    @ManyToOne(fetch = FetchType.EAGER)
+    @ManyToOne(fetch = FetchType.EAGER, optional = false)
     private JPARealm realm;
 
     private String workflowId;

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
index c7da0ae..7678fc2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
@@ -32,6 +32,7 @@ import javax.persistence.Enumerated;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.constraints.NotNull;
@@ -41,6 +42,7 @@ import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.ConnectorCapability;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.ConnPoolConf;
+import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.jpa.validation.entity.ConnInstanceCheck;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -57,6 +59,9 @@ public class JPAConnInstance extends AbstractGeneratedKeyEntity implements ConnI
 
     private static final int DEFAULT_TIMEOUT = 10;
 
+    @ManyToOne(fetch = FetchType.EAGER, optional = false)
+    private JPARealm adminRealm;
+
     /**
      * URI identifying the local / remote ConnId location where the related connector bundle is found.
      */
@@ -125,6 +130,17 @@ public class JPAConnInstance extends AbstractGeneratedKeyEntity implements ConnI
     private JPAConnPoolConf poolConf;
 
     @Override
+    public Realm getAdminRealm() {
+        return adminRealm;
+    }
+
+    @Override
+    public void setAdminRealm(final Realm adminRealm) {
+        checkType(adminRealm, JPARealm.class);
+        this.adminRealm = (JPARealm) adminRealm;
+    }
+
+    @Override
     public String getLocation() {
         return location;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
index b8eb01a..5020adb 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
@@ -23,18 +23,30 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.ConnConfPropSchema;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
+import org.apache.syncope.core.spring.security.SyncopeAuthenticationDetails;
+import org.apache.syncope.core.spring.security.SyncopeGrantedAuthority;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.transaction.annotation.Transactional;
 
 @Transactional("Master")
@@ -45,21 +57,44 @@ public class ConnInstanceTest extends AbstractTest {
 
     @Test
     public void findAll() {
-        List<ConnInstance> connectors = connInstanceDAO.findAll();
-        assertNotNull(connectors);
-        assertFalse(connectors.isEmpty());
+        List<GrantedAuthority> authorities = CollectionUtils.collect(StandardEntitlement.values(),
+                new Transformer<String, GrantedAuthority>() {
+
+            @Override
+            public GrantedAuthority transform(final String entitlement) {
+                return new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM);
+            }
+        }, new ArrayList<GrantedAuthority>());
+
+        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
+                new org.springframework.security.core.userdetails.User(
+                        "admin", "FAKE_PASSWORD", authorities), "FAKE_PASSWORD", authorities);
+        auth.setDetails(new SyncopeAuthenticationDetails("Master"));
+        SecurityContextHolder.getContext().setAuthentication(auth);
+
+        try {
+            List<ConnInstance> connectors = connInstanceDAO.findAll();
+            assertNotNull(connectors);
+            assertFalse(connectors.isEmpty());
+        } finally {
+            SecurityContextHolder.getContext().setAuthentication(null);
+        }
     }
 
     @Test
     public void findById() {
-        ConnInstance connectorInstance = connInstanceDAO.find("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
-
-        assertNotNull("findById did not work", connectorInstance);
-
+        ConnInstance connInstance = connInstanceDAO.find("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
+        assertNotNull(connInstance);
         assertEquals("invalid connector name",
-                "net.tirasa.connid.bundles.soap.WebServiceConnector", connectorInstance.getConnectorName());
-
-        assertEquals("invalid bundle name", "net.tirasa.connid.bundles.soap", connectorInstance.getBundleName());
+                "net.tirasa.connid.bundles.soap.WebServiceConnector", connInstance.getConnectorName());
+        assertEquals("invalid bundle name", "net.tirasa.connid.bundles.soap", connInstance.getBundleName());
+
+        try {
+            connInstanceDAO.authFind("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
+            fail();
+        } catch (DelegatedAdministrationException e) {
+            assertNotNull(e);
+        }
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
index 3fcf4ae..03b516d 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -74,6 +75,13 @@ public class ResourceTest extends AbstractTest {
                 return "7f55b09c-b573-41dc-a9eb-ccd80bd3ea7a".equals(item.getKey());
             }
         }));
+
+        try {
+            resourceDAO.authFind("ws-target-resource-1");
+            fail();
+        } catch (DelegatedAdministrationException e) {
+            assertNotNull(e);
+        }
     }
 
     @Test
@@ -91,13 +99,6 @@ public class ResourceTest extends AbstractTest {
     }
 
     @Test
-    public void findAllByPriority() {
-        List<ExternalResource> resources = resourceDAO.findAllByPriority();
-        assertNotNull(resources);
-        assertFalse(resources.isEmpty());
-    }
-
-    @Test
     public void getConnObjectKey() {
         ExternalResource resource = resourceDAO.find("ws-target-resource-2");
         assertNotNull(resource);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 83bacf0..717535f 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -274,6 +274,18 @@ under the License.
   <SyncopeRole_entitlements entitlement="USER_SEARCH" role_id="Search for realm evenTwo"/>
   <SyncopeRole_Realm role_id="Search for realm evenTwo" realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
 
+  <SyncopeRole id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_Realm role_id="Connector and Resource for realm evenTwo"
+                     realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
+
   <SyncopeUser id="1417acbe-cbf6-4277-9372-e75e04f97000" workflowId="4" status="active"
                password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
                realm_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"
@@ -303,6 +315,7 @@ under the License.
                username="puccini" creator="admin" lastModifier="admin" 
                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"/>
   <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Search for realm evenTwo"/>
+  <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Connector and Resource for realm evenTwo"/>
   
   <SyncopeGroup id="37d15e4c-cdc1-460b-a591-8505c8133806" name="root"
                 realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
@@ -614,6 +627,7 @@ under the License.
   <GPlainAttrValue attribute_id="22690472-ed3f-4972-8979-4c9251fab044" id="e16765e6-f806-469e-ae34-1ddf56f2102a" stringValue="r13"/>
 
   <ConnInstance id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" displayName="ConnInstance100"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -625,6 +639,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="SEARCH"/>
 
   <ConnInstance id="5aa5b8be-7521-481a-9651-c557aea078c1" displayName="H2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 bundleName="net.tirasa.connid.bundles.db.table"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
@@ -638,6 +653,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="SYNC"/>
 
   <ConnInstance id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" displayName="ConnInstance102"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -650,6 +666,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="SEARCH"/>
 
   <ConnInstance id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" displayName="ConnInstance103"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -657,6 +674,7 @@ under the License.
                 jsonConf='[{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["http://localhost:${cargo.servlet.port}/syncope-fit-build-tools/cxf/soap/provisioning"]},{"schema":{"name":"servicename","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["net.tirasa.connid.bundles.soap.provisioning.interfaces.Provisioning"]}]'/>
 
   <ConnInstance id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" displayName="CSVDir"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.csvdir"
                 connectorName="net.tirasa.connid.bundles.csvdir.CSVDirConnector"
@@ -668,7 +686,9 @@ under the License.
   <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SEARCH"/>
   <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SYNC"/>
     
-  <ConnInstance id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" bundleName="net.tirasa.connid.bundles.ldap" displayName="ApacheDS"
+  <ConnInstance id="74141a3b-0762-4720-a4aa-fc3e374ef3ef"
+                bundleName="net.tirasa.connid.bundles.ldap" displayName="ApacheDS"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
                 version="${connid.ldap.version}" 
@@ -679,6 +699,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="SEARCH"/>
   
   <ConnInstance id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" displayName="H2-test2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 bundleName="net.tirasa.connid.bundles.db.table"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
@@ -690,6 +711,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="SYNC"/>
   
   <ConnInstance id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" bundleName="net.tirasa.connid.bundles.db.table" 
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector" 
                 displayName="H2-testpull" version="${connid.database.version}"
@@ -700,6 +722,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="SEARCH"/>
   
   <ConnInstance id="a6d017fd-a705-4507-bb7c-6ab6a6745997" bundleName="net.tirasa.connid.bundles.db.scriptedsql" 
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorName="net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector"
                 displayName="Scripted SQL" version="${connid.database.version}"
@@ -711,6 +734,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="SYNC"/>
   
   <ConnInstance id="44c02549-19c3-483c-8025-4919c3283c37" bundlename="net.tirasa.connid.bundles.rest"
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorname="net.tirasa.connid.bundles.rest.RESTConnector"
                 displayname="REST" version="${connid.rest.version}"

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
index d4949d8..4fd3db7 100644
--- a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
@@ -185,6 +185,7 @@ we are happy to inform you that the password request was successfully executed f
   <Notification_events notification_id="71769807-7f74-4dc3-ba61-e4a7a00eb8ad" event="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>
 
   <ConnInstance id="b7ea96c3-c633-488b-98a0-b52ac35850f7" bundleName="net.tirasa.connid.bundles.ldap" displayName="LDAP"
+                adminRealm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
                 location="${connid.location}"
                 connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
                 version="${connid.ldap.version}" 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
index 49810c7..a21e1de 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
@@ -21,6 +21,9 @@ package org.apache.syncope.core.provisioning.api.utils;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 
 public final class RealmUtils {
 
@@ -57,6 +60,50 @@ public final class RealmUtils {
         return normalized;
     }
 
+    private static class StartsWithPredicate implements Predicate<String> {
+
+        private final Collection<String> targets;
+
+        StartsWithPredicate(final Collection<String> targets) {
+            this.targets = targets;
+        }
+
+        @Override
+        public boolean evaluate(final String realm) {
+            return IterableUtils.matchesAny(targets, new Predicate<String>() {
+
+                @Override
+                public boolean evaluate(final String target) {
+                    return realm.startsWith(target);
+                }
+            });
+        }
+
+    }
+
+    public static class DynRealmsPredicate implements Predicate<String> {
+
+        @Override
+        public boolean evaluate(final String realm) {
+            return !realm.startsWith("/");
+        }
+    }
+
+    public static Set<String> getEffective(final Set<String> allowedRealms, final String requestedRealm) {
+        Set<String> allowed = RealmUtils.normalize(allowedRealms);
+        Set<String> requested = new HashSet<>();
+        requested.add(requestedRealm);
+
+        Set<String> effective = new HashSet<>();
+        CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective);
+        CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective);
+
+        // includes dynamic realms
+        CollectionUtils.select(allowedRealms, new DynRealmsPredicate(), effective);
+
+        return effective;
+    }
+
     private RealmUtils() {
         // empty constructor for static utility class 
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
index e63eb2c..901acc2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
@@ -90,6 +90,7 @@ public class ConnectorManager implements ConnectorRegistry, ConnectorFactory, Sy
         }
 
         ConnInstance override = entityFactory.newEntity(ConnInstance.class);
+        override.setAdminRealm(connInstance.getAdminRealm());
         override.setConnectorName(connInstance.getConnectorName());
         override.setDisplayName(connInstance.getDisplayName());
         override.setBundleName(connInstance.getBundleName());

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
index ba4d62d..06a8021 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
@@ -24,8 +24,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
@@ -37,9 +35,11 @@ import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceHistoryConfDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.ConnInstanceHistoryConf;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
 import org.apache.syncope.core.provisioning.api.utils.ConnPoolConfUtils;
 import org.identityconnectors.framework.api.ConfigurationProperties;
@@ -54,7 +54,7 @@ import org.springframework.stereotype.Component;
 @Component
 public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
-    private static final String[] IGNORE_PROPERTIES = { "poolConf", "location" };
+    private static final String[] IGNORE_PROPERTIES = { "poolConf", "location", "adminRealm" };
 
     @Autowired
     private ConnIdBundleManager connIdBundleManager;
@@ -66,6 +66,9 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
     private ConnInstanceHistoryConfDAO connInstanceHistoryConfDAO;
 
     @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
     private ConfDAO confDAO;
 
     @Autowired
@@ -98,6 +101,12 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         ConnInstance connInstance = entityFactory.newEntity(ConnInstance.class);
 
         BeanUtils.copyProperties(connInstanceTO, connInstance, IGNORE_PROPERTIES);
+        if (connInstanceTO.getAdminRealm() != null) {
+            connInstance.setAdminRealm(realmDAO.findByFullPath(connInstanceTO.getAdminRealm()));
+        }
+        if (connInstance.getAdminRealm() == null) {
+            sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+        }
         if (connInstanceTO.getLocation() != null) {
             connInstance.setLocation(connInstanceTO.getLocation());
         }
@@ -116,7 +125,7 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
     @Override
     public ConnInstance update(final ConnInstanceTO connInstanceTO) {
-        ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+        ConnInstance connInstance = connInstanceDAO.authFind(connInstanceTO.getKey());
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
         }
@@ -143,6 +152,16 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         connInstance.getCapabilities().clear();
         connInstance.getCapabilities().addAll(connInstanceTO.getCapabilities());
 
+        if (connInstanceTO.getAdminRealm() != null) {
+            Realm realm = realmDAO.findByFullPath(connInstanceTO.getAdminRealm());
+            if (realm == null) {
+                SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+                sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+                throw sce;
+            }
+            connInstance.setAdminRealm(realm);
+        }
+
         if (connInstanceTO.getLocation() != null) {
             connInstance.setLocation(connInstanceTO.getLocation());
         }
@@ -181,9 +200,9 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         try {
             connInstance = connInstanceDAO.save(connInstance);
         } catch (Exception e) {
-            SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
-            ex.getElements().add(e.getMessage());
-            throw ex;
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+            sce.getElements().add(e.getMessage());
+            throw sce;
         }
 
         return connInstance;
@@ -220,25 +239,18 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
         Pair<URI, ConnectorInfo> info = connIdBundleManager.getConnectorInfo(connInstance);
         BeanUtils.copyProperties(connInstance, connInstanceTO, IGNORE_PROPERTIES);
+        connInstanceTO.setAdminRealm(connInstance.getAdminRealm().getFullPath());
         connInstanceTO.setLocation(info.getLeft().toASCIIString());
         // refresh stored properties in the given connInstance with direct information from underlying connector
         ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(info.getRight());
         for (final String propName : properties.getPropertyNames()) {
             ConnConfPropSchema schema = build(properties.getProperty(propName));
 
-            ConnConfProperty property = IterableUtils.find(connInstanceTO.getConf(),
-                    new Predicate<ConnConfProperty>() {
-
-                @Override
-                public boolean evaluate(final ConnConfProperty candidate) {
-                    return propName.equals(candidate.getSchema().getName());
-                }
-            });
+            ConnConfProperty property = connInstanceTO.getConf(propName);
             if (property == null) {
                 property = new ConnConfProperty();
                 connInstanceTO.getConf().add(property);
             }
-
             property.setSchema(schema);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
index 0ee414a..392ce41 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
@@ -24,7 +24,7 @@ public class DelegatedAdministrationException extends RuntimeException {
 
     private static final long serialVersionUID = 7540587364235915081L;
 
-    public DelegatedAdministrationException(final String realm, final AnyTypeKind type, final String key) {
+    public DelegatedAdministrationException(final String realm, final String type, final String key) {
         super("Missing entitlement or realm administration under " + realm + " for "
                 + (key == null
                         ? "new " + type

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
index c5190b3..5bed533 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
@@ -38,12 +38,15 @@ import java.util.Set;
 import java.util.UUID;
 import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.ConnBundleTO;
 import org.apache.syncope.common.lib.to.ConnIdObjectClassTO;
 import org.apache.syncope.common.lib.to.ConnInstanceHistoryConfTO;
@@ -54,6 +57,7 @@ import org.apache.syncope.common.lib.to.MappingTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.ConnConfPropSchema;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.ConnectorCapability;
@@ -117,6 +121,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void create() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connectorTO.setLocation(connectorService.read(
                 "88a7a819-dab5-46b4-9b90-0b9769eabdb8", Locale.ENGLISH.getLanguage()).getLocation());
         connectorTO.setVersion(connIdSoapVersion);
@@ -217,6 +222,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void update() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
 
         // set connector instance key
         connectorTO.setKey("fcf9f2b0-f7d6-42c9-84a6-61b28255a42b");
@@ -358,6 +364,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void validate() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connectorTO.setLocation(connectorServerLocation);
         connectorTO.setVersion(connIdDbVersion);
         connectorTO.setConnectorName("net.tirasa.connid.bundles.db.table.DatabaseTableConnector");
@@ -519,6 +526,52 @@ public class ConnectorITCase extends AbstractITCase {
     }
 
     @Test
+    public void authorizations() {
+        SyncopeClient puccini = clientFactory.create("puccini", ADMIN_PWD);
+        ConnectorService pcs = puccini.getService(ConnectorService.class);
+
+        // 1. list connectors: get only the ones allowed
+        List<ConnInstanceTO> connInstances = pcs.list(null);
+        assertEquals(2, connInstances.size());
+
+        assertTrue(IterableUtils.matchesAll(connInstances, new Predicate<ConnInstanceTO>() {
+
+            @Override
+            public boolean evaluate(final ConnInstanceTO object) {
+                return "a6d017fd-a705-4507-bb7c-6ab6a6745997".equals(object.getKey())
+                        || "44c02549-19c3-483c-8025-4919c3283c37".equals(object.getKey());
+            }
+        }));
+
+        // 2. attempt to read a connector with a different admin realm: fail
+        try {
+            pcs.read("88a7a819-dab5-46b4-9b90-0b9769eabdb8", null);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
+        }
+
+        // 3. read and upate a connector in the realm for which entitlements are owned: succeed
+        try {
+            ConnInstanceTO scriptedsql = pcs.read("a6d017fd-a705-4507-bb7c-6ab6a6745997", null);
+            ConnConfProperty reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            assertEquals("true", reloadScriptOnExecution.getValues().get(0).toString());
+
+            reloadScriptOnExecution.getValues().set(0, "false");
+            pcs.update(scriptedsql);
+
+            scriptedsql = pcs.read(scriptedsql.getKey(), null);
+            reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            assertEquals("false", reloadScriptOnExecution.getValues().get(0).toString());
+        } finally {
+            ConnInstanceTO scriptedsql = connectorService.read("a6d017fd-a705-4507-bb7c-6ab6a6745997", null);
+            ConnConfProperty reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            reloadScriptOnExecution.getValues().set(0, "true");
+            connectorService.update(scriptedsql);
+        }
+    }
+
+    @Test
     public void issueSYNCOPE10() {
         // ----------------------------------
         // Copy resource and connector in order to create new objects.
@@ -616,6 +669,7 @@ public class ConnectorITCase extends AbstractITCase {
         // Create a new connector
         // ----------------------------------------
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
 
         connectorTO.setLocation(connectorService.read(
                 "88a7a819-dab5-46b4-9b90-0b9769eabdb8", Locale.ENGLISH.getLanguage()).getLocation());

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
index 9017a9b..36286e0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
@@ -31,6 +31,7 @@ import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.io.IOUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AbstractTaskTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -166,6 +167,7 @@ public class MigrationITCase extends AbstractTaskITCase {
 
     private String setupConnector() {
         ConnInstanceTO connInstanceTO = new ConnInstanceTO();
+        connInstanceTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connInstanceTO.setLocation(connectorServerLocation);
         connInstanceTO.setConnectorName("net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector");
         connInstanceTO.setBundleName("net.tirasa.connid.bundles.db.scriptedsql");

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
index 751ce0e..8f881de 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
@@ -39,6 +39,7 @@ import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
@@ -610,6 +611,36 @@ public class ResourceITCase extends AbstractITCase {
     }
 
     @Test
+    public void authorizations() {
+        SyncopeClient puccini = clientFactory.create("puccini", ADMIN_PWD);
+        ResourceService prs = puccini.getService(ResourceService.class);
+
+        // 1. attempt to read a resource for a connector with a different admin realm: fail
+        try {
+            prs.read(RESOURCE_NAME_WS1);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
+        }
+
+        // 2. read and upate a resource for a connector in the realm for which entitlements are owned: succeed
+        try {
+            ResourceTO scriptedsql = prs.read(RESOURCE_NAME_DBSCRIPTED);
+            assertEquals(TraceLevel.ALL, scriptedsql.getCreateTraceLevel());
+
+            scriptedsql.setCreateTraceLevel(TraceLevel.FAILURES);
+            prs.update(scriptedsql);
+
+            scriptedsql = prs.read(RESOURCE_NAME_DBSCRIPTED);
+            assertEquals(TraceLevel.FAILURES, scriptedsql.getCreateTraceLevel());
+        } finally {
+            ResourceTO scriptedsql = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
+            scriptedsql.setCreateTraceLevel(TraceLevel.ALL);
+            resourceService.update(scriptedsql);
+        }
+    }
+
+    @Test
     public void issueSYNCOPE323() {
         ResourceTO actual = resourceService.read(RESOURCE_NAME_TESTDB);
         assertNotNull(actual);


[3/4] syncope git commit: [SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index f3ada03..5b7ec8e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -191,7 +191,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
             }
             if (authRealms == null || authRealms.isEmpty() || !authorized) {
                 throw new DelegatedAdministrationException(
-                        user.getRealm().getFullPath(), AnyTypeKind.USER, user.getKey());
+                        user.getRealm().getFullPath(), AnyTypeKind.USER.name(), user.getKey());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
index 449b0f3..bd5a108 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
@@ -38,7 +38,7 @@ public abstract class AbstractAny<P extends PlainAttr<?>> extends AbstractAnnota
 
     private static final long serialVersionUID = -2666540708092702810L;
 
-    @ManyToOne(fetch = FetchType.EAGER)
+    @ManyToOne(fetch = FetchType.EAGER, optional = false)
     private JPARealm realm;
 
     private String workflowId;

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
index c7da0ae..7678fc2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAConnInstance.java
@@ -32,6 +32,7 @@ import javax.persistence.Enumerated;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.constraints.NotNull;
@@ -41,6 +42,7 @@ import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.ConnectorCapability;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.ConnPoolConf;
+import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.jpa.validation.entity.ConnInstanceCheck;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -57,6 +59,9 @@ public class JPAConnInstance extends AbstractGeneratedKeyEntity implements ConnI
 
     private static final int DEFAULT_TIMEOUT = 10;
 
+    @ManyToOne(fetch = FetchType.EAGER, optional = false)
+    private JPARealm adminRealm;
+
     /**
      * URI identifying the local / remote ConnId location where the related connector bundle is found.
      */
@@ -125,6 +130,17 @@ public class JPAConnInstance extends AbstractGeneratedKeyEntity implements ConnI
     private JPAConnPoolConf poolConf;
 
     @Override
+    public Realm getAdminRealm() {
+        return adminRealm;
+    }
+
+    @Override
+    public void setAdminRealm(final Realm adminRealm) {
+        checkType(adminRealm, JPARealm.class);
+        this.adminRealm = (JPARealm) adminRealm;
+    }
+
+    @Override
     public String getLocation() {
         return location;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
index b8eb01a..5020adb 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConnInstanceTest.java
@@ -23,18 +23,30 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.ConnConfPropSchema;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
+import org.apache.syncope.core.spring.security.SyncopeAuthenticationDetails;
+import org.apache.syncope.core.spring.security.SyncopeGrantedAuthority;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.transaction.annotation.Transactional;
 
 @Transactional("Master")
@@ -45,21 +57,44 @@ public class ConnInstanceTest extends AbstractTest {
 
     @Test
     public void findAll() {
-        List<ConnInstance> connectors = connInstanceDAO.findAll();
-        assertNotNull(connectors);
-        assertFalse(connectors.isEmpty());
+        List<GrantedAuthority> authorities = CollectionUtils.collect(StandardEntitlement.values(),
+                new Transformer<String, GrantedAuthority>() {
+
+            @Override
+            public GrantedAuthority transform(final String entitlement) {
+                return new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM);
+            }
+        }, new ArrayList<GrantedAuthority>());
+
+        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
+                new org.springframework.security.core.userdetails.User(
+                        "admin", "FAKE_PASSWORD", authorities), "FAKE_PASSWORD", authorities);
+        auth.setDetails(new SyncopeAuthenticationDetails("Master"));
+        SecurityContextHolder.getContext().setAuthentication(auth);
+
+        try {
+            List<ConnInstance> connectors = connInstanceDAO.findAll();
+            assertNotNull(connectors);
+            assertFalse(connectors.isEmpty());
+        } finally {
+            SecurityContextHolder.getContext().setAuthentication(null);
+        }
     }
 
     @Test
     public void findById() {
-        ConnInstance connectorInstance = connInstanceDAO.find("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
-
-        assertNotNull("findById did not work", connectorInstance);
-
+        ConnInstance connInstance = connInstanceDAO.find("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
+        assertNotNull(connInstance);
         assertEquals("invalid connector name",
-                "net.tirasa.connid.bundles.soap.WebServiceConnector", connectorInstance.getConnectorName());
-
-        assertEquals("invalid bundle name", "net.tirasa.connid.bundles.soap", connectorInstance.getBundleName());
+                "net.tirasa.connid.bundles.soap.WebServiceConnector", connInstance.getConnectorName());
+        assertEquals("invalid bundle name", "net.tirasa.connid.bundles.soap", connInstance.getBundleName());
+
+        try {
+            connInstanceDAO.authFind("88a7a819-dab5-46b4-9b90-0b9769eabdb8");
+            fail();
+        } catch (DelegatedAdministrationException e) {
+            assertNotNull(e);
+        }
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
index 3fcf4ae..03b516d 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ResourceTest.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -74,6 +75,13 @@ public class ResourceTest extends AbstractTest {
                 return "7f55b09c-b573-41dc-a9eb-ccd80bd3ea7a".equals(item.getKey());
             }
         }));
+
+        try {
+            resourceDAO.authFind("ws-target-resource-1");
+            fail();
+        } catch (DelegatedAdministrationException e) {
+            assertNotNull(e);
+        }
     }
 
     @Test
@@ -91,13 +99,6 @@ public class ResourceTest extends AbstractTest {
     }
 
     @Test
-    public void findAllByPriority() {
-        List<ExternalResource> resources = resourceDAO.findAllByPriority();
-        assertNotNull(resources);
-        assertFalse(resources.isEmpty());
-    }
-
-    @Test
     public void getConnObjectKey() {
         ExternalResource resource = resourceDAO.find("ws-target-resource-2");
         assertNotNull(resource);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 83bacf0..717535f 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -274,6 +274,18 @@ under the License.
   <SyncopeRole_entitlements entitlement="USER_SEARCH" role_id="Search for realm evenTwo"/>
   <SyncopeRole_Realm role_id="Search for realm evenTwo" realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
 
+  <SyncopeRole id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_Realm role_id="Connector and Resource for realm evenTwo"
+                     realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
+
   <SyncopeUser id="1417acbe-cbf6-4277-9372-e75e04f97000" workflowId="4" status="active"
                password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
                realm_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"
@@ -303,6 +315,7 @@ under the License.
                username="puccini" creator="admin" lastModifier="admin" 
                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"/>
   <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Search for realm evenTwo"/>
+  <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Connector and Resource for realm evenTwo"/>
   
   <SyncopeGroup id="37d15e4c-cdc1-460b-a591-8505c8133806" name="root"
                 realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
@@ -614,6 +627,7 @@ under the License.
   <GPlainAttrValue attribute_id="22690472-ed3f-4972-8979-4c9251fab044" id="e16765e6-f806-469e-ae34-1ddf56f2102a" stringValue="r13"/>
 
   <ConnInstance id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" displayName="ConnInstance100"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -625,6 +639,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="SEARCH"/>
 
   <ConnInstance id="5aa5b8be-7521-481a-9651-c557aea078c1" displayName="H2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 bundleName="net.tirasa.connid.bundles.db.table"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
@@ -638,6 +653,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="SYNC"/>
 
   <ConnInstance id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" displayName="ConnInstance102"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -650,6 +666,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="SEARCH"/>
 
   <ConnInstance id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" displayName="ConnInstance103"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.soap"
                 connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
@@ -657,6 +674,7 @@ under the License.
                 jsonConf='[{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["http://localhost:${cargo.servlet.port}/syncope-fit-build-tools/cxf/soap/provisioning"]},{"schema":{"name":"servicename","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["net.tirasa.connid.bundles.soap.provisioning.interfaces.Provisioning"]}]'/>
 
   <ConnInstance id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" displayName="CSVDir"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 bundleName="net.tirasa.connid.bundles.csvdir"
                 connectorName="net.tirasa.connid.bundles.csvdir.CSVDirConnector"
@@ -668,7 +686,9 @@ under the License.
   <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SEARCH"/>
   <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SYNC"/>
     
-  <ConnInstance id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" bundleName="net.tirasa.connid.bundles.ldap" displayName="ApacheDS"
+  <ConnInstance id="74141a3b-0762-4720-a4aa-fc3e374ef3ef"
+                bundleName="net.tirasa.connid.bundles.ldap" displayName="ApacheDS"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"
                 connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
                 version="${connid.ldap.version}" 
@@ -679,6 +699,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="SEARCH"/>
   
   <ConnInstance id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" displayName="H2-test2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 bundleName="net.tirasa.connid.bundles.db.table"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
@@ -690,6 +711,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="SYNC"/>
   
   <ConnInstance id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" bundleName="net.tirasa.connid.bundles.db.table" 
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector" 
                 displayName="H2-testpull" version="${connid.database.version}"
@@ -700,6 +722,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="SEARCH"/>
   
   <ConnInstance id="a6d017fd-a705-4507-bb7c-6ab6a6745997" bundleName="net.tirasa.connid.bundles.db.scriptedsql" 
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorName="net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector"
                 displayName="Scripted SQL" version="${connid.database.version}"
@@ -711,6 +734,7 @@ under the License.
   <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="SYNC"/>
   
   <ConnInstance id="44c02549-19c3-483c-8025-4919c3283c37" bundlename="net.tirasa.connid.bundles.rest"
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
                 location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
                 connectorname="net.tirasa.connid.bundles.rest.RESTConnector"
                 displayname="REST" version="${connid.rest.version}"

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
index d4949d8..4fd3db7 100644
--- a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
@@ -185,6 +185,7 @@ we are happy to inform you that the password request was successfully executed f
   <Notification_events notification_id="71769807-7f74-4dc3-ba61-e4a7a00eb8ad" event="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>
 
   <ConnInstance id="b7ea96c3-c633-488b-98a0-b52ac35850f7" bundleName="net.tirasa.connid.bundles.ldap" displayName="LDAP"
+                adminRealm_id="ea696a4f-e77a-4ef1-be67-8f8093bc8686"
                 location="${connid.location}"
                 connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
                 version="${connid.ldap.version}" 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
index 49810c7..a21e1de 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/utils/RealmUtils.java
@@ -21,6 +21,9 @@ package org.apache.syncope.core.provisioning.api.utils;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 
 public final class RealmUtils {
 
@@ -57,6 +60,50 @@ public final class RealmUtils {
         return normalized;
     }
 
+    private static class StartsWithPredicate implements Predicate<String> {
+
+        private final Collection<String> targets;
+
+        StartsWithPredicate(final Collection<String> targets) {
+            this.targets = targets;
+        }
+
+        @Override
+        public boolean evaluate(final String realm) {
+            return IterableUtils.matchesAny(targets, new Predicate<String>() {
+
+                @Override
+                public boolean evaluate(final String target) {
+                    return realm.startsWith(target);
+                }
+            });
+        }
+
+    }
+
+    public static class DynRealmsPredicate implements Predicate<String> {
+
+        @Override
+        public boolean evaluate(final String realm) {
+            return !realm.startsWith("/");
+        }
+    }
+
+    public static Set<String> getEffective(final Set<String> allowedRealms, final String requestedRealm) {
+        Set<String> allowed = RealmUtils.normalize(allowedRealms);
+        Set<String> requested = new HashSet<>();
+        requested.add(requestedRealm);
+
+        Set<String> effective = new HashSet<>();
+        CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective);
+        CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective);
+
+        // includes dynamic realms
+        CollectionUtils.select(allowedRealms, new DynRealmsPredicate(), effective);
+
+        return effective;
+    }
+
     private RealmUtils() {
         // empty constructor for static utility class 
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
index e63eb2c..901acc2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorManager.java
@@ -90,6 +90,7 @@ public class ConnectorManager implements ConnectorRegistry, ConnectorFactory, Sy
         }
 
         ConnInstance override = entityFactory.newEntity(ConnInstance.class);
+        override.setAdminRealm(connInstance.getAdminRealm());
         override.setConnectorName(connInstance.getConnectorName());
         override.setDisplayName(connInstance.getDisplayName());
         override.setBundleName(connInstance.getBundleName());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
index ba4d62d..06a8021 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
@@ -24,8 +24,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
@@ -37,9 +35,11 @@ import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceHistoryConfDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.ConnInstanceHistoryConf;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
 import org.apache.syncope.core.provisioning.api.utils.ConnPoolConfUtils;
 import org.identityconnectors.framework.api.ConfigurationProperties;
@@ -54,7 +54,7 @@ import org.springframework.stereotype.Component;
 @Component
 public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
-    private static final String[] IGNORE_PROPERTIES = { "poolConf", "location" };
+    private static final String[] IGNORE_PROPERTIES = { "poolConf", "location", "adminRealm" };
 
     @Autowired
     private ConnIdBundleManager connIdBundleManager;
@@ -66,6 +66,9 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
     private ConnInstanceHistoryConfDAO connInstanceHistoryConfDAO;
 
     @Autowired
+    private RealmDAO realmDAO;
+
+    @Autowired
     private ConfDAO confDAO;
 
     @Autowired
@@ -98,6 +101,12 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         ConnInstance connInstance = entityFactory.newEntity(ConnInstance.class);
 
         BeanUtils.copyProperties(connInstanceTO, connInstance, IGNORE_PROPERTIES);
+        if (connInstanceTO.getAdminRealm() != null) {
+            connInstance.setAdminRealm(realmDAO.findByFullPath(connInstanceTO.getAdminRealm()));
+        }
+        if (connInstance.getAdminRealm() == null) {
+            sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+        }
         if (connInstanceTO.getLocation() != null) {
             connInstance.setLocation(connInstanceTO.getLocation());
         }
@@ -116,7 +125,7 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
     @Override
     public ConnInstance update(final ConnInstanceTO connInstanceTO) {
-        ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+        ConnInstance connInstance = connInstanceDAO.authFind(connInstanceTO.getKey());
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
         }
@@ -143,6 +152,16 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         connInstance.getCapabilities().clear();
         connInstance.getCapabilities().addAll(connInstanceTO.getCapabilities());
 
+        if (connInstanceTO.getAdminRealm() != null) {
+            Realm realm = realmDAO.findByFullPath(connInstanceTO.getAdminRealm());
+            if (realm == null) {
+                SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+                sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+                throw sce;
+            }
+            connInstance.setAdminRealm(realm);
+        }
+
         if (connInstanceTO.getLocation() != null) {
             connInstance.setLocation(connInstanceTO.getLocation());
         }
@@ -181,9 +200,9 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
         try {
             connInstance = connInstanceDAO.save(connInstance);
         } catch (Exception e) {
-            SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
-            ex.getElements().add(e.getMessage());
-            throw ex;
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+            sce.getElements().add(e.getMessage());
+            throw sce;
         }
 
         return connInstance;
@@ -220,25 +239,18 @@ public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
 
         Pair<URI, ConnectorInfo> info = connIdBundleManager.getConnectorInfo(connInstance);
         BeanUtils.copyProperties(connInstance, connInstanceTO, IGNORE_PROPERTIES);
+        connInstanceTO.setAdminRealm(connInstance.getAdminRealm().getFullPath());
         connInstanceTO.setLocation(info.getLeft().toASCIIString());
         // refresh stored properties in the given connInstance with direct information from underlying connector
         ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(info.getRight());
         for (final String propName : properties.getPropertyNames()) {
             ConnConfPropSchema schema = build(properties.getProperty(propName));
 
-            ConnConfProperty property = IterableUtils.find(connInstanceTO.getConf(),
-                    new Predicate<ConnConfProperty>() {
-
-                @Override
-                public boolean evaluate(final ConnConfProperty candidate) {
-                    return propName.equals(candidate.getSchema().getName());
-                }
-            });
+            ConnConfProperty property = connInstanceTO.getConf(propName);
             if (property == null) {
                 property = new ConnConfProperty();
                 connInstanceTO.getConf().add(property);
             }
-
             property.setSchema(schema);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
index 0ee414a..392ce41 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DelegatedAdministrationException.java
@@ -24,7 +24,7 @@ public class DelegatedAdministrationException extends RuntimeException {
 
     private static final long serialVersionUID = 7540587364235915081L;
 
-    public DelegatedAdministrationException(final String realm, final AnyTypeKind type, final String key) {
+    public DelegatedAdministrationException(final String realm, final String type, final String key) {
         super("Missing entitlement or realm administration under " + realm + " for "
                 + (key == null
                         ? "new " + type

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
index c5190b3..5bed533 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConnectorITCase.java
@@ -38,12 +38,15 @@ import java.util.Set;
 import java.util.UUID;
 import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.ConnBundleTO;
 import org.apache.syncope.common.lib.to.ConnIdObjectClassTO;
 import org.apache.syncope.common.lib.to.ConnInstanceHistoryConfTO;
@@ -54,6 +57,7 @@ import org.apache.syncope.common.lib.to.MappingTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.ConnConfPropSchema;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.ConnectorCapability;
@@ -117,6 +121,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void create() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connectorTO.setLocation(connectorService.read(
                 "88a7a819-dab5-46b4-9b90-0b9769eabdb8", Locale.ENGLISH.getLanguage()).getLocation());
         connectorTO.setVersion(connIdSoapVersion);
@@ -217,6 +222,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void update() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
 
         // set connector instance key
         connectorTO.setKey("fcf9f2b0-f7d6-42c9-84a6-61b28255a42b");
@@ -358,6 +364,7 @@ public class ConnectorITCase extends AbstractITCase {
     @Test
     public void validate() {
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connectorTO.setLocation(connectorServerLocation);
         connectorTO.setVersion(connIdDbVersion);
         connectorTO.setConnectorName("net.tirasa.connid.bundles.db.table.DatabaseTableConnector");
@@ -519,6 +526,52 @@ public class ConnectorITCase extends AbstractITCase {
     }
 
     @Test
+    public void authorizations() {
+        SyncopeClient puccini = clientFactory.create("puccini", ADMIN_PWD);
+        ConnectorService pcs = puccini.getService(ConnectorService.class);
+
+        // 1. list connectors: get only the ones allowed
+        List<ConnInstanceTO> connInstances = pcs.list(null);
+        assertEquals(2, connInstances.size());
+
+        assertTrue(IterableUtils.matchesAll(connInstances, new Predicate<ConnInstanceTO>() {
+
+            @Override
+            public boolean evaluate(final ConnInstanceTO object) {
+                return "a6d017fd-a705-4507-bb7c-6ab6a6745997".equals(object.getKey())
+                        || "44c02549-19c3-483c-8025-4919c3283c37".equals(object.getKey());
+            }
+        }));
+
+        // 2. attempt to read a connector with a different admin realm: fail
+        try {
+            pcs.read("88a7a819-dab5-46b4-9b90-0b9769eabdb8", null);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
+        }
+
+        // 3. read and upate a connector in the realm for which entitlements are owned: succeed
+        try {
+            ConnInstanceTO scriptedsql = pcs.read("a6d017fd-a705-4507-bb7c-6ab6a6745997", null);
+            ConnConfProperty reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            assertEquals("true", reloadScriptOnExecution.getValues().get(0).toString());
+
+            reloadScriptOnExecution.getValues().set(0, "false");
+            pcs.update(scriptedsql);
+
+            scriptedsql = pcs.read(scriptedsql.getKey(), null);
+            reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            assertEquals("false", reloadScriptOnExecution.getValues().get(0).toString());
+        } finally {
+            ConnInstanceTO scriptedsql = connectorService.read("a6d017fd-a705-4507-bb7c-6ab6a6745997", null);
+            ConnConfProperty reloadScriptOnExecution = scriptedsql.getConf("reloadScriptOnExecution");
+            reloadScriptOnExecution.getValues().set(0, "true");
+            connectorService.update(scriptedsql);
+        }
+    }
+
+    @Test
     public void issueSYNCOPE10() {
         // ----------------------------------
         // Copy resource and connector in order to create new objects.
@@ -616,6 +669,7 @@ public class ConnectorITCase extends AbstractITCase {
         // Create a new connector
         // ----------------------------------------
         ConnInstanceTO connectorTO = new ConnInstanceTO();
+        connectorTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
 
         connectorTO.setLocation(connectorService.read(
                 "88a7a819-dab5-46b4-9b90-0b9769eabdb8", Locale.ENGLISH.getLanguage()).getLocation());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
index 9017a9b..36286e0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MigrationITCase.java
@@ -31,6 +31,7 @@ import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.io.IOUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AbstractTaskTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -166,6 +167,7 @@ public class MigrationITCase extends AbstractTaskITCase {
 
     private String setupConnector() {
         ConnInstanceTO connInstanceTO = new ConnInstanceTO();
+        connInstanceTO.setAdminRealm(SyncopeConstants.ROOT_REALM);
         connInstanceTO.setLocation(connectorServerLocation);
         connInstanceTO.setConnectorName("net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector");
         connInstanceTO.setBundleName("net.tirasa.connid.bundles.db.scriptedsql");

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
index 751ce0e..8f881de 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
@@ -39,6 +39,7 @@ import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
@@ -610,6 +611,36 @@ public class ResourceITCase extends AbstractITCase {
     }
 
     @Test
+    public void authorizations() {
+        SyncopeClient puccini = clientFactory.create("puccini", ADMIN_PWD);
+        ResourceService prs = puccini.getService(ResourceService.class);
+
+        // 1. attempt to read a resource for a connector with a different admin realm: fail
+        try {
+            prs.read(RESOURCE_NAME_WS1);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.DelegatedAdministration, e.getType());
+        }
+
+        // 2. read and upate a resource for a connector in the realm for which entitlements are owned: succeed
+        try {
+            ResourceTO scriptedsql = prs.read(RESOURCE_NAME_DBSCRIPTED);
+            assertEquals(TraceLevel.ALL, scriptedsql.getCreateTraceLevel());
+
+            scriptedsql.setCreateTraceLevel(TraceLevel.FAILURES);
+            prs.update(scriptedsql);
+
+            scriptedsql = prs.read(RESOURCE_NAME_DBSCRIPTED);
+            assertEquals(TraceLevel.FAILURES, scriptedsql.getCreateTraceLevel());
+        } finally {
+            ResourceTO scriptedsql = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
+            scriptedsql.setCreateTraceLevel(TraceLevel.ALL);
+            resourceService.update(scriptedsql);
+        }
+    }
+
+    @Test
     public void issueSYNCOPE323() {
         ResourceTO actual = resourceService.read(RESOURCE_NAME_TESTDB);
         assertNotNull(actual);


[2/4] syncope git commit: [SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes

Posted by il...@apache.org.
[SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes


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

Branch: refs/heads/2_0_X
Commit: b5d6dc4aab3026374ff263a90d76b802a823173e
Parents: 699b3c6
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Jul 10 18:35:33 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Jul 10 18:35:33 2017 +0200

----------------------------------------------------------------------
 .../client/console/SyncopeConsoleSession.java   | 28 ++++-----
 .../client/console/panels/RealmChoicePanel.java | 11 ++--
 .../client/console/topology/Topology.java       | 49 +++++++++------
 .../console/wizards/any/AnyWizardBuilder.java   |  7 +--
 .../client/console/wizards/any/Details.java     |  3 +-
 .../console/wizards/any/UserWizardBuilder.java  |  1 -
 .../resources/ConnectorDetailsPanel.java        | 49 +++++++++++++++
 .../resources/ConnectorDetailsPanel.html        |  4 ++
 .../resources/ConnectorDetailsPanel.properties  |  1 +
 .../ConnectorDetailsPanel_it.properties         |  1 +
 .../ConnectorDetailsPanel_pt_BR.properties      |  1 +
 .../ConnectorDetailsPanel_ru.properties         |  1 +
 .../syncope/common/lib/to/ConnInstanceTO.java   | 10 +++
 .../syncope/core/logic/AbstractAnyLogic.java    | 53 ++--------------
 .../syncope/core/logic/AnyObjectLogic.java      | 23 +++----
 .../syncope/core/logic/ConnectorLogic.java      | 53 +++++++++++++++-
 .../apache/syncope/core/logic/GroupLogic.java   | 30 ++++-----
 .../syncope/core/logic/ResourceLogic.java       | 66 +++++++++++++++++---
 .../apache/syncope/core/logic/UserLogic.java    | 38 +++++------
 .../persistence/api/dao/ConnInstanceDAO.java    |  2 +
 .../api/dao/ExternalResourceDAO.java            |  6 +-
 .../persistence/api/entity/ConnInstance.java    |  4 ++
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    |  2 +-
 .../persistence/jpa/dao/JPAConnInstanceDAO.java | 54 +++++++++++++++-
 .../jpa/dao/JPAExternalResourceDAO.java         | 49 ++++++++++-----
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  2 +-
 .../core/persistence/jpa/dao/JPAUserDAO.java    |  2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  2 +-
 .../persistence/jpa/entity/JPAConnInstance.java | 16 +++++
 .../persistence/jpa/inner/ConnInstanceTest.java | 55 +++++++++++++---
 .../persistence/jpa/inner/ResourceTest.java     | 15 ++---
 .../test/resources/domains/MasterContent.xml    | 26 +++++++-
 .../src/test/resources/domains/TwoContent.xml   |  1 +
 .../core/provisioning/api/utils/RealmUtils.java | 47 ++++++++++++++
 .../provisioning/java/ConnectorManager.java     |  1 +
 .../java/data/ConnInstanceDataBinderImpl.java   | 44 ++++++++-----
 .../DelegatedAdministrationException.java       |  2 +-
 .../syncope/fit/core/ConnectorITCase.java       | 54 ++++++++++++++++
 .../syncope/fit/core/MigrationITCase.java       |  2 +
 .../apache/syncope/fit/core/ResourceITCase.java | 31 +++++++++
 40 files changed, 632 insertions(+), 214 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index af8295a..ab84d10 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -19,9 +19,10 @@
 package org.apache.syncope.client.console;
 
 import java.text.DateFormat;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -29,9 +30,9 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.MediaType;
-import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.list.SetUniqueList;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.commons.lang3.tuple.Pair;
@@ -217,25 +218,18 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession {
         return selfTO;
     }
 
-    public Set<String> getAvailableRealms(final String... entitlements) {
-        final Set<String> availableRealms = new HashSet<>();
-        if (entitlements != null && entitlements.length > 0) {
-            for (String entitlement : entitlements) {
-                final Set<String> realms = auth.get(entitlement);
-                if (CollectionUtils.isNotEmpty(realms)) {
-                    availableRealms.addAll(realms);
-                }
-            }
-        } else {
-            for (Map.Entry<String, Set<String>> entitlement : auth.entrySet()) {
-                availableRealms.addAll(entitlement.getValue());
-            }
+    public List<String> getAuthRealms() {
+        List<String> sortable = new ArrayList<>();
+        List<String> available = SetUniqueList.setUniqueList(sortable);
+        for (Map.Entry<String, Set<String>> entitlement : auth.entrySet()) {
+            available.addAll(entitlement.getValue());
         }
-        return availableRealms;
+        Collections.sort(sortable);
+        return sortable;
     }
 
     public boolean owns(final String entitlements) {
-        return owns(entitlements, "/");
+        return owns(entitlements, SyncopeConstants.ROOT_REALM);
     }
 
     public boolean owns(final String entitlements, final String realm) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
index 4a0ee0a..a141a72 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
@@ -27,12 +27,12 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.image.GlyphIconType;
 import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.StringUtils;
@@ -72,7 +72,7 @@ public class RealmChoicePanel extends Panel {
 
     private final Model<RealmTO> model;
 
-    private final Set<String> availableRealms;
+    private final Collection<String> availableRealms;
 
     private final Map<String, Pair<RealmTO, List<RealmTO>>> tree;
 
@@ -146,13 +146,13 @@ public class RealmChoicePanel extends Panel {
         container.setOutputMarkupId(true);
         add(container);
 
-        availableRealms = SyncopeConsoleSession.get().getAvailableRealms();
+        availableRealms = SyncopeConsoleSession.get().getAuthRealms();
 
         reloadRealmTree();
     }
 
     public final void reloadRealmTree() {
-        final Label realmLabel = new Label("realmLabel", new Model<String>());
+        final Label realmLabel = new Label("realmLabel", new Model<>());
         realmLabel.setOutputMarkupId(true);
 
         container.addOrReplace(realmLabel);
@@ -186,7 +186,6 @@ public class RealmChoicePanel extends Panel {
 
                     @Override
                     public void onClick(final AjaxRequestTarget target) {
-
                     }
 
                     @Override
@@ -288,7 +287,7 @@ public class RealmChoicePanel extends Panel {
 
                                     @Override
                                     public boolean evaluate(final String availableRealm) {
-                                        return "/".equals(availableRealm)
+                                        return SyncopeConstants.ROOT_REALM.equals(availableRealm)
                                                 || realmTO.getKey().equals(availableRealm);
                                     }
                                 });

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
index d2ba682..606a32d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
@@ -22,10 +22,13 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 import java.io.Serializable;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.jaxrs.client.WebClient;
@@ -39,6 +42,7 @@ import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -92,8 +96,8 @@ public class Topology extends BasePage {
         }
     };
 
-    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel
-            = new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
+    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel =
+            new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
 
         private static final long serialVersionUID = 5275935387613157432L;
 
@@ -116,8 +120,8 @@ public class Topology extends BasePage {
         }
     };
 
-    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel
-            = new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
+    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel =
+            new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
 
         private static final long serialVersionUID = 5275935387613157433L;
 
@@ -177,7 +181,7 @@ public class Topology extends BasePage {
             public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomIn($('#drawing')[0]);");
             }
-        }, ActionLink.ActionType.ZOOM_IN, StandardEntitlement.RESOURCE_LIST).disableIndicator().hideLabel();
+        }, ActionLink.ActionType.ZOOM_IN, StandardEntitlement.CONNECTOR_LIST).disableIndicator().hideLabel();
         zoomActionPanel.add(new ActionLink<Serializable>() {
 
             private static final long serialVersionUID = -3722207913631435501L;
@@ -186,7 +190,7 @@ public class Topology extends BasePage {
             public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomOut($('#drawing')[0]);");
             }
-        }, ActionLink.ActionType.ZOOM_OUT, StandardEntitlement.RESOURCE_LIST).disableIndicator().hideLabel();
+        }, ActionLink.ActionType.ZOOM_OUT, StandardEntitlement.CONNECTOR_LIST).disableIndicator().hideLabel();
 
         body.add(zoomActionPanel);
         // -----------------------------------------
@@ -366,24 +370,31 @@ public class Topology extends BasePage {
         // -----------------------------------------
         // Add Resources
         // -----------------------------------------
+        final Collection<String> administrableConns = new HashSet<>();
+        for (List<ConnInstanceTO> connInstances : connModel.getObject().values()) {
+            administrableConns.addAll(CollectionUtils.collect(connInstances, EntityTOUtils.keyTransformer()));
+        }
+
         final List<String> connToBeProcessed = new ArrayList<>();
-        for (ResourceTO resourceTO : resModel.getObject()) {
-            final TopologyNode topologynode = new TopologyNode(
-                    resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
+        for (final ResourceTO resourceTO : resModel.getObject()) {
+            if (administrableConns.contains(resourceTO.getConnector())) {
+                final TopologyNode topologynode = new TopologyNode(
+                        resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
 
-            final Map<Serializable, TopologyNode> remoteConnections;
+                final Map<Serializable, TopologyNode> remoteConnections;
 
-            if (connections.containsKey(resourceTO.getConnector())) {
-                remoteConnections = connections.get(resourceTO.getConnector());
-            } else {
-                remoteConnections = new HashMap<>();
-                connections.put(resourceTO.getConnector(), remoteConnections);
-            }
+                if (connections.containsKey(resourceTO.getConnector())) {
+                    remoteConnections = connections.get(resourceTO.getConnector());
+                } else {
+                    remoteConnections = new HashMap<>();
+                    connections.put(resourceTO.getConnector(), remoteConnections);
+                }
 
-            remoteConnections.put(topologynode.getKey(), topologynode);
+                remoteConnections.put(topologynode.getKey(), topologynode);
 
-            if (!connToBeProcessed.contains(resourceTO.getConnector())) {
-                connToBeProcessed.add(resourceTO.getConnector());
+                if (!connToBeProcessed.contains(resourceTO.getConnector())) {
+                    connToBeProcessed.add(resourceTO.getConnector());
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/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 9b3bce6..37377ef 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
@@ -152,15 +152,14 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde
     }
 
     protected Details<A> addOptionalDetailsPanel(final AnyWrapper<A> modelObject) {
-
-        if (modelObject.getInnerObject().getKey() != null) {
+        if (modelObject.getInnerObject().getKey() == null) {
+            return null;
+        } else {
             return new Details<>(
                     modelObject,
                     mode == AjaxWizard.Mode.TEMPLATE,
                     true,
                     pageRef);
-        } else {
-            return null;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index e5a92d2..a7dd79a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -73,8 +73,7 @@ public class Details<T extends AnyTO> extends WizardStep {
                     "destinationRealm", "destinationRealm", new PropertyModel<String>(inner, "realm"), false);
 
             ((AjaxDropDownChoicePanel<String>) realm).setChoices(CollectionUtils.collect(
-                    realms,
-                    new Transformer<RealmTO, String>() {
+                    realms, new Transformer<RealmTO, String>() {
 
                 @Override
                 public String transform(final RealmTO input) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
index f56e24d..6cf6023 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
@@ -104,7 +104,6 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> implements UserF
 
     @Override
     protected Details<UserTO> addOptionalDetailsPanel(final AnyWrapper<UserTO> modelObject) {
-
         return new UserDetails(
                 UserWrapper.class.cast(modelObject),
                 mode == AjaxWizard.Mode.TEMPLATE,

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
index 89c692f..43d4d85 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
@@ -19,12 +19,16 @@
 package org.apache.syncope.client.console.wizards.resources;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.RealmRestClient;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSpinnerFieldPanel;
@@ -32,19 +36,64 @@ import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPa
 import org.apache.syncope.common.lib.to.ConnBundleTO;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ConnPoolConfTO;
+import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.extensions.wizard.WizardStep;
 import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.PropertyModel;
 
 public class ConnectorDetailsPanel extends WizardStep {
 
     private static final long serialVersionUID = -2435937897614232137L;
 
+    private final LoadableDetachableModel<List<String>> realms;
+
     public ConnectorDetailsPanel(final ConnInstanceTO connInstanceTO, final List<ConnBundleTO> bundles) {
         super();
         setOutputMarkupId(true);
 
+        final List<String> authRealms = SyncopeConsoleSession.get().getAuthRealms();
+        realms = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                List<RealmTO> allRealms = new RealmRestClient().list();
+                CollectionUtils.filter(allRealms, new Predicate<RealmTO>() {
+
+                    @Override
+                    public boolean evaluate(final RealmTO realm) {
+                        return IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                            @Override
+                            public boolean evaluate(final String fullpath) {
+                                return realm.getFullPath().startsWith(fullpath);
+                            }
+                        });
+                    }
+                });
+
+                List<String> result = CollectionUtils.collect(allRealms, new Transformer<RealmTO, String>() {
+
+                    @Override
+                    public String transform(final RealmTO realm) {
+                        return realm.getFullPath();
+                    }
+                }, new ArrayList<String>());
+                Collections.sort(result);
+                return result;
+            }
+        };
+
+        AjaxDropDownChoicePanel<String> realm = new AjaxDropDownChoicePanel<>(
+                "adminRealm", "adminRealm", new PropertyModel<String>(connInstanceTO, "adminRealm"), false);
+        realm.setChoices(realms);
+        realm.setOutputMarkupId(true);
+        realm.addRequiredLabel();
+        add(realm);
+
         AjaxTextFieldPanel displayName = new AjaxTextFieldPanel(
                 "displayName", "displayName", new PropertyModel<String>(connInstanceTO, "displayName"), false);
         displayName.setOutputMarkupId(true);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
index 87fc624..01ac512 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
@@ -23,6 +23,10 @@ under the License.
   <body>
     <wicket:panel>
       <div class="form-group">
+        <span wicket:id="adminRealm">[adminRealm]</span>
+      </div>
+
+      <div class="form-group">
         <span wicket:id="displayName">[displayName]</span>
       </div>
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
index 6c11adc..23711a9 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
@@ -24,3 +24,4 @@ poolMinIdle=Min idle objects
 poolMaxIdle=Max idle objects
 poolMaxWait=Max waiting time (msec)
 poolMinEvictableIdleTime=Min eviction time (msec)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
index ed69987..0fd9aa7 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
@@ -24,3 +24,4 @@ poolMinIdle=Max oggetti attivi
 poolMaxIdle=Max oggetti inattivi
 poolMaxWait=Tempo max attesa
 poolMinEvictableIdleTime=Tempo min espulsione
+adminRealm=Realm di amministrazione

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
index a2915b1..db06733 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
@@ -24,3 +24,4 @@ poolMinIdle=Min idle objects
 poolMaxIdle=Max idle objects
 poolMaxWait=Max waiting time (msec)
 poolMinEvictableIdleTime=Min eviction time (msec)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
index 0194990..c5d4b3f 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
@@ -25,3 +25,4 @@ poolMinIdle=\u041c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0431\u044a\u0435\
 poolMaxIdle=\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438
 poolMaxWait=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441)
 poolMinEvictableIdleTime=\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
index d7c8be7..9440972 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
@@ -42,6 +42,8 @@ public class ConnInstanceTO extends AbstractBaseBean implements EntityTO {
 
     private String key;
 
+    private String adminRealm;
+
     private String location;
 
     private String connectorName;
@@ -71,6 +73,14 @@ public class ConnInstanceTO extends AbstractBaseBean implements EntityTO {
         this.key = key;
     }
 
+    public String getAdminRealm() {
+        return adminRealm;
+    }
+
+    public void setAdminRealm(final String adminRealm) {
+        this.adminRealm = adminRealm;
+    }
+
     public String getLocation() {
         return location;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index 7c96979..bf83632 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.logic;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -40,7 +39,6 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
@@ -53,6 +51,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.provisioning.api.LogicActions;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 
@@ -230,50 +229,6 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> ext
         return result;
     }
 
-    private static class StartsWithPredicate implements Predicate<String> {
-
-        private final Collection<String> targets;
-
-        StartsWithPredicate(final Collection<String> targets) {
-            this.targets = targets;
-        }
-
-        @Override
-        public boolean evaluate(final String realm) {
-            return IterableUtils.matchesAny(targets, new Predicate<String>() {
-
-                @Override
-                public boolean evaluate(final String target) {
-                    return realm.startsWith(target);
-                }
-            });
-        }
-
-    }
-
-    protected static class DynRealmsPredicate implements Predicate<String> {
-
-        @Override
-        public boolean evaluate(final String realm) {
-            return !realm.startsWith("/");
-        }
-    }
-
-    protected Set<String> getEffectiveRealms(final Set<String> allowedRealms, final String requestedRealm) {
-        Set<String> allowed = RealmUtils.normalize(allowedRealms);
-        Set<String> requested = new HashSet<>();
-        requested.add(requestedRealm);
-
-        Set<String> effective = new HashSet<>();
-        CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective);
-        CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective);
-
-        // includes dynamic realms
-        CollectionUtils.select(allowedRealms, new DynRealmsPredicate(), effective);
-
-        return effective;
-    }
-
     protected boolean securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
         boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
 
@@ -293,15 +248,15 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> ext
         if (!authorized) {
             throw new DelegatedAdministrationException(
                     realm,
-                    this instanceof UserLogic
+                    (this instanceof UserLogic
                             ? AnyTypeKind.USER
                             : this instanceof GroupLogic
                                     ? AnyTypeKind.GROUP
-                                    : AnyTypeKind.ANY_OBJECT,
+                                    : AnyTypeKind.ANY_OBJECT).name(),
                     key);
         }
 
-        return IterableUtils.matchesAny(effectiveRealms, new DynRealmsPredicate());
+        return IterableUtils.matchesAny(effectiveRealms, new RealmUtils.DynRealmsPredicate());
     }
 
     public abstract Date findLastChange(String key);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
index 8805221..49d18db 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
@@ -49,6 +49,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
 import org.apache.syncope.core.provisioning.api.LogicActions;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -109,7 +110,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw new UnsupportedOperationException("Need to specify " + AnyType.class.getSimpleName());
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.SEARCH.getFor(searchCond.hasAnyTypeCond())),
                 realm);
 
@@ -125,7 +126,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw new UnsupportedOperationException("Need to specify " + AnyType.class.getSimpleName());
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.SEARCH.getFor(searchCond.hasAnyTypeCond())),
                 realm);
 
@@ -152,7 +153,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw SyncopeClientException.build(ClientExceptionType.InvalidAnyType);
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.CREATE.getFor(before.getLeft().getType())),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -174,7 +175,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
                 before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())
                 ? before.getLeft().getRealm().getValue()
                 : anyObjectTO.getRealm();
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 realm);
         boolean authDynRealms = securityChecks(effectiveRealms, realm, before.getLeft().getKey());
@@ -194,7 +195,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
         AnyObjectTO anyObject = binder.getAnyObjectTO(key);
         Pair<AnyObjectTO, List<LogicActions>> before = beforeDelete(anyObject);
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.DELETE.getFor(before.getLeft().getType())),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -211,7 +212,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
     public AnyObjectTO unlink(final String key, final Collection<String> resources) {
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -233,7 +234,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
     public AnyObjectTO link(final String key, final Collection<String> resources) {
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -257,7 +258,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -285,7 +286,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -309,7 +310,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -332,7 +333,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
index e84dfe5..6532936 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
@@ -26,6 +26,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.PredicateUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.ArrayUtils;
@@ -44,6 +46,9 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
 import org.apache.syncope.core.provisioning.api.ConnectorFactory;
 import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.common.l10n.CurrentLocale;
 import org.identityconnectors.framework.api.ConfigurationProperties;
 import org.identityconnectors.framework.api.ConnectorInfo;
@@ -75,23 +80,61 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     @Autowired
     private ConnectorFactory connFactory;
 
+    protected void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
+        boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
+
+            @Override
+            public boolean evaluate(final String ownedRealm) {
+                return realm.startsWith(ownedRealm);
+            }
+        });
+        if (!authorized) {
+            throw new DelegatedAdministrationException(realm, ConnInstance.class.getSimpleName(), key);
+        }
+    }
+
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_CREATE + "')")
     public ConnInstanceTO create(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_CREATE),
+                connInstanceTO.getAdminRealm());
+        securityChecks(effectiveRealms, connInstanceTO.getAdminRealm(), null);
+
         return binder.getConnInstanceTO(connInstanceDAO.save(binder.getConnInstance(connInstanceTO)));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_UPDATE + "')")
     public ConnInstanceTO update(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+            sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+            throw sce;
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_UPDATE),
+                connInstanceTO.getAdminRealm());
+        securityChecks(effectiveRealms, connInstanceTO.getAdminRealm(), connInstanceTO.getKey());
+
         return binder.getConnInstanceTO(binder.update(connInstanceTO));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_DELETE + "')")
     public ConnInstanceTO delete(final String key) {
-        ConnInstance connInstance = connInstanceDAO.find(key);
+        ConnInstance connInstance = connInstanceDAO.authFind(key);
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_DELETE),
+                connInstance.getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, connInstance.getAdminRealm().getFullPath(), connInstance.getKey());
+
         if (!connInstance.getResources().isEmpty()) {
             SyncopeClientException associatedResources = SyncopeClientException.build(
                     ClientExceptionType.AssociatedResources);
@@ -136,7 +179,7 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     public ConnInstanceTO read(final String key, final String lang) {
         CurrentLocale.set(StringUtils.isBlank(lang) ? Locale.ENGLISH : new Locale(lang));
 
-        ConnInstance connInstance = connInstanceDAO.find(key);
+        ConnInstance connInstance = connInstanceDAO.authFind(key);
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + key + "'");
         }
@@ -183,7 +226,7 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     public List<ConnIdObjectClassTO> buildObjectClassInfo(
             final ConnInstanceTO connInstanceTO, final boolean includeSpecial) {
 
-        ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+        ConnInstance connInstance = connInstanceDAO.authFind(connInstanceTO.getKey());
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
         }
@@ -214,6 +257,10 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_READ + "')")
     @Transactional(readOnly = true)
     public void check(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+        }
+
         connFactory.createConnector(binder.getConnInstance(connInstanceTO)).test();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
index ca3e080..7e9b88b 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
@@ -122,10 +122,10 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             authorized = !CollectionUtils.intersection(groupDAO.findDynRealms(key), effectiveRealms).isEmpty();
         }
         if (!authorized) {
-            throw new DelegatedAdministrationException(realm, AnyTypeKind.GROUP, key);
+            throw new DelegatedAdministrationException(realm, AnyTypeKind.GROUP.name(), key);
         }
 
-        return IterableUtils.matchesAny(effectiveRealms, new AbstractAnyLogic.DynRealmsPredicate());
+        return IterableUtils.matchesAny(effectiveRealms, new RealmUtils.DynRealmsPredicate());
     }
 
     @Transactional(readOnly = true)
@@ -177,7 +177,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     @Transactional(readOnly = true)
     @Override
     public int count(final String realm) {
-        return groupDAO.count(getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm));
+        return groupDAO.count(RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm));
     }
 
     @PreAuthorize("isAuthenticated()")
@@ -188,7 +188,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             final String realm, final boolean details) {
 
         return CollectionUtils.collect(groupDAO.findAll(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 page, size, orderBy),
                 new Transformer<Group, GroupTO>() {
 
@@ -205,7 +205,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     @Override
     public int searchCount(final SearchCond searchCondition, final String realm) {
         return searchDAO.count(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 searchCondition, AnyTypeKind.GROUP);
     }
 
@@ -216,7 +216,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             final List<OrderByClause> orderBy, final String realm, final boolean details) {
 
         List<Group> matchingGroups = searchDAO.search(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 searchCondition, page, size, orderBy, AnyTypeKind.GROUP);
         return CollectionUtils.collect(matchingGroups, new Transformer<Group, GroupTO>() {
 
@@ -237,7 +237,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_CREATE),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -259,7 +259,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
                 before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())
                 ? before.getLeft().getRealm().getValue()
                 : groupTO.getRealm();
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 realm);
         boolean authDynRealms = securityChecks(effectiveRealms, realm, before.getLeft().getKey());
@@ -280,7 +280,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
         GroupTO group = binder.getGroupTO(key);
         Pair<GroupTO, List<LogicActions>> before = beforeDelete(group);
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_DELETE),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -312,7 +312,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     public GroupTO unlink(final String key, final Collection<String> resources) {
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -335,7 +335,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     public GroupTO link(final String key, final Collection<String> resources) {
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -360,7 +360,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -389,7 +389,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -414,7 +414,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -438,7 +438,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 5269c1e..1cde745 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -25,7 +25,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.ArrayUtils;
@@ -62,7 +64,10 @@ import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -113,6 +118,19 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @Autowired
     private ConnectorFactory connFactory;
 
+    protected void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
+        boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
+
+            @Override
+            public boolean evaluate(final String ownedRealm) {
+                return realm.startsWith(ownedRealm);
+            }
+        });
+        if (!authorized) {
+            throw new DelegatedAdministrationException(realm, ExternalResource.class.getSimpleName(), key);
+        }
+    }
+
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_CREATE + "')")
     public ResourceTO create(final ResourceTO resourceTO) {
         if (StringUtils.isBlank(resourceTO.getKey())) {
@@ -121,7 +139,19 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw sce;
         }
 
-        if (resourceDAO.find(resourceTO.getKey()) != null) {
+        ConnInstance connInstance = connInstanceDAO.authFind(resourceTO.getConnector());
+        if (connInstance == null) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidExternalResource);
+            sce.getElements().add("Connector " + resourceTO.getConnector());
+            throw sce;
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_CREATE),
+                connInstance.getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, connInstance.getAdminRealm().getFullPath(), null);
+
+        if (resourceDAO.authFind(resourceTO.getKey()) != null) {
             throw new DuplicateException(resourceTO.getKey());
         }
 
@@ -130,17 +160,22 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public ResourceTO update(final ResourceTO resourceTO) {
-        ExternalResource resource = resourceDAO.find(resourceTO.getKey());
+        ExternalResource resource = resourceDAO.authFind(resourceTO.getKey());
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceTO.getKey() + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         return binder.getResourceTO(resourceDAO.save(binder.update(resource, resourceTO)));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public void setLatestSyncToken(final String key, final String anyTypeKey) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -153,6 +188,11 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw new NotFoundException("Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         Connector connector;
         try {
             connector = connFactory.getConnector(resource);
@@ -168,7 +208,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public void removeSyncToken(final String key, final String anyTypeKey) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -181,17 +221,27 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw new NotFoundException("Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         provision.setSyncToken(null);
         resourceDAO.save(resource);
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_DELETE + "')")
     public ResourceTO delete(final String key) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_DELETE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         ResourceTO resourceToDelete = binder.getResourceTO(resource);
 
         resourceDAO.delete(key);
@@ -202,7 +252,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_READ + "')")
     @Transactional(readOnly = true)
     public ResourceTO read(final String key) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -225,7 +275,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     private Triple<ExternalResource, AnyType, Provision> connObjectInit(
             final String resourceKey, final String anyTypeKey) {
 
-        ExternalResource resource = resourceDAO.find(resourceKey);
+        ExternalResource resource = resourceDAO.authFind(resourceKey);
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceKey + "'");
         }
@@ -305,7 +355,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         ObjectClass objectClass;
         OperationOptions options;
         if (SyncopeConstants.REALM_ANYTYPE.equals(anyTypeKey)) {
-            resource = resourceDAO.find(key);
+            resource = resourceDAO.authFind(key);
             if (resource == null) {
                 throw new NotFoundException("Resource '" + key + "'");
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index 54a43f3..ee68a4e 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -55,6 +55,7 @@ import org.apache.syncope.core.provisioning.api.LogicActions;
 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -95,8 +96,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     @Transactional(readOnly = true)
     @Override
     public int count(final String realm) {
-        return userDAO.count(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm));
+        return userDAO.count(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.USER_SEARCH + "')")
@@ -106,9 +107,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
             final int page, final int size, final List<OrderByClause> orderBy,
             final String realm, final boolean details) {
 
-        return CollectionUtils.collect(userDAO.findAll(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
-                page, size, orderBy),
+        return CollectionUtils.collect(userDAO.findAll(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm), page, size, orderBy),
                 new Transformer<User, UserTO>() {
 
             @Transactional(readOnly = true)
@@ -138,8 +138,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     @Transactional(readOnly = true)
     @Override
     public int searchCount(final SearchCond searchCondition, final String realm) {
-        return searchDAO.count(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
+        return searchDAO.count(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
                 searchCondition, AnyTypeKind.USER);
     }
 
@@ -149,8 +149,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public List<UserTO> search(final SearchCond searchCondition, final int page, final int size,
             final List<OrderByClause> orderBy, final String realm, final boolean details) {
 
-        List<User> matchingUsers = searchDAO.search(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
+        List<User> matchingUsers = searchDAO.search(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
                 searchCondition, page, size, orderBy, AnyTypeKind.USER);
         return CollectionUtils.collect(matchingUsers, new Transformer<User, UserTO>() {
 
@@ -195,7 +195,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         }
 
         if (!self) {
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_CREATE),
                     before.getLeft().getRealm());
             securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -233,7 +233,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
                 && before.getLeft().getRealm() != null
                 && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())) {
 
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                     before.getLeft().getRealm().getValue());
             authDynRealms =
@@ -278,7 +278,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public ProvisioningResult<UserTO> status(final StatusPatch statusPatch, final boolean nullPriorityAsync) {
         // security checks
         UserTO toUpdate = binder.getUserTO(statusPatch.getKey());
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 toUpdate.getRealm());
         securityChecks(effectiveRealms, toUpdate.getRealm(), toUpdate.getKey());
@@ -354,7 +354,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         Pair<UserTO, List<LogicActions>> before = beforeDelete(userTO);
 
         if (!self) {
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_DELETE),
                     before.getLeft().getRealm());
             securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -391,7 +391,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public UserTO unlink(final String key, final Collection<String> resources) {
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -414,7 +414,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public UserTO link(final String key, final Collection<String> resources) {
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -439,7 +439,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -468,7 +468,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -498,7 +498,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -522,7 +522,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
index a7ba370..bb27896 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
@@ -25,6 +25,8 @@ public interface ConnInstanceDAO extends DAO<ConnInstance> {
 
     ConnInstance find(String key);
 
+    ConnInstance authFind(String key);
+
     List<ConnInstance> findAll();
 
     ConnInstance save(ConnInstance connector);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
index 6afa771..b48fd79 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
@@ -30,16 +30,14 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> {
 
     ExternalResource find(String key);
 
+    ExternalResource authFind(String key);
+
     List<Provision> findProvisionsByAuxClass(AnyTypeClass anyTypeClass);
 
     List<ExternalResource> findByPolicy(Policy policy);
 
-    List<ExternalResource> findWithoutPolicy(Class<? extends Policy> policyClass);
-
     List<ExternalResource> findAll();
 
-    List<ExternalResource> findAllByPriority();
-
     ExternalResource save(ExternalResource resource);
 
     void deleteMapping(String schemaName);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
index 90650a2..908bb39 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
@@ -26,6 +26,10 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface ConnInstance extends Entity {
 
+    Realm getAdminRealm();
+
+    void setAdminRealm(Realm adminRealm);
+
     void setConnectorName(String connectorName);
 
     String getConnectorName();

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 3cf4376..b052f30 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -148,7 +148,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
         }
         if (authRealms == null || authRealms.isEmpty() || !authorized) {
             throw new DelegatedAdministrationException(
-                    anyObject.getRealm().getFullPath(), AnyTypeKind.ANY_OBJECT, anyObject.getKey());
+                    anyObject.getRealm().getFullPath(), AnyTypeKind.ANY_OBJECT.name(), anyObject.getKey());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
index 8972b8b..7d4c0c8 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
@@ -18,11 +18,17 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import javax.persistence.TypedQuery;
 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.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceHistoryConfDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -31,6 +37,8 @@ import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance;
 import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
@@ -52,10 +60,54 @@ public class JPAConnInstanceDAO extends AbstractDAO<ConnInstance> implements Con
     }
 
     @Override
+    public ConnInstance authFind(final String key) {
+        final ConnInstance connInstance = find(key);
+        if (connInstance == null) {
+            return null;
+        }
+
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_READ);
+        if (authRealms == null || authRealms.isEmpty()
+                || !IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return connInstance.getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                })) {
+
+            throw new DelegatedAdministrationException(
+                    connInstance.getAdminRealm().getFullPath(),
+                    ConnInstance.class.getSimpleName(),
+                    connInstance.getKey());
+        }
+
+        return connInstance;
+    }
+
+    @Override
     public List<ConnInstance> findAll() {
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_LIST);
+        if (authRealms == null || authRealms.isEmpty()) {
+            return Collections.emptyList();
+        }
+
         TypedQuery<ConnInstance> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAConnInstance.class.getSimpleName() + " e", ConnInstance.class);
-        return query.getResultList();
+
+        return CollectionUtils.select(query.getResultList(), new Predicate<ConnInstance>() {
+
+            @Override
+            public boolean evaluate(final ConnInstance connInstance) {
+                return IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return connInstance.getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                });
+            }
+        }, new ArrayList<ConnInstance>());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
index c49bd5a..8989fc5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
@@ -23,6 +23,9 @@ import java.util.List;
 import java.util.Set;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -53,6 +56,8 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
 import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
@@ -165,6 +170,33 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     }
 
     @Override
+    public ExternalResource authFind(final String key) {
+        final ExternalResource resource = find(key);
+        if (resource == null) {
+            return null;
+        }
+
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_READ);
+        if (authRealms == null || authRealms.isEmpty()
+                || !IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return resource.getConnector() != null
+                                && resource.getConnector().getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                })) {
+
+            throw new DelegatedAdministrationException(
+                    resource.getConnector().getAdminRealm().getFullPath(),
+                    ExternalResource.class.getSimpleName(),
+                    resource.getKey());
+        }
+
+        return resource;
+    }
+
+    @Override
     public List<Provision> findProvisionsByAuxClass(final AnyTypeClass anyTypeClass) {
         TypedQuery<Provision> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAProvision.class.getSimpleName()
@@ -193,19 +225,12 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     @Override
     public List<ExternalResource> findByPolicy(final Policy policy) {
         TypedQuery<ExternalResource> query = entityManager().createQuery(
-                getByPolicyQuery(policy.getClass()).append(" = :policy").toString(), ExternalResource.class);
+                getByPolicyQuery(policy.getClass()).append("=:policy").toString(), ExternalResource.class);
         query.setParameter("policy", policy);
         return query.getResultList();
     }
 
     @Override
-    public List<ExternalResource> findWithoutPolicy(final Class<? extends Policy> policyClass) {
-        TypedQuery<ExternalResource> query = entityManager().createQuery(
-                getByPolicyQuery(policyClass).append(" IS NULL").toString(), ExternalResource.class);
-        return query.getResultList();
-    }
-
-    @Override
     public List<ExternalResource> findAll() {
         TypedQuery<ExternalResource> query = entityManager().createQuery(
                 "SELECT e FROM  " + JPAExternalResource.class.getSimpleName() + " e", ExternalResource.class);
@@ -213,14 +238,6 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     }
 
     @Override
-    public List<ExternalResource> findAllByPriority() {
-        TypedQuery<ExternalResource> query = entityManager().createQuery(
-                "SELECT e FROM  " + JPAExternalResource.class.getSimpleName() + " e ORDER BY e.propagationPriority",
-                ExternalResource.class);
-        return query.getResultList();
-    }
-
-    @Override
     @Transactional(rollbackFor = { Throwable.class })
     public ExternalResource save(final ExternalResource resource) {
         ExternalResource merged = entityManager().merge(resource);

http://git-wip-us.apache.org/repos/asf/syncope/blob/b5d6dc4a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 4c79d1b..4fb49e1 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -172,7 +172,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
         if (authRealms == null || authRealms.isEmpty() || !authorized) {
             throw new DelegatedAdministrationException(
-                    group.getRealm().getFullPath(), AnyTypeKind.GROUP, group.getKey());
+                    group.getRealm().getFullPath(), AnyTypeKind.GROUP.name(), group.getKey());
         }
     }
 


[4/4] syncope git commit: [SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes

Posted by il...@apache.org.
[SYNCOPE-1143] Now connector instances require an admin realm, which is used to enforce access control on it for administrative purposes


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

Branch: refs/heads/master
Commit: 9779e13e0d55efa445c6b046c51781d55d91991d
Parents: f1eaaa2
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Mon Jul 10 18:35:33 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Mon Jul 10 18:35:46 2017 +0200

----------------------------------------------------------------------
 .../client/console/SyncopeConsoleSession.java   | 28 ++++-----
 .../client/console/panels/RealmChoicePanel.java | 11 ++--
 .../client/console/topology/Topology.java       | 49 +++++++++------
 .../console/wizards/any/AnyWizardBuilder.java   |  7 +--
 .../client/console/wizards/any/Details.java     |  3 +-
 .../console/wizards/any/UserWizardBuilder.java  |  1 -
 .../resources/ConnectorDetailsPanel.java        | 49 +++++++++++++++
 .../resources/ConnectorDetailsPanel.html        |  4 ++
 .../resources/ConnectorDetailsPanel.properties  |  1 +
 .../ConnectorDetailsPanel_it.properties         |  1 +
 .../ConnectorDetailsPanel_pt_BR.properties      |  1 +
 .../ConnectorDetailsPanel_ru.properties         |  1 +
 .../syncope/common/lib/to/ConnInstanceTO.java   | 10 +++
 .../syncope/core/logic/AbstractAnyLogic.java    | 53 ++--------------
 .../syncope/core/logic/AnyObjectLogic.java      | 23 +++----
 .../syncope/core/logic/ConnectorLogic.java      | 53 +++++++++++++++-
 .../apache/syncope/core/logic/GroupLogic.java   | 30 ++++-----
 .../syncope/core/logic/ResourceLogic.java       | 66 +++++++++++++++++---
 .../apache/syncope/core/logic/UserLogic.java    | 38 +++++------
 .../persistence/api/dao/ConnInstanceDAO.java    |  2 +
 .../api/dao/ExternalResourceDAO.java            |  6 +-
 .../persistence/api/entity/ConnInstance.java    |  4 ++
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    |  2 +-
 .../persistence/jpa/dao/JPAConnInstanceDAO.java | 54 +++++++++++++++-
 .../jpa/dao/JPAExternalResourceDAO.java         | 49 ++++++++++-----
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  2 +-
 .../core/persistence/jpa/dao/JPAUserDAO.java    |  2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  2 +-
 .../persistence/jpa/entity/JPAConnInstance.java | 16 +++++
 .../persistence/jpa/inner/ConnInstanceTest.java | 55 +++++++++++++---
 .../persistence/jpa/inner/ResourceTest.java     | 15 ++---
 .../test/resources/domains/MasterContent.xml    | 26 +++++++-
 .../src/test/resources/domains/TwoContent.xml   |  1 +
 .../core/provisioning/api/utils/RealmUtils.java | 47 ++++++++++++++
 .../provisioning/java/ConnectorManager.java     |  1 +
 .../java/data/ConnInstanceDataBinderImpl.java   | 44 ++++++++-----
 .../DelegatedAdministrationException.java       |  2 +-
 .../syncope/fit/core/ConnectorITCase.java       | 54 ++++++++++++++++
 .../syncope/fit/core/MigrationITCase.java       |  2 +
 .../apache/syncope/fit/core/ResourceITCase.java | 31 +++++++++
 40 files changed, 632 insertions(+), 214 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index af8295a..ab84d10 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -19,9 +19,10 @@
 package org.apache.syncope.client.console;
 
 import java.text.DateFormat;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -29,9 +30,9 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.MediaType;
-import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.list.SetUniqueList;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.commons.lang3.tuple.Pair;
@@ -217,25 +218,18 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession {
         return selfTO;
     }
 
-    public Set<String> getAvailableRealms(final String... entitlements) {
-        final Set<String> availableRealms = new HashSet<>();
-        if (entitlements != null && entitlements.length > 0) {
-            for (String entitlement : entitlements) {
-                final Set<String> realms = auth.get(entitlement);
-                if (CollectionUtils.isNotEmpty(realms)) {
-                    availableRealms.addAll(realms);
-                }
-            }
-        } else {
-            for (Map.Entry<String, Set<String>> entitlement : auth.entrySet()) {
-                availableRealms.addAll(entitlement.getValue());
-            }
+    public List<String> getAuthRealms() {
+        List<String> sortable = new ArrayList<>();
+        List<String> available = SetUniqueList.setUniqueList(sortable);
+        for (Map.Entry<String, Set<String>> entitlement : auth.entrySet()) {
+            available.addAll(entitlement.getValue());
         }
-        return availableRealms;
+        Collections.sort(sortable);
+        return sortable;
     }
 
     public boolean owns(final String entitlements) {
-        return owns(entitlements, "/");
+        return owns(entitlements, SyncopeConstants.ROOT_REALM);
     }
 
     public boolean owns(final String entitlements, final String realm) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
index bfbb460..d569b14 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
@@ -27,12 +27,12 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.image.GlyphIconType;
 import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.StringUtils;
@@ -72,7 +72,7 @@ public class RealmChoicePanel extends Panel {
 
     private final Model<RealmTO> model;
 
-    private final Set<String> availableRealms;
+    private final Collection<String> availableRealms;
 
     private final Map<String, Pair<RealmTO, List<RealmTO>>> tree;
 
@@ -146,13 +146,13 @@ public class RealmChoicePanel extends Panel {
         container.setOutputMarkupId(true);
         add(container);
 
-        availableRealms = SyncopeConsoleSession.get().getAvailableRealms();
+        availableRealms = SyncopeConsoleSession.get().getAuthRealms();
 
         reloadRealmTree();
     }
 
     public final void reloadRealmTree() {
-        final Label realmLabel = new Label("realmLabel", new Model<String>());
+        final Label realmLabel = new Label("realmLabel", new Model<>());
         realmLabel.setOutputMarkupId(true);
 
         container.addOrReplace(realmLabel);
@@ -186,7 +186,6 @@ public class RealmChoicePanel extends Panel {
 
                     @Override
                     public void onClick(final AjaxRequestTarget target) {
-
                     }
 
                     @Override
@@ -288,7 +287,7 @@ public class RealmChoicePanel extends Panel {
 
                                     @Override
                                     public boolean evaluate(final String availableRealm) {
-                                        return "/".equals(availableRealm)
+                                        return SyncopeConstants.ROOT_REALM.equals(availableRealm)
                                                 || realmTO.getKey().equals(availableRealm);
                                     }
                                 });

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
index d2ba682..606a32d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
@@ -22,10 +22,13 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 import java.io.Serializable;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.jaxrs.client.WebClient;
@@ -39,6 +42,7 @@ import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -92,8 +96,8 @@ public class Topology extends BasePage {
         }
     };
 
-    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel
-            = new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
+    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel =
+            new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
 
         private static final long serialVersionUID = 5275935387613157432L;
 
@@ -116,8 +120,8 @@ public class Topology extends BasePage {
         }
     };
 
-    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel
-            = new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
+    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel =
+            new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
 
         private static final long serialVersionUID = 5275935387613157433L;
 
@@ -177,7 +181,7 @@ public class Topology extends BasePage {
             public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomIn($('#drawing')[0]);");
             }
-        }, ActionLink.ActionType.ZOOM_IN, StandardEntitlement.RESOURCE_LIST).disableIndicator().hideLabel();
+        }, ActionLink.ActionType.ZOOM_IN, StandardEntitlement.CONNECTOR_LIST).disableIndicator().hideLabel();
         zoomActionPanel.add(new ActionLink<Serializable>() {
 
             private static final long serialVersionUID = -3722207913631435501L;
@@ -186,7 +190,7 @@ public class Topology extends BasePage {
             public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomOut($('#drawing')[0]);");
             }
-        }, ActionLink.ActionType.ZOOM_OUT, StandardEntitlement.RESOURCE_LIST).disableIndicator().hideLabel();
+        }, ActionLink.ActionType.ZOOM_OUT, StandardEntitlement.CONNECTOR_LIST).disableIndicator().hideLabel();
 
         body.add(zoomActionPanel);
         // -----------------------------------------
@@ -366,24 +370,31 @@ public class Topology extends BasePage {
         // -----------------------------------------
         // Add Resources
         // -----------------------------------------
+        final Collection<String> administrableConns = new HashSet<>();
+        for (List<ConnInstanceTO> connInstances : connModel.getObject().values()) {
+            administrableConns.addAll(CollectionUtils.collect(connInstances, EntityTOUtils.keyTransformer()));
+        }
+
         final List<String> connToBeProcessed = new ArrayList<>();
-        for (ResourceTO resourceTO : resModel.getObject()) {
-            final TopologyNode topologynode = new TopologyNode(
-                    resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
+        for (final ResourceTO resourceTO : resModel.getObject()) {
+            if (administrableConns.contains(resourceTO.getConnector())) {
+                final TopologyNode topologynode = new TopologyNode(
+                        resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
 
-            final Map<Serializable, TopologyNode> remoteConnections;
+                final Map<Serializable, TopologyNode> remoteConnections;
 
-            if (connections.containsKey(resourceTO.getConnector())) {
-                remoteConnections = connections.get(resourceTO.getConnector());
-            } else {
-                remoteConnections = new HashMap<>();
-                connections.put(resourceTO.getConnector(), remoteConnections);
-            }
+                if (connections.containsKey(resourceTO.getConnector())) {
+                    remoteConnections = connections.get(resourceTO.getConnector());
+                } else {
+                    remoteConnections = new HashMap<>();
+                    connections.put(resourceTO.getConnector(), remoteConnections);
+                }
 
-            remoteConnections.put(topologynode.getKey(), topologynode);
+                remoteConnections.put(topologynode.getKey(), topologynode);
 
-            if (!connToBeProcessed.contains(resourceTO.getConnector())) {
-                connToBeProcessed.add(resourceTO.getConnector());
+                if (!connToBeProcessed.contains(resourceTO.getConnector())) {
+                    connToBeProcessed.add(resourceTO.getConnector());
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/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 9b3bce6..37377ef 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
@@ -152,15 +152,14 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde
     }
 
     protected Details<A> addOptionalDetailsPanel(final AnyWrapper<A> modelObject) {
-
-        if (modelObject.getInnerObject().getKey() != null) {
+        if (modelObject.getInnerObject().getKey() == null) {
+            return null;
+        } else {
             return new Details<>(
                     modelObject,
                     mode == AjaxWizard.Mode.TEMPLATE,
                     true,
                     pageRef);
-        } else {
-            return null;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index e5a92d2..a7dd79a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -73,8 +73,7 @@ public class Details<T extends AnyTO> extends WizardStep {
                     "destinationRealm", "destinationRealm", new PropertyModel<String>(inner, "realm"), false);
 
             ((AjaxDropDownChoicePanel<String>) realm).setChoices(CollectionUtils.collect(
-                    realms,
-                    new Transformer<RealmTO, String>() {
+                    realms, new Transformer<RealmTO, String>() {
 
                 @Override
                 public String transform(final RealmTO input) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
index f56e24d..6cf6023 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
@@ -104,7 +104,6 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> implements UserF
 
     @Override
     protected Details<UserTO> addOptionalDetailsPanel(final AnyWrapper<UserTO> modelObject) {
-
         return new UserDetails(
                 UserWrapper.class.cast(modelObject),
                 mode == AjaxWizard.Mode.TEMPLATE,

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
index 89c692f..43d4d85 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
@@ -19,12 +19,16 @@
 package org.apache.syncope.client.console.wizards.resources;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.RealmRestClient;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSpinnerFieldPanel;
@@ -32,19 +36,64 @@ import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPa
 import org.apache.syncope.common.lib.to.ConnBundleTO;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ConnPoolConfTO;
+import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.extensions.wizard.WizardStep;
 import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.PropertyModel;
 
 public class ConnectorDetailsPanel extends WizardStep {
 
     private static final long serialVersionUID = -2435937897614232137L;
 
+    private final LoadableDetachableModel<List<String>> realms;
+
     public ConnectorDetailsPanel(final ConnInstanceTO connInstanceTO, final List<ConnBundleTO> bundles) {
         super();
         setOutputMarkupId(true);
 
+        final List<String> authRealms = SyncopeConsoleSession.get().getAuthRealms();
+        realms = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                List<RealmTO> allRealms = new RealmRestClient().list();
+                CollectionUtils.filter(allRealms, new Predicate<RealmTO>() {
+
+                    @Override
+                    public boolean evaluate(final RealmTO realm) {
+                        return IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                            @Override
+                            public boolean evaluate(final String fullpath) {
+                                return realm.getFullPath().startsWith(fullpath);
+                            }
+                        });
+                    }
+                });
+
+                List<String> result = CollectionUtils.collect(allRealms, new Transformer<RealmTO, String>() {
+
+                    @Override
+                    public String transform(final RealmTO realm) {
+                        return realm.getFullPath();
+                    }
+                }, new ArrayList<String>());
+                Collections.sort(result);
+                return result;
+            }
+        };
+
+        AjaxDropDownChoicePanel<String> realm = new AjaxDropDownChoicePanel<>(
+                "adminRealm", "adminRealm", new PropertyModel<String>(connInstanceTO, "adminRealm"), false);
+        realm.setChoices(realms);
+        realm.setOutputMarkupId(true);
+        realm.addRequiredLabel();
+        add(realm);
+
         AjaxTextFieldPanel displayName = new AjaxTextFieldPanel(
                 "displayName", "displayName", new PropertyModel<String>(connInstanceTO, "displayName"), false);
         displayName.setOutputMarkupId(true);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
index 87fc624..01ac512 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html
@@ -23,6 +23,10 @@ under the License.
   <body>
     <wicket:panel>
       <div class="form-group">
+        <span wicket:id="adminRealm">[adminRealm]</span>
+      </div>
+
+      <div class="form-group">
         <span wicket:id="displayName">[displayName]</span>
       </div>
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
index 6c11adc..23711a9 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties
@@ -24,3 +24,4 @@ poolMinIdle=Min idle objects
 poolMaxIdle=Max idle objects
 poolMaxWait=Max waiting time (msec)
 poolMinEvictableIdleTime=Min eviction time (msec)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
index ed69987..0fd9aa7 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties
@@ -24,3 +24,4 @@ poolMinIdle=Max oggetti attivi
 poolMaxIdle=Max oggetti inattivi
 poolMaxWait=Tempo max attesa
 poolMinEvictableIdleTime=Tempo min espulsione
+adminRealm=Realm di amministrazione

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
index a2915b1..db06733 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties
@@ -24,3 +24,4 @@ poolMinIdle=Min idle objects
 poolMaxIdle=Max idle objects
 poolMaxWait=Max waiting time (msec)
 poolMinEvictableIdleTime=Min eviction time (msec)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
index 0194990..c5d4b3f 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties
@@ -25,3 +25,4 @@ poolMinIdle=\u041c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0431\u044a\u0435\
 poolMaxIdle=\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438
 poolMaxWait=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441)
 poolMinEvictableIdleTime=\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441)
+adminRealm=Administration Realm

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
index d7c8be7..9440972 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
@@ -42,6 +42,8 @@ public class ConnInstanceTO extends AbstractBaseBean implements EntityTO {
 
     private String key;
 
+    private String adminRealm;
+
     private String location;
 
     private String connectorName;
@@ -71,6 +73,14 @@ public class ConnInstanceTO extends AbstractBaseBean implements EntityTO {
         this.key = key;
     }
 
+    public String getAdminRealm() {
+        return adminRealm;
+    }
+
+    public void setAdminRealm(final String adminRealm) {
+        this.adminRealm = adminRealm;
+    }
+
     public String getLocation() {
         return location;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index 7c96979..bf83632 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.logic;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -40,7 +39,6 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
@@ -53,6 +51,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.provisioning.api.LogicActions;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 
@@ -230,50 +229,6 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> ext
         return result;
     }
 
-    private static class StartsWithPredicate implements Predicate<String> {
-
-        private final Collection<String> targets;
-
-        StartsWithPredicate(final Collection<String> targets) {
-            this.targets = targets;
-        }
-
-        @Override
-        public boolean evaluate(final String realm) {
-            return IterableUtils.matchesAny(targets, new Predicate<String>() {
-
-                @Override
-                public boolean evaluate(final String target) {
-                    return realm.startsWith(target);
-                }
-            });
-        }
-
-    }
-
-    protected static class DynRealmsPredicate implements Predicate<String> {
-
-        @Override
-        public boolean evaluate(final String realm) {
-            return !realm.startsWith("/");
-        }
-    }
-
-    protected Set<String> getEffectiveRealms(final Set<String> allowedRealms, final String requestedRealm) {
-        Set<String> allowed = RealmUtils.normalize(allowedRealms);
-        Set<String> requested = new HashSet<>();
-        requested.add(requestedRealm);
-
-        Set<String> effective = new HashSet<>();
-        CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective);
-        CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective);
-
-        // includes dynamic realms
-        CollectionUtils.select(allowedRealms, new DynRealmsPredicate(), effective);
-
-        return effective;
-    }
-
     protected boolean securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
         boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
 
@@ -293,15 +248,15 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch> ext
         if (!authorized) {
             throw new DelegatedAdministrationException(
                     realm,
-                    this instanceof UserLogic
+                    (this instanceof UserLogic
                             ? AnyTypeKind.USER
                             : this instanceof GroupLogic
                                     ? AnyTypeKind.GROUP
-                                    : AnyTypeKind.ANY_OBJECT,
+                                    : AnyTypeKind.ANY_OBJECT).name(),
                     key);
         }
 
-        return IterableUtils.matchesAny(effectiveRealms, new DynRealmsPredicate());
+        return IterableUtils.matchesAny(effectiveRealms, new RealmUtils.DynRealmsPredicate());
     }
 
     public abstract Date findLastChange(String key);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
index 8805221..49d18db 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
@@ -49,6 +49,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
 import org.apache.syncope.core.provisioning.api.LogicActions;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -109,7 +110,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw new UnsupportedOperationException("Need to specify " + AnyType.class.getSimpleName());
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.SEARCH.getFor(searchCond.hasAnyTypeCond())),
                 realm);
 
@@ -125,7 +126,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw new UnsupportedOperationException("Need to specify " + AnyType.class.getSimpleName());
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.SEARCH.getFor(searchCond.hasAnyTypeCond())),
                 realm);
 
@@ -152,7 +153,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
             throw SyncopeClientException.build(ClientExceptionType.InvalidAnyType);
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.CREATE.getFor(before.getLeft().getType())),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -174,7 +175,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
                 before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())
                 ? before.getLeft().getRealm().getValue()
                 : anyObjectTO.getRealm();
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 realm);
         boolean authDynRealms = securityChecks(effectiveRealms, realm, before.getLeft().getKey());
@@ -194,7 +195,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
         AnyObjectTO anyObject = binder.getAnyObjectTO(key);
         Pair<AnyObjectTO, List<LogicActions>> before = beforeDelete(anyObject);
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.DELETE.getFor(before.getLeft().getType())),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -211,7 +212,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
     public AnyObjectTO unlink(final String key, final Collection<String> resources) {
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -233,7 +234,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
     public AnyObjectTO link(final String key, final Collection<String> resources) {
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -257,7 +258,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -285,7 +286,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -309,7 +310,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());
@@ -332,7 +333,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch
 
         // security checks
         AnyObjectTO anyObjectTO = binder.getAnyObjectTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(AnyEntitlement.UPDATE.getFor(anyObjectTO.getType())),
                 anyObjectTO.getRealm());
         securityChecks(effectiveRealms, anyObjectTO.getRealm(), anyObjectTO.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
index e84dfe5..6532936 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
@@ -26,6 +26,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.PredicateUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.ArrayUtils;
@@ -44,6 +46,9 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
 import org.apache.syncope.core.provisioning.api.ConnectorFactory;
 import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.common.l10n.CurrentLocale;
 import org.identityconnectors.framework.api.ConfigurationProperties;
 import org.identityconnectors.framework.api.ConnectorInfo;
@@ -75,23 +80,61 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     @Autowired
     private ConnectorFactory connFactory;
 
+    protected void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
+        boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
+
+            @Override
+            public boolean evaluate(final String ownedRealm) {
+                return realm.startsWith(ownedRealm);
+            }
+        });
+        if (!authorized) {
+            throw new DelegatedAdministrationException(realm, ConnInstance.class.getSimpleName(), key);
+        }
+    }
+
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_CREATE + "')")
     public ConnInstanceTO create(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_CREATE),
+                connInstanceTO.getAdminRealm());
+        securityChecks(effectiveRealms, connInstanceTO.getAdminRealm(), null);
+
         return binder.getConnInstanceTO(connInstanceDAO.save(binder.getConnInstance(connInstanceTO)));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_UPDATE + "')")
     public ConnInstanceTO update(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+            sce.getElements().add("Invalid or null realm specified: " + connInstanceTO.getAdminRealm());
+            throw sce;
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_UPDATE),
+                connInstanceTO.getAdminRealm());
+        securityChecks(effectiveRealms, connInstanceTO.getAdminRealm(), connInstanceTO.getKey());
+
         return binder.getConnInstanceTO(binder.update(connInstanceTO));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_DELETE + "')")
     public ConnInstanceTO delete(final String key) {
-        ConnInstance connInstance = connInstanceDAO.find(key);
+        ConnInstance connInstance = connInstanceDAO.authFind(key);
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_DELETE),
+                connInstance.getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, connInstance.getAdminRealm().getFullPath(), connInstance.getKey());
+
         if (!connInstance.getResources().isEmpty()) {
             SyncopeClientException associatedResources = SyncopeClientException.build(
                     ClientExceptionType.AssociatedResources);
@@ -136,7 +179,7 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     public ConnInstanceTO read(final String key, final String lang) {
         CurrentLocale.set(StringUtils.isBlank(lang) ? Locale.ENGLISH : new Locale(lang));
 
-        ConnInstance connInstance = connInstanceDAO.find(key);
+        ConnInstance connInstance = connInstanceDAO.authFind(key);
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + key + "'");
         }
@@ -183,7 +226,7 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     public List<ConnIdObjectClassTO> buildObjectClassInfo(
             final ConnInstanceTO connInstanceTO, final boolean includeSpecial) {
 
-        ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+        ConnInstance connInstance = connInstanceDAO.authFind(connInstanceTO.getKey());
         if (connInstance == null) {
             throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
         }
@@ -214,6 +257,10 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.CONNECTOR_READ + "')")
     @Transactional(readOnly = true)
     public void check(final ConnInstanceTO connInstanceTO) {
+        if (connInstanceTO.getAdminRealm() == null) {
+            throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+        }
+
         connFactory.createConnector(binder.getConnInstance(connInstanceTO)).test();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
index ca3e080..7e9b88b 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
@@ -122,10 +122,10 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             authorized = !CollectionUtils.intersection(groupDAO.findDynRealms(key), effectiveRealms).isEmpty();
         }
         if (!authorized) {
-            throw new DelegatedAdministrationException(realm, AnyTypeKind.GROUP, key);
+            throw new DelegatedAdministrationException(realm, AnyTypeKind.GROUP.name(), key);
         }
 
-        return IterableUtils.matchesAny(effectiveRealms, new AbstractAnyLogic.DynRealmsPredicate());
+        return IterableUtils.matchesAny(effectiveRealms, new RealmUtils.DynRealmsPredicate());
     }
 
     @Transactional(readOnly = true)
@@ -177,7 +177,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     @Transactional(readOnly = true)
     @Override
     public int count(final String realm) {
-        return groupDAO.count(getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm));
+        return groupDAO.count(RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm));
     }
 
     @PreAuthorize("isAuthenticated()")
@@ -188,7 +188,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             final String realm, final boolean details) {
 
         return CollectionUtils.collect(groupDAO.findAll(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 page, size, orderBy),
                 new Transformer<Group, GroupTO>() {
 
@@ -205,7 +205,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     @Override
     public int searchCount(final SearchCond searchCondition, final String realm) {
         return searchDAO.count(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 searchCondition, AnyTypeKind.GROUP);
     }
 
@@ -216,7 +216,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             final List<OrderByClause> orderBy, final String realm, final boolean details) {
 
         List<Group> matchingGroups = searchDAO.search(
-                getEffectiveRealms(SyncopeConstants.FULL_ADMIN_REALMS, realm),
+                RealmUtils.getEffective(SyncopeConstants.FULL_ADMIN_REALMS, realm),
                 searchCondition, page, size, orderBy, AnyTypeKind.GROUP);
         return CollectionUtils.collect(matchingGroups, new Transformer<Group, GroupTO>() {
 
@@ -237,7 +237,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
             throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
         }
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_CREATE),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -259,7 +259,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
                 before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())
                 ? before.getLeft().getRealm().getValue()
                 : groupTO.getRealm();
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 realm);
         boolean authDynRealms = securityChecks(effectiveRealms, realm, before.getLeft().getKey());
@@ -280,7 +280,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
         GroupTO group = binder.getGroupTO(key);
         Pair<GroupTO, List<LogicActions>> before = beforeDelete(group);
 
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_DELETE),
                 before.getLeft().getRealm());
         securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -312,7 +312,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     public GroupTO unlink(final String key, final Collection<String> resources) {
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -335,7 +335,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
     public GroupTO link(final String key, final Collection<String> resources) {
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -360,7 +360,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -389,7 +389,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -414,7 +414,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
@@ -438,7 +438,7 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
         // security checks
         GroupTO group = binder.getGroupTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.GROUP_UPDATE),
                 group.getRealm());
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 5269c1e..1cde745 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -25,7 +25,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.ArrayUtils;
@@ -62,7 +64,10 @@ import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -113,6 +118,19 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @Autowired
     private ConnectorFactory connFactory;
 
+    protected void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
+        boolean authorized = IterableUtils.matchesAny(effectiveRealms, new Predicate<String>() {
+
+            @Override
+            public boolean evaluate(final String ownedRealm) {
+                return realm.startsWith(ownedRealm);
+            }
+        });
+        if (!authorized) {
+            throw new DelegatedAdministrationException(realm, ExternalResource.class.getSimpleName(), key);
+        }
+    }
+
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_CREATE + "')")
     public ResourceTO create(final ResourceTO resourceTO) {
         if (StringUtils.isBlank(resourceTO.getKey())) {
@@ -121,7 +139,19 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw sce;
         }
 
-        if (resourceDAO.find(resourceTO.getKey()) != null) {
+        ConnInstance connInstance = connInstanceDAO.authFind(resourceTO.getConnector());
+        if (connInstance == null) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidExternalResource);
+            sce.getElements().add("Connector " + resourceTO.getConnector());
+            throw sce;
+        }
+
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_CREATE),
+                connInstance.getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, connInstance.getAdminRealm().getFullPath(), null);
+
+        if (resourceDAO.authFind(resourceTO.getKey()) != null) {
             throw new DuplicateException(resourceTO.getKey());
         }
 
@@ -130,17 +160,22 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public ResourceTO update(final ResourceTO resourceTO) {
-        ExternalResource resource = resourceDAO.find(resourceTO.getKey());
+        ExternalResource resource = resourceDAO.authFind(resourceTO.getKey());
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceTO.getKey() + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         return binder.getResourceTO(resourceDAO.save(binder.update(resource, resourceTO)));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public void setLatestSyncToken(final String key, final String anyTypeKey) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -153,6 +188,11 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw new NotFoundException("Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         Connector connector;
         try {
             connector = connFactory.getConnector(resource);
@@ -168,7 +208,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_UPDATE + "')")
     public void removeSyncToken(final String key, final String anyTypeKey) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -181,17 +221,27 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw new NotFoundException("Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_UPDATE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         provision.setSyncToken(null);
         resourceDAO.save(resource);
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_DELETE + "')")
     public ResourceTO delete(final String key) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
 
+        Set<String> effectiveRealms = RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_DELETE),
+                resource.getConnector().getAdminRealm().getFullPath());
+        securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());
+
         ResourceTO resourceToDelete = binder.getResourceTO(resource);
 
         resourceDAO.delete(key);
@@ -202,7 +252,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.RESOURCE_READ + "')")
     @Transactional(readOnly = true)
     public ResourceTO read(final String key) {
-        ExternalResource resource = resourceDAO.find(key);
+        ExternalResource resource = resourceDAO.authFind(key);
         if (resource == null) {
             throw new NotFoundException("Resource '" + key + "'");
         }
@@ -225,7 +275,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     private Triple<ExternalResource, AnyType, Provision> connObjectInit(
             final String resourceKey, final String anyTypeKey) {
 
-        ExternalResource resource = resourceDAO.find(resourceKey);
+        ExternalResource resource = resourceDAO.authFind(resourceKey);
         if (resource == null) {
             throw new NotFoundException("Resource '" + resourceKey + "'");
         }
@@ -305,7 +355,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
         ObjectClass objectClass;
         OperationOptions options;
         if (SyncopeConstants.REALM_ANYTYPE.equals(anyTypeKey)) {
-            resource = resourceDAO.find(key);
+            resource = resourceDAO.authFind(key);
             if (resource == null) {
                 throw new NotFoundException("Resource '" + key + "'");
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index 54a43f3..ee68a4e 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -55,6 +55,7 @@ import org.apache.syncope.core.provisioning.api.LogicActions;
 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -95,8 +96,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     @Transactional(readOnly = true)
     @Override
     public int count(final String realm) {
-        return userDAO.count(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm));
+        return userDAO.count(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm));
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.USER_SEARCH + "')")
@@ -106,9 +107,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
             final int page, final int size, final List<OrderByClause> orderBy,
             final String realm, final boolean details) {
 
-        return CollectionUtils.collect(userDAO.findAll(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
-                page, size, orderBy),
+        return CollectionUtils.collect(userDAO.findAll(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm), page, size, orderBy),
                 new Transformer<User, UserTO>() {
 
             @Transactional(readOnly = true)
@@ -138,8 +138,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     @Transactional(readOnly = true)
     @Override
     public int searchCount(final SearchCond searchCondition, final String realm) {
-        return searchDAO.count(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
+        return searchDAO.count(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
                 searchCondition, AnyTypeKind.USER);
     }
 
@@ -149,8 +149,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public List<UserTO> search(final SearchCond searchCondition, final int page, final int size,
             final List<OrderByClause> orderBy, final String realm, final boolean details) {
 
-        List<User> matchingUsers = searchDAO.search(
-                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
+        List<User> matchingUsers = searchDAO.search(RealmUtils.getEffective(
+                AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_SEARCH), realm),
                 searchCondition, page, size, orderBy, AnyTypeKind.USER);
         return CollectionUtils.collect(matchingUsers, new Transformer<User, UserTO>() {
 
@@ -195,7 +195,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         }
 
         if (!self) {
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_CREATE),
                     before.getLeft().getRealm());
             securityChecks(effectiveRealms, before.getLeft().getRealm(), null);
@@ -233,7 +233,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
                 && before.getLeft().getRealm() != null
                 && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())) {
 
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                     before.getLeft().getRealm().getValue());
             authDynRealms =
@@ -278,7 +278,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public ProvisioningResult<UserTO> status(final StatusPatch statusPatch, final boolean nullPriorityAsync) {
         // security checks
         UserTO toUpdate = binder.getUserTO(statusPatch.getKey());
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 toUpdate.getRealm());
         securityChecks(effectiveRealms, toUpdate.getRealm(), toUpdate.getKey());
@@ -354,7 +354,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
         Pair<UserTO, List<LogicActions>> before = beforeDelete(userTO);
 
         if (!self) {
-            Set<String> effectiveRealms = getEffectiveRealms(
+            Set<String> effectiveRealms = RealmUtils.getEffective(
                     AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_DELETE),
                     before.getLeft().getRealm());
             securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
@@ -391,7 +391,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public UserTO unlink(final String key, final Collection<String> resources) {
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -414,7 +414,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
     public UserTO link(final String key, final Collection<String> resources) {
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -439,7 +439,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -468,7 +468,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -498,7 +498,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
@@ -522,7 +522,7 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
         // security checks
         UserTO user = binder.getUserTO(key);
-        Set<String> effectiveRealms = getEffectiveRealms(
+        Set<String> effectiveRealms = RealmUtils.getEffective(
                 AuthContextUtils.getAuthorizations().get(StandardEntitlement.USER_UPDATE),
                 user.getRealm());
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
index a7ba370..bb27896 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ConnInstanceDAO.java
@@ -25,6 +25,8 @@ public interface ConnInstanceDAO extends DAO<ConnInstance> {
 
     ConnInstance find(String key);
 
+    ConnInstance authFind(String key);
+
     List<ConnInstance> findAll();
 
     ConnInstance save(ConnInstance connector);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
index 6afa771..b48fd79 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
@@ -30,16 +30,14 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> {
 
     ExternalResource find(String key);
 
+    ExternalResource authFind(String key);
+
     List<Provision> findProvisionsByAuxClass(AnyTypeClass anyTypeClass);
 
     List<ExternalResource> findByPolicy(Policy policy);
 
-    List<ExternalResource> findWithoutPolicy(Class<? extends Policy> policyClass);
-
     List<ExternalResource> findAll();
 
-    List<ExternalResource> findAllByPriority();
-
     ExternalResource save(ExternalResource resource);
 
     void deleteMapping(String schemaName);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
index 90650a2..908bb39 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/ConnInstance.java
@@ -26,6 +26,10 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface ConnInstance extends Entity {
 
+    Realm getAdminRealm();
+
+    void setAdminRealm(Realm adminRealm);
+
     void setConnectorName(String connectorName);
 
     String getConnectorName();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 3cf4376..b052f30 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -148,7 +148,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
         }
         if (authRealms == null || authRealms.isEmpty() || !authorized) {
             throw new DelegatedAdministrationException(
-                    anyObject.getRealm().getFullPath(), AnyTypeKind.ANY_OBJECT, anyObject.getKey());
+                    anyObject.getRealm().getFullPath(), AnyTypeKind.ANY_OBJECT.name(), anyObject.getKey());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
index 8972b8b..7d4c0c8 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java
@@ -18,11 +18,17 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import javax.persistence.TypedQuery;
 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.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceHistoryConfDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -31,6 +37,8 @@ import org.apache.syncope.core.persistence.api.entity.ConnInstance;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance;
 import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
@@ -52,10 +60,54 @@ public class JPAConnInstanceDAO extends AbstractDAO<ConnInstance> implements Con
     }
 
     @Override
+    public ConnInstance authFind(final String key) {
+        final ConnInstance connInstance = find(key);
+        if (connInstance == null) {
+            return null;
+        }
+
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_READ);
+        if (authRealms == null || authRealms.isEmpty()
+                || !IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return connInstance.getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                })) {
+
+            throw new DelegatedAdministrationException(
+                    connInstance.getAdminRealm().getFullPath(),
+                    ConnInstance.class.getSimpleName(),
+                    connInstance.getKey());
+        }
+
+        return connInstance;
+    }
+
+    @Override
     public List<ConnInstance> findAll() {
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.CONNECTOR_LIST);
+        if (authRealms == null || authRealms.isEmpty()) {
+            return Collections.emptyList();
+        }
+
         TypedQuery<ConnInstance> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAConnInstance.class.getSimpleName() + " e", ConnInstance.class);
-        return query.getResultList();
+
+        return CollectionUtils.select(query.getResultList(), new Predicate<ConnInstance>() {
+
+            @Override
+            public boolean evaluate(final ConnInstance connInstance) {
+                return IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return connInstance.getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                });
+            }
+        }, new ArrayList<ConnInstance>());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
index c49bd5a..8989fc5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java
@@ -23,6 +23,9 @@ import java.util.List;
 import java.util.Set;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -53,6 +56,8 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
 import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
@@ -165,6 +170,33 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     }
 
     @Override
+    public ExternalResource authFind(final String key) {
+        final ExternalResource resource = find(key);
+        if (resource == null) {
+            return null;
+        }
+
+        final Set<String> authRealms = AuthContextUtils.getAuthorizations().get(StandardEntitlement.RESOURCE_READ);
+        if (authRealms == null || authRealms.isEmpty()
+                || !IterableUtils.matchesAny(authRealms, new Predicate<String>() {
+
+                    @Override
+                    public boolean evaluate(final String realm) {
+                        return resource.getConnector() != null
+                                && resource.getConnector().getAdminRealm().getFullPath().startsWith(realm);
+                    }
+                })) {
+
+            throw new DelegatedAdministrationException(
+                    resource.getConnector().getAdminRealm().getFullPath(),
+                    ExternalResource.class.getSimpleName(),
+                    resource.getKey());
+        }
+
+        return resource;
+    }
+
+    @Override
     public List<Provision> findProvisionsByAuxClass(final AnyTypeClass anyTypeClass) {
         TypedQuery<Provision> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAProvision.class.getSimpleName()
@@ -193,19 +225,12 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     @Override
     public List<ExternalResource> findByPolicy(final Policy policy) {
         TypedQuery<ExternalResource> query = entityManager().createQuery(
-                getByPolicyQuery(policy.getClass()).append(" = :policy").toString(), ExternalResource.class);
+                getByPolicyQuery(policy.getClass()).append("=:policy").toString(), ExternalResource.class);
         query.setParameter("policy", policy);
         return query.getResultList();
     }
 
     @Override
-    public List<ExternalResource> findWithoutPolicy(final Class<? extends Policy> policyClass) {
-        TypedQuery<ExternalResource> query = entityManager().createQuery(
-                getByPolicyQuery(policyClass).append(" IS NULL").toString(), ExternalResource.class);
-        return query.getResultList();
-    }
-
-    @Override
     public List<ExternalResource> findAll() {
         TypedQuery<ExternalResource> query = entityManager().createQuery(
                 "SELECT e FROM  " + JPAExternalResource.class.getSimpleName() + " e", ExternalResource.class);
@@ -213,14 +238,6 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource> implem
     }
 
     @Override
-    public List<ExternalResource> findAllByPriority() {
-        TypedQuery<ExternalResource> query = entityManager().createQuery(
-                "SELECT e FROM  " + JPAExternalResource.class.getSimpleName() + " e ORDER BY e.propagationPriority",
-                ExternalResource.class);
-        return query.getResultList();
-    }
-
-    @Override
     @Transactional(rollbackFor = { Throwable.class })
     public ExternalResource save(final ExternalResource resource) {
         ExternalResource merged = entityManager().merge(resource);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9779e13e/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 4c79d1b..4fb49e1 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -172,7 +172,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
         if (authRealms == null || authRealms.isEmpty() || !authorized) {
             throw new DelegatedAdministrationException(
-                    group.getRealm().getFullPath(), AnyTypeKind.GROUP, group.getKey());
+                    group.getRealm().getFullPath(), AnyTypeKind.GROUP.name(), group.getKey());
         }
     }