You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2015/12/28 15:49:37 UTC

[1/2] syncope git commit: [SYNCOPE-745] providing roles management

Repository: syncope
Updated Branches:
  refs/heads/master 33fd83021 -> f93b48951


http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_pt_BR.properties
index 5099690..889e6f0 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_pt_BR.properties
@@ -29,6 +29,6 @@ creationDate=Data de Cria\u00e7\u00e3o
 tokenValued=Atribu\u00eddo
 tokenNotValued=N\u00e3o Atribu\u00eddo
 
-any.edit=Alterar ${type} ${key}
-any.new=Novo ${type}
+any.edit=Alterar ${anyTO.type} ${key}
+any.new=Novo ${anyTO.type}
 any.attr.display=Attributes to be displayed

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel.properties
new file mode 100644
index 0000000..441110e
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel.properties
@@ -0,0 +1,18 @@
+# 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.
+any.edit=Edit role ${roleTO.key}
+any.new=New role

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_it.properties
new file mode 100644
index 0000000..b048546
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_it.properties
@@ -0,0 +1,18 @@
+# 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.
+any.edit=Modifica ruolo ${roleTO.key}
+any.new=Nuovo ruolo

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_pt_BR.properties
new file mode 100644
index 0000000..9ae44c5
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RoleSearchResultPanel_pt_BR.properties
@@ -0,0 +1,18 @@
+# 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.
+any.edit=Alterar fun\u00e7\u00e3o ${roleTO.key}
+any.new=Novo fun\u00e7\u00e3o

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

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

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


[2/2] syncope git commit: [SYNCOPE-745] providing roles management

Posted by fm...@apache.org.
[SYNCOPE-745] providing roles management


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

Branch: refs/heads/master
Commit: f93b48951c2696d71608559b51d8d63699797b9e
Parents: 33fd830
Author: fmartelli <fa...@gmail.com>
Authored: Mon Dec 28 15:48:30 2015 +0100
Committer: fmartelli <fa...@gmail.com>
Committed: Mon Dec 28 15:48:30 2015 +0100

----------------------------------------------------------------------
 .../client/console/commons/AnyDataProvider.java |  24 ++-
 .../client/console/commons/Constants.java       |   6 +
 .../console/commons/RoleDataProvider.java       |  58 ++++++
 .../console/commons/SearchableDataProvider.java |  38 ++++
 .../syncope/client/console/pages/BasePage.java  |   5 +
 .../syncope/client/console/pages/Roles.java     |  75 ++++++++
 .../panels/AbstractSearchResultPanel.java       |  92 ++++------
 .../panels/AnyObjectSearchResultPanel.java      |  72 +++++++-
 .../console/panels/GroupSearchResultPanel.java  |  28 ++-
 .../client/console/panels/ListViewPanel.java    |   7 +-
 .../syncope/client/console/panels/Realm.java    |   2 +-
 .../console/panels/RoleSearchResultPanel.java   | 179 +++++++++++++++++++
 .../console/panels/UserSearchResultPanel.java   |  23 ++-
 .../search/GroupSelectionSearchResultPanel.java |   3 +-
 .../search/UserSelectionSearchResultPanel.java  |   3 +-
 .../client/console/rest/RoleRestClient.java     |  31 ++++
 .../markup/html/form/AjaxPalettePanel.java      |  66 ++++++-
 .../client/console/wizards/WizardMgtPanel.java  |  41 +++--
 .../console/wizards/any/GroupHandler.java       |   4 +-
 .../console/wizards/role/RoleHandler.java       |  73 ++++++++
 .../console/wizards/role/RoleWizardBuilder.java | 167 +++++++++++++++++
 .../syncope/client/console/pages/BasePage.html  |   1 +
 .../syncope/client/console/pages/Roles.html     |  48 +++++
 .../client/console/pages/Roles.properties       |  18 ++
 .../client/console/pages/Roles_it.properties    |  18 ++
 .../client/console/pages/Roles_pt_BR.properties |  18 ++
 .../client/console/pages/SecurityQuestions.html |   2 +-
 .../AbstractSearchResultPanel_it.properties     |   4 +-
 .../AbstractSearchResultPanel_pt_BR.properties  |   4 +-
 .../panels/RoleSearchResultPanel.properties     |  18 ++
 .../panels/RoleSearchResultPanel_it.properties  |  18 ++
 .../RoleSearchResultPanel_pt_BR.properties      |  18 ++
 .../wizards/role/RoleWizardBuilder$Details.html |  29 +++
 .../role/RoleWizardBuilder$Entitlements.html    |  28 +++
 .../wizards/role/RoleWizardBuilder$Realms.html  |  28 +++
 35 files changed, 1106 insertions(+), 143 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
index a4ffcae..05d18e3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
@@ -24,23 +24,20 @@ import java.util.List;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
-import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
 
-public class AnyDataProvider<T extends AnyTO> extends SortableDataProvider<T, String> {
+public class AnyDataProvider<T extends AnyTO> extends SearchableDataProvider<T> {
 
     private static final long serialVersionUID = 6267494272884913376L;
 
     private final SortableAnyProviderComparator<T> comparator;
 
-    private String fiql = null;
-
-    private final int paginatorRows;
+    private final AbstractAnyRestClient<T> restClient;
 
-    private final boolean filtered;
+    protected String fiql;
 
-    private final AbstractAnyRestClient<T> restClient;
+    protected final boolean filtered;
 
     private final String realm;
 
@@ -53,11 +50,11 @@ public class AnyDataProvider<T extends AnyTO> extends SortableDataProvider<T, St
             final String realm,
             final String type) {
 
-        super();
+        super(paginatorRows);
 
         this.restClient = restClient;
+
         this.filtered = filtered;
-        this.paginatorRows = paginatorRows;
 
         // default sorting
         setSort("key", SortOrder.ASCENDING);
@@ -68,10 +65,6 @@ public class AnyDataProvider<T extends AnyTO> extends SortableDataProvider<T, St
         this.type = type;
     }
 
-    public void setFIQL(final String fiql) {
-        this.fiql = fiql;
-    }
-
     @Override
     public Iterator<T> iterator(final long first, final long count) {
         List<T> result;
@@ -103,6 +96,11 @@ public class AnyDataProvider<T extends AnyTO> extends SortableDataProvider<T, St
         return result;
     }
 
+    public AnyDataProvider<T> setFIQL(final String fiql) {
+        this.fiql = fiql;
+        return this;
+    }
+
     @Override
     public IModel<T> model(final T object) {
         return new CompoundPropertyModel<>(object);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
index 8f78562..ac38364 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
@@ -82,6 +82,12 @@ public final class Constants {
 
     public static final String PREF_USERS_PAGINATOR_ROWS = "users.paginator.rows";
 
+    public static final String PREF_ANYOBJECT_PAGINATOR_ROWS = "anyobject.paginator.rows";
+
+    public static final String PREF_GROUP_PAGINATOR_ROWS = "group.paginator.rows";
+
+    public static final String PREF_ROLE_PAGINATOR_ROWS = "role.paginator.rows";
+
     public static final String PREF_RESOURCES_PAGINATOR_ROWS = "resources.paginator.rows";
 
     public static final String PREF_CONNECTORS_PAGINATOR_ROWS = "connectors.paginator.rows";

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/commons/RoleDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/RoleDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/RoleDataProvider.java
new file mode 100644
index 0000000..5d85ec5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/RoleDataProvider.java
@@ -0,0 +1,58 @@
+/*
+ * 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.commons;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+public class RoleDataProvider extends SearchableDataProvider<RoleTO> {
+
+    private static final long serialVersionUID = 6267494272884913376L;
+
+    private final SortableDataProviderComparator<RoleTO> comparator;
+
+    private final RoleRestClient restClient = new RoleRestClient();
+
+    public RoleDataProvider(final int paginatorRows) {
+        super(paginatorRows);
+        this.comparator = new SortableDataProviderComparator<>(this);
+    }
+
+    @Override
+    public Iterator<RoleTO> iterator(final long first, final long count) {
+        final List<RoleTO> result = restClient.list();
+        Collections.sort(result, comparator);
+        return result.iterator();
+    }
+
+    @Override
+    public long size() {
+        return restClient.count();
+    }
+
+    @Override
+    public IModel<RoleTO> model(final RoleTO object) {
+        return new CompoundPropertyModel<>(object);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/commons/SearchableDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/SearchableDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/SearchableDataProvider.java
new file mode 100644
index 0000000..37701a7
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/SearchableDataProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons;
+
+import java.io.Serializable;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+
+public abstract class SearchableDataProvider<T extends Serializable> extends SortableDataProvider<T, String> {
+
+    private static final long serialVersionUID = 6267494272884913376L;
+
+    protected final int paginatorRows;
+
+    public SearchableDataProvider(final int paginatorRows) {
+        super();
+        this.paginatorRows = paginatorRows;
+
+        // default sorting
+        setSort("key", SortOrder.ASCENDING);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
index 79b4dbe..b7132cd 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
@@ -120,6 +120,11 @@ public class BasePage extends AbstractBasePage implements IAjaxIndicatorAware {
         MetaDataRoleAuthorizationStrategy.authorize(typesLink, WebPage.ENABLE, StandardEntitlement.SCHEMA_LIST);
         liContainer.add(typesLink);
 
+        liContainer = new WebMarkupContainer(getLIContainerId("roles"));
+        confULContainer.add(liContainer);
+        liContainer.add(new BookmarkablePageLink<>("roles", Roles.class));
+        MetaDataRoleAuthorizationStrategy.authorize(liContainer, WebPage.RENDER, StandardEntitlement.ROLE_LIST);
+        
         liContainer = new WebMarkupContainer(getLIContainerId("policies"));
         confULContainer.add(liContainer);
         liContainer.add(new BookmarkablePageLink<>("policies", Policies.class));

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
new file mode 100644
index 0000000..7910c9a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
@@ -0,0 +1,75 @@
+/*
+ * 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.pages;
+
+import static org.apache.wicket.Component.ENABLE;
+
+import org.apache.syncope.client.console.panels.RoleSearchResultPanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.client.console.wizards.role.RoleHandler;
+import org.apache.syncope.client.console.wizards.role.RoleWizardBuilder;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class Roles extends BasePage {
+
+    private static final long serialVersionUID = -1100228004207271271L;
+
+    public Roles(final PageParameters parameters) {
+        super(parameters);
+
+        final WebMarkupContainer content = new WebMarkupContainer("content");
+        content.add(new Label("header", getString("header_title", new Model<>(), "Roles")));
+        content.setOutputMarkupId(true);
+        add(content);
+
+        final WizardMgtPanel<RoleHandler> roleSearchResultPanel
+                = new RoleSearchResultPanel.Builder(getPageReference()) {
+
+            private static final long serialVersionUID = -5960765294082359003L;
+
+        }.addNewItemPanelBuilder(new RoleWizardBuilder(BaseModal.CONTENT_ID, new RoleTO(), getPageReference()), false).
+                build("roles");
+
+        final AjaxLink<RoleTO> createLink = new AjaxLink<RoleTO>("add") {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                send(roleSearchResultPanel, Broadcast.EXACT, new AjaxWizard.NewItemActionEvent<RoleTO>(null, target));
+            }
+        };
+
+        content.add(createLink);
+        MetaDataRoleAuthorizationStrategy.authorize(createLink, ENABLE, StandardEntitlement.ROLE_CREATE);
+
+        content.add(roleSearchResultPanel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
index 49e3aa6..d588a9c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
@@ -18,18 +18,17 @@
  */
 package org.apache.syncope.client.console.panels;
 
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
 import org.apache.syncope.client.console.PreferenceManager;
-import org.apache.syncope.client.console.commons.AnyDataProvider;
 import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.pages.AbstractBasePage;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.client.console.rest.BaseRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
-import org.apache.syncope.client.console.wizards.any.AnyHandler;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
@@ -44,7 +43,9 @@ import org.apache.wicket.model.PropertyModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardMgtPanel<AnyHandler<T>> {
+public abstract class AbstractSearchResultPanel<
+        T extends Serializable, W extends Serializable, DP extends SearchableDataProvider<T>, E extends BaseRestClient>
+        extends WizardMgtPanel<W> {
 
     private static final long serialVersionUID = -9170191461250434024L;
 
@@ -55,12 +56,12 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
      */
     protected PreferenceManager prefMan = new PreferenceManager();
 
-    protected final AbstractAnyRestClient<T> restClient;
+    protected final E restClient;
 
     /**
      * Number of rows per page.
      */
-    private final int rows;
+    protected int rows;
 
     /**
      * Container used to refresh table.
@@ -76,16 +77,11 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
      * Specify if results are about a filtered search or not. Using this attribute it is possible to use this panel to
      * show results about user list and user search.
      */
-    private final boolean filtered;
+    protected final boolean filtered;
 
     private final boolean checkBoxEnabled;
 
     /**
-     * Filter used in case of filtered search.
-     */
-    private String fiql;
-
-    /**
      * Result table.
      */
     private AjaxDataTablePanel<T, String> resultTable;
@@ -93,26 +89,16 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
     /**
      * Data provider used to search for users.
      */
-    private AnyDataProvider<T> dataProvider;
+    protected DP dataProvider;
 
     /**
      * Owner page.
      */
     protected final AbstractBasePage page;
 
-    /**
-     * Realm related to current panel.
-     */
-    private final String realm;
+    protected AbstractSearchResultPanel(final String id, final Builder<T, W, E> builder) {
 
-    /**
-     * Any type related to current panel.
-     */
-    protected final String type;
-
-    protected AbstractSearchResultPanel(final String id, final Builder<T> builder) {
-
-        super(id, builder.getPageRef(), true);
+        super(id, true);
 
         setOutputMarkupId(true);
 
@@ -120,7 +106,6 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
 
         this.filtered = builder.filtered;
         this.checkBoxEnabled = builder.checkBoxEnabled;
-        this.fiql = builder.fiql;
         this.feedbackPanel = page.getFeedbackPanel();
 
         this.restClient = builder.restClient;
@@ -130,14 +115,17 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
         container.setOutputMarkupId(true);
         add(container);
 
-        rows = prefMan.getPaginatorRows(getRequest(), Constants.PREF_USERS_PAGINATOR_ROWS);
-
-        this.realm = builder.realm;
-        this.type = builder.type;
+        rows = prefMan.getPaginatorRows(getRequest(), paginatorRowsKey());
 
         setWindowClosedReloadCallback(modal);
     }
 
+    protected abstract DP dataProvider();
+
+    protected abstract String paginatorRowsKey();
+
+    protected abstract List<IColumn<T, String>> getColumns();
+
     protected void initResultTable() {
         // ---------------------------
         // Result table initialization
@@ -160,7 +148,7 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
 
             @Override
             protected void onUpdate(final AjaxRequestTarget target) {
-                prefMan.set(getRequest(), getResponse(), Constants.PREF_USERS_PAGINATOR_ROWS, String.valueOf(rows));
+                prefMan.set(getRequest(), getResponse(), paginatorRowsKey(), String.valueOf(rows));
 
                 final EventDataWrapper data = new EventDataWrapper();
                 data.setTarget(target);
@@ -173,9 +161,7 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
         // ---------------------------
     }
 
-    public void search(final String fiql, final AjaxRequestTarget target) {
-        this.fiql = fiql;
-        dataProvider.setFIQL(fiql);
+    public void search(final AjaxRequestTarget target) {
         target.add(container);
     }
 
@@ -184,8 +170,7 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
     }
 
     private void updateResultTable(final boolean create, final int rows) {
-        dataProvider = new AnyDataProvider<>(restClient, rows, filtered, realm, type);
-        dataProvider.setFIQL(fiql);
+        dataProvider = dataProvider();
 
         final int currentPage = resultTable != null
                 ? (create ? (int) resultTable.getPageCount() - 1 : (int) resultTable.getCurrentPage()) : 0;
@@ -208,8 +193,6 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
         container.addOrReplace(resultTable);
     }
 
-    protected abstract List<IColumn<T, String>> getColumns();
-
     @Override
     public void onEvent(final IEvent<?> event) {
         if (event.getPayload() instanceof EventDataWrapper) {
@@ -286,11 +269,12 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
         }
     }
 
-    protected abstract <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions();
+    protected abstract Collection<ActionLink.ActionType> getBulkActions();
 
     protected abstract String getPageId();
 
-    public abstract static class Builder<T extends AnyTO> extends WizardMgtPanel.Builder<AnyHandler<T>> {
+    public abstract static class Builder<T extends Serializable, W extends Serializable, E extends BaseRestClient>
+            extends WizardMgtPanel.Builder<W> {
 
         private static final long serialVersionUID = 5088962796986706805L;
 
@@ -307,44 +291,28 @@ public abstract class AbstractSearchResultPanel<T extends AnyTO> extends WizardM
          */
         protected String fiql;
 
-        protected final AbstractAnyRestClient<T> restClient;
-
-        /**
-         * Realm related to current panel.
-         */
-        protected String realm = "/";
-
-        /**
-         * Any type related to current panel.
-         */
-        protected final String type;
+        protected final E restClient;
 
-        protected Builder(final AbstractAnyRestClient<T> restClient, final String type, final PageReference pageRef) {
+        protected Builder(final E restClient, final PageReference pageRef) {
             super(pageRef);
             this.restClient = restClient;
-            this.type = type;
         }
 
-        public Builder<T> setFiltered(final boolean filtered) {
+        public Builder<T, W, E> setFiltered(final boolean filtered) {
             this.filtered = filtered;
             return this;
         }
 
-        public Builder<T> disableCheckBoxes() {
+        public Builder<T, W, E> disableCheckBoxes() {
             this.checkBoxEnabled = false;
             return this;
         }
 
-        public Builder<T> setFiql(final String fiql) {
+        public Builder<T, W, E> setFiql(final String fiql) {
             this.fiql = fiql;
             return this;
         }
 
-        public Builder<T> setRealm(final String realm) {
-            this.realm = realm;
-            return this;
-        }
-
         private PageReference getPageRef() {
             return pageRef;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
index 4dcfee5..badfbd5 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
@@ -26,6 +26,7 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.client.console.commons.AnyDataProvider;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.AnyDisplayAttributesModalPage;
 import org.apache.syncope.client.console.pages.BasePage;
@@ -56,7 +57,8 @@ import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
 import org.springframework.util.ReflectionUtils;
 
-public class AnyObjectSearchResultPanel<T extends AnyTO> extends AbstractSearchResultPanel<T> {
+public class AnyObjectSearchResultPanel<T extends AnyTO>
+        extends AbstractSearchResultPanel<T, AnyHandler<T>, AnyDataProvider<T>, AbstractAnyRestClient<T>> {
 
     private static final long serialVersionUID = -1100228004207271270L;
 
@@ -66,10 +68,28 @@ public class AnyObjectSearchResultPanel<T extends AnyTO> extends AbstractSearchR
 
     protected final List<String> dSchemaNames;
 
-    protected final String pageID = "Any";
+    private final String pageID = "Any";
 
-    protected AnyObjectSearchResultPanel(final String id, final AbstractSearchResultPanel.Builder<T> builder) {
+    /**
+     * Filter used in case of filtered search.
+     */
+    private String fiql;
+
+    /**
+     * Realm related to current panel.
+     */
+    protected final String realm;
+
+    /**
+     * Any type related to current panel.
+     */
+    protected final String type;
+
+    protected AnyObjectSearchResultPanel(final String id, final Builder<T> builder) {
         super(id, builder);
+        this.realm = builder.realm;
+        this.type = builder.type;
+        this.fiql = builder.fiql;
 
         modal.size(Modal.Size.Large);
 
@@ -88,6 +108,17 @@ public class AnyObjectSearchResultPanel<T extends AnyTO> extends AbstractSearchR
     }
 
     @Override
+    protected AnyDataProvider<T> dataProvider() {
+        final AnyDataProvider<T> dp = new AnyDataProvider<>(restClient, rows, filtered, realm, type);
+        return dp.setFIQL(this.fiql);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_ANYOBJECT_PAGINATOR_ROWS;
+    }
+
+    @Override
     protected List<IColumn<T, String>> getColumns() {
         final List<IColumn<T, String>> columns = new ArrayList<>();
 
@@ -214,8 +245,14 @@ public class AnyObjectSearchResultPanel<T extends AnyTO> extends AbstractSearchR
         return columns;
     }
 
+    public void search(final String fiql, final AjaxRequestTarget target) {
+        this.fiql = fiql;
+        dataProvider.setFIQL(fiql);
+        super.search(target);
+    }
+
     @Override
-    protected <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions() {
+    protected Collection<ActionLink.ActionType> getBulkActions() {
         final List<ActionLink.ActionType> bulkActions = new ArrayList<>();
 
         bulkActions.add(ActionLink.ActionType.DELETE);
@@ -235,26 +272,43 @@ public class AnyObjectSearchResultPanel<T extends AnyTO> extends AbstractSearchR
         List<AnyTypeClassTO> getAnyTypeClassTOs();
     }
 
-    public static final class Builder extends AbstractSearchResultPanel.Builder<AnyObjectTO>
+    public static class Builder<T extends AnyTO>
+            extends AbstractSearchResultPanel.Builder<T, AnyHandler<T>, AbstractAnyRestClient<T>>
             implements AnySearchResultPanelBuilder {
 
         private static final long serialVersionUID = -6828423611982275640L;
 
+        /**
+         * Realm related to current panel.
+         */
+        protected String realm = "/";
+
+        /**
+         * Any type related to current panel.
+         */
+        protected final String type;
+
         private final List<AnyTypeClassTO> anyTypeClassTOs;
 
         public Builder(
                 final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<AnyObjectTO> restClient,
+                final AbstractAnyRestClient<T> restClient,
                 final String type,
                 final PageReference pageRef) {
 
-            super(restClient, type, pageRef);
+            super(restClient, pageRef);
             this.anyTypeClassTOs = anyTypeClassTOs;
+            this.type = type;
         }
 
         @Override
-        protected WizardMgtPanel<AnyHandler<AnyObjectTO>> newInstance(final String id) {
-            return new AnyObjectSearchResultPanel<>(id, this);
+        protected WizardMgtPanel<AnyHandler<T>> newInstance(final String id) {
+            return new AnyObjectSearchResultPanel<T>(id, this);
+        }
+
+        public Builder<T> setRealm(final String realm) {
+            this.realm = realm;
+            return this;
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
index 4712328..8ac8812 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
@@ -41,7 +41,6 @@ import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.client.console.wizards.any.GroupHandler;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -59,11 +58,18 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
 
     private static final long serialVersionUID = -1100228004207271270L;
 
+    private final String pageID = "Groups";
+
     protected GroupSearchResultPanel(final String id, final Builder builder) {
         super(id, builder);
     }
 
     @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_GROUP_PAGINATOR_ROWS;
+    }
+
+    @Override
     protected List<IColumn<GroupTO, String>> getColumns() {
         final List<IColumn<GroupTO, String>> columns = new ArrayList<>();
 
@@ -114,7 +120,7 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
                     private static final long serialVersionUID = -7978723352517770644L;
 
                     @Override
-                    public void onClick(final AjaxRequestTarget target, final GroupTO anyTO) {
+                    public void onClick(final AjaxRequestTarget target, final GroupTO ignore) {
                         send(GroupSearchResultPanel.this, Broadcast.EXACT,
                                 new AjaxWizard.EditItemActionEvent<GroupHandler>(
                                         new GroupHandler(new GroupRestClient().read(model.getObject().getKey())),
@@ -125,7 +131,7 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
                     private static final long serialVersionUID = -7978723352517770644L;
 
                     @Override
-                    public void onClick(final AjaxRequestTarget target, final GroupTO anyTO) {
+                    public void onClick(final AjaxRequestTarget target, final GroupTO ignore) {
                         final GroupTO clone = SerializationUtils.clone(model.getObject());
                         clone.setKey(0L);
                         send(GroupSearchResultPanel.this, Broadcast.EXACT,
@@ -136,7 +142,7 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
                     private static final long serialVersionUID = -7978723352517770644L;
 
                     @Override
-                    public void onClick(final AjaxRequestTarget target, final GroupTO anyTO) {
+                    public void onClick(final AjaxRequestTarget target, final GroupTO ignore) {
                         try {
                             restClient.delete(model.getObject().getETagValue(), model.getObject().getKey());
                             info(getString(Constants.OPERATION_SUCCEEDED));
@@ -187,7 +193,7 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
     }
 
     @Override
-    protected <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions() {
+    protected Collection<ActionLink.ActionType> getBulkActions() {
         final List<ActionType> bulkActions = new ArrayList<>();
 
         bulkActions.add(ActionType.DELETE);
@@ -202,31 +208,23 @@ public class GroupSearchResultPanel extends AnyObjectSearchResultPanel<GroupTO>
         return pageID;
     }
 
-    public static class Builder extends AbstractSearchResultPanel.Builder<GroupTO>
+    public static class Builder extends AnyObjectSearchResultPanel.Builder<GroupTO>
             implements AnySearchResultPanelBuilder {
 
         private static final long serialVersionUID = 1L;
 
-        private final List<AnyTypeClassTO> anyTypeClassTOs;
-
         public Builder(
                 final List<AnyTypeClassTO> anyTypeClassTOs,
                 final AbstractAnyRestClient<GroupTO> restClient,
                 final String type,
                 final PageReference pageRef) {
 
-            super(restClient, type, pageRef);
-            this.anyTypeClassTOs = anyTypeClassTOs;
+            super(anyTypeClassTOs, restClient, type, pageRef);
         }
 
         @Override
         protected WizardMgtPanel<AnyHandler<GroupTO>> newInstance(final String id) {
             return new GroupSearchResultPanel(id, this);
         }
-
-        @Override
-        public List<AnyTypeClassTO> getAnyTypeClassTOs() {
-            return this.anyTypeClassTOs;
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
index 5aa35de..c1ac5b1 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
@@ -98,9 +98,8 @@ public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPan
             final ActionLinksPanel.Builder<T> actions,
             final CheckAvailability check,
             final boolean reuseItem,
-            final IModel<? extends Collection<T>> model,
-            final PageReference pageRef) {
-        super(id, pageRef);
+            final IModel<? extends Collection<T>> model) {
+        super(id);
         setOutputMarkupId(true);
 
         this.check = Model.of(check);
@@ -341,7 +340,7 @@ public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPan
 
         @Override
         protected WizardMgtPanel<T> newInstance(final String id) {
-            return new ListViewPanel<T>(id, items, reference, includes, actions, check, reuseItem, model, pageRef) {
+            return new ListViewPanel<T>(id, items, reference, includes, actions, check, reuseItem, model) {
 
                 private static final long serialVersionUID = 1L;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index 73d39e0..1a58169 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -149,7 +149,7 @@ public class Realm extends Panel {
                 final AnyObjectTO anyObjectTO = new AnyObjectTO();
                 anyObjectTO.setRealm(realmTO.getFullPath());
                 anyObjectTO.setType(anyTypeTO.getKey());
-                panel = new AnyObjectSearchResultPanel.Builder(
+                panel = new AnyObjectSearchResultPanel.Builder<AnyObjectTO>(
                         anyTypeRestClient.getAnyTypeClass(anyTypeTO.getClasses().toArray(new String[] {})),
                         anyObjectRestClient,
                         anyTypeTO.getKey(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/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..7986cd6
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleSearchResultPanel.java
@@ -0,0 +1,179 @@
+/*
+ * 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 de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RoleDataProvider;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+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.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.client.console.wizards.role.RoleHandler;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.event.Broadcast;
+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.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class RoleSearchResultPanel
+        extends AbstractSearchResultPanel<RoleTO, RoleHandler, RoleDataProvider, RoleRestClient> {
+
+    private static final long serialVersionUID = -1100228004207271270L;
+
+    private final String pageID = "Roles";
+
+    protected RoleSearchResultPanel(final String id, final Builder builder) {
+        super(id, builder);
+        modal.size(Modal.Size.Large);
+        initResultTable();
+    }
+
+    @Override
+    protected RoleDataProvider dataProvider() {
+        return new RoleDataProvider(rows);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_ROLE_PAGINATOR_ROWS;
+    }
+
+    @Override
+    protected List<IColumn<RoleTO, String>> getColumns() {
+        final List<IColumn<RoleTO, String>> columns = new ArrayList<>();
+
+        columns.add(new PropertyColumn<RoleTO, String>(new ResourceModel("key", "key"), "key", "key"));
+        columns.add(new PropertyColumn<RoleTO, String>(
+                new ResourceModel("entitlements", "entitlements"), "entitlements", "entitlements"));
+        columns.add(new PropertyColumn<RoleTO, String>(
+                new ResourceModel("realms", "realms"), "realms", "realms"));
+
+        columns.add(new ActionColumn<RoleTO, String>(new ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = -3503023501954863131L;
+
+            @Override
+            public ActionLinksPanel<RoleTO> getActions(final String componentId, final IModel<RoleTO> model) {
+                final ActionLinksPanel.Builder<RoleTO> panel = ActionLinksPanel.builder(page.getPageReference());
+
+                panel.add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        send(RoleSearchResultPanel.this, Broadcast.EXACT,
+                                new AjaxWizard.EditItemActionEvent<RoleHandler>(
+                                        new RoleHandler(new RoleRestClient().read(model.getObject().getKey())),
+                                        target));
+                    }
+                }, ActionLink.ActionType.EDIT, StandardEntitlement.ROLE_READ).add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        final RoleTO clone = SerializationUtils.clone(model.getObject());
+                        clone.setKey(null);
+                        send(RoleSearchResultPanel.this, Broadcast.EXACT,
+                                new AjaxWizard.NewItemActionEvent<RoleHandler>(new RoleHandler(clone), target));
+                    }
+                }, ActionLink.ActionType.CLONE, StandardEntitlement.ROLE_CREATE).add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        try {
+                            restClient.delete(model.getObject().getKey());
+                            info(getString(Constants.OPERATION_SUCCEEDED));
+                            target.add(container);
+                        } catch (SyncopeClientException e) {
+                            error(getString(Constants.ERROR) + ": " + e.getMessage());
+                            LOG.error("While deleting object {}", model.getObject().getKey(), e);
+                        }
+                        ((BasePage) getPage()).getFeedbackPanel().refresh(target);
+                    }
+                }, ActionLink.ActionType.DELETE, StandardEntitlement.ROLE_DELETE);
+
+                return panel.build(componentId);
+            }
+
+            @Override
+            public ActionLinksPanel<RoleTO> getHeader(final String componentId) {
+                final ActionLinksPanel.Builder<RoleTO> panel = ActionLinksPanel.builder(page.getPageReference());
+
+                return panel.add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        if (target != null) {
+                            target.add(container);
+                        }
+                    }
+                }, ActionLink.ActionType.RELOAD, StandardEntitlement.ROLE_LIST).build(componentId);
+            }
+        });
+
+        return columns;
+    }
+
+    @Override
+    protected Collection<ActionLink.ActionType> getBulkActions() {
+        final List<ActionType> bulkActions = new ArrayList<>();
+        bulkActions.add(ActionType.DELETE);
+        return bulkActions;
+    }
+
+    @Override
+    protected String getPageId() {
+        return pageID;
+    }
+
+    public abstract static class Builder
+            extends AbstractSearchResultPanel.Builder<RoleTO, RoleHandler, RoleRestClient> {
+
+        private static final long serialVersionUID = 5088962796986706805L;
+
+        public Builder(final PageReference pageRef) {
+            super(new RoleRestClient(), pageRef);
+        }
+
+        @Override
+        protected WizardMgtPanel<RoleHandler> newInstance(final String id) {
+            return new RoleSearchResultPanel(id, this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
index 327d9fc..65b4947 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
@@ -42,7 +42,6 @@ import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -62,11 +61,18 @@ public class UserSearchResultPanel extends AnyObjectSearchResultPanel<UserTO> {
 
     private static final long serialVersionUID = -1100228004207271270L;
 
+    private final String pageID = "Users";
+
     protected UserSearchResultPanel(final String id, final Builder builder) {
         super(id, builder);
     }
 
     @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_USERS_PAGINATOR_ROWS;
+    }
+
+    @Override
     protected List<IColumn<UserTO, String>> getColumns() {
 
         final List<IColumn<UserTO, String>> columns = new ArrayList<>();
@@ -227,7 +233,7 @@ public class UserSearchResultPanel extends AnyObjectSearchResultPanel<UserTO> {
     }
 
     @Override
-    protected <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions() {
+    protected Collection<ActionLink.ActionType> getBulkActions() {
         final List<ActionType> bulkActions = new ArrayList<>();
 
         bulkActions.add(ActionType.DELETE);
@@ -242,31 +248,22 @@ public class UserSearchResultPanel extends AnyObjectSearchResultPanel<UserTO> {
         return pageID;
     }
 
-    public static class Builder extends AbstractSearchResultPanel.Builder<UserTO>
-            implements AnySearchResultPanelBuilder {
+    public static class Builder extends AnyObjectSearchResultPanel.Builder<UserTO> {
 
         private static final long serialVersionUID = 1L;
 
-        private final List<AnyTypeClassTO> anyTypeClassTOs;
-
         public Builder(
                 final List<AnyTypeClassTO> anyTypeClassTOs,
                 final AbstractAnyRestClient<UserTO> restClient,
                 final String type,
                 final PageReference pageRef) {
 
-            super(restClient, type, pageRef);
-            this.anyTypeClassTOs = anyTypeClassTOs;
+            super(anyTypeClassTOs, restClient, type, pageRef);
         }
 
         @Override
         protected WizardMgtPanel<AnyHandler<UserTO>> newInstance(final String id) {
             return new UserSearchResultPanel(id, this);
         }
-
-        @Override
-        public List<AnyTypeClassTO> getAnyTypeClassTOs() {
-            return this.anyTypeClassTOs;
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
index 4ed3e68..e6b5b2b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
@@ -36,7 +36,6 @@ 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.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -140,7 +139,7 @@ public final class GroupSelectionSearchResultPanel extends GroupSearchResultPane
     }
 
     @Override
-    protected <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions() {
+    protected Collection<ActionLink.ActionType> getBulkActions() {
         return Collections.<ActionLink.ActionType>emptyList();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
index 1af9901..c37e670 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
@@ -36,7 +36,6 @@ 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.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -142,7 +141,7 @@ public final class UserSelectionSearchResultPanel extends UserSearchResultPanel
     }
 
     @Override
-    protected <T extends AnyTO> Collection<ActionLink.ActionType> getBulkActions() {
+    protected Collection<ActionLink.ActionType> getBulkActions() {
         return Collections.<ActionLink.ActionType>emptyList();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
index d82ee37..a2ec369 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
@@ -18,6 +18,9 @@
  */
 package org.apache.syncope.client.console.rest;
 
+import static org.apache.syncope.client.console.rest.BaseRestClient.getService;
+
+import java.util.ArrayList;
 import java.util.List;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.rest.api.service.RoleService;
@@ -31,7 +34,35 @@ public class RoleRestClient extends BaseRestClient {
 
     private static final long serialVersionUID = 1L;
 
+    public void delete(final String key) {
+        getService(RoleService.class).delete(key);
+    }
+
+    public RoleTO read(final String key) {
+        return getService(RoleService.class).read(key);
+    }
+
+    public void update(final RoleTO roleTO) {
+        getService(RoleService.class).update(roleTO);
+    }
+
+    public void create(final RoleTO roleTO) {
+        getService(RoleService.class).create(roleTO);
+    }
+
     public List<RoleTO> getAll() {
         return getService(RoleService.class).list();
     }
+
+    public List<RoleTO> list() {
+        return getService(RoleService.class).list();
+    }
+
+    public int count() {
+        return getService(RoleService.class).list().size();
+    }
+
+    public List<String> getAllAvailableEntitlements() {
+        return new ArrayList<>(getSyncopeService().info().getEntitlements());
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxPalettePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxPalettePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxPalettePanel.java
index 76f6285..bdeb26c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxPalettePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxPalettePanel.java
@@ -20,6 +20,7 @@ package org.apache.syncope.client.console.wicket.markup.html.form;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -32,6 +33,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
 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.basic.Label;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.IChoiceRenderer;
@@ -94,18 +96,72 @@ public class AjaxPalettePanel<T extends Serializable> extends AbstractFieldPanel
         this.palette = new NonI18nPalette<T>(
                 "paletteField", model, choicesModel, builder.renderer, 8, builder.allowOrder, builder.allowMoveAll) {
 
-                    private static final long serialVersionUID = -3074655279011678437L;
+            private static final long serialVersionUID = -3074655279011678437L;
+
+            @Override
+            protected Component newAvailableHeader(final String componentId) {
+                return new Label(componentId, new ResourceModel("palette.available", builder.availableLabel));
+            }
+
+            @Override
+            protected Component newSelectedHeader(final String componentId) {
+                return new Label(componentId, new ResourceModel("palette.selected", builder.selectedLabel));
+            }
+
+            @Override
+            protected Recorder<T> newRecorderComponent() {
+                return new Recorder<T>("recorder", this) {
+
+                    private static final long serialVersionUID = -9169109967480083523L;
 
                     @Override
-                    protected Component newAvailableHeader(final String componentId) {
-                        return new Label(componentId, new ResourceModel("palette.available", builder.availableLabel));
+                    public List<T> getUnselectedList() {
+                        final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
+                        final Collection<? extends T> choices = getPalette().getChoices();
+                        final List<T> unselected = new ArrayList<>(choices.size());
+                        final List<String> ids = Arrays.asList(getValue().split(","));
+
+                        for (final T choice : choices) {
+                            final String choiceId = renderer.getIdValue(choice, 0);
+
+                            if (!ids.contains(choiceId)) {
+                                unselected.add(choice);
+                            }
+                        }
+
+                        return unselected;
                     }
 
                     @Override
-                    protected Component newSelectedHeader(final String componentId) {
-                        return new Label(componentId, new ResourceModel("palette.selected", builder.selectedLabel));
+                    public List<T> getSelectedList() {
+                        final IChoiceRenderer<? super T> renderer = getPalette().getChoiceRenderer();
+                        final Collection<? extends T> choices = getPalette().getChoices();
+                        final List<T> selected = new ArrayList<>(choices.size());
+
+                        // reduce number of method calls by building a lookup table
+                        final Map<T, String> idForChoice = new HashMap<>(choices.size());
+                        for (final T choice : choices) {
+                            idForChoice.put(choice, renderer.getIdValue(choice, 0));
+                        }
+
+                        final String value = getValue();
+                        int start = value.indexOf(';') + 1;
+
+                        for (final String id : Strings.split(value.substring(start), ',')) {
+                            for (final T choice : choices) {
+                                final String idValue = idForChoice.get(choice);
+                                if (id.equals(idValue)) {
+                                    selected.add(choice);
+                                    break;
+                                }
+                            }
+                        }
+
+                        return selected;
                     }
                 };
+            }
+        };
 
         add(palette.setOutputMarkupId(true));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
index dcf83bf..56b1cc5 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
@@ -51,8 +51,6 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
     private NotificationPanel notificationPanel;
 
-    private final PageReference pageRef;
-
     /**
      * Modal window.
      */
@@ -70,14 +68,13 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
     private final boolean wizardInModal;
 
-    protected WizardMgtPanel(final String id, final PageReference pageRef) {
-        this(id, pageRef, false);
+    protected WizardMgtPanel(final String id) {
+        this(id, false);
     }
 
-    protected WizardMgtPanel(final String id, final PageReference pageRef, final boolean wizardInModal) {
+    protected WizardMgtPanel(final String id, final boolean wizardInModal) {
         super(id);
         setOutputMarkupId(true);
-        this.pageRef = pageRef;
         this.wizardInModal = wizardInModal;
 
         add(modal);
@@ -156,12 +153,13 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
         super.onEvent(event);
     }
 
-    private WizardMgtPanel<T> addNewItemPanelBuilder(final AjaxWizardBuilder<T> panelBuilder) {
+    private WizardMgtPanel<T> addNewItemPanelBuilder(
+            final AjaxWizardBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
         this.newItemPanelBuilder = panelBuilder;
 
         if (this.newItemPanelBuilder != null) {
-            addAjaxLink.setEnabled(true);
-            addAjaxLink.setVisible(true);
+            addAjaxLink.setEnabled(newItemDefaultButtonEnabled);
+            addAjaxLink.setVisible(newItemDefaultButtonEnabled);
         }
 
         return this;
@@ -185,6 +183,8 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
         private AjaxWizardBuilder<T> newItemPanelBuilder;
 
+        private boolean newItemDefaultButtonEnabled = true;
+
         private NotificationPanel notificationPanel;
 
         protected Builder(final PageReference pageRef) {
@@ -200,7 +200,9 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
          * @return List view.
          */
         public WizardMgtPanel<T> build(final String id) {
-            return newInstance(id).addNewItemPanelBuilder(newItemPanelBuilder).addNotificationPanel(notificationPanel);
+            return newInstance(id).
+                    addNewItemPanelBuilder(newItemPanelBuilder, newItemDefaultButtonEnabled).
+                    addNotificationPanel(notificationPanel);
         }
 
         public Builder<T> addNewItemPanelBuilder(final AjaxWizardBuilder<T> panelBuilder) {
@@ -208,6 +210,25 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
             return this;
         }
 
+        /**
+         * Adds new item panel builder.
+         *
+         * @param panelBuilder new item panel builder.
+         * @param newItemDefaultButtonEnabled enable default button to adda new item.
+         * @return the current builder.
+         */
+        public Builder<T> addNewItemPanelBuilder(
+                final AjaxWizardBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
+            this.newItemDefaultButtonEnabled = newItemDefaultButtonEnabled;
+            return addNewItemPanelBuilder(panelBuilder);
+        }
+
+        /**
+         * Adds new item panel builder and enables default button to adda new item.
+         *
+         * @param notificationPanel new item panel builder.
+         * @return the current builder.
+         */
         public Builder<T> addNotificationPanel(final NotificationPanel notificationPanel) {
             this.notificationPanel = notificationPanel;
             return this;

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupHandler.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupHandler.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupHandler.java
index 0afba05..59fc58d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupHandler.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupHandler.java
@@ -36,8 +36,8 @@ public class GroupHandler extends AnyHandler<GroupTO> {
 
     private Map<String, List<SearchClause>> aDynClauses;
 
-    public GroupHandler(final GroupTO anyTO) {
-        super(anyTO);
+    public GroupHandler(final GroupTO groupTO) {
+        super(groupTO);
     }
 
     public List<SearchClause> getUDynClauses() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleHandler.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleHandler.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleHandler.java
new file mode 100644
index 0000000..19ce196
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wizards.role;
+
+import java.io.Serializable;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.syncope.client.console.panels.search.SearchClause;
+import org.apache.syncope.client.console.panels.search.SearchUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.to.RoleTO;
+
+public class RoleHandler implements Serializable {
+
+    private static final long serialVersionUID = 8058288034211558376L;
+
+    private final RoleTO roleTO;
+
+    private List<SearchClause> dynClauses;
+
+    public RoleHandler(final RoleTO roleTO) {
+        this.roleTO = roleTO;
+    }
+
+    public List<SearchClause> getDynClauses() {
+        if (this.dynClauses == null) {
+            this.dynClauses = SearchUtils.getSearchClauses(this.roleTO.getDynMembershipCond());
+        }
+        return this.dynClauses;
+    }
+
+    public void setDynClauses(final List<SearchClause> dynClauses) {
+        this.dynClauses = dynClauses;
+    }
+
+    public String getDynMembershipCond() {
+        if (CollectionUtils.isEmpty(this.dynClauses)) {
+            return this.roleTO.getDynMembershipCond();
+        } else {
+            return getFIQLString(this.dynClauses, SyncopeClient.getUserSearchConditionBuilder());
+        }
+    }
+
+    private String getFIQLString(final List<SearchClause> clauses, final AbstractFiqlSearchConditionBuilder bld) {
+        return SearchUtils.buildFIQL(clauses, bld);
+    }
+
+    public RoleTO fillDynamicConditions() {
+        this.roleTO.setDynMembershipCond(this.getDynMembershipCond());
+        return this.roleTO;
+    }
+
+    public RoleTO getInnerObject() {
+        return this.roleTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
new file mode 100644
index 0000000..b14bf7a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/role/RoleWizardBuilder.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.client.console.wizards.role;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.Collapsible;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.panels.search.SearchClause;
+import org.apache.syncope.client.console.panels.search.UserSearchPanel;
+import org.apache.syncope.client.console.rest.RealmRestClient;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
+import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class RoleWizardBuilder extends AjaxWizardBuilder<RoleHandler> {
+
+    private static final long serialVersionUID = 5945391813567245081L;
+
+    private final RoleRestClient groupRestClient = new RoleRestClient();
+
+    /**
+     * Construct.
+     *
+     * @param id The component id
+     * @param roleTO role
+     * @param pageRef Caller page reference.
+     */
+    public RoleWizardBuilder(final String id, final RoleTO roleTO, final PageReference pageRef) {
+        super(id, new RoleHandler(roleTO), pageRef);
+    }
+
+    /**
+     * This method has been overridden to manage asynchronous translation of FIQL string to search clases list and
+     * viceversa.
+     *
+     * @param item wizard backend item.
+     * @return the current builder.
+     */
+    @Override
+    public AjaxWizardBuilder<RoleHandler> setItem(final RoleHandler item) {
+        return item == null ? super.setItem(item) : super.setItem(new RoleHandler(item.getInnerObject()));
+    }
+
+    @Override
+    protected void onApplyInternal(final RoleHandler modelObject) {
+        modelObject.fillDynamicConditions();
+        if (getOriginalItem() == null || getOriginalItem().getInnerObject() == null
+                || StringUtils.isBlank(getOriginalItem().getInnerObject().getKey())) {
+            groupRestClient.create(modelObject.getInnerObject());
+        } else {
+            groupRestClient.update(modelObject.getInnerObject());
+        }
+    }
+
+    @Override
+    protected WizardModel buildModelSteps(final RoleHandler modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new Details(modelObject));
+        wizardModel.add(new Entitlements(modelObject.getInnerObject()));
+        wizardModel.add(new Realms(modelObject.getInnerObject()));
+        return wizardModel;
+    }
+
+    @Override
+    protected void onCancelInternal(final RoleHandler modelObject) {
+        // nothing to do
+    }
+
+    public static class Details extends WizardStep {
+
+        private static final long serialVersionUID = 5514523040031722255L;
+
+        public Details(final RoleHandler modelObject) {
+            add(new AjaxTextFieldPanel(
+                    "key", "key", new PropertyModel<String>(modelObject.getInnerObject(), "key"), false));
+
+            // ------------------------
+            // dynMembershipCond
+            // ------------------------
+            add(new Collapsible("dynMembershipCond", Collections.<ITab>singletonList(
+                    new AbstractTab(new ResourceModel("dynMembershipCond", "Dynamic USER Membership Conditions")) {
+
+                private static final long serialVersionUID = 1037272333056449378L;
+
+                @Override
+                public Panel getPanel(final String panelId) {
+                    return new UserSearchPanel.Builder(
+                            new PropertyModel<List<SearchClause>>(modelObject, "dynClauses")).
+                            required(false).build(panelId);
+                }
+            }), Model.of(StringUtils.isBlank(modelObject.getDynMembershipCond()) ? -1 : 0)).setOutputMarkupId(true));
+            // ------------------------ 
+        }
+    }
+
+    public static class Entitlements extends WizardStep {
+
+        private static final long serialVersionUID = 5514523040031722256L;
+
+        public Entitlements(final RoleTO modelObject) {
+            add(new AjaxPalettePanel.Builder<String>().build("entitlements",
+                    new PropertyModel<List<String>>(modelObject, "entitlements") {
+
+                private static final long serialVersionUID = -7809699384012595307L;
+
+                @Override
+                public List<String> getObject() {
+                    return new ArrayList<>(modelObject.getEntitlements());
+                }
+
+                @Override
+                public void setObject(final List<String> object) {
+                    modelObject.getEntitlements().clear();
+                    modelObject.getEntitlements().addAll(object);
+                }
+            }, new ListModel<>(new RoleRestClient().getAllAvailableEntitlements())).setOutputMarkupId(true));
+        }
+    }
+
+    public static class Realms extends WizardStep {
+
+        private static final long serialVersionUID = 5514523040031722257L;
+
+        public Realms(final RoleTO modelObject) {
+            add(new AjaxPalettePanel.Builder<String>().build("realms",
+                    new PropertyModel<List<String>>(modelObject, "realms"),
+                    new ListModel<>(
+                            CollectionUtils.collect(new RealmRestClient().list(), new Transformer<RealmTO, String>() {
+
+                                @Override
+                                public String transform(final RealmTO input) {
+                                    return input.getFullPath();
+                                }
+                            }, new ArrayList<String>()))).setOutputMarkupId(true));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
index 1987fcb..b24dbdc 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
@@ -110,6 +110,7 @@ under the License.
             <li wicket:id="configurationLI" class="treeview">
               <a href="#"><i class="fa fa-edit"></i><span>Configuration</span> <i class="fa fa-angle-left pull-right"></i></a>
               <ul wicket:id="configurationUL" class="treeview-menu">
+                <li wicket:id="rolesLI"><a href="#" wicket:id="roles"><i class="fa fa-users"></i>Roles</a></li>
                 <li wicket:id="policiesLI"><a href="#" wicket:id="policies"><i class="fa fa-circle-o"></i>Policies</a></li>
                 <li wicket:id="securityquestionsLI"><a href="#" wicket:id="securityquestions"><i class="fa fa-circle-o"></i>Security Questions</a></li>
                 <li wicket:id="workflowLI"><a href="#" wicket:id="workflow"><i class="fa fa-circle-o"></i>Workflow</a></li>

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.html
new file mode 100644
index 0000000..4180c56
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div class="wrapper">
+      <div class="admin-content-page" wicket:id="content">
+        <div class="box box-solid box-primary">
+          <div class="box-header with-border">
+            <h3 class="box-title">
+              <span wicket:id="header"></span>
+            </h3>
+            <div class="box-tools pull-right">
+              <ul class="nav navbar-nav actions">
+                <li>
+                  <a wicket:message="title:add" alt="add icon" wicket:id="add">
+                    <i class="glyphicon glyphicon-plus"></i>
+                  </a>                  
+                </li>
+              </ul>
+            </div>
+          </div>
+          <div class="box-body">
+            <div class="realms">
+              <div wicket:id="roles"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </wicket:extend>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.properties b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.properties
new file mode 100644
index 0000000..f03583a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles.properties
@@ -0,0 +1,18 @@
+# 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.
+header_title=Roles
+add=Create new Role

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_it.properties
new file mode 100644
index 0000000..c9797dd
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_it.properties
@@ -0,0 +1,18 @@
+# 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.
+header_title=Ruoli
+add=Crea un nuovo Ruolo

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_pt_BR.properties
new file mode 100644
index 0000000..e9ebe1c
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Roles_pt_BR.properties
@@ -0,0 +1,18 @@
+# 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.
+header_title=Fun\u00e7\u00e3os
+add=Cria um novo fun\u00e7\u00e3o

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/pages/SecurityQuestions.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/SecurityQuestions.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/SecurityQuestions.html
index 93608d2..8d35765 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/SecurityQuestions.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/SecurityQuestions.html
@@ -30,7 +30,7 @@ under the License.
               <ul class="nav navbar-nav actions">
                 <li>
                   <a wicket:message="title:createSecurityQuestion" wicket:id="createSecurityQuestion">
-                    <i class="glyphicon glyphicon-link"></i>
+                    <i class="glyphicon glyphicon-plus"></i>
                   </a>                  
                 </li>
               </ul>

http://git-wip-us.apache.org/repos/asf/syncope/blob/f93b4895/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_it.properties
index 278ca4d..70e378a 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AbstractSearchResultPanel_it.properties
@@ -29,6 +29,6 @@ creationDate=Data Creazione
 tokenValued=Valued
 tokenNotValued=Not valued
 
-any.edit=Modifica ${type} ${key}
-any.new=Nuovo ${type}
+any.edit=Modifica ${anyTO.type} ${key}
+any.new=Nuovo ${anyTO.type}
 any.attr.display=Attributes to be displayed