[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/b9a5c5d1 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/b9a5c5d1 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/b9a5c5d1 Branch: refs/heads/2_0_X Commit: b9a5c5d1ebc97d7f78afba8befda3c4c5fbe6f82 Parents: 865bd70 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:31:20 2018 +0200 ---------------------------------------------------------------------- .../client/console/SyncopeConsoleSession.java | 45 ++++++++++++++------ .../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 | 17 +++++--- .../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, 87 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/b9a5c5d1/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 aa8a28c..bda14db 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; @@ -33,6 +35,7 @@ import javax.ws.rs.core.MediaType; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.Predicate; 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; @@ -213,25 +216,39 @@ 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 || IterableUtils.matchesAny(auth.get(entitlement), new Predicate<String>() { - - @Override - public boolean evaluate(final String ownedRealm) { - return realm.startsWith(ownedRealm); - } - }))) { - return true; + if (auth.containsKey(entitlement)) { + boolean owns = false; + + Set<String> owned = auth.get(entitlement); + for (final String realm : requested) { + if (realm.startsWith(SyncopeConstants.ROOT_REALM)) { + owns |= IterableUtils.matchesAny(owned, new Predicate<String>() { + + @Override + public boolean evaluate(final String ownedRealm) { + return realm.startsWith(ownedRealm); + } + }); + } else { + owns |= owned.contains(realm); + } + } + + return owns; } } http://git-wip-us.apache.org/repos/asf/syncope/blob/b9a5c5d1/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 c2b10fd..5eb6f82 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 @@ -104,7 +104,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; @@ -251,6 +255,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. */ @@ -274,6 +280,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/b9a5c5d1/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/b9a5c5d1/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/b9a5c5d1/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 188e21a..c371cc7 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>() { @@ -334,7 +335,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/b9a5c5d1/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 d9b89a5..9c42ecb 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 @@ -143,7 +143,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>() { @@ -185,7 +185,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>() { @@ -208,8 +209,8 @@ public class UserDirectoryPanel extends AnyDirectoryPanel<UserTO, UserRestClient displayAttributeModal.show(true); } - }, ActionType.PASSWORD_MANAGEMENT, - new StringBuilder().append(StandardEntitlement.USER_UPDATE).toString()).setRealm(realm); + }, ActionType.PASSWORD_MANAGEMENT, StandardEntitlement.USER_UPDATE). + setRealms(realm, model.getObject().getDynRealms()); if (SyncopeConsoleSession.get().getPlatformInfo().isPwdResetAllowed() && !SyncopeConsoleSession.get().getPlatformInfo().isPwdResetRequiringSecurityQuestions()) { @@ -233,7 +234,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>() { @@ -258,7 +260,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>() { @@ -284,7 +287,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/b9a5c5d1/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/b9a5c5d1/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/b9a5c5d1/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 04246bd..175375c 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 @@ -602,10 +602,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 CollectionUtils.collect(user.getRoles(), EntityUtils.<Role>keyTransformer(), userTO.getRoles()); http://git-wip-us.apache.org/repos/asf/syncope/blob/b9a5c5d1/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 ee23565..91401c9 100644 --- a/src/main/asciidoc/reference-guide/concepts/roles.adoc +++ b/src/main/asciidoc/reference-guide/concepts/roles.adoc @@ -102,4 +102,5 @@ For example, the following entitlements are normally required to be granted for . `USER_READ` . `ANYTYPE_READ` . `REALM_LIST` +. `GROUP_SEARCH` ====