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 2015/02/16 09:06:59 UTC

[34/59] [abbrv] [partial] syncope git commit: [SYNCOPE-620] Re-organization completed

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
new file mode 100644
index 0000000..40e031a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceSecurityPanel.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.client.console.rest.PolicyRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.ChoiceRenderer;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class ResourceSecurityPanel extends Panel {
+
+    private static final long serialVersionUID = -7982691107029848579L;
+
+    @SpringBean
+    private PolicyRestClient policyRestClient;
+
+    private IModel<Map<Long, String>> passwordPolicies = null;
+
+    private IModel<Map<Long, String>> accountPolicies = null;
+
+    private IModel<Map<Long, String>> syncPolicies = null;
+
+    public ResourceSecurityPanel(final String id, final ResourceTO resourceTO) {
+
+        super(id);
+
+        setOutputMarkupId(true);
+
+        passwordPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.PASSWORD, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        accountPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = -2012833443695917883L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.ACCOUNT, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        syncPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = -2012833443695917883L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.SYNC, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        final WebMarkupContainer securityContainer = new WebMarkupContainer("security");
+
+        securityContainer.setOutputMarkupId(true);
+        add(securityContainer);
+
+        // -------------------------------
+        // Password policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> passwordPolicy = new AjaxDropDownChoicePanel<Long>("passwordPolicy",
+                new ResourceModel("passwordPolicy", "passwordPolicy").getObject(), new PropertyModel<Long>(resourceTO,
+                        "passwordPolicy"));
+
+        passwordPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.PASSWORD));
+
+        passwordPolicy.setChoices(new ArrayList<>(passwordPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) passwordPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(passwordPolicy);
+        // -------------------------------
+
+        // -------------------------------
+        // Account policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> accountPolicy = new AjaxDropDownChoicePanel<Long>("accountPolicy",
+                new ResourceModel("accountPolicy", "accountPolicy").getObject(), new PropertyModel<Long>(resourceTO,
+                        "accountPolicy"));
+
+        accountPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.ACCOUNT));
+
+        accountPolicy.setChoices(new ArrayList<Long>(accountPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) accountPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(accountPolicy);
+        // -------------------------------
+
+        // -------------------------------
+        // Sync policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> syncPolicy = new AjaxDropDownChoicePanel<Long>("syncPolicy",
+                new ResourceModel("syncPolicy", "syncPolicy").getObject(), new PropertyModel<Long>(resourceTO,
+                        "syncPolicy"));
+
+        syncPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.SYNC));
+
+        syncPolicy.setChoices(new ArrayList<Long>(syncPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) syncPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(syncPolicy);
+        // -------------------------------
+    }
+
+    private class PolicyRenderer extends ChoiceRenderer<Long> {
+
+        private static final long serialVersionUID = 8060500161321947000L;
+
+        private PolicyType type;
+
+        public PolicyRenderer(final PolicyType type) {
+            super();
+            this.type = type;
+        }
+
+        @Override
+        public Object getDisplayValue(final Long object) {
+            switch (type) {
+                case GLOBAL_ACCOUNT:
+                case ACCOUNT:
+                    return accountPolicies.getObject().get(object);
+                case GLOBAL_PASSWORD:
+                case PASSWORD:
+                    return passwordPolicies.getObject().get(object);
+                case GLOBAL_SYNC:
+                case SYNC:
+                    return syncPolicies.getObject().get(object);
+                default:
+                    return "";
+            }
+        }
+
+        @Override
+        public String getIdValue(final Long object, final int index) {
+            return String.valueOf(object != null
+                    ? object
+                    : 0L);
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourcesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourcesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourcesPanel.java
new file mode 100644
index 0000000..67e2281
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourcesPanel.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RoleTreeBuilder;
+import org.apache.syncope.client.console.commons.RoleUtils;
+import org.apache.syncope.client.console.commons.SelectChoiceRenderer;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.NonI18nPalette;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
+import org.apache.wicket.extensions.markup.html.form.palette.component.Recorder;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class ResourcesPanel extends Panel {
+
+    private static final long serialVersionUID = -8728071019777410008L;
+
+    @SpringBean
+    private ResourceRestClient resourceRestClient;
+
+    @SpringBean
+    private RoleTreeBuilder roleTreeBuilder;
+
+    private final AbstractSubjectTO subjectTO;
+
+    private final Set<String> previousResources;
+
+    private final List<String> allResources;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 8644108944633025494L;
+
+        private String id;
+
+        private Object to;
+
+        private StatusPanel statusPanel;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public Builder attributableTO(final Object to) {
+            this.to = to;
+            return this;
+        }
+
+        public Builder statusPanel(final StatusPanel statusPanel) {
+            this.statusPanel = statusPanel;
+            return this;
+        }
+
+        public ResourcesPanel build() {
+            return new ResourcesPanel(this);
+        }
+    }
+
+    private ResourcesPanel(final Builder builder) {
+        super(builder.id);
+        subjectTO = (AbstractSubjectTO) builder.to;
+        previousResources = new HashSet<>(subjectTO.getResources());
+        allResources = new ArrayList<>();
+        for (ResourceTO resourceTO : resourceRestClient.getAll()) {
+            allResources.add(resourceTO.getKey());
+        }
+        Collections.sort(allResources);
+
+        AjaxPalettePanel<String> resourcesPalette = null;
+
+        if (subjectTO instanceof UserTO) {
+            resourcesPalette = new AjaxRecordingPalettePanel<>("resourcesPalette",
+                    new PropertyModel<List<String>>(subjectTO, "resources"),
+                    new ListModel<>(allResources), builder.statusPanel);
+        } else if (subjectTO instanceof RoleTO) {
+            resourcesPalette = new AjaxPalettePanel<>("resourcesPalette",
+                    new PropertyModel<List<String>>(subjectTO, "resources"), new ListModel<>(allResources));
+        }
+        add(resourcesPalette);
+    }
+
+    private class AjaxRecordingPalettePanel<T> extends AjaxPalettePanel<T> {
+
+        private static final long serialVersionUID = -4215625881756021988L;
+
+        private final StatusPanel statusPanel;
+
+        public AjaxRecordingPalettePanel(final String id, final IModel<List<T>> model, final ListModel<T> choices,
+                final StatusPanel statusPanel) {
+
+            super(id, model, choices, new SelectChoiceRenderer<T>(), false, false);
+            this.statusPanel = statusPanel;
+        }
+
+        @Override
+        protected Palette<T> createPalette(final IModel<List<T>> model, final ListModel<T> choices,
+                final IChoiceRenderer<T> renderer, final boolean allowOrder, final boolean allowMoveAll) {
+
+            return new NonI18nPalette<T>("paletteField", model, choices, renderer, 8, allowOrder, false) {
+
+                private static final long serialVersionUID = -3415146226879212841L;
+
+                @Override
+                protected Recorder<T> newRecorderComponent() {
+                    Recorder<T> recorder = super.newRecorderComponent();
+                    recorder.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                        private static final long serialVersionUID = 5538299138211283825L;
+
+                        @Override
+                        protected void onUpdate(final AjaxRequestTarget target) {
+                            if (subjectTO instanceof UserTO) {
+                                UserTO userTO = (UserTO) subjectTO;
+
+                                Set<String> resourcesToRemove = new HashSet<String>(previousResources);
+                                resourcesToRemove.removeAll(userTO.getResources());
+                                if (!resourcesToRemove.isEmpty()) {
+                                    Set<String> resourcesAssignedViaMembership = new HashSet<String>();
+                                    for (MembershipTO membTO : userTO.getMemberships()) {
+                                        RoleTO roleTO = RoleUtils.findRole(roleTreeBuilder, membTO.getRoleId());
+                                        if (roleTO != null) {
+                                            resourcesAssignedViaMembership.addAll(roleTO.getResources());
+                                        }
+                                    }
+                                    resourcesToRemove.removeAll(resourcesAssignedViaMembership);
+                                }
+
+                                previousResources.clear();
+                                previousResources.addAll(userTO.getResources());
+
+                                StatusUtils.update(
+                                        userTO, statusPanel, target, userTO.getResources(), resourcesToRemove);
+                            }
+                        }
+                    });
+                    return recorder;
+                }
+            };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDetailsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDetailsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDetailsPanel.java
new file mode 100644
index 0000000..03d2e75
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDetailsPanel.java
@@ -0,0 +1,435 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.JexlHelpUtil;
+import org.apache.syncope.client.console.pages.RoleSelectModalPage;
+import org.apache.syncope.client.console.pages.UserOwnerSelectModalPage;
+import org.apache.syncope.client.console.panels.AttrTemplatesPanel.RoleAttrTemplatesChange;
+import org.apache.syncope.client.console.panels.AttrTemplatesPanel.Type;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.wicket.Page;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoleDetailsPanel extends Panel {
+
+    private static final long serialVersionUID = 855618618337931784L;
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(RoleDetailsPanel.class);
+
+    @SpringBean
+    private UserRestClient userRestClient;
+
+    @SpringBean
+    private RoleRestClient roleRestClient;
+
+    private final Fragment parentFragment;
+
+    private final WebMarkupContainer ownerContainer;
+
+    private final OwnerModel userOwnerModel;
+
+    private final OwnerModel roleOwnerModel;
+
+    private ParentModel parentModel;
+
+    public RoleDetailsPanel(final String id, final RoleTO roleTO, final boolean templateMode) {
+        super(id);
+
+        ownerContainer = new WebMarkupContainer("ownerContainer");
+        ownerContainer.setOutputMarkupId(true);
+        this.add(ownerContainer);
+
+        final ModalWindow userOwnerSelectWin = new ModalWindow("userOwnerSelectWin");
+        userOwnerSelectWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        userOwnerSelectWin.setCookieName("create-userOwnerSelect-modal");
+        this.add(userOwnerSelectWin);
+        final ModalWindow roleOwnerSelectWin = new ModalWindow("roleOwnerSelectWin");
+        roleOwnerSelectWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        roleOwnerSelectWin.setCookieName("create-roleOwnerSelect-modal");
+        this.add(roleOwnerSelectWin);
+        final ModalWindow parentSelectWin = new ModalWindow("parentSelectWin");
+        parentSelectWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        parentSelectWin.setCookieName("create-parentSelect-modal");
+        this.add(parentSelectWin);
+
+        if (templateMode) {
+            parentFragment = new Fragment("parent", "parentFragment", this);
+
+            parentModel = new ParentModel(roleTO);
+            @SuppressWarnings("unchecked")
+            final AjaxTextFieldPanel parent = new AjaxTextFieldPanel("parent", "parent", parentModel);
+            parent.setReadOnly(true);
+            parent.setOutputMarkupId(true);
+            parentFragment.add(parent);
+            final AjaxLink<Void> parentSelect = new IndicatingAjaxLink<Void>("parentSelect") {
+
+                private static final long serialVersionUID = -7978723352517770644L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target) {
+                    parentSelectWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                        private static final long serialVersionUID = -7834632442532690940L;
+
+                        @Override
+                        public Page createPage() {
+                            return new RoleSelectModalPage(getPage().getPageReference(), parentSelectWin,
+                                    ParentSelectPayload.class);
+                        }
+                    });
+                    parentSelectWin.show(target);
+                }
+            };
+            parentFragment.add(parentSelect);
+            final IndicatingAjaxLink<Void> parentReset = new IndicatingAjaxLink<Void>("parentReset") {
+
+                private static final long serialVersionUID = -7978723352517770644L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target) {
+                    parentModel.setObject(null);
+                    target.add(parent);
+                }
+            };
+            parentFragment.add(parentReset);
+        } else {
+            parentFragment = new Fragment("parent", "emptyFragment", this);
+        }
+        parentFragment.setOutputMarkupId(true);
+        this.add(parentFragment);
+
+        final AjaxTextFieldPanel name =
+                new AjaxTextFieldPanel("name", "name", new PropertyModel<String>(roleTO, "key"));
+
+        final WebMarkupContainer jexlHelp = JexlHelpUtil.getJexlHelpWebContainer("jexlHelp");
+
+        final AjaxLink<Void> questionMarkJexlHelp = JexlHelpUtil.getAjaxLink(jexlHelp, "questionMarkJexlHelp");
+        this.add(questionMarkJexlHelp);
+        questionMarkJexlHelp.add(jexlHelp);
+
+        if (!templateMode) {
+            name.addRequiredLabel();
+            questionMarkJexlHelp.setVisible(false);
+        }
+        this.add(name);
+
+        userOwnerModel = new OwnerModel(roleTO, AttributableType.USER);
+        @SuppressWarnings("unchecked")
+        final AjaxTextFieldPanel userOwner = new AjaxTextFieldPanel("userOwner", "userOwner", userOwnerModel);
+        userOwner.setReadOnly(true);
+        userOwner.setOutputMarkupId(true);
+        ownerContainer.add(userOwner);
+        final AjaxLink<Void> userOwnerSelect = new IndicatingAjaxLink<Void>("userOwnerSelect") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                userOwnerSelectWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        return new UserOwnerSelectModalPage(getPage().getPageReference(), userOwnerSelectWin);
+                    }
+                });
+                userOwnerSelectWin.show(target);
+            }
+        };
+        ownerContainer.add(userOwnerSelect);
+        final IndicatingAjaxLink<Void> userOwnerReset = new IndicatingAjaxLink<Void>("userOwnerReset") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                userOwnerModel.setObject(null);
+                target.add(userOwner);
+            }
+        };
+        ownerContainer.add(userOwnerReset);
+
+        roleOwnerModel = new OwnerModel(roleTO, AttributableType.ROLE);
+        @SuppressWarnings("unchecked")
+        final AjaxTextFieldPanel roleOwner = new AjaxTextFieldPanel("roleOwner", "roleOwner", roleOwnerModel);
+        roleOwner.setReadOnly(true);
+        roleOwner.setOutputMarkupId(true);
+        ownerContainer.add(roleOwner);
+        final AjaxLink<Void> roleOwnerSelect = new IndicatingAjaxLink<Void>("roleOwnerSelect") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                parentSelectWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        return new RoleSelectModalPage(getPage().getPageReference(), parentSelectWin,
+                                RoleOwnerSelectPayload.class);
+                    }
+                });
+                parentSelectWin.show(target);
+            }
+        };
+        ownerContainer.add(roleOwnerSelect);
+        final IndicatingAjaxLink<Void> roleOwnerReset = new IndicatingAjaxLink<Void>("roleOwnerReset") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                roleOwnerModel.setObject(null);
+                target.add(roleOwner);
+            }
+        };
+        ownerContainer.add(roleOwnerReset);
+
+        final AjaxCheckBoxPanel inhOwner = new AjaxCheckBoxPanel("inheritOwner", "inheritOwner",
+                new PropertyModel<Boolean>(roleTO, "inheritOwner"));
+        this.add(inhOwner);
+
+        final AjaxCheckBoxPanel inhTemplates = new AjaxCheckBoxPanel("inheritTemplates", "inheritTemplates",
+                new PropertyModel<Boolean>(roleTO, "inheritTemplates"));
+        inhTemplates.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(getPage(), Broadcast.BREADTH, new RoleAttrTemplatesChange(Type.rPlainAttrTemplates, target));
+                send(getPage(), Broadcast.BREADTH, new RoleAttrTemplatesChange(Type.rDerAttrTemplates, target));
+                send(getPage(), Broadcast.BREADTH, new RoleAttrTemplatesChange(Type.rVirAttrTemplates, target));
+            }
+        });
+        this.add(inhTemplates);
+    }
+
+    /**
+     * This is waiting for events from opened modal windows: first to get the selected user / role, then to update the
+     * respective text panel.
+     *
+     * {@inheritDoc }
+     */
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+
+        if (event.getPayload() instanceof ParentSelectPayload) {
+            parentModel.setObject(((ParentSelectPayload) event.getPayload()).getRoleId());
+        }
+        if (event.getPayload() instanceof UserOwnerSelectPayload) {
+            userOwnerModel.setObject(((UserOwnerSelectPayload) event.getPayload()).getUserId());
+        }
+        if (event.getPayload() instanceof RoleOwnerSelectPayload) {
+            roleOwnerModel.setObject(((RoleOwnerSelectPayload) event.getPayload()).getRoleId());
+        }
+
+        if (event.getPayload() instanceof AjaxRequestTarget) {
+            ((AjaxRequestTarget) event.getPayload()).add(parentFragment);
+            ((AjaxRequestTarget) event.getPayload()).add(ownerContainer);
+        }
+    }
+
+    private class OwnerModel implements IModel {
+
+        private static final long serialVersionUID = -3865621970810102714L;
+
+        private final RoleTO roleTO;
+
+        private final AttributableType type;
+
+        public OwnerModel(final RoleTO roleTO, final AttributableType type) {
+            this.roleTO = roleTO;
+            this.type = type;
+        }
+
+        @Override
+        public Object getObject() {
+            String object = null;
+
+            switch (type) {
+                case USER:
+                    if (roleTO.getUserOwner() != null) {
+                        UserTO user = null;
+                        try {
+                            user = userRestClient.read(roleTO.getUserOwner());
+                        } catch (Exception e) {
+                            LOG.warn("Could not find user with id {}, ignoring", roleTO.getUserOwner(), e);
+                        }
+                        if (user == null) {
+                            roleTO.setUserOwner(null);
+                        } else {
+                            object = user.getKey() + " " + user.getUsername();
+                        }
+                    }
+                    break;
+
+                case ROLE:
+                    RoleTO role = null;
+                    if (roleTO.getRoleOwner() != null) {
+                        try {
+                            role = roleRestClient.read(roleTO.getRoleOwner());
+                        } catch (Exception e) {
+                            LOG.warn("Could not find role with id {}, ignoring", roleTO.getRoleOwner(), e);
+                        }
+                        if (role == null) {
+                            roleTO.setRoleOwner(null);
+                        } else {
+                            object = role.getDisplayName();
+                        }
+                    }
+                    break;
+
+                case MEMBERSHIP:
+                default:
+            }
+
+            return object;
+        }
+
+        @Override
+        public void setObject(final Object object) {
+            switch (type) {
+                case USER:
+                    roleTO.setUserOwner((Long) object);
+                    break;
+
+                case ROLE:
+                    roleTO.setRoleOwner((Long) object);
+                    break;
+
+                case MEMBERSHIP:
+                default:
+            }
+        }
+
+        @Override
+        public void detach() {
+            // ignore
+        }
+    }
+
+    private class ParentModel implements IModel {
+
+        private static final long serialVersionUID = 1006546156848990721L;
+
+        private final RoleTO roleTO;
+
+        public ParentModel(final RoleTO roleTO) {
+            this.roleTO = roleTO;
+        }
+
+        @Override
+        public Object getObject() {
+            Object object = null;
+            if (roleTO.getParent() != 0) {
+                RoleTO parent = null;
+                try {
+                    parent = roleRestClient.read(roleTO.getParent());
+                } catch (Exception e) {
+                    LOG.warn("Could not find role with id {}, ignoring", roleTO.getParent(), e);
+                }
+                if (parent == null) {
+                    roleTO.setParent(0);
+                } else {
+                    object = parent.getDisplayName();
+                }
+            }
+            return object;
+        }
+
+        @Override
+        public void setObject(final Object object) {
+            roleTO.setParent((object instanceof Long) ? ((Long) object) : 0);
+        }
+
+        @Override
+        public void detach() {
+            // ignore
+        }
+    }
+
+    public static class UserOwnerSelectPayload {
+
+        private final Long userId;
+
+        public UserOwnerSelectPayload(final Long userId) {
+            this.userId = userId;
+        }
+
+        public Long getUserId() {
+            return userId;
+        }
+    }
+
+    public static class RoleOwnerSelectPayload {
+
+        private final Long roleId;
+
+        public RoleOwnerSelectPayload(final Long roleId) {
+            this.roleId = roleId;
+        }
+
+        public Long getRoleId() {
+            return roleId;
+        }
+    }
+
+    public static class ParentSelectPayload {
+
+        private final Long roleId;
+
+        public ParentSelectPayload(final Long roleId) {
+            this.roleId = roleId;
+        }
+
+        public Long getRoleId() {
+            return roleId;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RolePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RolePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RolePanel.java
new file mode 100644
index 0000000..da04397
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RolePanel.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.rest.AuthRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class RolePanel extends Panel {
+
+    private static final long serialVersionUID = 4216376097320768369L;
+
+    @SpringBean
+    private AuthRestClient authRestClient;
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    private final AjaxPalettePanel<String> entitlements;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 8150440254654306070L;
+
+        private String id;
+
+        private Form form;
+
+        private RoleTO roleTO;
+
+        private Mode mode;
+
+        private PageReference pageReference;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public Builder form(final Form form) {
+            this.form = form;
+            return this;
+        }
+
+        public Builder roleTO(final RoleTO roleTO) {
+            this.roleTO = roleTO;
+            return this;
+        }
+
+        public Builder roleModalPageMode(final Mode mode) {
+            this.mode = mode;
+            return this;
+        }
+
+        public Builder pageRef(final PageReference pageReference) {
+            this.pageReference = pageReference;
+            return this;
+        }
+
+        public RolePanel build() {
+            return new RolePanel(this);
+        }
+    }
+
+    private RolePanel(final Builder builder) {
+        super(builder.id);
+
+        this.add(new RoleDetailsPanel("details", builder.roleTO, builder.mode == Mode.TEMPLATE));
+
+        if (builder.pageReference == null || builder.roleTO.getKey() == 0) {
+            this.add(new Label("statuspanel", ""));
+        } else {
+            StatusPanel statusPanel = new StatusPanel(
+                    "statuspanel", builder.roleTO, new ArrayList<StatusBean>(), builder.pageReference);
+            statusPanel.setOutputMarkupId(true);
+            MetaDataRoleAuthorizationStrategy.authorize(
+                    statusPanel, RENDER, xmlRolesReader.getEntitlement("Resources", "getConnectorObject"));
+            this.add(statusPanel);
+        }
+
+        this.add(new AnnotatedBeanPanel("systeminformation", builder.roleTO));
+
+        //--------------------------------
+        // Attribute templates panel
+        //--------------------------------
+        AttrTemplatesPanel attrTemplates = new AttrTemplatesPanel("templates", builder.roleTO);
+        this.add(attrTemplates);
+
+        //--------------------------------
+        // Attributes panel
+        //--------------------------------
+        this.add(new PlainAttrsPanel(
+                "plainAttrs", builder.roleTO, builder.form, builder.mode, attrTemplates));
+
+        final AjaxCheckBoxPanel inhAttributes = new AjaxCheckBoxPanel("inheritPlainAttrs", "inheritPlainAttrs",
+                new PropertyModel<Boolean>(builder.roleTO, "inheritPlainAttrs"));
+        inhAttributes.setOutputMarkupId(true);
+        this.add(inhAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Derived attributes panel
+        //--------------------------------
+        this.add(new DerAttrsPanel("derAttrs", builder.roleTO, attrTemplates));
+
+        final AjaxCheckBoxPanel inhDerivedAttributes = new AjaxCheckBoxPanel("inheritDerAttrs",
+                "inheritDerAttrs", new PropertyModel<Boolean>(builder.roleTO, "inheritDerAttrs"));
+        inhDerivedAttributes.setOutputMarkupId(true);
+        this.add(inhDerivedAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Virtual attributes panel
+        //--------------------------------
+        this.add(new VirAttrsPanel(
+                "virAttrs", builder.roleTO, builder.mode == Mode.TEMPLATE, attrTemplates));
+
+        final AjaxCheckBoxPanel inhVirtualAttributes = new AjaxCheckBoxPanel("inheritVirAttrs",
+                "inheritVirAttrs", new PropertyModel<Boolean>(builder.roleTO, "inheritVirAttrs"));
+        inhVirtualAttributes.setOutputMarkupId(true);
+        this.add(inhVirtualAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Resources panel
+        //--------------------------------
+        this.add(new ResourcesPanel.Builder("resources").attributableTO(builder.roleTO).build().
+                setOutputMarkupId(true));
+        //--------------------------------
+
+        //--------------------------------
+        // Entitlements
+        //--------------------------------
+        ListModel<String> selectedEntitlements = new ListModel<String>(builder.roleTO.getEntitlements());
+
+        List<String> allEntitlements = authRestClient.getAllEntitlements();
+        if (allEntitlements != null && !allEntitlements.isEmpty()) {
+            Collections.sort(allEntitlements);
+        }
+        ListModel<String> availableEntitlements = new ListModel<String>(allEntitlements);
+
+        entitlements = new AjaxPalettePanel<String>("entitlements", selectedEntitlements, availableEntitlements);
+        this.add(entitlements);
+
+        //--------------------------------
+        // Security panel
+        //--------------------------------
+        this.add(new RoleSecurityPanel("security", builder.roleTO).setOutputMarkupId(true));
+        //--------------------------------
+    }
+
+    public Collection<String> getSelectedEntitlements() {
+        return this.entitlements.getModelCollection();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchPanel.java
new file mode 100644
index 0000000..c8d9727
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchPanel.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.search.SyncopeFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.wicket.model.LoadableDetachableModel;
+
+public class RoleSearchPanel extends AbstractSearchPanel {
+
+    private static final long serialVersionUID = 5757183539269316263L;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 6308997285778809579L;
+
+        private String id;
+
+        private String fiql = null;
+
+        private boolean required = true;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public Builder fiql(final String fiql) {
+            this.fiql = fiql;
+            return this;
+        }
+
+        public Builder required(final boolean required) {
+            this.required = required;
+            return this;
+        }
+
+        public RoleSearchPanel build() {
+            return new RoleSearchPanel(this);
+        }
+    }
+
+    private RoleSearchPanel(final Builder builder) {
+        super(builder.id, AttributableType.ROLE, builder.fiql, builder.required);
+    }
+
+    @Override
+    protected void populate() {
+        super.populate();
+
+        this.types = new LoadableDetachableModel<List<SearchClause.Type>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<SearchClause.Type> load() {
+                final List<SearchClause.Type> result = new ArrayList<SearchClause.Type>();
+                result.add(SearchClause.Type.ATTRIBUTE);
+                result.add(SearchClause.Type.ENTITLEMENT);
+                result.add(SearchClause.Type.RESOURCE);
+                return result;
+            }
+        };
+
+        this.roleNames = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                return Collections.<String>emptyList();
+            }
+        };
+    }
+
+    @Override
+    protected SyncopeFiqlSearchConditionBuilder getSearchConditionBuilder() {
+        return SyncopeClient.getRoleSearchConditionBuilder();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchResultPanel.java
new file mode 100644
index 0000000..dfd40d5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchResultPanel.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.ResultStatusModalPage;
+import org.apache.syncope.client.console.pages.RoleModalPage;
+import org.apache.syncope.client.console.pages.StatusModalPage;
+import org.apache.syncope.client.console.rest.AbstractSubjectRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class RoleSearchResultPanel extends AbstractSearchResultPanel {
+
+    private static final long serialVersionUID = -1180593361914008764L;
+
+    private final static String PAGEID = "Roles";
+
+    public <T extends AbstractAttributableTO> RoleSearchResultPanel(final String id, final boolean filtered,
+            final String fiql, final PageReference callerRef, final AbstractSubjectRestClient restClient) {
+
+        super(id, filtered, fiql, callerRef, restClient);
+        initResultTable();
+    }
+
+    @Override
+    protected List<IColumn<AbstractAttributableTO, String>> getColumns() {
+        final List<IColumn<AbstractAttributableTO, String>> columns = new ArrayList<>();
+
+        for (String item : new String[] { "key", "name", "entitlements" }) {
+            columns.add(new PropertyColumn<AbstractAttributableTO, String>(new ResourceModel(item, item), item, item));
+        }
+
+        columns.add(new AbstractColumn<AbstractAttributableTO, String>(new ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = -3503023501954863131L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(final Item<ICellPopulator<AbstractAttributableTO>> cellItem,
+                    final String componentId, final IModel<AbstractAttributableTO> model) {
+
+                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, page.getPageReference());
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        statusmodal.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new StatusModalPage<RoleTO>(
+                                        page.getPageReference(), statusmodal, (RoleTO) model.getObject());
+                            }
+                        });
+
+                        statusmodal.show(target);
+                    }
+                }, ActionLink.ActionType.MANAGE_RESOURCES, PAGEID);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        editmodal.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new RoleModalPage(
+                                        page.getPageReference(), editmodal, (RoleTO) model.getObject());
+                            }
+                        });
+
+                        editmodal.show(target);
+                    }
+                }, ActionLink.ActionType.EDIT, PAGEID);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        try {
+                            final RoleTO roleTO = (RoleTO) restClient.
+                                    delete(model.getObject().getETagValue(), model.getObject().getKey());
+
+                            page.setModalResult(true);
+
+                            editmodal.setPageCreator(new ModalWindow.PageCreator() {
+
+                                private static final long serialVersionUID = -7834632442532690940L;
+
+                                @Override
+                                public Page createPage() {
+                                    return new ResultStatusModalPage.Builder(editmodal, roleTO).build();
+                                }
+                            });
+
+                            editmodal.show(target);
+                        } catch (SyncopeClientException scce) {
+                            error(getString(Constants.OPERATION_ERROR) + ": " + scce.getMessage());
+                            feedbackPanel.refresh(target);
+                        }
+                    }
+                }, ActionLink.ActionType.DELETE, PAGEID);
+
+                cellItem.add(panel);
+            }
+        });
+
+        return columns;
+    }
+
+    @Override
+    protected Collection<ActionType> getBulkActions() {
+        return Collections.<ActionLink.ActionType>singletonList(ActionLink.ActionType.DELETE);
+    }
+
+    @Override
+    protected String getPageId() {
+        return PAGEID;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSecurityPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSecurityPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSecurityPanel.java
new file mode 100644
index 0000000..b60d1e4
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSecurityPanel.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.PolicyRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.ChoiceRenderer;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoleSecurityPanel extends Panel {
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(RoleSecurityPanel.class);
+
+    private static final long serialVersionUID = -7982691107029848579L;
+
+    @SpringBean
+    private PolicyRestClient policyRestClient;
+
+    private IModel<Map<Long, String>> passwordPolicies = null;
+
+    private IModel<Map<Long, String>> accountPolicies = null;
+
+    public <T extends AbstractAttributableTO> RoleSecurityPanel(final String id, final T entityTO) {
+        super(id);
+
+        setOutputMarkupId(true);
+
+        passwordPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.PASSWORD, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        accountPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = -2012833443695917883L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : policyRestClient.getPolicies(PolicyType.ACCOUNT, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        final WebMarkupContainer securityContainer = new WebMarkupContainer("security");
+
+        securityContainer.setOutputMarkupId(true);
+        add(securityContainer);
+
+        // -------------------------------
+        // Password policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> passwordPolicy = new AjaxDropDownChoicePanel<Long>("passwordPolicy",
+                "passwordPolicy", new PropertyModel<Long>(entityTO, "passwordPolicy"));
+
+        passwordPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.PASSWORD));
+
+        passwordPolicy.setChoices(new ArrayList<Long>(passwordPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) passwordPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(passwordPolicy);
+
+        final AjaxCheckBoxPanel inhPasswordPolicy = new AjaxCheckBoxPanel("inheritPasswordPolicy",
+                "inheritPasswordPolicy", new PropertyModel<Boolean>(entityTO, "inheritPasswordPolicy"));
+
+        passwordPolicy.setReadOnly(inhPasswordPolicy.getModelObject());
+
+        inhPasswordPolicy.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                passwordPolicy.setReadOnly(inhPasswordPolicy.getModelObject());
+                target.add(passwordPolicy);
+            }
+        });
+
+        securityContainer.add(inhPasswordPolicy);
+        // -------------------------------
+
+        // -------------------------------
+        // Account policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> accountPolicy = new AjaxDropDownChoicePanel<Long>("accountPolicy",
+                "accountPolicy", new PropertyModel<Long>(entityTO, "accountPolicy"));
+
+        accountPolicy.setChoiceRenderer(new PolicyRenderer(PolicyType.ACCOUNT));
+
+        accountPolicy.setChoices(new ArrayList<Long>(accountPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) accountPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(accountPolicy);
+
+        final AjaxCheckBoxPanel inhAccountPolicy = new AjaxCheckBoxPanel("inheritAccountPolicy",
+                "inheritAccountPolicy", new PropertyModel<Boolean>(entityTO, "inheritAccountPolicy"));
+        accountPolicy.setReadOnly(inhAccountPolicy.getModelObject());
+
+        inhAccountPolicy.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                accountPolicy.setReadOnly(inhAccountPolicy.getModelObject());
+                target.add(accountPolicy);
+            }
+        });
+
+        securityContainer.add(inhAccountPolicy);
+        // -------------------------------
+    }
+
+    private class PolicyRenderer extends ChoiceRenderer<Long> {
+
+        private static final long serialVersionUID = 8060500161321947000L;
+
+        private PolicyType type;
+
+        public PolicyRenderer(final PolicyType type) {
+            super();
+            this.type = type;
+        }
+
+        @Override
+        public Object getDisplayValue(final Long object) {
+            Object displayValue;
+            switch (type) {
+                case ACCOUNT:
+                    displayValue = accountPolicies.getObject().get(object);
+                    break;
+                case PASSWORD:
+                    displayValue = passwordPolicies.getObject().get(object);
+                    break;
+                default:
+                    displayValue = "";
+            }
+            return displayValue;
+        }
+
+        @Override
+        public String getIdValue(Long object, int index) {
+            return String.valueOf(object != null
+                    ? object
+                    : 0L);
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSummaryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSummaryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSummaryPanel.java
new file mode 100644
index 0000000..d7663be
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSummaryPanel.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.RoleModalPage;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoleSummaryPanel extends Panel {
+
+    private static final long serialVersionUID = 643769814985593156L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(RoleSummaryPanel.class);
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private RoleRestClient restClient;
+
+    private RoleTO selectedNode;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 4164563358509351832L;
+
+        private String id;
+
+        private ModalWindow window;
+
+        private PageReference callerPageRef;
+
+        private Long selectedNodeId = null;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public RoleSummaryPanel.Builder window(final ModalWindow window) {
+            this.window = window;
+            return this;
+        }
+
+        public RoleSummaryPanel.Builder callerPageRef(final PageReference callerPageRef) {
+            this.callerPageRef = callerPageRef;
+            return this;
+        }
+
+        public RoleSummaryPanel.Builder selectedNodeId(final Long selectedNodeId) {
+            this.selectedNodeId = selectedNodeId;
+            return this;
+        }
+
+        public RoleSummaryPanel build() {
+            return new RoleSummaryPanel(this);
+        }
+    }
+
+    private RoleSummaryPanel(final Builder builder) {
+        super(builder.id);
+
+        if (builder.selectedNodeId == null || builder.selectedNodeId == 0) {
+            selectedNode = null;
+        } else {
+            try {
+                selectedNode = restClient.read(builder.selectedNodeId);
+            } catch (SyncopeClientException e) {
+                LOG.error("Could not read {}", builder.selectedNodeId, e);
+                selectedNode = null;
+                builder.selectedNodeId = null;
+            }
+        }
+
+        Fragment fragment = new Fragment("roleSummaryPanel",
+                builder.selectedNodeId == null
+                        ? "fakerootFrag"
+                        : (builder.selectedNodeId == 0 ? "rootPanel" : "roleViewPanel"),
+                this);
+
+        if (builder.selectedNodeId != null) {
+            if (builder.selectedNodeId == 0) {
+                @SuppressWarnings("rawtypes")
+                final ActionLinksPanel links = new ActionLinksPanel("actionLinks", new Model(), builder.callerPageRef);
+                links.setOutputMarkupId(true);
+                fragment.add(links);
+
+                links.addWithRoles(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        builder.window.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new RoleModalPage(builder.callerPageRef, builder.window, new RoleTO());
+                            }
+                        });
+
+                        builder.window.show(target);
+                    }
+                }, ActionLink.ActionType.CREATE, xmlRolesReader.getEntitlement("Roles", "create"));
+            } else {
+                RoleTabPanel roleTabPanel =
+                        new RoleTabPanel("nodeViewPanel", selectedNode, builder.window, builder.callerPageRef);
+                roleTabPanel.setOutputMarkupId(true);
+                fragment.add(roleTabPanel);
+            }
+        }
+        add(fragment);
+    }
+
+    public RoleTO getSelectedNode() {
+        return selectedNode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleTabPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleTabPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleTabPanel.java
new file mode 100644
index 0000000..7c483b5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleTabPanel.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.ResultStatusModalPage;
+import org.apache.syncope.client.console.pages.RoleModalPage;
+import org.apache.syncope.client.console.pages.Roles;
+import org.apache.syncope.client.console.pages.StatusModalPage;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class RoleTabPanel extends Panel {
+
+    private static final long serialVersionUID = 859236186975983959L;
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private RoleRestClient roleRestClient;
+
+    @SpringBean
+    private UserRestClient userRestClient;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public RoleTabPanel(final String id, final RoleTO selectedNode, final ModalWindow window,
+            final PageReference pageRef) {
+
+        super(id);
+
+        this.add(new Label("displayName", selectedNode.getDisplayName()));
+
+        final ActionLinksPanel links = new ActionLinksPanel("actionLinks", new Model(), pageRef);
+        links.setOutputMarkupId(true);
+        this.add(links);
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        RoleTO roleTO = new RoleTO();
+                        roleTO.setParent(selectedNode.getKey());
+                        return new RoleModalPage(pageRef, window, roleTO);
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.CREATE, xmlRolesReader.getEntitlement("Roles", "create"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        return new StatusModalPage<RoleTO>(pageRef, window, roleRestClient.read(selectedNode.getKey()));
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.MANAGE_RESOURCES, xmlRolesReader.getEntitlement("Roles", "update"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        RoleTO roleTO = roleRestClient.read(selectedNode.getKey());
+                        return new RoleModalPage(pageRef, window, roleTO);
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.EDIT, xmlRolesReader.getEntitlement("Roles", "update"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    final RoleTO roleTO = roleRestClient.delete(selectedNode.getETagValue(), selectedNode.getKey());
+
+                    ((Roles) pageRef.getPage()).setModalResult(true);
+
+                    window.setPageCreator(new ModalWindow.PageCreator() {
+
+                        private static final long serialVersionUID = -7834632442532690940L;
+
+                        @Override
+                        public Page createPage() {
+                            return new ResultStatusModalPage.Builder(window, roleTO).build();
+                        }
+                    });
+
+                    window.show(target);
+                } catch (SyncopeClientException e) {
+                    error(getString(Constants.OPERATION_ERROR) + ": " + e.getMessage());
+                    ((Roles) pageRef.getPage()).getFeedbackPanel().refresh(target);
+                }
+            }
+        }, ActionLink.ActionType.DELETE, xmlRolesReader.getEntitlement("Roles", "delete"));
+
+        final Form form = new Form("roleForm");
+        form.setModel(new CompoundPropertyModel(selectedNode));
+        form.setOutputMarkupId(true);
+
+        final RolePanel rolePanel = new RolePanel.Builder("rolePanel").form(form).roleTO(selectedNode).
+                roleModalPageMode(Mode.ADMIN).build();
+        rolePanel.setEnabled(false);
+        form.add(rolePanel);
+
+        final WebMarkupContainer userListContainer = new WebMarkupContainer("userListContainer");
+
+        userListContainer.setOutputMarkupId(true);
+        userListContainer.setEnabled(true);
+        userListContainer.add(new UserSearchResultPanel("userList", true, null, pageRef, userRestClient));
+        userListContainer.add(new ClearIndicatingAjaxButton("search", new ResourceModel("search"), pageRef) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+                userListContainer.replace(new UserSearchResultPanel("userList",
+                        true,
+                        SyncopeClient.getUserSearchConditionBuilder().hasRoles(selectedNode.getKey()).query(),
+                        pageRef,
+                        userRestClient));
+
+                target.add(userListContainer);
+            }
+        });
+
+        form.add(userListContainer);
+        add(form);
+    }
+}