[SYNCOPE-1360] Reworking DynRealms-based delegated administration from Admin 
Console


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

Branch: refs/heads/master
Commit: 4fec32be0708252585f4cbfbc9dd25b5670d37ff
Parents: d7f034a
Author: Francesco Chicchiriccò <ilgro...@apache.org>
Authored: Mon Sep 3 17:28:05 2018 +0200
Committer: Francesco Chicchiriccò <ilgro...@apache.org>
Committed: Mon Sep 3 17:28:14 2018 +0200

----------------------------------------------------------------------
 .../client/console/SyncopeConsoleSession.java   | 33 +++++++++++++++-----
 .../console/panels/AnyDirectoryPanel.java       | 13 +++++++-
 .../console/panels/AnyObjectDirectoryPanel.java |  4 +--
 .../syncope/client/console/panels/AnyPanel.java |  6 ++--
 .../console/panels/GroupDirectoryPanel.java     |  9 +++---
 .../console/panels/UserDirectoryPanel.java      | 16 ++++++----
 .../console/wicket/markup/html/form/Action.java | 24 +++++++++++---
 .../wicket/markup/html/form/ActionPanel.java    |  2 +-
 .../java/data/UserDataBinderImpl.java           |  6 ++--
 .../reference-guide/concepts/roles.adoc         |  1 +
 10 files changed, 81 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/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 bfde815..2f952ee 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
@@ -20,8 +20,10 @@ package org.apache.syncope.client.console;
 
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -32,6 +34,7 @@ import java.util.concurrent.Future;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.MediaType;
 import org.apache.commons.collections4.list.SetUniqueList;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.commons.lang3.tuple.Pair;
@@ -224,19 +227,33 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession {
         return sortable;
     }
 
-    public boolean owns(final String entitlements) {
-        return owns(entitlements, SyncopeConstants.ROOT_REALM);
-    }
-
-    public boolean owns(final String entitlements, final String realm) {
+    public boolean owns(final String entitlements, final String... realms) {
         if (StringUtils.isEmpty(entitlements)) {
             return true;
         }
 
+        if (auth == null) {
+            return false;
+        }
+
+        Set<String> requested = ArrayUtils.isEmpty(realms)
+                ? Collections.singleton(SyncopeConstants.ROOT_REALM)
+                : new HashSet<>(Arrays.asList(realms));
+
         for (String entitlement : entitlements.split(",")) {
-            if (auth != null && auth.containsKey(entitlement) && (realm == null
-                    || auth.get(entitlement).stream().anyMatch(ownedRealm -> 
realm.startsWith(ownedRealm)))) {
-                return true;
+            if (auth.containsKey(entitlement)) {
+                boolean owns = false;
+
+                Set<String> owned = auth.get(entitlement);
+                for (String realm : requested) {
+                    if (realm.startsWith(SyncopeConstants.ROOT_REALM)) {
+                        owns |= owned.stream().anyMatch(ownedRealm -> 
realm.startsWith(ownedRealm));
+                    } else {
+                        owns |= owned.contains(realm);
+                    }
+                }
+
+                return owns;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
index 8fdc994..ec8a995 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
@@ -101,7 +101,11 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E 
extends AbstractAnyRe
         } else {
             MetaDataRoleAuthorizationStrategy.unauthorizeAll(addAjaxLink, 
RENDER);
         }
-        
setReadOnly(!SyncopeConsoleSession.get().owns(String.format("%s_UPDATE", 
builder.type), builder.realm));
+        if (builder.dynRealm == null) {
+            
setReadOnly(!SyncopeConsoleSession.get().owns(String.format("%s_UPDATE", 
builder.type), builder.realm));
+        } else {
+            
setReadOnly(!SyncopeConsoleSession.get().owns(String.format("%s_UPDATE", 
builder.type), builder.dynRealm));
+        }
 
         this.realm = builder.realm;
         this.type = builder.type;
@@ -243,6 +247,8 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E 
extends AbstractAnyRe
          */
         protected String realm = SyncopeConstants.ROOT_REALM;
 
+        protected String dynRealm = null;
+
         /**
          * Any type related to current panel.
          */
@@ -266,6 +272,11 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E 
extends AbstractAnyRe
             return this;
         }
 
+        public Builder<A, E> setDynRealm(final String dynRealm) {
+            this.dynRealm = dynRealm;
+            return this;
+        }
+
         @Override
         public List<AnyTypeClassTO> getAnyTypeClassTOs() {
             return this.anyTypeClassTOs;

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
index 7a642dc..34eeed5 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
@@ -111,7 +111,7 @@ public class AnyObjectDirectoryPanel extends 
AnyDirectoryPanel<AnyObjectTO, AnyO
             }
         }, ActionType.EDIT,
                 String.format("%s,%s", AnyEntitlement.READ.getFor(type), 
AnyEntitlement.UPDATE.getFor(type))).
-                setRealm(realm);
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<AnyObjectTO>() {
 
@@ -156,7 +156,7 @@ public class AnyObjectDirectoryPanel extends 
AnyDirectoryPanel<AnyObjectTO, AnyO
                 }
             }, ActionType.MANAGE_RESOURCES,
                     String.format("%s,%s", AnyEntitlement.READ.getFor(type), 
AnyEntitlement.UPDATE.getFor(type))).
-                    setRealm(realm);
+                    setRealms(realm, model.getObject().getDynRealms());
 
             panel.add(
                     new ActionLink<AnyObjectTO>() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
index 127471b..12ec331 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
@@ -250,7 +250,7 @@ public class AnyPanel extends Panel implements ModalPanel {
                 panel = new UserDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
-                        pageRef).setRealm(realm).setFiltered(true).
+                        
pageRef).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
                         
setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
                         userTO,
                         anyTypeTO.getClasses(),
@@ -269,7 +269,7 @@ public class AnyPanel extends Panel implements ModalPanel {
                 panel = new GroupDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
-                        pageRef).setRealm(realm).setFiltered(true).
+                        
pageRef).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
                         
setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
                         groupTO,
                         anyTypeTO.getClasses(),
@@ -291,7 +291,7 @@ public class AnyPanel extends Panel implements ModalPanel {
                 panel = new AnyObjectDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
-                        pageRef).setRealm(realm).setFiltered(true).
+                        
pageRef).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
                         
setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
                         anyObjectTO,
                         anyTypeTO.getClasses(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
index ac5663b..e7026c2 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
@@ -216,7 +216,7 @@ public class GroupDirectoryPanel extends 
AnyDirectoryPanel<GroupTO, GroupRestCli
             }
         }, ActionType.EDIT,
                 String.format("%s,%s", StandardEntitlement.GROUP_READ, 
StandardEntitlement.GROUP_UPDATE)).
-                setRealm(realm);
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<GroupTO>() {
 
@@ -247,7 +247,8 @@ public class GroupDirectoryPanel extends 
AnyDirectoryPanel<GroupTO, GroupRestCli
                 typeExtensionsModal.header(new 
StringResourceModel("typeExtensions", model));
                 typeExtensionsModal.show(true);
             }
-        }, ActionType.TYPE_EXTENSIONS, 
StandardEntitlement.GROUP_UPDATE).setRealm(realm);
+        }, ActionType.TYPE_EXTENSIONS, StandardEntitlement.GROUP_UPDATE).
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<GroupTO>() {
 
@@ -265,7 +266,7 @@ public class GroupDirectoryPanel extends 
AnyDirectoryPanel<GroupTO, GroupRestCli
             }
         }, ActionType.MEMBERS,
                 String.format("%s,%s", StandardEntitlement.GROUP_READ, 
StandardEntitlement.GROUP_UPDATE)).
-                setRealm(realm);
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<GroupTO>() {
 
@@ -333,7 +334,7 @@ public class GroupDirectoryPanel extends 
AnyDirectoryPanel<GroupTO, GroupRestCli
             }
         }, ActionType.MANAGE_RESOURCES,
                 String.format("%s,%s", StandardEntitlement.GROUP_READ, 
StandardEntitlement.GROUP_UPDATE)).
-                setRealm(realm);
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<GroupTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
index b0edf68..597a4f5 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
@@ -141,7 +141,7 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
             }
         }, ActionType.EDIT,
                 String.format("%s,%s", StandardEntitlement.USER_READ, 
StandardEntitlement.USER_UPDATE)).
-                setRealm(realm);
+                setRealms(realm, model.getObject().getDynRealms());
 
         panel.add(new ActionLink<UserTO>() {
 
@@ -183,7 +183,8 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
                 }
                 ((BasePage) 
pageRef.getPage()).getNotificationPanel().refresh(target);
             }
-        }, ActionType.MUSTCHANGEPASSWORD, 
StandardEntitlement.USER_UPDATE).setRealm(realm);
+        }, ActionType.MUSTCHANGEPASSWORD, StandardEntitlement.USER_UPDATE).
+                setRealms(realm, model.getObject().getDynRealms());
 
         if (wizardInModal) {
             panel.add(new ActionLink<UserTO>() {
@@ -206,7 +207,8 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
 
                     displayAttributeModal.show(true);
                 }
-            }, ActionType.PASSWORD_MANAGEMENT, 
StandardEntitlement.USER_UPDATE).setRealm(realm);
+            }, ActionType.PASSWORD_MANAGEMENT, 
StandardEntitlement.USER_UPDATE).
+                    setRealms(realm, model.getObject().getDynRealms());
 
             if 
(SyncopeConsoleSession.get().getPlatformInfo().isPwdResetAllowed()
                     && 
!SyncopeConsoleSession.get().getPlatformInfo().isPwdResetRequiringSecurityQuestions())
 {
@@ -230,7 +232,8 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
                         }
                         ((BasePage) 
pageRef.getPage()).getNotificationPanel().refresh(target);
                     }
-                }, ActionType.REQUEST_PASSWORD_RESET, 
StandardEntitlement.USER_UPDATE).setRealm(realm);
+                }, ActionType.REQUEST_PASSWORD_RESET, 
StandardEntitlement.USER_UPDATE).
+                        setRealms(realm, model.getObject().getDynRealms());
             }
 
             panel.add(new ActionLink<UserTO>() {
@@ -255,7 +258,8 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
 
                     altDefaultModal.show(true);
                 }
-            }, ActionType.ENABLE, 
StandardEntitlement.USER_UPDATE).setRealm(realm);
+            }, ActionType.ENABLE, StandardEntitlement.USER_UPDATE).
+                    setRealms(realm, model.getObject().getDynRealms());
 
             panel.add(new ActionLink<UserTO>() {
 
@@ -281,7 +285,7 @@ public class UserDirectoryPanel extends 
AnyDirectoryPanel<UserTO, UserRestClient
                 }
             }, ActionType.MANAGE_RESOURCES,
                     String.format("%s,%s", StandardEntitlement.USER_READ, 
StandardEntitlement.USER_UPDATE)).
-                    setRealm(realm);
+                    setRealms(realm, model.getObject().getDynRealms());
 
             panel.add(new ActionLink<UserTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/Action.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/Action.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/Action.java
index 98d2556..f01a984 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/Action.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/Action.java
@@ -19,6 +19,8 @@
 package org.apache.syncope.client.console.wicket.markup.html.form;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.wicket.model.Model;
 
@@ -31,7 +33,7 @@ public final class Action<T extends Serializable> implements 
Serializable {
 
     private static final long serialVersionUID = -7989237020377623993L;
 
-    private String realm = null;
+    private final List<String> realms = new ArrayList<>();
 
     private final ActionLink<T> link;
 
@@ -66,12 +68,24 @@ public final class Action<T extends Serializable> 
implements Serializable {
         this.indicator = true;
     }
 
-    public String getRealm() {
-        return realm;
+    public String[] getRealms() {
+        return realms.toArray(new String[realms.size()]);
     }
 
     public void setRealm(final String realm) {
-        this.realm = realm;
+        this.realms.clear();
+
+        if (realm != null) {
+            this.realms.add(realm);
+        }
+    }
+
+    public void setRealms(final String realm, final List<String> dynRealms) {
+        setRealm(realm);
+
+        if (dynRealms != null) {
+            this.realms.addAll(dynRealms);
+        }
     }
 
     public ActionLink<T> getLink() {
@@ -104,7 +118,7 @@ public final class Action<T extends Serializable> 
implements Serializable {
         this.visibleLabel = false;
         return this;
     }
-    
+
     public Action<T> showLabel() {
         this.visibleLabel = true;
         return this;

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
----------------------------------------------------------------------
diff --git 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
index 91f83b9..6b98619 100644
--- 
a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
+++ 
b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
@@ -130,7 +130,7 @@ public final class ActionPanel<T extends Serializable> 
extends Panel {
             };
         }
 
-        if (SyncopeConsoleSession.get().owns(action.getEntitlements(), 
action.getRealm())) {
+        if (SyncopeConsoleSession.get().owns(action.getEntitlements(), 
action.getRealms())) {
             MetaDataRoleAuthorizationStrategy.authorizeAll(actionLink, RENDER);
         } else {
             MetaDataRoleAuthorizationStrategy.unauthorizeAll(actionLink, 
RENDER);

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index df2f270..d328c43 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -586,10 +586,10 @@ public class UserDataBinderImpl extends 
AbstractAnyDataBinder implements UserDat
                 userDAO.findAllResources(user),
                 details);
 
-        if (details) {
-            // dynamic realms
-            userTO.getDynRealms().addAll(userDAO.findDynRealms(user.getKey()));
+        // dynamic realms
+        userTO.getDynRealms().addAll(userDAO.findDynRealms(user.getKey()));
 
+        if (details) {
             // roles
             
userTO.getRoles().addAll(user.getRoles().stream().map(Entity::getKey).collect(Collectors.toList()));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/4fec32be/src/main/asciidoc/reference-guide/concepts/roles.adoc
----------------------------------------------------------------------
diff --git a/src/main/asciidoc/reference-guide/concepts/roles.adoc 
b/src/main/asciidoc/reference-guide/concepts/roles.adoc
index 28e00e7..af28661 100644
--- a/src/main/asciidoc/reference-guide/concepts/roles.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/roles.adoc
@@ -104,4 +104,5 @@ For example, the following entitlements are normally 
required to be granted for
 . `USER_READ`
 . `ANYTYPE_READ`
 . `REALM_LIST`
+. `GROUP_SEARCH`
 ====

Reply via email to