syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [syncope] 02/02: [SYNCOPE-1455] Console support
Date Fri, 07 Jun 2019 14:05:43 GMT
This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 56326567d62b417605bc5da683e350027a57c742
Author: Francesco Chicchiriccò <ilgrosso@apache.org>
AuthorDate: Fri Jun 7 16:05:28 2019 +0200

    [SYNCOPE-1455] Console support
---
 client/am/console/pom.xml                          |   99 +
 .../client/console/commons/AMConstants.java}       |   21 +-
 .../syncope/client/console/pages/Gateway.java      |   79 +
 .../console/panels/GatewayRouteDirectoryPanel.java |  211 ++
 .../console/panels/GatewayRouteFilterPanel.java    |  153 ++
 .../console/panels/GatewayRoutePredicatePanel.java |  164 ++
 .../console/panels/GatewayRouteWizardBuilder.java  |  130 ++
 .../console/rest/GatewayRouteRestClient.java       |   52 +
 .../syncope/client/console/pages/Gateway.html}     |   24 +-
 .../client/console/pages/Gateway.properties        |   24 +-
 .../console/pages/GatewayRouteDirectoryPanel.html} |   24 +-
 .../client/console/pages/Gateway_it.properties     |   24 +-
 .../client/console/pages/Gateway_ja.properties     |   24 +-
 .../client/console/pages/Gateway_pt_BR.properties  |   24 +-
 .../client/console/pages/Gateway_ru.properties     |   24 +-
 .../console/panels/GatewayRouteFilterPanel.html    |   62 +
 .../panels/GatewayRouteFilterPanel.properties      |   17 +-
 .../panels/GatewayRouteFilterPanel_it.properties   |   17 +-
 .../panels/GatewayRouteFilterPanel_ja.properties   |   17 +-
 .../GatewayRouteFilterPanel_pt_BR.properties       |   17 +-
 .../panels/GatewayRouteFilterPanel_ru.properties   |   17 +-
 .../console/panels/GatewayRoutePredicatePanel.html |   70 +
 .../panels/GatewayRoutePredicatePanel.properties   |   19 +-
 .../GatewayRoutePredicatePanel_it.properties       |   19 +-
 .../GatewayRoutePredicatePanel_ja.properties       |   19 +-
 .../GatewayRoutePredicatePanel_pt_BR.properties    |   19 +-
 .../GatewayRoutePredicatePanel_ru.properties       |   19 +-
 .../panels/GatewayRouteWizardBuilder$Filters.html} |   10 +-
 .../GatewayRouteWizardBuilder$Predicates.html}     |   10 +-
 .../panels/GatewayRouteWizardBuilder$Profile.html} |   13 +-
 client/am/pom.xml                                  |    1 +
 .../syncope/client/console/pages/Remediations.java |    1 -
 .../wizards/resources/AbstractMappingPanel.java    |   37 +-
 .../wizards/resources}/MappingPurposePanel.java    |    2 +-
 .../wizards/resources}/MappingPurposePanel.html    |    0
 client/idrepo/common-ui/pom.xml                    |    8 +-
 .../client/console/SyncopeWebApplication.java      |    5 +-
 .../syncope/client/console/annotations/AMPage.java |   53 +
 .../init/ClassPathScanImplementationLookup.java    |   15 +
 .../syncope/client/console/pages/BasePage.java     |   42 +-
 .../console/panels/PrivilegeDirectoryPanel.java    |    2 +-
 .../console/panels/SchemaTypeWizardBuilder.java    |   16 +-
 .../console/policies/PolicyRuleDirectoryPanel.java |    2 +-
 .../console/reports/ReportDirectoryPanel.java      |    4 +-
 .../reports/ReportTemplateDirectoryPanel.java      |   12 +-
 .../console/reports/ReportletDirectoryPanel.java   |    2 +-
 .../console/tasks/SchedTaskDirectoryPanel.java     |    2 +-
 .../wicket/markup/html/form/ActionLink.java        |    2 +
 .../markup/html/form/ActionLinksTogglePanel.java   |   13 +-
 .../client/console/wizards/WizardMgtPanel.java     |   25 +-
 .../syncope/client/console/pages/BasePage.html     |    5 +
 .../wicket/markup/html/form/ActionPanel.properties |    8 +
 .../markup/html/form/ActionPanel_it.properties     |    8 +
 .../markup/html/form/ActionPanel_ja.properties     |    8 +
 .../markup/html/form/ActionPanel_pt_BR.properties  |    8 +
 .../markup/html/form/ActionPanel_ru.properties     |    8 +
 .../client/console/wizards/WizardMgtPanel.html     |    6 +-
 .../syncope/common/lib/to/GatewayRouteTO.java      |    4 +-
 .../syncope/common/lib/to/NamedEntityTO.java       |   21 +-
 .../org/apache/syncope/common/lib/to/RealmTO.java  |    4 +-
 .../org/apache/syncope/common/lib/to/ReportTO.java |    4 +-
 .../apache/syncope/common/lib/to/SchedTaskTO.java  |    4 +-
 .../syncope/core/logic/GatewayRouteLogic.java      |    6 +-
 .../validation/entity/GatewayRouteValidator.java   |   14 +-
 deb/console/pom.xml                                |    5 +
 docker/console/pom.xml                             |    5 +
 fit/console-reference/pom.xml                      |    5 +
 .../src/test/resources/hotswap-agent.properties    |    1 +
 .../org/apache/syncope/fit/OIDCClientITCase.java   |    2 +-
 .../src/test/resources/sso/realm.json              | 2171 --------------------
 pom.xml                                            |   15 +-
 71 files changed, 1421 insertions(+), 2557 deletions(-)

diff --git a/client/am/console/pom.xml b/client/am/console/pom.xml
new file mode 100644
index 0000000..1b3fea6
--- /dev/null
+++ b/client/am/console/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.client</groupId>
+    <artifactId>syncope-client-am</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Client AM Console</name>
+  <description>Apache Syncope Client AM Console</description>
+  <groupId>org.apache.syncope.client.am</groupId>
+  <artifactId>syncope-client-am-console</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+  
+  <dependencies>
+    <dependency> 
+      <groupId>javax.servlet</groupId> 
+      <artifactId>javax.servlet-api</artifactId> 
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.syncope.client.idrepo</groupId>
+      <artifactId>syncope-client-idrepo-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.client.am</groupId>
+      <artifactId>syncope-client-am-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      
+      <plugin>
+        <groupId>nl.geodienstencentrum.maven</groupId>
+        <artifactId>sass-maven-plugin</artifactId>
+        <inherited>true</inherited>
+        <executions>
+          <execution>
+            <id>sass-compilation</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>update-stylesheets</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <resources>
+            <resource>
+              <source>
+                <directory>${basedir}/src/main/resources/META-INF/resources/css</directory>
+              </source>
+              <destination>${project.build.outputDirectory}/META-INF/resources/css</destination>
+            </resource>
+          </resources>
+        </configuration>
+      </plugin>
+    </plugins>
+    
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+  </build>
+</project>
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
similarity index 60%
copy from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
copy to client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
index b31bbab..6a2b169 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
@@ -16,24 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.syncope.client.console.wicket.markup.html.form;
+package org.apache.syncope.client.console.commons;
 
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.IModel;
+public final class AMConstants {
 
-/**
- * This empty class must exist because there not seems to be alternative to
- * provide specialized HTML for links.
- */
-public class LinkPanel extends Panel {
-
-    private static final long serialVersionUID = 4799005986804366330L;
-
-    public LinkPanel(final String id) {
-        super(id);
-    }
+    public static final String PREF_GATEWAYROUTE_PAGINATOR_ROWS = "gatewayroute.paginator.rows";
 
-    public LinkPanel(final String id, final IModel<?> model) {
-        super(id, model);
+    private AMConstants() {
+        // private constructor for static utility class
     }
 }
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/Gateway.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/Gateway.java
new file mode 100644
index 0000000..5d79158
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/Gateway.java
@@ -0,0 +1,79 @@
+/*
+ * 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 de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.annotations.AMPage;
+import org.apache.syncope.client.console.panels.GatewayRouteDirectoryPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+@AMPage(label = "Gateway", icon = "fa-share-alt", listEntitlement = "", priority = 0)
+public class Gateway extends BasePage {
+
+    private static final long serialVersionUID = 9200112197134882164L;
+
+    public Gateway(final PageParameters parameters) {
+        super(parameters);
+
+        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+        WebMarkupContainer content = new WebMarkupContainer("content");
+        content.setOutputMarkupId(true);
+        AjaxBootstrapTabbedPanel<ITab> tabbedPanel = new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList());
+        content.add(tabbedPanel);
+
+        body.add(content);
+    }
+
+    private List<ITab> buildTabList() {
+        List<ITab> tabs = new ArrayList<>(2);
+
+        tabs.add(new AbstractTab(new ResourceModel("routes")) {
+
+            private static final long serialVersionUID = 5211692813425391144L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new GatewayRouteDirectoryPanel(panelId, getPageReference());
+            }
+        });
+
+        tabs.add(new AbstractTab(new ResourceModel("metrics")) {
+
+            private static final long serialVersionUID = 5211692813425391144L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new AjaxTextFieldPanel(panelId, panelId, Model.of(""));
+            }
+        });
+
+        return tabs;
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteDirectoryPanel.java
new file mode 100644
index 0000000..c1787a8
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteDirectoryPanel.java
@@ -0,0 +1,211 @@
+/*
+ * 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.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.AMConstants;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.GatewayRouteDirectoryPanel.GatewayRouteProvider;
+import org.apache.syncope.client.console.rest.GatewayRouteRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.DirectoryDataProvider;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.GatewayRouteTO;
+import org.apache.syncope.common.lib.types.AMEntitlement;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+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.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.StringResourceModel;
+
+public class GatewayRouteDirectoryPanel
+        extends DirectoryPanel<GatewayRouteTO, GatewayRouteTO, GatewayRouteProvider, GatewayRouteRestClient> {
+
+    private static final long serialVersionUID = -2334397933375604015L;
+
+    public GatewayRouteDirectoryPanel(final String id, final PageReference pageRef) {
+        super(id, pageRef);
+        disableCheckBoxes();
+
+        modal.size(Modal.Size.Large);
+        modal.addSubmitButton();
+
+        modal.setWindowClosedCallback(target -> {
+            updateResultTable(target);
+            modal.show(false);
+        });
+
+        restClient = new GatewayRouteRestClient();
+
+        addNewItemPanelBuilder(new GatewayRouteWizardBuilder(new GatewayRouteTO(), pageRef), true);
+        initResultTable();
+
+        utilityAjaxLink = new AjaxLink<GatewayRouteTO>("utility") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    restClient.push();
+                    SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(container);
+                } catch (Exception e) {
+                    LOG.error("While pushing to SRA", e);
+                    SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                            ? e.getClass().getName() : e.getMessage());
+                }
+                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+        };
+        initialFragment.addOrReplace(utilityAjaxLink);
+        utilityAjaxLink.add(utilityIcon);
+        utilityIcon.add(new AttributeModifier("class", "fa fa-fast-forward"));
+        enableUtilityButton();
+    }
+
+    @Override
+    protected List<IColumn<GatewayRouteTO, String>> getColumns() {
+        List<IColumn<GatewayRouteTO, String>> columns = new ArrayList<>();
+
+        columns.add(new KeyPropertyColumn<>(new StringResourceModel("key", this), "key"));
+        columns.add(new PropertyColumn<>(new StringResourceModel("name", this), "name", "name"));
+        columns.add(new PropertyColumn<>(new StringResourceModel("order", this), "order", "order"));
+        columns.add(new PropertyColumn<>(new StringResourceModel("target", this), "target", "target"));
+        columns.add(new PropertyColumn<>(new StringResourceModel("status", this), "status", "status"));
+
+        return columns;
+    }
+
+    @Override
+    protected ActionsPanel<GatewayRouteTO> getActions(final IModel<GatewayRouteTO> model) {
+        ActionsPanel<GatewayRouteTO> panel = super.getActions(model);
+
+        panel.add(new ActionLink<GatewayRouteTO>() {
+
+            private static final long serialVersionUID = -4608353559809323466L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final GatewayRouteTO ignore) {
+                send(GatewayRouteDirectoryPanel.this, Broadcast.EXACT,
+                        new AjaxWizard.EditItemActionEvent<>(
+                                restClient.read(model.getObject().getKey()), target));
+            }
+        }, ActionLink.ActionType.EDIT, AMEntitlement.GATEWAY_ROUTE_UPDATE);
+
+        panel.add(new ActionLink<GatewayRouteTO>() {
+
+            private static final long serialVersionUID = -4608353559809323466L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final GatewayRouteTO ignore) {
+                GatewayRouteTO clone = SerializationUtils.clone(model.getObject());
+                clone.setKey(null);
+                send(GatewayRouteDirectoryPanel.this, Broadcast.EXACT,
+                        new AjaxWizard.EditItemActionEvent<>(clone, target));
+            }
+        }, ActionLink.ActionType.CLONE, AMEntitlement.GATEWAY_ROUTE_CREATE);
+
+        panel.add(new ActionLink<GatewayRouteTO>() {
+
+            private static final long serialVersionUID = -4608353559809323466L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final GatewayRouteTO ignore) {
+                GatewayRouteTO route = model.getObject();
+                try {
+                    restClient.delete(route.getKey());
+                    SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(container);
+                } catch (SyncopeClientException e) {
+                    LOG.error("While deleting {}", route.getKey(), e);
+                    SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                            ? e.getClass().getName() : e.getMessage());
+                }
+                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+        }, ActionLink.ActionType.DELETE, AMEntitlement.GATEWAY_ROUTE_DELETE, true);
+
+        return panel;
+    }
+
+    @Override
+    protected Collection<ActionLink.ActionType> getBatches() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected GatewayRouteProvider dataProvider() {
+        return new GatewayRouteProvider(rows);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return AMConstants.PREF_GATEWAYROUTE_PAGINATOR_ROWS;
+    }
+
+    protected final class GatewayRouteProvider extends DirectoryDataProvider<GatewayRouteTO> {
+
+        private static final long serialVersionUID = 5282134321828253058L;
+
+        private final SortableDataProviderComparator<GatewayRouteTO> comparator;
+
+        public GatewayRouteProvider(final int paginatorRows) {
+            super(paginatorRows);
+            setSort("name", SortOrder.ASCENDING);
+            comparator = new SortableDataProviderComparator<>(this);
+        }
+
+        @Override
+        public Iterator<? extends GatewayRouteTO> iterator(final long first, final long count) {
+            List<GatewayRouteTO> list = restClient.list();
+            Collections.sort(list, comparator);
+            return list.subList((int) first, (int) first + (int) count).iterator();
+        }
+
+        @Override
+        public long size() {
+            return restClient.list().size();
+        }
+
+        @Override
+        public IModel<GatewayRouteTO> model(final GatewayRouteTO route) {
+            return new CompoundPropertyModel<>(route);
+        }
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.java
new file mode 100644
index 0000000..dc9e5d0
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverBehavior;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverConfig;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.types.GatewayRouteFilter;
+import org.apache.syncope.common.lib.types.FilterFactory;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class GatewayRouteFilterPanel extends Panel {
+
+    private static final long serialVersionUID = -4576690020841569281L;
+
+    public GatewayRouteFilterPanel(final String id, final IModel<List<GatewayRouteFilter>> model) {
+        super(id);
+        setOutputMarkupId(true);
+
+        WebMarkupContainer filterContainer = new WebMarkupContainer("filterContainer");
+        filterContainer.setOutputMarkupId(true);
+        add(filterContainer);
+
+        filterContainer.add(new Label("factoryInfo", Model.of()).add(new PopoverBehavior(
+                Model.<String>of(),
+                Model.of(getString("factoryInfo.help")),
+                new PopoverConfig().withHtml(true).withPlacement(TooltipConfig.Placement.right)) {
+
+            private static final long serialVersionUID = -7032694831250368230L;
+
+            @Override
+            protected String createRelAttribute() {
+                return "factoryInfo";
+            }
+        }));
+
+        ListView<GatewayRouteFilter> filters = new ListView<GatewayRouteFilter>("filters", model) {
+
+            private static final long serialVersionUID = 6741044372185745296L;
+
+            @Override
+            protected void populateItem(final ListItem<GatewayRouteFilter> item) {
+                GatewayRouteFilter filter = item.getModelObject();
+
+                AjaxDropDownChoicePanel<FilterFactory> factory =
+                        new AjaxDropDownChoicePanel<>("factory", "factory", new PropertyModel<>(filter, "factory"));
+                factory.setChoices(Arrays.asList(FilterFactory.values()));
+                item.add(factory.hideLabel());
+
+                AjaxTextFieldPanel args =
+                        new AjaxTextFieldPanel("args", "args", new PropertyModel<>(filter, "args"));
+                item.add(args.hideLabel());
+
+                ActionsPanel<Serializable> actions = new ActionsPanel<>("actions", null);
+                actions.add(new ActionLink<Serializable>() {
+
+                    private static final long serialVersionUID = 2041211756396714619L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                        model.getObject().remove(item.getIndex());
+
+                        item.getParent().removeAll();
+                        target.add(GatewayRouteFilterPanel.this);
+                    }
+                }, ActionLink.ActionType.DELETE, StringUtils.EMPTY, true).hideLabel();
+                if (model.getObject().size() > 1) {
+                    if (item.getIndex() > 0) {
+                        actions.add(new ActionLink<Serializable>() {
+
+                            private static final long serialVersionUID = 2041211756396714619L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                                GatewayRouteFilter pre = model.getObject().get(item.getIndex() - 1);
+                                model.getObject().set(item.getIndex(), pre);
+                                model.getObject().set(item.getIndex() - 1, filter);
+
+                                item.getParent().removeAll();
+                                target.add(GatewayRouteFilterPanel.this);
+                            }
+                        }, ActionLink.ActionType.UP, StringUtils.EMPTY).hideLabel();
+                    }
+                    if (item.getIndex() < model.getObject().size() - 1) {
+                        actions.add(new ActionLink<Serializable>() {
+
+                            private static final long serialVersionUID = 2041211756396714619L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                                GatewayRouteFilter post = model.getObject().get(item.getIndex() + 1);
+                                model.getObject().set(item.getIndex(), post);
+                                model.getObject().set(item.getIndex() + 1, filter);
+
+                                item.getParent().removeAll();
+                                target.add(GatewayRouteFilterPanel.this);
+                            }
+                        }, ActionLink.ActionType.DOWN, StringUtils.EMPTY).hideLabel();
+                    }
+                }
+                item.add(actions);
+            }
+        };
+        filters.setReuseItems(true);
+        filterContainer.add(filters);
+
+        IndicatingAjaxButton addFilterBtn = new IndicatingAjaxButton("addFilterBtn") {
+
+            private static final long serialVersionUID = -4804368561204623354L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target) {
+                model.getObject().add(new GatewayRouteFilter());
+                target.add(GatewayRouteFilterPanel.this);
+            }
+        };
+        addFilterBtn.setDefaultFormProcessing(false);
+        filterContainer.add(addFilterBtn);
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
new file mode 100644
index 0000000..523f0f4
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
@@ -0,0 +1,164 @@
+/*
+ * 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.components.PopoverBehavior;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverConfig;
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
+import org.apache.syncope.common.lib.types.PredicateCond;
+import org.apache.syncope.common.lib.types.PredicateFactory;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class GatewayRoutePredicatePanel extends Panel {
+
+    private static final long serialVersionUID = -5321936363511301735L;
+
+    public GatewayRoutePredicatePanel(final String id, final IModel<List<GatewayRoutePredicate>> model) {
+        super(id);
+        setOutputMarkupId(true);
+
+        WebMarkupContainer predicateContainer = new WebMarkupContainer("predicateContainer");
+        predicateContainer.setOutputMarkupId(true);
+        add(predicateContainer);
+
+        predicateContainer.add(new Label("factoryInfo", Model.of()).add(new PopoverBehavior(
+                Model.<String>of(),
+                Model.of(getString("factoryInfo.help")),
+                new PopoverConfig().withHtml(true).withPlacement(TooltipConfig.Placement.right)) {
+
+            private static final long serialVersionUID = -7032694831250368230L;
+
+            @Override
+            protected String createRelAttribute() {
+                return "factoryInfo";
+            }
+        }));
+
+        ListView<GatewayRoutePredicate> predicates = new ListView<GatewayRoutePredicate>("predicates", model) {
+
+            private static final long serialVersionUID = 1814616131938968887L;
+
+            @Override
+            protected void populateItem(final ListItem<GatewayRoutePredicate> item) {
+                GatewayRoutePredicate predicate = item.getModelObject();
+
+                AjaxCheckBoxPanel negate =
+                        new AjaxCheckBoxPanel("negate", "negate", new PropertyModel<>(predicate, "negate"));
+                item.add(negate.hideLabel());
+
+                AjaxDropDownChoicePanel<PredicateFactory> factory =
+                        new AjaxDropDownChoicePanel<>("factory", "factory", new PropertyModel<>(predicate, "factory"));
+                factory.setChoices(Arrays.asList(PredicateFactory.values()));
+                item.add(factory.hideLabel());
+
+                AjaxTextFieldPanel args =
+                        new AjaxTextFieldPanel("args", "args", new PropertyModel<>(predicate, "args"));
+                item.add(args.hideLabel());
+
+                AjaxDropDownChoicePanel<PredicateCond> cond =
+                        new AjaxDropDownChoicePanel<>("cond", "cond", new PropertyModel<>(predicate, "cond"));
+                cond.setChoices(Arrays.asList(PredicateCond.values()));
+                item.add(cond.hideLabel());
+
+                ActionsPanel<Serializable> actions = new ActionsPanel<>("actions", null);
+                actions.add(new ActionLink<Serializable>() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                        model.getObject().remove(item.getIndex());
+
+                        item.getParent().removeAll();
+                        target.add(GatewayRoutePredicatePanel.this);
+                    }
+                }, ActionLink.ActionType.DELETE, StringUtils.EMPTY, true).hideLabel();
+                if (model.getObject().size() > 1) {
+                    if (item.getIndex() > 0) {
+                        actions.add(new ActionLink<Serializable>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                                GatewayRoutePredicate pre = model.getObject().get(item.getIndex() - 1);
+                                model.getObject().set(item.getIndex(), pre);
+                                model.getObject().set(item.getIndex() - 1, predicate);
+
+                                item.getParent().removeAll();
+                                target.add(GatewayRoutePredicatePanel.this);
+                            }
+                        }, ActionLink.ActionType.UP, StringUtils.EMPTY).hideLabel();
+                    }
+                    if (item.getIndex() < model.getObject().size() - 1) {
+                        actions.add(new ActionLink<Serializable>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                                GatewayRoutePredicate post = model.getObject().get(item.getIndex() + 1);
+                                model.getObject().set(item.getIndex(), post);
+                                model.getObject().set(item.getIndex() + 1, predicate);
+
+                                item.getParent().removeAll();
+                                target.add(GatewayRoutePredicatePanel.this);
+                            }
+                        }, ActionLink.ActionType.DOWN, StringUtils.EMPTY).hideLabel();
+                    }
+                }
+                item.add(actions);
+            }
+        };
+        predicates.setReuseItems(true);
+        predicateContainer.add(predicates);
+
+        IndicatingAjaxButton addPredicateBtn = new IndicatingAjaxButton("addPredicateBtn") {
+
+            private static final long serialVersionUID = -4804368561204623354L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target) {
+                model.getObject().add(new GatewayRoutePredicate());
+                target.add(GatewayRoutePredicatePanel.this);
+            }
+        };
+        addPredicateBtn.setDefaultFormProcessing(false);
+        predicateContainer.add(addPredicateBtn);
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
new file mode 100644
index 0000000..a71df41
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Arrays;
+import org.apache.syncope.client.console.rest.GatewayRouteRestClient;
+import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.GatewayRouteTO;
+import org.apache.syncope.common.lib.types.GatewayRouteStatus;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.model.IModel;
+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;
+import org.apache.wicket.validation.validator.UrlValidator;
+
+public class GatewayRouteWizardBuilder extends BaseAjaxWizardBuilder<GatewayRouteTO> {
+
+    private static final long serialVersionUID = 2060352959114706419L;
+
+    private final GatewayRouteRestClient restClient = new GatewayRouteRestClient();
+
+    public GatewayRouteWizardBuilder(final GatewayRouteTO route, final PageReference pageRef) {
+        super(route, pageRef);
+    }
+
+    @Override
+    protected Serializable onApplyInternal(final GatewayRouteTO modelObject) {
+        if (modelObject.getKey() == null) {
+            restClient.create(modelObject);
+        } else {
+            restClient.update(modelObject);
+        }
+        return modelObject;
+    }
+
+    @Override
+    protected WizardModel buildModelSteps(final GatewayRouteTO modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new Profile(modelObject));
+        wizardModel.add(new Predicates(modelObject));
+        wizardModel.add(new Filters(modelObject));
+        return wizardModel;
+    }
+
+    public class Profile extends WizardStep {
+
+        private static final long serialVersionUID = 8610155719550948702L;
+
+        public Profile(final GatewayRouteTO route) {
+            add(new AjaxTextFieldPanel(
+                    "name", "name", new PropertyModel<>(route, "name"), false).
+                    addRequiredLabel().setEnabled(true));
+
+            add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(0).build(
+                    "order", "order", Integer.class, new PropertyModel<>(route, "order")).
+                    setRequired(true));
+
+            AjaxTextFieldPanel target = new AjaxTextFieldPanel(
+                    "target", "target", new IModel<String>() {
+
+                private static final long serialVersionUID = 1015030402166681242L;
+
+                @Override
+                public String getObject() {
+                    return route.getTarget() == null ? null : route.getTarget().toASCIIString();
+                }
+
+                @Override
+                public void setObject(final String object) {
+                    if (object == null) {
+                        route.setTarget(null);
+                    } else {
+                        route.setTarget(URI.create(object));
+                    }
+                }
+            }, false);
+            target.addRequiredLabel().setEnabled(true);
+            target.getField().add(new UrlValidator(new String[] { "http", "https" }));
+            add(target);
+
+            add(new AjaxDropDownChoicePanel<>(
+                    "status", "status", new PropertyModel<>(route, "status")).
+                    setChoices(Arrays.asList((Serializable[]) GatewayRouteStatus.values())));
+        }
+    }
+
+    public class Predicates extends WizardStep {
+
+        private static final long serialVersionUID = 5934389493874714599L;
+
+        public Predicates(final GatewayRouteTO route) {
+            super(new ResourceModel("predicates"), Model.of());
+            add(new GatewayRoutePredicatePanel("predicates", new ListModel<>(route.getPredicates())));
+        }
+    }
+
+    public class Filters extends WizardStep {
+
+        private static final long serialVersionUID = -6552124285142294023L;
+
+        public Filters(final GatewayRouteTO route) {
+            super(new ResourceModel("filters"), Model.of());
+            add(new GatewayRouteFilterPanel("filters", new ListModel<>(route.getFilters())));
+        }
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/GatewayRouteRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/GatewayRouteRestClient.java
new file mode 100644
index 0000000..cd08975
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/GatewayRouteRestClient.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rest;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.GatewayRouteTO;
+import org.apache.syncope.common.rest.api.service.GatewayRouteService;
+
+public class GatewayRouteRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = -7379778542101161274L;
+
+    public List<GatewayRouteTO> list() {
+        return getService(GatewayRouteService.class).list();
+    }
+
+    public GatewayRouteTO read(final String key) {
+        return getService(GatewayRouteService.class).read(key);
+    }
+
+    public void create(final GatewayRouteTO route) {
+        getService(GatewayRouteService.class).create(route);
+    }
+
+    public void update(final GatewayRouteTO route) {
+        getService(GatewayRouteService.class).update(route);
+    }
+
+    public void delete(final String key) {
+        getService(GatewayRouteService.class).delete(key);
+    }
+
+    public void push() {
+        getService(GatewayRouteService.class).pushToSRA();
+    }
+}
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.html
similarity index 62%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.html
index 46be9d4..1123afa 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.html
@@ -17,15 +17,19 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
+  <wicket:extend>
+    <section class="content-header">
+      <h1>&nbsp;</h1>
+      <ol class="breadcrumb">
+        <li><a wicket:id="dashboardBr"><i class="fa fa-dashboard"></i> <wicket:message key="dashboard">[DASHBOARD]</wicket:message></a></li>
+        <li class="active"><wicket:message key="gateway"/></li>
+      </ol>
+    </section>
 
-    <a href="#" wicket:id="propagationPurposeLink"><i class="fa fa-arrow-circle-o-right"></i></a>
-
-    <a href="#" wicket:id="pullPurposeLink"><i class="fa fa-arrow-circle-o-left"></i></a>
-
-    <a href="#" wicket:id="bothPurposeLink"><i class="fa fa-exchange"></i></a>
-
-    <a href="#" wicket:id="nonePurposeLink"><i class="fa fa-chain-broken"></i></a>
-
-  </wicket:panel>
+    <section class="content" wicket:id="content">
+      <div class="box">
+        <div class="box-body" wicket:id="tabbedPanel"/>
+      </div>
+    </section>
+  </wicket:extend>
 </html>
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.properties
index 9ec5374..98fbee2 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway.properties
@@ -14,17 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+gateway=Gateway
+routes=Routes
+metrics=Metrics
+order=Order
+target=Target
+status=Status
+any.new=New gateway route
+any.edit=Edit ${name}
+predicates=Predicates
+filters=Filters
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/GatewayRouteDirectoryPanel.html
similarity index 62%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/GatewayRouteDirectoryPanel.html
index 46be9d4..1123afa 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/GatewayRouteDirectoryPanel.html
@@ -17,15 +17,19 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
+  <wicket:extend>
+    <section class="content-header">
+      <h1>&nbsp;</h1>
+      <ol class="breadcrumb">
+        <li><a wicket:id="dashboardBr"><i class="fa fa-dashboard"></i> <wicket:message key="dashboard">[DASHBOARD]</wicket:message></a></li>
+        <li class="active"><wicket:message key="gateway"/></li>
+      </ol>
+    </section>
 
-    <a href="#" wicket:id="propagationPurposeLink"><i class="fa fa-arrow-circle-o-right"></i></a>
-
-    <a href="#" wicket:id="pullPurposeLink"><i class="fa fa-arrow-circle-o-left"></i></a>
-
-    <a href="#" wicket:id="bothPurposeLink"><i class="fa fa-exchange"></i></a>
-
-    <a href="#" wicket:id="nonePurposeLink"><i class="fa fa-chain-broken"></i></a>
-
-  </wicket:panel>
+    <section class="content" wicket:id="content">
+      <div class="box">
+        <div class="box-body" wicket:id="tabbedPanel"/>
+      </div>
+    </section>
+  </wicket:extend>
 </html>
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_it.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_it.properties
index 9ec5374..e9f5f85 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_it.properties
@@ -14,17 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+gateway=Gateway
+routes=Rotte
+metrics=Metriche
+order=Ordine
+target=Obiettivo
+status=Stato
+any.new=Nuova rotta del gateway
+any.edit=Modifica ${name}
+predicates=Predicates
+filters=Filters
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ja.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ja.properties
index 9ec5374..98fbee2 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ja.properties
@@ -14,17 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+gateway=Gateway
+routes=Routes
+metrics=Metrics
+order=Order
+target=Target
+status=Status
+any.new=New gateway route
+any.edit=Edit ${name}
+predicates=Predicates
+filters=Filters
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_pt_BR.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_pt_BR.properties
index 9ec5374..98fbee2 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_pt_BR.properties
@@ -14,17 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+gateway=Gateway
+routes=Routes
+metrics=Metrics
+order=Order
+target=Target
+status=Status
+any.new=New gateway route
+any.edit=Edit ${name}
+predicates=Predicates
+filters=Filters
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ru.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ru.properties
index 9ec5374..98fbee2 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/Gateway_ru.properties
@@ -14,17 +14,13 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+gateway=Gateway
+routes=Routes
+metrics=Metrics
+order=Order
+target=Target
+status=Status
+any.new=New gateway route
+any.edit=Edit ${name}
+predicates=Predicates
+filters=Filters
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.html
new file mode 100644
index 0000000..947fb29
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.html
@@ -0,0 +1,62 @@
+<!--
+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:panel>
+    <div class="table-responsive no-padding">
+      <table id="mappings"
+             class="table table-hover"
+             style="font-size: 1em;margin-top:2px;"
+             wicket:id="filterContainer">
+        <tbody>
+          <tr>
+            <th>
+              <wicket:message key="factory"/>
+              <span id="factoryInfo" wicket:id="factoryInfo" class="glyphicon glyphicon-info-sign"></span>
+            </th>
+            <th class="col-sm-6"><wicket:message key="args"/></th>
+            <th class="col-sm-2"></th>
+          </tr>
+          <tr wicket:id="filters">
+            <td>
+              <span wicket:id="factory">[factory]</span>
+            </td>
+            <td>
+              <span wicket:id="args">[args]</span>
+            </td>
+            <td>
+              <div id="inline-actions">
+                <span wicket:id="actions"/>
+              </div>
+            </td>
+          </tr>
+        </tbody>
+
+        <tfoot>
+          <tr>
+            <td colspan="10" style="padding: 5px; text-align: right">
+              <button type="submit" class="btn btn-primary btn-circle btn-lg" wicket:id="addFilterBtn">
+                <i class="glyphicon glyphicon-plus"></i>
+              </button>
+            </td>
+          </tr>
+        </tfoot>
+      </table>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.properties
index 9ec5374..86d82d1 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel.properties
@@ -14,17 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+factory=Factory
+args=Arguments
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#_gatewayfilter_factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_it.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_it.properties
index 9ec5374..3acb535 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_it.properties
@@ -14,17 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+factory=Factory
+args=Argomenti
+factoryInfo.help=Consultare la <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#\n_gatewayfilter_factories"  target="blank">documentazione di Spring Cloud Gateay</a> per maggiori informazioni
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ja.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ja.properties
index 9ec5374..86d82d1 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ja.properties
@@ -14,17 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+factory=Factory
+args=Arguments
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#_gatewayfilter_factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_pt_BR.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_pt_BR.properties
index 9ec5374..86d82d1 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_pt_BR.properties
@@ -14,17 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+factory=Factory
+args=Arguments
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#_gatewayfilter_factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ru.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ru.properties
index 9ec5374..86d82d1 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteFilterPanel_ru.properties
@@ -14,17 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+factory=Factory
+args=Arguments
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#_gatewayfilter_factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.html
new file mode 100644
index 0000000..1b6def7
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.html
@@ -0,0 +1,70 @@
+<!--
+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:panel>
+    <div class="table-responsive no-padding">
+      <table id="mappings"
+             class="table table-hover"
+             style="font-size: 1em;margin-top:2px;"
+             wicket:id="predicateContainer">
+        <tbody>
+          <tr>
+            <th><wicket:message key="negate"/></th>
+            <th>
+              <wicket:message key="factory"/>
+              <span id="factoryInfo" wicket:id="factoryInfo" class="glyphicon glyphicon-info-sign"></span>
+            </th>
+            <th class="col-sm-6"><wicket:message key="args"/></th>
+            <th><wicket:message key="cond"/></th>
+            <th class="col-sm-2"></th>
+          </tr>
+          <tr wicket:id="predicates">
+            <td>
+              <span wicket:id="negate">[negate]</span>
+            </td>
+            <td>
+              <span wicket:id="factory">[factory]</span>
+            </td>
+            <td>
+              <span wicket:id="args">[args]</span>
+            </td>
+            <td>
+              <span wicket:id="cond">[cond]</span>
+            </td>
+            <td>
+              <div id="inline-actions">
+                <span wicket:id="actions"/>
+              </div>
+            </td>
+          </tr>
+        </tbody>
+
+        <tfoot>
+          <tr>
+            <td colspan="10" style="padding: 5px; text-align: right">
+              <button type="submit" class="btn btn-primary btn-circle btn-lg" wicket:id="addPredicateBtn">
+                <i class="glyphicon glyphicon-plus"></i>
+              </button>
+            </td>
+          </tr>
+        </tfoot>
+      </table>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.properties
index 9ec5374..38f1101 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.properties
@@ -14,17 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+negate=Negate
+factory=Factory
+args=Arguments
+cond=Condition
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#gateway-request-predicates-factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_it.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_it.properties
index 9ec5374..a980422 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_it.properties
@@ -14,17 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+negate=Nega
+factory=Factory
+args=Argomenti
+cond=Condizione
+factoryInfo.help=Consultare la <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#gateway-request-predicates-factories"  target="blank">documentazione di Spring Cloud Gateay</a> per maggiori informazioni
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ja.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ja.properties
index 9ec5374..38f1101 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ja.properties
@@ -14,17 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+negate=Negate
+factory=Factory
+args=Arguments
+cond=Condition
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#gateway-request-predicates-factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_pt_BR.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_pt_BR.properties
index 9ec5374..38f1101 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_pt_BR.properties
@@ -14,17 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+negate=Negate
+factory=Factory
+args=Arguments
+cond=Condition
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#gateway-request-predicates-factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ru.properties
similarity index 58%
copy from fit/console-reference/src/test/resources/hotswap-agent.properties
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ru.properties
index 9ec5374..38f1101 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel_ru.properties
@@ -14,17 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
-LOGGER=error
-
-autoHotswap=true
-
-extraClasspath=\
-${basedir}/../../client/idrepo/common-ui/target/classes/org,\
-${basedir}/../../client/idrepo/console/target/classes/org,\
-${basedir}/../../client/idm/console/target/classes/org,\
-${basedir}/../../ext/camel/client-console/target/classes/org,\
-${basedir}/../../ext/flowable/client-console/target/classes/org,\
-${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
-${basedir}/../../ext/scimv2/client-console/target/classes/org,\
-${basedir}/../../ext/oidcclient/client-console/target/classes/org
+negate=Negate
+factory=Factory
+args=Arguments
+cond=Condition
+factoryInfo.help=Check <a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/${spring-cloud-gateway.version}/single/spring-cloud-gateway.html#gateway-request-predicates-factories"  target="blank">Spring Cloud Gateay documentation</a> for more information
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Filters.html
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Filters.html
index c4b75f0..24c716b 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Filters.html
@@ -16,8 +16,8 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<wicket:panel>
-  <a href="#" wicket:id="link">
-          <span wicket:id="linkTitle"/> 
-  </a>
-</wicket:panel>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="filters">[filters]</div>
+  </wicket:panel>
+</html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Predicates.html
similarity index 81%
rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html
rename to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Predicates.html
index c4b75f0..215fe1a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Predicates.html
@@ -16,8 +16,8 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<wicket:panel>
-  <a href="#" wicket:id="link">
-          <span wicket:id="linkTitle"/> 
-  </a>
-</wicket:panel>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="predicates">[predicates]</div>
+  </wicket:panel>
+</html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
similarity index 71%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
copy to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
index 46be9d4..382d1fb 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
@@ -18,14 +18,9 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-
-    <a href="#" wicket:id="propagationPurposeLink"><i class="fa fa-arrow-circle-o-right"></i></a>
-
-    <a href="#" wicket:id="pullPurposeLink"><i class="fa fa-arrow-circle-o-left"></i></a>
-
-    <a href="#" wicket:id="bothPurposeLink"><i class="fa fa-exchange"></i></a>
-
-    <a href="#" wicket:id="nonePurposeLink"><i class="fa fa-chain-broken"></i></a>
-
+    <div class="form-group"><span wicket:id="name">[name]</span></div>
+    <div class="form-group"><span wicket:id="order">[order]</span></div>
+    <div class="form-group"><span wicket:id="target">[target]</span></div>
+    <div class="form-group"><span wicket:id="status">[status]</span></div>
   </wicket:panel>
 </html>
diff --git a/client/am/pom.xml b/client/am/pom.xml
index b23ba18..d530d1d 100644
--- a/client/am/pom.xml
+++ b/client/am/pom.xml
@@ -39,5 +39,6 @@ under the License.
   
   <modules>
     <module>lib</module>
+    <module>console</module>
   </modules>
 </project>
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java
index 8e539d5..d5c20d3 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java
@@ -38,5 +38,4 @@ public class Remediations extends BasePage {
 
         content.add(new RemediationDirectoryPanel("remediations", getPageReference()));
     }
-
 }
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/AbstractMappingPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/AbstractMappingPanel.java
index 6a7eacf..8c08eb5 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/AbstractMappingPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/AbstractMappingPanel.java
@@ -34,7 +34,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.MappingPurposePanel;
 import org.apache.syncope.client.console.widgets.JEXLTransformerWidget;
 import org.apache.syncope.client.console.widgets.ItemTransformerWidget;
 import org.apache.syncope.common.lib.to.ItemTO;
@@ -184,7 +183,7 @@ public abstract class AbstractMappingPanel extends Panel {
                 // -------------------------------
                 AjaxTextFieldPanel intAttrName = new AjaxTextFieldPanel(
                         "intAttrName",
-                        getString("intAttrName"),
+                        "intAttrName",
                         new PropertyModel<>(itemTO, "intAttrName"),
                         false);
                 intAttrName.setChoices(Collections.<String>emptyList());
@@ -195,9 +194,9 @@ public abstract class AbstractMappingPanel extends Panel {
                 //--------------------------------
                 // External attribute
                 // -------------------------------
-                final AjaxTextFieldPanel extAttrName = new AjaxTextFieldPanel(
+                AjaxTextFieldPanel extAttrName = new AjaxTextFieldPanel(
+                        "extAttrName",
                         "extAttrName",
-                        getString("extAttrName"),
                         new PropertyModel<>(itemTO, "extAttrName"));
                 extAttrName.setChoices(getExtAttrNames().getObject());
 
@@ -224,9 +223,9 @@ public abstract class AbstractMappingPanel extends Panel {
                 //--------------------------------
                 // Mandatory
                 // -------------------------------
-                final AjaxTextFieldPanel mandatory = new AjaxTextFieldPanel(
+                AjaxTextFieldPanel mandatory = new AjaxTextFieldPanel(
+                        "mandatoryCondition",
                         "mandatoryCondition",
-                        new ResourceModel("mandatoryCondition", "mandatoryCondition").getObject(),
                         new PropertyModel<>(itemTO, "mandatoryCondition"));
                 mandatory.hideLabel();
                 mandatory.setChoices(Arrays.asList(new String[] { "true", "false" }));
@@ -237,9 +236,9 @@ public abstract class AbstractMappingPanel extends Panel {
                 //--------------------------------
                 // Connector object key
                 // -------------------------------
-                final AjaxCheckBoxPanel connObjectKey = new AjaxCheckBoxPanel(
+                AjaxCheckBoxPanel connObjectKey = new AjaxCheckBoxPanel(
+                        "connObjectKey",
                         "connObjectKey",
-                        new ResourceModel("connObjectKey", "connObjectKey").getObject(),
                         new PropertyModel<>(itemTO, "connObjectKey"), false);
                 connObjectKey.hideLabel();
                 item.add(connObjectKey);
@@ -248,9 +247,9 @@ public abstract class AbstractMappingPanel extends Panel {
                 //--------------------------------
                 // Password
                 // -------------------------------
-                final AjaxCheckBoxPanel password = new AjaxCheckBoxPanel(
+                AjaxCheckBoxPanel password = new AjaxCheckBoxPanel(
+                        "password",
                         "password",
-                        new ResourceModel("password", "password").getObject(),
                         new PropertyModel<>(itemTO, "password"), false);
                 item.add(password.hideLabel());
                 // -------------------------------
@@ -261,7 +260,7 @@ public abstract class AbstractMappingPanel extends Panel {
                 WebMarkupContainer purpose = new WebMarkupContainer("purpose");
                 purpose.setOutputMarkupId(true);
 
-                final MappingPurposePanel purposeActions = new MappingPurposePanel(
+                MappingPurposePanel purposeActions = new MappingPurposePanel(
                         "purposeActions", new PropertyModel<>(itemTO, "purpose"), purpose);
                 purpose.add(purposeActions.setRenderBodyOnly(true));
                 item.add(purpose);
@@ -270,25 +269,17 @@ public abstract class AbstractMappingPanel extends Panel {
                 //--------------------------------
                 // Remove
                 // -------------------------------
-                final ActionsPanel<Serializable> actions = new ActionsPanel<>("toRemove", null);
+                ActionsPanel<Serializable> actions = new ActionsPanel<>("toRemove", null);
                 actions.add(new ActionLink<Serializable>() {
 
                     private static final long serialVersionUID = -3722207913631435501L;
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                        int index = -1;
-                        for (int i = 0; i < model.getObject().size() && index == -1; i++) {
-                            if (itemTO.equals(model.getObject().get(i))) {
-                                index = i;
-                            }
-                        }
+                        model.getObject().remove(item.getIndex());
 
-                        if (index != -1) {
-                            model.getObject().remove(index);
-                            item.getParent().removeAll();
-                            target.add(AbstractMappingPanel.this);
-                        }
+                        item.getParent().removeAll();
+                        target.add(AbstractMappingPanel.this);
                     }
                 }, ActionLink.ActionType.DELETE, IdMEntitlement.RESOURCE_UPDATE, true).hideLabel();
                 item.add(actions);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingPurposePanel.java
similarity index 98%
rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
rename to client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingPurposePanel.java
index 7a5e6ce..4b045a6 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingPurposePanel.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.syncope.client.console.wicket.markup.html.form;
+package org.apache.syncope.client.console.wizards.resources;
 
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.wicket.AttributeModifier;
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingPurposePanel.html
similarity index 100%
rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/MappingPurposePanel.html
rename to client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingPurposePanel.html
diff --git a/client/idrepo/common-ui/pom.xml b/client/idrepo/common-ui/pom.xml
index fc01405..ffb4bc3 100644
--- a/client/idrepo/common-ui/pom.xml
+++ b/client/idrepo/common-ui/pom.xml
@@ -59,6 +59,10 @@ under the License.
       <artifactId>wicket-auth-roles</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-native-websocket-javax</artifactId>
+    </dependency>
+    <dependency>
       <groupId>com.googlecode.wicket-jquery-ui</groupId>
       <artifactId>wicket-jquery-ui</artifactId>
     </dependency>
@@ -79,10 +83,6 @@ under the License.
       <artifactId>wicket-kendo-ui-theme-bootstrap</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.wicket</groupId>
-      <artifactId>wicket-native-websocket-javax</artifactId>
-    </dependency>
-    <dependency>
       <groupId>de.agilecoders.wicket</groupId>
       <artifactId>wicket-bootstrap-core</artifactId>
     </dependency>
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
index 3f4bef1..90ab9cc 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
@@ -73,7 +73,6 @@ import org.apache.syncope.common.keymaster.client.api.ServiceOps;
 import org.apache.wicket.request.component.IRequestablePage;
 import org.apache.wicket.request.cycle.IRequestCycleListener;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
-import org.apache.wicket.resource.JQueryResourceReference;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
@@ -210,8 +209,6 @@ public class SyncopeWebApplication extends WicketBootSecuredWebApplication {
 
         getResourceSettings().setThrowExceptionOnMissingResource(true);
 
-        getJavaScriptLibrarySettings().setJQueryReference(JQueryResourceReference.getV2());
-
         getSecuritySettings().setAuthorizationStrategy(new MetaDataRoleAuthorizationStrategy(this));
 
         resourceProvider = lookup.getResourceProvider();
@@ -227,7 +224,7 @@ public class SyncopeWebApplication extends WicketBootSecuredWebApplication {
 
         getMarkupSettings().setStripWicketTags(true);
         getMarkupSettings().setCompressWhitespace(true);
-        
+
         if (csrf) {
             getRequestCycleListeners().add(new WebSocketAwareCsrfPreventionRequestCycleListener());
         }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java
new file mode 100644
index 0000000..86a9c6d
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java
@@ -0,0 +1,53 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AMPage {
+
+    /**
+     * @return the i18n key for the label shown under the "Extensions" menu item, on the left pane
+     */
+    String label();
+
+    /**
+     * @return the icon shown next to the label, under the "Extensions" menu item, on the left pane;
+     * check https://fortawesome.github.io/Font-Awesome/icons/ for more
+     */
+    String icon() default "fa-circle-o";
+
+    /**
+     * @return the entitlement required to access this extension page
+     */
+    String listEntitlement();
+
+    /**
+     * @return the priority used to determine the display order under the "Extensions" menu item, on the left pane; the
+     * higher value, the higher rank
+     */
+    int priority() default 0;
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
index 1602cc2..5f250a7 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.Set;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.ObjectUtils;
+import org.apache.syncope.client.console.annotations.AMPage;
 import org.apache.syncope.client.console.annotations.ExtPage;
 import org.apache.syncope.client.console.pages.BaseExtPage;
 import org.apache.syncope.client.ui.commons.annotations.BinaryPreview;
@@ -125,6 +126,8 @@ public class ClassPathScanImplementationLookup {
 
     private List<Class<? extends BasePage>> idmPages;
 
+    private List<Class<? extends BasePage>> amPages;
+
     private List<Class<? extends BaseExtPage>> extPages;
 
     private List<Class<? extends BaseExtWidget>> extWidgets;
@@ -159,6 +162,7 @@ public class ClassPathScanImplementationLookup {
         pages = new ArrayList<>();
         previewers = new ArrayList<>();
         idmPages = new ArrayList<>();
+        amPages = new ArrayList<>();
         extPages = new ArrayList<>();
         extWidgets = new ArrayList<>();
         extAlertWidgets = new ArrayList<>();
@@ -221,6 +225,8 @@ public class ClassPathScanImplementationLookup {
                     } else if (BasePage.class.isAssignableFrom(clazz)) {
                         if (clazz.isAnnotationPresent(IdMPage.class)) {
                             idmPages.add((Class<? extends BasePage>) clazz);
+                        } else if (clazz.isAnnotationPresent(AMPage.class)) {
+                            amPages.add((Class<? extends BasePage>) clazz);
                         } else {
                             pages.add((Class<? extends BasePage>) clazz);
                         }
@@ -314,6 +320,11 @@ public class ClassPathScanImplementationLookup {
                 o2.getAnnotation(IdMPage.class).priority()));
         idmPages = Collections.unmodifiableList(idmPages);
 
+        amPages.sort((o1, o2) -> ObjectUtils.compare(
+                o1.getAnnotation(IdMPage.class).priority(),
+                o2.getAnnotation(IdMPage.class).priority()));
+        amPages = Collections.unmodifiableList(amPages);
+
         extPages.sort((o1, o2) -> ObjectUtils.compare(
                 o1.getAnnotation(ExtPage.class).priority(),
                 o2.getAnnotation(ExtPage.class).priority()));
@@ -389,6 +400,10 @@ public class ClassPathScanImplementationLookup {
         return idmPages;
     }
 
+    public List<Class<? extends BasePage>> getAMPageClasses() {
+        return amPages;
+    }
+
     public List<Class<? extends BaseExtPage>> getExtPageClasses() {
         return extPages;
     }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
index caca92c..61b3bdd 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.annotations.AMPage;
 import org.apache.syncope.client.console.annotations.ExtPage;
 import org.apache.syncope.client.console.annotations.IdMPage;
 import org.apache.syncope.client.ui.commons.HttpResourceStream;
@@ -159,7 +160,6 @@ public class BasePage extends BaseWebPage {
         liContainer.add(link);
 
         List<Class<? extends BasePage>> idmPageClasses = lookup.getIdMPageClasses();
-
         ListView<Class<? extends BasePage>> idmPages = new ListView<Class<? extends BasePage>>(
                 "idmPages", idmPageClasses) {
 
@@ -199,6 +199,46 @@ public class BasePage extends BaseWebPage {
         idmPages.setOutputMarkupId(true);
         body.add(idmPages);
 
+        List<Class<? extends BasePage>> amPageClasses = lookup.getAMPageClasses();
+        ListView<Class<? extends BasePage>> amPages = new ListView<Class<? extends BasePage>>(
+                "amPages", amPageClasses) {
+
+            private static final long serialVersionUID = -9112553137618363167L;
+
+            @Override
+            protected void populateItem(final ListItem<Class<? extends BasePage>> item) {
+                WebMarkupContainer containingLI = new WebMarkupContainer("amPageLI");
+                item.add(containingLI);
+                if (item.getModelObject().equals(BasePage.this.getClass())) {
+                    containingLI.add(new Behavior() {
+
+                        private static final long serialVersionUID = 1469628524240283489L;
+
+                        @Override
+                        public void onComponentTag(final Component component, final ComponentTag tag) {
+                            tag.put("class", "active");
+                        }
+                    });
+                }
+
+                AMPage ann = item.getModelObject().getAnnotation(AMPage.class);
+
+                BookmarkablePageLink<Page> link = new BookmarkablePageLink<>("amPage", item.getModelObject());
+                link.add(new Label("amPageLabel", ann.label()));
+                if (StringUtils.isNotBlank(ann.listEntitlement())) {
+                    MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.RENDER, ann.listEntitlement());
+                }
+                containingLI.add(link);
+
+                Label amPageIcon = new Label("amPageIcon");
+                amPageIcon.add(new AttributeModifier("class", "fa " + ann.icon()));
+                link.add(amPageIcon);
+            }
+        };
+        amPages.setRenderBodyOnly(true);
+        amPages.setOutputMarkupId(true);
+        body.add(amPages);
+
         WebMarkupContainer keymasterLIContainer = new WebMarkupContainer(getLIContainerId("keymaster"));
         body.add(keymasterLIContainer);
         WebMarkupContainer keymasterULContainer = new WebMarkupContainer(getULContainerId("keymaster"));
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/PrivilegeDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/PrivilegeDirectoryPanel.java
index 4bfcd78..54c5a89 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/PrivilegeDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/PrivilegeDirectoryPanel.java
@@ -73,7 +73,7 @@ public class PrivilegeDirectoryPanel extends DirectoryPanel<
         restClient = new ApplicationRestClient();
 
         disableCheckBoxes();
-        enableExitButton();
+        enableUtilityButton();
 
         this.addNewItemPanelBuilder(new PrivilegeWizardBuilder(application, new PrivilegeTO(), pageRef), true);
 
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypeWizardBuilder.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypeWizardBuilder.java
index 57bd37d..4bb161c 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypeWizardBuilder.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypeWizardBuilder.java
@@ -207,18 +207,10 @@ public class SchemaTypeWizardBuilder extends BaseAjaxWizardBuilder<SchemaTO> {
 
                         @Override
                         public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                            int index = -1;
-                            for (int i = 0; i < translations.getObject().size() && index == -1; i++) {
-                                if (entry.equals(translations.getObject().get(i))) {
-                                    index = i;
-                                }
-                            }
-
-                            if (index != -1) {
-                                translations.getObject().remove(index);
-                                item.getParent().removeAll();
-                                target.add(Labels.this);
-                            }
+                            translations.getObject().remove(item.getIndex());
+
+                            item.getParent().removeAll();
+                            target.add(Labels.this);
                         }
                     }, ActionLink.ActionType.DELETE, IdRepoEntitlement.SCHEMA_UPDATE, true).hideLabel();
                     item.add(actions);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
index 9cde5e3..488d53f 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
@@ -102,7 +102,7 @@ public class PolicyRuleDirectoryPanel<T extends PolicyTO> extends DirectoryPanel
         this.policy = policy;
         this.restClient = new PolicyRestClient();
 
-        enableExitButton();
+        enableUtilityButton();
 
         this.addNewItemPanelBuilder(
                 new PolicyRuleWizardBuilder(policy, type, new PolicyRuleWrapper(true), pageRef), true);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
index 70e07fd..07dd7dc 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
@@ -306,8 +306,8 @@ public abstract class ReportDirectoryPanel
         }
 
         @Override
-        public IModel<ReportTO> model(final ReportTO object) {
-            return new CompoundPropertyModel<>(object);
+        public IModel<ReportTO> model(final ReportTO report) {
+            return new CompoundPropertyModel<>(report);
         }
     }
 }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
index 220fc90..0f5edbf 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
@@ -225,7 +225,7 @@ public class ReportTemplateDirectoryPanel
 
         @Override
         public Iterator<ReportTemplateTO> iterator(final long first, final long count) {
-            final List<ReportTemplateTO> list = restClient.listTemplates();
+            List<ReportTemplateTO> list = restClient.listTemplates();
             Collections.sort(list, comparator);
             return list.subList((int) first, (int) first + (int) count).iterator();
         }
@@ -237,15 +237,7 @@ public class ReportTemplateDirectoryPanel
 
         @Override
         public IModel<ReportTemplateTO> model(final ReportTemplateTO reportTemplateTO) {
-            return new IModel<ReportTemplateTO>() {
-
-                private static final long serialVersionUID = 774694801558497248L;
-
-                @Override
-                public ReportTemplateTO getObject() {
-                    return reportTemplateTO;
-                }
-            };
+            return () -> reportTemplateTO;
         }
     }
 
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
index 7d0fce3..44cd1b3 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
@@ -90,7 +90,7 @@ public class ReportletDirectoryPanel extends DirectoryPanel<
         this.report = report;
         this.restClient = new ReportRestClient();
 
-        enableExitButton();
+        enableUtilityButton();
 
         this.addNewItemPanelBuilder(
                 new ReportletWizardBuilder(report, new ReportletWrapper(true), pageRef), true);
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
index 8bfccb6..7043da8 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
@@ -103,7 +103,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
 
         MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.TASK_CREATE);
 
-        enableExitButton();
+        enableUtilityButton();
         setFooterVisibility(false);
 
         initResultTable();
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index c237bd4..f37e91b 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -42,6 +42,8 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
 
     public enum ActionType {
 
+        UP("up"),
+        DOWN("down"),
         MAPPING("update"),
         MUSTCHANGEPASSWORD("update"),
         SET_LATEST_SYNC_TOKEN("update"),
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksTogglePanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksTogglePanel.java
index 9c434a5..79a2009 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksTogglePanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksTogglePanel.java
@@ -33,7 +33,6 @@ import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.to.ReportTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.Attr;
 import org.apache.syncope.common.lib.to.SecurityQuestionTO;
@@ -41,7 +40,6 @@ import org.apache.syncope.common.lib.policy.PolicyTO;
 import org.apache.syncope.common.lib.to.AccessTokenTO;
 import org.apache.syncope.common.lib.to.ExecTO;
 import org.apache.syncope.common.lib.to.JobTO;
-import org.apache.syncope.common.lib.to.SchedTaskTO;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.event.IEvent;
@@ -51,6 +49,7 @@ import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.syncope.client.console.panels.ToggleableTarget;
 import org.apache.syncope.common.keymaster.client.api.model.Domain;
+import org.apache.syncope.common.lib.to.NamedEntityTO;
 
 public class ActionLinksTogglePanel<T extends Serializable> extends TogglePanel<Serializable> {
 
@@ -88,8 +87,6 @@ public class ActionLinksTogglePanel<T extends Serializable> extends TogglePanel<
         } else if (modelObject instanceof AnyWrapper
                 && AnyWrapper.class.cast(modelObject).getInnerObject() instanceof AnyObjectTO) {
             header = ((AnyObjectTO) ((AnyWrapper) modelObject).getInnerObject()).getName();
-        } else if (modelObject instanceof ReportTO) {
-            header = ((ReportTO) modelObject).getName();
         } else if (modelObject instanceof Attr) {
             header = ((Attr) modelObject).getSchema();
         } else if (modelObject instanceof ConfParam) {
@@ -102,10 +99,6 @@ public class ActionLinksTogglePanel<T extends Serializable> extends TogglePanel<
             header = ((AccessTokenTO) modelObject).getOwner();
         } else if (modelObject instanceof ExecTO) {
             header = ((ExecTO) modelObject).getKey();
-        } else if (modelObject instanceof SchedTaskTO) {
-            header = ((SchedTaskTO) modelObject).getName();
-        } else if (modelObject instanceof EntityTO) {
-            header = ((EntityTO) modelObject).getKey();
         } else if (modelObject instanceof StatusBean) {
             header = ((StatusBean) modelObject).getResource();
         } else if (modelObject instanceof PolicyRuleWrapper) {
@@ -121,6 +114,10 @@ public class ActionLinksTogglePanel<T extends Serializable> extends TogglePanel<
             header = ((ToggleableTarget) modelObject).getAnyType();
         } else if (modelObject instanceof Domain) {
             header = ((Domain) modelObject).getKey();
+        } else if (modelObject instanceof NamedEntityTO) {
+            header = ((NamedEntityTO) modelObject).getName();
+        } else if (modelObject instanceof EntityTO) {
+            header = ((EntityTO) modelObject).getKey();
         } else {
             header = new ResourceModel("actions", StringUtils.EMPTY).getObject();
         }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
index 286260f..1440025 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
@@ -62,7 +62,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends AbstractWiz
 
     private final WebMarkupContainer container;
 
-    private final Fragment initialFragment;
+    protected final Fragment initialFragment;
 
     protected final boolean wizardInModal;
 
@@ -72,7 +72,9 @@ public abstract class WizardMgtPanel<T extends Serializable> extends AbstractWiz
 
     protected final AjaxLink<?> addAjaxLink;
 
-    protected final AjaxLink<?> exitAjaxLink;
+    protected Label utilityIcon;
+
+    protected AjaxLink<?> utilityAjaxLink;
 
     protected ModalPanelBuilder<T> newItemPanelBuilder;
 
@@ -133,7 +135,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends AbstractWiz
         addAjaxLink.setVisible(false);
         initialFragment.addOrReplace(addAjaxLink);
 
-        exitAjaxLink = new AjaxLink<T>("exit") {
+        utilityAjaxLink = new AjaxLink<T>("utility") {
 
             private static final long serialVersionUID = -7978723352517770644L;
 
@@ -143,9 +145,12 @@ public abstract class WizardMgtPanel<T extends Serializable> extends AbstractWiz
             }
         };
 
-        exitAjaxLink.setEnabled(false);
-        exitAjaxLink.setVisible(false);
-        initialFragment.addOrReplace(exitAjaxLink);
+        utilityAjaxLink.setEnabled(false);
+        utilityAjaxLink.setVisible(false);
+        initialFragment.addOrReplace(utilityAjaxLink);
+
+        utilityIcon = new Label("utilityIcon");
+        utilityAjaxLink.add(utilityIcon);
 
         add(new ListView<Component>("outerObjectsRepeater", outerObjects) {
 
@@ -276,13 +281,13 @@ public abstract class WizardMgtPanel<T extends Serializable> extends AbstractWiz
     }
 
     /**
-     * Show exit butto sending ExitEvent paylad.
+     * Show utility button sending ExitEvent payload by default.
      *
      * @return the current instance.
      */
-    protected final WizardMgtPanel<T> enableExitButton() {
-        exitAjaxLink.setEnabled(true);
-        exitAjaxLink.setVisible(true);
+    protected final WizardMgtPanel<T> enableUtilityButton() {
+        utilityAjaxLink.setEnabled(true);
+        utilityAjaxLink.setVisible(true);
         return this;
     }
 
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
index c38ee0d..e18f828 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
@@ -117,6 +117,11 @@ under the License.
                 <a href="#" wicket:id="idmPage"><i wicket:id="idmPageIcon"></i><span wicket:id="idmPageLabel"/></a>
               </li>
             </wicket:container>
+            <wicket:container wicket:id="amPages">
+              <li wicket:id="amPageLI">
+                <a href="#" wicket:id="amPage"><i wicket:id="amPageIcon"></i><span wicket:id="amPageLabel"/></a>
+              </li>
+            </wicket:container>
             <li wicket:id="keymasterLI" class="treeview">
               <a href="#"><i class="fa fa-magic"></i><span><wicket:message key="keymaster"/></span> <span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span></a>
               <ul wicket:id="keymasterUL" class="treeview-menu">
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.properties
index 698e4cc..a9d0d7d 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.properties
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+up.class=fa fa-arrow-up
+up.title=move up
+up.alt=arrow up icon
+
+down.class=fa fa-arrow-down
+down.title=move down
+down.alt=arrow down icon
+
 mapping.class=fa fa-exchange
 mapping.title=mapping
 mapping.alt=mapping icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_it.properties
index 4bfa686..f065aab 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_it.properties
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+up.class=fa fa-arrow-up
+up.title=move up
+up.alt=arrow up icon
+
+down.class=fa fa-arrow-down
+down.title=move down
+down.alt=arrow down icon
+
 mapping.class=fa fa-exchange
 mapping.title=mapping
 mapping.alt=mapping icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ja.properties
index 6b011c7..a3cb0d9 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ja.properties
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+up.class=fa fa-arrow-up
+up.title=move up
+up.alt=arrow up icon
+
+down.class=fa fa-arrow-down
+down.title=move down
+down.alt=arrow down icon
+
 mapping.class=fa fa-exchange
 mapping.title=\u30de\u30c3\u30d4\u30f3\u30b0
 mapping.alt=\u30de\u30c3\u30d4\u30f3\u30b0
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_pt_BR.properties
index b362779..122c790 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_pt_BR.properties
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+up.class=fa fa-arrow-up
+up.title=move up
+up.alt=arrow up icon
+
+down.class=fa fa-arrow-down
+down.title=move down
+down.alt=arrow down icon
+
 mapping.class=fa fa-exchange
 mapping.title=mapping
 mapping.alt=mapping icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ru.properties
index dfea5ea..182c65c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel_ru.properties
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+up.class=fa fa-arrow-up
+up.title=move up
+up.alt=arrow up icon
+
+down.class=fa fa-arrow-down
+down.title=move down
+down.alt=arrow down icon
+
 mapping.class=fa fa-exchange
 mapping.title=mapping
 mapping.alt=mapping icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
index 80736d2..f1bc7a2 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
@@ -43,10 +43,10 @@ under the License.
 
       <wicket:enclosure child="add">
         <div class="modal-footer" style="text-align: right">
-          <a href="#"  class="btn btn-default btn-circle btn-lg pull-left" wicket:id="exit">
-            <i class="fa fa-sign-out"></i>
+          <a href="#" class="btn btn-default btn-circle btn-lg pull-left" wicket:id="utility">
+            <i wicket:id="utilityIcon" class="fa fa-sign-out"></i>
           </a>
-          <a href="#"  class="btn btn-primary btn-circle btn-lg" wicket:id="add">
+          <a href="#" class="btn btn-primary btn-circle btn-lg" wicket:id="add">
             <i class="glyphicon glyphicon-plus"></i>
           </a>
         </div>
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
index 17ae03a..aeb8e2d 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
@@ -35,7 +35,7 @@ import org.apache.syncope.common.lib.types.GatewayRouteStatus;
 
 @XmlRootElement(name = "gatewayRoute")
 @XmlType
-public class GatewayRouteTO implements EntityTO {
+public class GatewayRouteTO implements NamedEntityTO {
 
     private static final long serialVersionUID = 4044528284951757870L;
 
@@ -64,10 +64,12 @@ public class GatewayRouteTO implements EntityTO {
         this.key = key;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public void setName(final String name) {
         this.name = name;
     }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NamedEntityTO.java
similarity index 59%
rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
rename to common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NamedEntityTO.java
index b31bbab..5c5599c 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/LinkPanel.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/NamedEntityTO.java
@@ -16,24 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.syncope.client.console.wicket.markup.html.form;
+package org.apache.syncope.common.lib.to;
 
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.IModel;
+public interface NamedEntityTO extends EntityTO {
 
-/**
- * This empty class must exist because there not seems to be alternative to
- * provide specialized HTML for links.
- */
-public class LinkPanel extends Panel {
-
-    private static final long serialVersionUID = 4799005986804366330L;
-
-    public LinkPanel(final String id) {
-        super(id);
-    }
+    String getName();
 
-    public LinkPanel(final String id, final IModel<?> model) {
-        super(id, model);
-    }
+    void setName(String name);
 }
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
index c38fc85..a841854 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
@@ -35,7 +35,7 @@ import org.apache.syncope.common.lib.jaxb.XmlGenericMapAdapter;
 
 @XmlRootElement(name = "realm")
 @XmlType
-public class RealmTO implements EntityTO, TemplatableTO {
+public class RealmTO implements NamedEntityTO, TemplatableTO {
 
     private static final long serialVersionUID = 516330662956254391L;
 
@@ -68,10 +68,12 @@ public class RealmTO implements EntityTO, TemplatableTO {
         this.key = key;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public void setName(final String name) {
         this.name = name;
     }
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
index 3de4ad1..dc7eced 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
@@ -32,7 +32,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
 
 @XmlRootElement(name = "report")
 @XmlType
-public class ReportTO extends AbstractStartEndBean implements EntityTO {
+public class ReportTO extends AbstractStartEndBean implements NamedEntityTO {
 
     private static final long serialVersionUID = 5274568072084814410L;
 
@@ -67,10 +67,12 @@ public class ReportTO extends AbstractStartEndBean implements EntityTO {
         this.key = key;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public void setName(final String name) {
         this.name = name;
     }
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
index 0ad6af2..9962745 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
@@ -33,7 +33,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
 @XmlType
 @XmlSeeAlso({ ProvisioningTaskTO.class })
 @Schema(allOf = { TaskTO.class }, subTypes = { ProvisioningTaskTO.class }, discriminatorProperty = "@class")
-public class SchedTaskTO extends TaskTO {
+public class SchedTaskTO extends TaskTO implements NamedEntityTO {
 
     private static final long serialVersionUID = -5722284116974636425L;
 
@@ -111,12 +111,14 @@ public class SchedTaskTO extends TaskTO {
         this.description = description;
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
     @JsonProperty(required = true)
     @XmlElement(required = true)
+    @Override
     public void setName(final String name) {
         this.name = name;
     }
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/GatewayRouteLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/GatewayRouteLogic.java
index 71a343e..e592fcf 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/GatewayRouteLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/GatewayRouteLogic.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.logic;
 
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.URI;
 import java.net.http.HttpClient;
@@ -26,6 +27,7 @@ import java.net.http.HttpResponse;
 import java.util.List;
 import java.util.stream.Collectors;
 import javax.annotation.Resource;
+import javax.ws.rs.InternalServerErrorException;
 import javax.ws.rs.core.HttpHeaders;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -115,7 +117,7 @@ public class GatewayRouteLogic extends AbstractTransactionalLogic<GatewayRouteTO
     public void pushToSRA() {
         try {
             NetworkService sra = serviceOps.get(NetworkService.Type.SRA);
-            HttpClient.newBuilder().build().sendAsync(
+            HttpClient.newBuilder().build().send(
                     HttpRequest.newBuilder(URI.create(
                             StringUtils.appendIfMissing(sra.getAddress(), "/") + "management/routes/refresh")).
                             header(HttpHeaders.AUTHORIZATION,
@@ -124,6 +126,8 @@ public class GatewayRouteLogic extends AbstractTransactionalLogic<GatewayRouteTO
                     HttpResponse.BodyHandlers.discarding());
         } catch (KeymasterException e) {
             throw new NotFoundException("Could not find any SRA instance", e);
+        } catch (IOException | InterruptedException e) {
+            throw new InternalServerErrorException("Errors while communicating with SRA instance", e);
         }
     }
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GatewayRouteValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GatewayRouteValidator.java
index 490528f..f46ad89 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GatewayRouteValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/GatewayRouteValidator.java
@@ -38,13 +38,13 @@ public class GatewayRouteValidator extends AbstractValidator<GatewayRouteCheck,
             isValid = false;
         }
 
-        if (route.getPredicates().size() > 1) {
-            if (route.getPredicates().stream().allMatch(predicate -> predicate.getCond() != null)) {
-                context.buildConstraintViolationWithTemplate(
-                        getTemplate(EntityViolationType.InvalidValueList,
-                                "Cond must be set when predicates are more than one")).
-                        addPropertyNode("predicates").addConstraintViolation();
-            }
+        if (route.getPredicates().size() > 1
+                && route.getPredicates().stream().allMatch(predicate -> predicate.getCond() != null)) {
+
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidValueList,
+                            "Cond must be set when predicates are more than one")).
+                    addPropertyNode("predicates").addConstraintViolation();
 
             isValid = false;
         }
diff --git a/deb/console/pom.xml b/deb/console/pom.xml
index decbf2d..1949937 100644
--- a/deb/console/pom.xml
+++ b/deb/console/pom.xml
@@ -43,6 +43,11 @@ under the License.
       <artifactId>syncope-client-idm-console</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.client.am</groupId>
+      <artifactId>syncope-client-am-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.syncope.ext.self-keymaster</groupId>
diff --git a/docker/console/pom.xml b/docker/console/pom.xml
index e81f8f1..6650c02 100644
--- a/docker/console/pom.xml
+++ b/docker/console/pom.xml
@@ -48,6 +48,11 @@ under the License.
       <artifactId>syncope-client-idm-console</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.client.am</groupId>
+      <artifactId>syncope-client-am-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.syncope.ext.self-keymaster</groupId>
diff --git a/fit/console-reference/pom.xml b/fit/console-reference/pom.xml
index 9b0acef..0bd5e67 100644
--- a/fit/console-reference/pom.xml
+++ b/fit/console-reference/pom.xml
@@ -43,6 +43,11 @@ under the License.
       <artifactId>syncope-client-idm-console</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.client.am</groupId>
+      <artifactId>syncope-client-am-console</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.syncope.ext.self-keymaster</groupId>
diff --git a/fit/console-reference/src/test/resources/hotswap-agent.properties b/fit/console-reference/src/test/resources/hotswap-agent.properties
index 9ec5374..4a504a6 100644
--- a/fit/console-reference/src/test/resources/hotswap-agent.properties
+++ b/fit/console-reference/src/test/resources/hotswap-agent.properties
@@ -23,6 +23,7 @@ extraClasspath=\
 ${basedir}/../../client/idrepo/common-ui/target/classes/org,\
 ${basedir}/../../client/idrepo/console/target/classes/org,\
 ${basedir}/../../client/idm/console/target/classes/org,\
+${basedir}/../../client/am/console/target/classes/org,\
 ${basedir}/../../ext/camel/client-console/target/classes/org,\
 ${basedir}/../../ext/flowable/client-console/target/classes/org,\
 ${basedir}/../../ext/saml2sp/client-console/target/classes/org,\
diff --git a/fit/enduser-reference/src/test/java/org/apache/syncope/fit/OIDCClientITCase.java b/fit/enduser-reference/src/test/java/org/apache/syncope/fit/OIDCClientITCase.java
index 6058ad2..b643107 100644
--- a/fit/enduser-reference/src/test/java/org/apache/syncope/fit/OIDCClientITCase.java
+++ b/fit/enduser-reference/src/test/java/org/apache/syncope/fit/OIDCClientITCase.java
@@ -48,7 +48,7 @@ import org.junit.jupiter.api.Test;
 public class OIDCClientITCase extends AbstractITCase {
 
     @BeforeAll
-    public static void samlSetup() {
+    public static void oidcSetup() {
         OIDCProviderTO keycloak = new OIDCProviderTO();
         keycloak.setName("Keyloack");
         keycloak.setClientID("oidc-syncope");
diff --git a/fit/enduser-reference/src/test/resources/sso/realm.json b/fit/enduser-reference/src/test/resources/sso/realm.json
deleted file mode 100644
index a591048..0000000
--- a/fit/enduser-reference/src/test/resources/sso/realm.json
+++ /dev/null
@@ -1,2171 +0,0 @@
-{
-  "id": "master",
-  "realm": "master",
-  "displayName": "Keycloak",
-  "displayNameHtml": "<div class=\"kc-logo-text\"><span>Keycloak</span></div>",
-  "notBefore": 0,
-  "revokeRefreshToken": false,
-  "refreshTokenMaxReuse": 0,
-  "accessTokenLifespan": 60,
-  "accessTokenLifespanForImplicitFlow": 900,
-  "ssoSessionIdleTimeout": 1800,
-  "ssoSessionMaxLifespan": 36000,
-  "ssoSessionIdleTimeoutRememberMe": 0,
-  "ssoSessionMaxLifespanRememberMe": 0,
-  "offlineSessionIdleTimeout": 2592000,
-  "offlineSessionMaxLifespanEnabled": false,
-  "offlineSessionMaxLifespan": 5184000,
-  "accessCodeLifespan": 60,
-  "accessCodeLifespanUserAction": 300,
-  "accessCodeLifespanLogin": 1800,
-  "actionTokenGeneratedByAdminLifespan": 43200,
-  "actionTokenGeneratedByUserLifespan": 300,
-  "enabled": true,
-  "sslRequired": "external",
-  "registrationAllowed": false,
-  "registrationEmailAsUsername": false,
-  "rememberMe": false,
-  "verifyEmail": false,
-  "loginWithEmailAllowed": true,
-  "duplicateEmailsAllowed": false,
-  "resetPasswordAllowed": false,
-  "editUsernameAllowed": false,
-  "bruteForceProtected": false,
-  "permanentLockout": false,
-  "maxFailureWaitSeconds": 900,
-  "minimumQuickLoginWaitSeconds": 60,
-  "waitIncrementSeconds": 60,
-  "quickLoginCheckMilliSeconds": 1000,
-  "maxDeltaTimeSeconds": 43200,
-  "failureFactor": 30,
-  "roles": {
-    "realm": [
-      {
-        "id": "3650e688-c539-4646-8222-010d51a34b2a",
-        "name": "admin",
-        "description": "${role_admin}",
-        "composite": true,
-        "composites": {
-          "realm": [
-            "create-realm"
-          ],
-          "client": {
-            "master-realm": [
-              "query-groups",
-              "manage-events",
-              "manage-authorization",
-              "impersonation",
-              "query-realms",
-              "view-clients",
-              "manage-realm",
-              "manage-users",
-              "create-client",
-              "view-authorization",
-              "manage-clients",
-              "manage-identity-providers",
-              "query-users",
-              "view-users",
-              "view-identity-providers",
-              "view-realm",
-              "view-events",
-              "query-clients"
-            ]
-          }
-        },
-        "clientRole": false,
-        "containerId": "master",
-        "attributes": {}
-      },
-      {
-        "id": "8dfabd84-8072-412e-af5f-5fb57c4a58e5",
-        "name": "create-realm",
-        "description": "${role_create-realm}",
-        "composite": false,
-        "clientRole": false,
-        "containerId": "master",
-        "attributes": {}
-      },
-      {
-        "id": "747ed7d7-6e7a-4339-b7ff-033fceb99af6",
-        "name": "offline_access",
-        "description": "${role_offline-access}",
-        "composite": false,
-        "clientRole": false,
-        "containerId": "master",
-        "attributes": {}
-      },
-      {
-        "id": "7d35cede-58ce-40cb-a63d-7ce27ceaf4db",
-        "name": "uma_authorization",
-        "description": "${role_uma_authorization}",
-        "composite": false,
-        "clientRole": false,
-        "containerId": "master",
-        "attributes": {}
-      }
-    ],
-    "client": {
-      "oidc-test": [
-        {
-          "id": "894b2e32-3f57-461a-9bd1-c94342a365df",
-          "name": "uma_protection",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "0543361e-6007-4b9a-ad3c-dcc473feaa68",
-          "attributes": {}
-        }
-      ],
-      "security-admin-console": [],
-      "admin-cli": [],
-      "http://localhost:9080/syncope-enduser/": [],
-      "master-realm": [
-        {
-          "id": "4167efac-ca8a-429d-b145-9ca572571073",
-          "name": "query-groups",
-          "description": "${role_query-groups}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "91947892-bd70-487f-8909-c66dedb50adf",
-          "name": "manage-events",
-          "description": "${role_manage-events}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "fe614065-daf1-472a-ac24-c8731a793123",
-          "name": "manage-authorization",
-          "description": "${role_manage-authorization}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "af81c41f-c56b-4b17-b70e-8df75ac312ff",
-          "name": "impersonation",
-          "description": "${role_impersonation}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "4ba3ad04-ed50-4a0c-a3e1-b35df435f617",
-          "name": "query-realms",
-          "description": "${role_query-realms}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "f05e152c-4498-4fba-b921-ab8460518de4",
-          "name": "view-clients",
-          "description": "${role_view-clients}",
-          "composite": true,
-          "composites": {
-            "client": {
-              "master-realm": [
-                "query-clients"
-              ]
-            }
-          },
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "30a080da-f204-40ad-b05e-0b44f2fcd272",
-          "name": "manage-realm",
-          "description": "${role_manage-realm}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "1271c59f-e5af-4d14-873c-1464adf49cfc",
-          "name": "manage-users",
-          "description": "${role_manage-users}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "0dbeecc1-7dc8-4b1b-af79-454764baec72",
-          "name": "create-client",
-          "description": "${role_create-client}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "f8242770-20b7-4ca4-80a2-e93d738f88a7",
-          "name": "manage-clients",
-          "description": "${role_manage-clients}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "827dde28-89de-484d-9a86-cc46a45aa212",
-          "name": "view-authorization",
-          "description": "${role_view-authorization}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "22240518-a563-49f3-8c76-e545b1940870",
-          "name": "manage-identity-providers",
-          "description": "${role_manage-identity-providers}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "678abcca-231e-419a-b319-54e79626e851",
-          "name": "query-users",
-          "description": "${role_query-users}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "175cd662-fdd4-4080-88c8-2f3aa7e45a0b",
-          "name": "view-identity-providers",
-          "description": "${role_view-identity-providers}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "38bda15b-0ef5-4d14-b477-07a9a66057d4",
-          "name": "view-users",
-          "description": "${role_view-users}",
-          "composite": true,
-          "composites": {
-            "client": {
-              "master-realm": [
-                "query-groups",
-                "query-users"
-              ]
-            }
-          },
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "aa13c02e-fe23-46c4-b8df-1ee0d74c1af8",
-          "name": "view-realm",
-          "description": "${role_view-realm}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "9820eacb-e9b8-43bc-ac91-295f8a1361f4",
-          "name": "query-clients",
-          "description": "${role_query-clients}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        },
-        {
-          "id": "1c2fe26f-bfa4-4321-b96b-2e7353eb6665",
-          "name": "view-events",
-          "description": "${role_view-events}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-          "attributes": {}
-        }
-      ],
-      "broker": [
-        {
-          "id": "c90009b0-6879-495e-9f85-c9d39c5fa1ba",
-          "name": "read-token",
-          "description": "${role_read-token}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "e5f1365e-8227-4f63-b03d-8c5b8ffed1ff",
-          "attributes": {}
-        }
-      ],
-      "account": [
-        {
-          "id": "0f834554-e8f0-4954-96c4-5df669b55a95",
-          "name": "view-profile",
-          "description": "${role_view-profile}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "9cb0aa44-7e89-4ed2-8702-7bee34b39fdc",
-          "attributes": {}
-        },
-        {
-          "id": "61eef459-9623-4420-b7c5-83d209f79ff9",
-          "name": "uma_protection",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "9cb0aa44-7e89-4ed2-8702-7bee34b39fdc",
-          "attributes": {}
-        },
-        {
-          "id": "e8b0e7f0-d57d-40b4-81d3-a10d999f925f",
-          "name": "manage-account",
-          "description": "${role_manage-account}",
-          "composite": true,
-          "composites": {
-            "client": {
-              "account": [
-                "manage-account-links"
-              ]
-            }
-          },
-          "clientRole": true,
-          "containerId": "9cb0aa44-7e89-4ed2-8702-7bee34b39fdc",
-          "attributes": {}
-        },
-        {
-          "id": "95244445-b81c-43e6-9439-1bfb746a4632",
-          "name": "manage-account-links",
-          "description": "${role_manage-account-links}",
-          "composite": false,
-          "clientRole": true,
-          "containerId": "9cb0aa44-7e89-4ed2-8702-7bee34b39fdc",
-          "attributes": {}
-        }
-      ]
-    }
-  },
-  "groups": [],
-  "defaultRoles": [
-    "offline_access",
-    "uma_authorization"
-  ],
-  "requiredCredentials": [
-    "password"
-  ],
-  "otpPolicyType": "totp",
-  "otpPolicyAlgorithm": "HmacSHA1",
-  "otpPolicyInitialCounter": 0,
-  "otpPolicyDigits": 6,
-  "otpPolicyLookAheadWindow": 1,
-  "otpPolicyPeriod": 30,
-  "otpSupportedApplications": [
-    "FreeOTP",
-    "Google Authenticator"
-  ],
-  "scopeMappings": [
-    {
-      "clientScope": "offline_access",
-      "roles": [
-        "offline_access"
-      ]
-    }
-  ],
-  "clients": [
-    {
-      "id": "9ae76ff0-02bd-4219-be28-1ad02acc24c9",
-      "clientId": "admin-cli",
-      "name": "${client_admin-cli}",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": false,
-      "standardFlowEnabled": false,
-      "implicitFlowEnabled": false,
-      "directAccessGrantsEnabled": true,
-      "serviceAccountsEnabled": false,
-      "publicClient": true,
-      "frontchannelLogout": false,
-      "protocol": "openid-connect",
-      "attributes": {},
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": false,
-      "nodeReRegistrationTimeout": 0,
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ]
-    },
-    {
-      "id": "afead16d-8b07-4b25-930a-034922529245",
-      "clientId": "http://localhost:9080/syncope-enduser/",
-      "name": "SAML Test",
-      "adminUrl": "http://localhost:9090/auth/realms/master",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [
-        "http://localhost:9080/*"
-      ],
-      "webOrigins": [
-        "http://localhost:9080"
-      ],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": false,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": false,
-      "directAccessGrantsEnabled": false,
-      "serviceAccountsEnabled": false,
-      "publicClient": false,
-      "frontchannelLogout": true,
-      "protocol": "saml",
-      "attributes": {
-        "saml.assertion.signature": "true",
-        "saml_assertion_consumer_url_redirect": "http://localhost:9080/syncope-enduser/saml2sp/assertion-consumer",
-        "saml_single_logout_service_url_post": "http://localhost:9080/syncope-enduser/saml2sp/logout",
-        "saml.force.post.binding": "true",
-        "saml.multivalued.roles": "false",
-        "saml.encrypt": "false",
-        "saml_assertion_consumer_url_post": "http://localhost:9080/syncope-enduser/saml2sp/assertion-consumer",
-        "saml.server.signature": "true",
-        "saml.server.signature.keyinfo.ext": "false",
-        "exclude.session.state.from.auth.response": "false",
-        "saml.signing.certificate": "MIIC9TCCAd0CBgFrCC7kezANBgkqhkiG9w0BAQsFADA+MTwwOgYDVQQDDDNodHRwOi8vc3luY29wZS1zYW1sMi10ZXN0LWNvbTo5MDgwL3N5bmNvcGUtZW5kdXNlci8wHhcNMTkwNTMwMDk1ODM5WhcNMjkwNTMwMTAwMDE5WjA+MTwwOgYDVQQDDDNodHRwOi8vc3luY29wZS1zYW1sMi10ZXN0LWNvbTo5MDgwL3N5bmNvcGUtZW5kdXNlci8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCF4QsiRZGD7BNx0Bglh4rgtACaIr7R/nDQfdGLN9uSA2HkEPygJzBRyluQLiQv9o/LKQMwvmia5fK4Xt99cgJnmrzKXraKo1KsZNz8vpygMpGJzCA2XUMLe065lYg28PV2bjk6hyUcMehlubjKFQ6USAJG5db [...]
-        "saml_single_logout_service_url_redirect": "http://localhost:9080/syncope-enduser/saml2sp/logout",
-        "saml.signature.algorithm": "RSA_SHA256",
-        "saml_force_name_id_format": "false",
-        "tls.client.certificate.bound.access.tokens": "false",
-        "saml.client.signature": "false",
-        "saml.authnstatement": "true",
-        "display.on.consent.screen": "false",
-        "saml_name_id_format": "persistent",
-        "saml.signing.private.key": "MIIEowIBAAKCAQEAheELIkWRg+wTcdAYJYeK4LQAmiK+0f5w0H3RizfbkgNh5BD8oCcwUcpbkC4kL/aPyykDML5omuXyuF7ffXICZ5q8yl62iqNSrGTc/L6coDKRicwgNl1DC3tOuZWINvD1dm45OoclHDHoZbm4yhUOlEgCRuXW660s+4ktox0GXMQmQHTzxaWlGaXCTzV1PJ/bPqXkLz3omEbvUFBAf6nv6J70P1iVF8RK8djx5rRvcniECqGnEr6w+q0h8AoMMSYKPrVtdkuG0V4+DcJtoffevT60DvC/HoApBeUS0ntIAWlqmp/R2CEOgf084LBq1DyBsO2QOFluxoC97WaV72WGSwIDAQABAoIBABXnJY0r2Iy+uMesBedN75inmlmdSZ7Ng+N4Uin2r4OJ7iAD73C8OJmJA8Xo5p66NfhE83KsFC0TZcxoKSQ63M3 [...]
-        "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#",
-        "saml.onetimeuse.condition": "false"
-      },
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": true,
-      "nodeReRegistrationTimeout": -1,
-      "protocolMappers": [
-        {
-          "id": "9cd8a79b-97f9-459f-a2fb-802f217059f3",
-          "name": "lastName",
-          "protocol": "saml",
-          "protocolMapper": "saml-user-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "attribute.nameformat": "Basic",
-            "user.attribute": "lastName",
-            "friendly.name": "lastName",
-            "attribute.name": "lastName"
-          }
-        },
-        {
-          "id": "c3bb90a6-8443-4dfa-9755-6cb90294b488",
-          "name": "fullName",
-          "protocol": "saml",
-          "protocolMapper": "saml-user-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "attribute.nameformat": "Basic",
-            "user.attribute": "fullName",
-            "friendly.name": "fullName",
-            "attribute.name": "fullName"
-          }
-        },
-        {
-          "id": "8b599498-cd22-4bf0-b999-2b8822b27c2b",
-          "name": "username",
-          "protocol": "saml",
-          "protocolMapper": "saml-user-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "attribute.nameformat": "Basic",
-            "user.attribute": "username",
-            "friendly.name": "username",
-            "attribute.name": "username"
-          }
-        },
-        {
-          "id": "a927aea7-2c71-460b-9eff-cdb1c1979f88",
-          "name": "email",
-          "protocol": "saml",
-          "protocolMapper": "saml-user-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "attribute.nameformat": "Basic",
-            "user.attribute": "email",
-            "friendly.name": "email",
-            "attribute.name": "email"
-          }
-        }
-      ],
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ]
-    },
-    {
-      "id": "f44a4b58-3873-4b1f-8907-8cdda73ba648",
-      "clientId": "master-realm",
-      "name": "master Realm",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": true,
-      "consentRequired": false,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": false,
-      "directAccessGrantsEnabled": false,
-      "serviceAccountsEnabled": false,
-      "publicClient": false,
-      "frontchannelLogout": false,
-      "attributes": {},
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": true,
-      "nodeReRegistrationTimeout": 0,
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ]
-    },
-    {
-      "id": "95e0b6dc-15fe-416c-be90-cc4a78aab0de",
-      "clientId": "security-admin-console",
-      "name": "${client_security-admin-console}",
-      "baseUrl": "/auth/admin/master/console/index.html",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [
-        "/auth/admin/master/console/*"
-      ],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": false,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": false,
-      "directAccessGrantsEnabled": false,
-      "serviceAccountsEnabled": false,
-      "publicClient": true,
-      "frontchannelLogout": false,
-      "protocol": "openid-connect",
-      "attributes": {},
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": false,
-      "nodeReRegistrationTimeout": 0,
-      "protocolMappers": [
-        {
-          "id": "e23cb190-a256-443f-8099-78f7e48fbff2",
-          "name": "locale",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "locale",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "locale",
-            "jsonType.label": "String"
-          }
-        }
-      ],
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ]
-    },
-    {
-      "id": "0543361e-6007-4b9a-ad3c-dcc473feaa68",
-      "clientId": "oidc-test",
-      "name": "OIDC Test",
-      "baseUrl": "/auth/realms/master/oidc-test",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [
-        "http://localhost:9080/syncope-console/oidcclient/code-consumer",
-        "/auth/realms/master/oidc-test/*",
-        "http://localhost:9080/syncope-enduser/oidcclient/code-consumer"
-      ],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": false,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": true,
-      "directAccessGrantsEnabled": true,
-      "serviceAccountsEnabled": true,
-      "authorizationServicesEnabled": true,
-      "publicClient": false,
-      "frontchannelLogout": false,
-      "protocol": "openid-connect",
-      "attributes": {
-        "saml.assertion.signature": "false",
-        "saml.multivalued.roles": "false",
-        "saml.force.post.binding": "false",
-        "saml.encrypt": "false",
-        "saml.server.signature": "false",
-        "saml.server.signature.keyinfo.ext": "false",
-        "exclude.session.state.from.auth.response": "false",
-        "saml_force_name_id_format": "false",
-        "saml.client.signature": "false",
-        "tls.client.certificate.bound.access.tokens": "false",
-        "saml.authnstatement": "false",
-        "display.on.consent.screen": "false",
-        "saml.onetimeuse.condition": "false"
-      },
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": true,
-      "nodeReRegistrationTimeout": -1,
-      "protocolMappers": [
-        {
-          "id": "3bbeb91e-7a38-4a03-aafc-5e364e4ef3ea",
-          "name": "Client Host",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientHost",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientHost",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "f6049611-4378-4aeb-8423-b8166df0e046",
-          "name": "Client ID",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientId",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientId",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "173d39bf-8c71-4c0f-9264-44d9bd143fd0",
-          "name": "Client IP Address",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientAddress",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientAddress",
-            "jsonType.label": "String"
-          }
-        }
-      ],
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ],
-      "authorizationSettings": {
-        "allowRemoteResourceManagement": true,
-        "policyEnforcementMode": "ENFORCING",
-        "resources": [
-          {
-            "name": "Default Resource",
-            "type": "urn:oidc-test:resources:default",
-            "ownerManagedAccess": false,
-            "attributes": {},
-            "_id": "f044b62c-be85-40b1-a646-ab000764337e",
-            "uris": [
-              "/*"
-            ]
-          }
-        ],
-        "policies": [
-          {
-            "id": "4077b1d8-acb5-4aab-b88a-0d4f07da107e",
-            "name": "Default Policy",
-            "description": "A policy that grants access only for users within this realm",
-            "type": "js",
-            "logic": "POSITIVE",
-            "decisionStrategy": "AFFIRMATIVE",
-            "config": {
-              "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
-            }
-          },
-          {
-            "id": "5e54be75-0d3f-483a-b47e-c24e36d0b666",
-            "name": "Default Permission",
-            "description": "A permission that applies to the default resource type",
-            "type": "resource",
-            "logic": "POSITIVE",
-            "decisionStrategy": "UNANIMOUS",
-            "config": {
-              "defaultResourceType": "urn:oidc-test:resources:default",
-              "applyPolicies": "[\"Default Policy\"]"
-            }
-          }
-        ],
-        "scopes": []
-      }
-    },
-    {
-      "id": "9cb0aa44-7e89-4ed2-8702-7bee34b39fdc",
-      "clientId": "account",
-      "name": "${client_account}",
-      "baseUrl": "/auth/realms/master/account",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "defaultRoles": [
-        "view-profile",
-        "manage-account"
-      ],
-      "redirectUris": [
-        "http://localhost:9080/syncope-console/oidcclient/code-consumer",
-        "/auth/realms/master/account/*",
-        "http://localhost:9080/syncope-enduser/oidcclient/code-consumer"
-      ],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": true,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": true,
-      "directAccessGrantsEnabled": true,
-      "serviceAccountsEnabled": true,
-      "authorizationServicesEnabled": true,
-      "publicClient": false,
-      "frontchannelLogout": false,
-      "protocol": "openid-connect",
-      "attributes": {
-        "saml.assertion.signature": "false",
-        "saml.force.post.binding": "false",
-        "saml.multivalued.roles": "false",
-        "saml.encrypt": "false",
-        "saml.server.signature": "false",
-        "saml.server.signature.keyinfo.ext": "false",
-        "exclude.session.state.from.auth.response": "false",
-        "saml_force_name_id_format": "false",
-        "saml.client.signature": "false",
-        "tls.client.certificate.bound.access.tokens": "false",
-        "saml.authnstatement": "false",
-        "display.on.consent.screen": "false",
-        "saml.onetimeuse.condition": "false"
-      },
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": false,
-      "nodeReRegistrationTimeout": 0,
-      "protocolMappers": [
-        {
-          "id": "6db42642-9862-4b48-a986-1fe7d2bf2a24",
-          "name": "name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "name",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "6efff622-0813-49f8-baf2-01c117cd9744",
-          "name": "Client IP Address",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientAddress",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientAddress",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "e46eb849-c977-425a-b2fe-c032ea0f4b95",
-          "name": "Client ID",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientId",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientId",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "76a37cf4-2f46-4f89-b7cd-cb1e75dc95a2",
-          "name": "fullName",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "fullName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "fullName",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "f6121e29-62b9-44e9-8e76-1c98d98b48d5",
-          "name": "email",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "email",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "email",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "e3adc691-0b44-491a-9778-769909091969",
-          "name": "lastName",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "lastName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "lastName",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "b5618073-5b83-4528-bd9a-99ca9807847d",
-          "name": "Client Host",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usersessionmodel-note-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.session.note": "clientHost",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "clientHost",
-            "jsonType.label": "String"
-          }
-        }
-      ],
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ],
-      "authorizationSettings": {
-        "allowRemoteResourceManagement": true,
-        "policyEnforcementMode": "ENFORCING",
-        "resources": [
-          {
-            "name": "Default Resource",
-            "type": "urn:account:resources:default",
-            "ownerManagedAccess": false,
-            "attributes": {},
-            "_id": "e85a7be3-724c-4846-9d60-67296333ef02",
-            "uris": [
-              "/*"
-            ]
-          }
-        ],
-        "policies": [
-          {
-            "id": "a75fd4f9-6936-4e39-a535-589ad7356f8f",
-            "name": "Default Policy",
-            "description": "A policy that grants access only for users within this realm",
-            "type": "js",
-            "logic": "POSITIVE",
-            "decisionStrategy": "AFFIRMATIVE",
-            "config": {
-              "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
-            }
-          },
-          {
-            "id": "92627286-24a8-4bf3-ad26-d618da21ea80",
-            "name": "Default Permission",
-            "description": "A permission that applies to the default resource type",
-            "type": "resource",
-            "logic": "POSITIVE",
-            "decisionStrategy": "UNANIMOUS",
-            "config": {
-              "defaultResourceType": "urn:account:resources:default",
-              "applyPolicies": "[\"Default Policy\"]"
-            }
-          }
-        ],
-        "scopes": []
-      }
-    },
-    {
-      "id": "e5f1365e-8227-4f63-b03d-8c5b8ffed1ff",
-      "clientId": "broker",
-      "name": "${client_broker}",
-      "surrogateAuthRequired": false,
-      "enabled": true,
-      "clientAuthenticatorType": "client-secret",
-      "secret": "**********",
-      "redirectUris": [],
-      "webOrigins": [],
-      "notBefore": 0,
-      "bearerOnly": false,
-      "consentRequired": false,
-      "standardFlowEnabled": true,
-      "implicitFlowEnabled": false,
-      "directAccessGrantsEnabled": false,
-      "serviceAccountsEnabled": false,
-      "publicClient": false,
-      "frontchannelLogout": false,
-      "protocol": "openid-connect",
-      "attributes": {},
-      "authenticationFlowBindingOverrides": {},
-      "fullScopeAllowed": false,
-      "nodeReRegistrationTimeout": 0,
-      "defaultClientScopes": [
-        "web-origins",
-        "role_list",
-        "profile",
-        "roles",
-        "email"
-      ],
-      "optionalClientScopes": [
-        "address",
-        "phone",
-        "offline_access",
-        "microprofile-jwt"
-      ]
-    }
-  ],
-  "clientScopes": [
-    {
-      "id": "207751c3-8697-414d-a451-adee6328df75",
-      "name": "microprofile-jwt",
-      "description": "Microprofile - JWT built-in scope",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "false"
-      },
-      "protocolMappers": [
-        {
-          "id": "b1bfd849-9f78-4e31-a3fd-f4c85ddfd37b",
-          "name": "upn",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "username",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "upn",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "27ab40ce-ce70-49a4-b153-d5375d2cc5b0",
-          "name": "groups",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-realm-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "multivalued": "true",
-            "user.attribute": "foo",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "groups",
-            "jsonType.label": "String"
-          }
-        }
-      ]
-    },
-    {
-      "id": "66d7c7ef-1ddf-48ec-b6f1-0d8119b5b151",
-      "name": "web-origins",
-      "description": "OpenID Connect scope for add allowed web origins to the access token",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "false",
-        "display.on.consent.screen": "false",
-        "consent.screen.text": ""
-      },
-      "protocolMappers": [
-        {
-          "id": "f1458f25-d330-496f-9c42-55f176dfe47c",
-          "name": "allowed web origins",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-allowed-origins-mapper",
-          "consentRequired": false,
-          "config": {}
-        }
-      ]
-    },
-    {
-      "id": "c89df48d-160a-4e7f-b9e9-41f7b7de9bdb",
-      "name": "roles",
-      "description": "OpenID Connect scope for add user roles to the access token",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "false",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${rolesScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "fa759cdc-914f-4012-bee0-0b6c89dde9f7",
-          "name": "realm roles",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-realm-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "multivalued": "true",
-            "user.attribute": "foo",
-            "access.token.claim": "true",
-            "claim.name": "realm_access.roles",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "a833736e-c483-4205-9172-038fd9f2e58e",
-          "name": "client roles",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-client-role-mapper",
-          "consentRequired": false,
-          "config": {
-            "multivalued": "true",
-            "user.attribute": "foo",
-            "access.token.claim": "true",
-            "claim.name": "resource_access.${client_id}.roles",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "6cfa6171-fc45-4048-854e-3971f34feae7",
-          "name": "audience resolve",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-audience-resolve-mapper",
-          "consentRequired": false,
-          "config": {}
-        }
-      ]
-    },
-    {
-      "id": "13bd781f-9c09-4586-b21f-0b4f793352b3",
-      "name": "phone",
-      "description": "OpenID Connect built-in scope: phone",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${phoneScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "9821b172-56a1-4ba3-aee3-1c7fa12e2c41",
-          "name": "phone number",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "phoneNumber",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "phone_number",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "554855cc-a829-4bdb-9bcf-c1f150df0c9b",
-          "name": "phone number verified",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "phoneNumberVerified",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "phone_number_verified",
-            "jsonType.label": "boolean"
-          }
-        }
-      ]
-    },
-    {
-      "id": "a99a4e9a-196b-4977-ba63-24c238f28ff6",
-      "name": "address",
-      "description": "OpenID Connect built-in scope: address",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${addressScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "bd77d1a7-e786-4a27-bf0a-3ed299346f95",
-          "name": "address",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-address-mapper",
-          "consentRequired": false,
-          "config": {
-            "user.attribute.formatted": "formatted",
-            "user.attribute.country": "country",
-            "user.attribute.postal_code": "postal_code",
-            "userinfo.token.claim": "true",
-            "user.attribute.street": "street",
-            "id.token.claim": "true",
-            "user.attribute.region": "region",
-            "access.token.claim": "true",
-            "user.attribute.locality": "locality"
-          }
-        }
-      ]
-    },
-    {
-      "id": "103bef92-6694-4dd9-bb94-860cf3891ea0",
-      "name": "email",
-      "description": "OpenID Connect built-in scope: email",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${emailScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "2caa0eee-d72d-4f4d-8515-3625f046f274",
-          "name": "email",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "email",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "email",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "e95028fa-6f26-4dad-bb10-89d39a466ab5",
-          "name": "email verified",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "emailVerified",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "email_verified",
-            "jsonType.label": "boolean"
-          }
-        }
-      ]
-    },
-    {
-      "id": "2165534b-1305-480e-8be6-e08428bd7710",
-      "name": "profile",
-      "description": "OpenID Connect built-in scope: profile",
-      "protocol": "openid-connect",
-      "attributes": {
-        "include.in.token.scope": "true",
-        "display.on.consent.screen": "true",
-        "consent.screen.text": "${profileScopeConsentText}"
-      },
-      "protocolMappers": [
-        {
-          "id": "b0a63a0f-d4a5-420e-b8c8-2b9e3de310df",
-          "name": "birthdate",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "birthdate",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "birthdate",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "f32785d8-3963-4570-b77a-5710326b32b6",
-          "name": "middle name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "middleName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "middle_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "ac364875-5fe9-443e-bdab-c779998ec18a",
-          "name": "given name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "firstName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "given_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "61244f24-5f5b-4bd1-a738-08f0d5147da0",
-          "name": "updated at",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "updatedAt",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "updated_at",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "e3ae74e7-11e3-469b-ad10-69419062e61e",
-          "name": "full name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-full-name-mapper",
-          "consentRequired": false,
-          "config": {
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "userinfo.token.claim": "true"
-          }
-        },
-        {
-          "id": "d39af8e4-7804-4209-b8fc-361c199e4eff",
-          "name": "gender",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "gender",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "gender",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "9b944fe3-04a5-4ed6-9743-57b1d93b3c12",
-          "name": "username",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "username",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "preferred_username",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "63a62a59-48aa-41c8-a878-6e2a49170671",
-          "name": "profile",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "profile",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "profile",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "d2b9e956-9f84-4239-b9fb-4aaa66efe5d3",
-          "name": "nickname",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "nickname",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "nickname",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "13172ca3-1175-433d-b5a9-e3e8904c76cb",
-          "name": "family name",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-property-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "lastName",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "family_name",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "d9d54937-de59-4040-a5e4-f721a9facaef",
-          "name": "zoneinfo",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "zoneinfo",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "zoneinfo",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "07e30efd-7f88-4e7e-9d65-eef422e3ba3c",
-          "name": "locale",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "locale",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "locale",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "6d69ff26-82d8-4750-bc1c-2c6a54951dc1",
-          "name": "website",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "website",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "website",
-            "jsonType.label": "String"
-          }
-        },
-        {
-          "id": "fcc5ca45-020e-4edc-8279-e6e7d8a5df29",
-          "name": "picture",
-          "protocol": "openid-connect",
-          "protocolMapper": "oidc-usermodel-attribute-mapper",
-          "consentRequired": false,
-          "config": {
-            "userinfo.token.claim": "true",
-            "user.attribute": "picture",
-            "id.token.claim": "true",
-            "access.token.claim": "true",
-            "claim.name": "picture",
-            "jsonType.label": "String"
-          }
-        }
-      ]
-    },
-    {
-      "id": "07e46091-35cc-491e-9776-03077bae3a0c",
-      "name": "role_list",
-      "description": "SAML role list",
-      "protocol": "saml",
-      "attributes": {
-        "consent.screen.text": "${samlRoleListScopeConsentText}",
-        "display.on.consent.screen": "true"
-      },
-      "protocolMappers": [
-        {
-          "id": "ff63d4a8-358f-4e0b-9807-32dfcc889bdc",
-          "name": "role list",
-          "protocol": "saml",
-          "protocolMapper": "saml-role-list-mapper",
-          "consentRequired": false,
-          "config": {
-            "single": "false",
-            "attribute.nameformat": "Basic",
-            "attribute.name": "Role"
-          }
-        }
-      ]
-    },
-    {
-      "id": "ff466f99-32f2-4584-bc41-72b6a13a6fbd",
-      "name": "offline_access",
-      "description": "OpenID Connect built-in scope: offline_access",
-      "protocol": "openid-connect",
-      "attributes": {
-        "consent.screen.text": "${offlineAccessScopeConsentText}",
-        "display.on.consent.screen": "true"
-      }
-    }
-  ],
-  "defaultDefaultClientScopes": [
-    "role_list",
-    "profile",
-    "email",
-    "roles",
-    "web-origins"
-  ],
-  "defaultOptionalClientScopes": [
-    "offline_access",
-    "address",
-    "phone",
-    "microprofile-jwt"
-  ],
-  "browserSecurityHeaders": {
-    "contentSecurityPolicyReportOnly": "",
-    "xContentTypeOptions": "nosniff",
-    "xRobotsTag": "none",
-    "xFrameOptions": "SAMEORIGIN",
-    "xXSSProtection": "1; mode=block",
-    "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
-    "strictTransportSecurity": "max-age=31536000; includeSubDomains"
-  },
-  "smtpServer": {},
-  "eventsEnabled": false,
-  "eventsListeners": [
-    "jboss-logging"
-  ],
-  "enabledEventTypes": [],
-  "adminEventsEnabled": false,
-  "adminEventsDetailsEnabled": false,
-  "components": {
-    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
-      {
-        "id": "f57951e7-7557-4c48-b779-b59216e9b1d8",
-        "name": "Allowed Client Scopes",
-        "providerId": "allowed-client-templates",
-        "subType": "authenticated",
-        "subComponents": {},
-        "config": {
-          "allow-default-scopes": [
-            "true"
-          ]
-        }
-      },
-      {
-        "id": "0fd0e4b7-b5d5-4132-9e84-d72bb95c976b",
-        "name": "Trusted Hosts",
-        "providerId": "trusted-hosts",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "host-sending-registration-request-must-match": [
-            "true"
-          ],
-          "client-uris-must-match": [
-            "true"
-          ]
-        }
-      },
-      {
-        "id": "db90a46c-a2d9-44af-ae23-9af115b07134",
-        "name": "Max Clients Limit",
-        "providerId": "max-clients",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "max-clients": [
-            "200"
-          ]
-        }
-      },
-      {
-        "id": "cff490e0-3924-4c22-bb4a-0f457a7bb37f",
-        "name": "Allowed Protocol Mapper Types",
-        "providerId": "allowed-protocol-mappers",
-        "subType": "authenticated",
-        "subComponents": {},
-        "config": {
-          "allowed-protocol-mapper-types": [
-            "saml-user-property-mapper",
-            "oidc-usermodel-property-mapper",
-            "oidc-usermodel-attribute-mapper",
-            "oidc-full-name-mapper",
-            "oidc-address-mapper",
-            "saml-role-list-mapper",
-            "oidc-sha256-pairwise-sub-mapper",
-            "saml-user-attribute-mapper"
-          ]
-        }
-      },
-      {
-        "id": "04570181-3b70-4571-b203-b53f2a34123a",
-        "name": "Consent Required",
-        "providerId": "consent-required",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {}
-      },
-      {
-        "id": "6397ae12-ae0d-4918-aa08-ee404d5144d8",
-        "name": "Allowed Protocol Mapper Types",
-        "providerId": "allowed-protocol-mappers",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "allowed-protocol-mapper-types": [
-            "saml-role-list-mapper",
-            "saml-user-attribute-mapper",
-            "oidc-address-mapper",
-            "oidc-usermodel-property-mapper",
-            "oidc-full-name-mapper",
-            "saml-user-property-mapper",
-            "oidc-usermodel-attribute-mapper",
-            "oidc-sha256-pairwise-sub-mapper"
-          ]
-        }
-      },
-      {
-        "id": "1b0218ee-94a7-4021-b46d-5edcc45af48a",
-        "name": "Full Scope Disabled",
-        "providerId": "scope",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {}
-      },
-      {
-        "id": "92eacde8-5c64-46d4-b75d-986330f0faf8",
-        "name": "Allowed Client Scopes",
-        "providerId": "allowed-client-templates",
-        "subType": "anonymous",
-        "subComponents": {},
-        "config": {
-          "allow-default-scopes": [
-            "true"
-          ]
-        }
-      }
-    ],
-    "org.keycloak.keys.KeyProvider": [
-      {
-        "id": "127db379-920f-49ba-a289-408038d1166d",
-        "name": "aes-generated",
-        "providerId": "aes-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ]
-        }
-      },
-      {
-        "id": "d9601add-c0f8-48c3-9f65-e41f870dc28d",
-        "name": "hmac-generated",
-        "providerId": "hmac-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ],
-          "algorithm": [
-            "HS256"
-          ]
-        }
-      },
-      {
-        "id": "d2b8c49a-c968-496d-9750-3ad7387ac7c7",
-        "name": "rsa-generated",
-        "providerId": "rsa-generated",
-        "subComponents": {},
-        "config": {
-          "priority": [
-            "100"
-          ]
-        }
-      }
-    ]
-  },
-  "internationalizationEnabled": false,
-  "supportedLocales": [],
-  "authenticationFlows": [
-    {
-      "id": "1a57c929-5fa2-432c-9113-574cc75cd0e0",
-      "alias": "Handle Existing Account",
-      "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "idp-confirm-link",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "idp-email-verification",
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "flowAlias": "Verify Existing Account by Re-authentication",
-          "userSetupAllowed": false,
-          "autheticatorFlow": true
-        }
-      ]
-    },
-    {
-      "id": "8cf6d3b5-e804-4b1e-8839-d3e5ce0c99ce",
-      "alias": "Verify Existing Account by Re-authentication",
-      "description": "Reauthentication of existing account",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "idp-username-password-form",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "auth-otp-form",
-          "requirement": "OPTIONAL",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "575a7ece-2a59-4432-ba6e-fafa3e7b73e8",
-      "alias": "browser",
-      "description": "browser based authentication",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "auth-cookie",
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "auth-spnego",
-          "requirement": "DISABLED",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "identity-provider-redirector",
-          "requirement": "ALTERNATIVE",
-          "priority": 25,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "flowAlias": "forms",
-          "userSetupAllowed": false,
-          "autheticatorFlow": true
-        }
-      ]
-    },
-    {
-      "id": "9290c4f5-e470-495a-b1d0-2d03eb9cbaf0",
-      "alias": "clients",
-      "description": "Base authentication for clients",
-      "providerId": "client-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "client-secret",
-          "requirement": "ALTERNATIVE",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "client-jwt",
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "client-secret-jwt",
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "client-x509",
-          "requirement": "ALTERNATIVE",
-          "priority": 40,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "1f8d6e9b-8859-4128-aa45-5e75cc234110",
-      "alias": "direct grant",
-      "description": "OpenID Connect Resource Owner Grant",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "direct-grant-validate-username",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "direct-grant-validate-password",
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "direct-grant-validate-otp",
-          "requirement": "OPTIONAL",
-          "priority": 30,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "5b09e811-0edc-45b1-ab78-abacb6cdf02b",
-      "alias": "docker auth",
-      "description": "Used by Docker clients to authenticate against the IDP",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "docker-http-basic-authenticator",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "5a59a45d-5795-4d35-ba9f-522b2564b289",
-      "alias": "first broker login",
-      "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticatorConfig": "review profile config",
-          "authenticator": "idp-review-profile",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticatorConfig": "create unique user config",
-          "authenticator": "idp-create-user-if-unique",
-          "requirement": "ALTERNATIVE",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "requirement": "ALTERNATIVE",
-          "priority": 30,
-          "flowAlias": "Handle Existing Account",
-          "userSetupAllowed": false,
-          "autheticatorFlow": true
-        }
-      ]
-    },
-    {
-      "id": "c7e0573a-560e-44e6-b226-c33126f56b60",
-      "alias": "forms",
-      "description": "Username, password, otp and other auth forms.",
-      "providerId": "basic-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "auth-username-password-form",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "auth-otp-form",
-          "requirement": "OPTIONAL",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "84931984-b55d-47fc-a0a0-d667fe94331a",
-      "alias": "http challenge",
-      "description": "An authentication flow based on challenge-response HTTP Authentication Schemes",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "no-cookie-redirect",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "basic-auth",
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "basic-auth-otp",
-          "requirement": "DISABLED",
-          "priority": 30,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "auth-spnego",
-          "requirement": "DISABLED",
-          "priority": 40,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "4d70a60e-37f4-454e-86e6-982f7e146758",
-      "alias": "registration",
-      "description": "registration flow",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "registration-page-form",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "flowAlias": "registration form",
-          "userSetupAllowed": false,
-          "autheticatorFlow": true
-        }
-      ]
-    },
-    {
-      "id": "90511fb9-b046-48cc-b0ac-700dba9ed988",
-      "alias": "registration form",
-      "description": "registration form",
-      "providerId": "form-flow",
-      "topLevel": false,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "registration-user-creation",
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "registration-profile-action",
-          "requirement": "REQUIRED",
-          "priority": 40,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "registration-password-action",
-          "requirement": "REQUIRED",
-          "priority": 50,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "registration-recaptcha-action",
-          "requirement": "DISABLED",
-          "priority": 60,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "ed15f1bd-61cc-43a1-b735-307321136ffc",
-      "alias": "reset credentials",
-      "description": "Reset credentials for a user if they forgot their password or something",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "reset-credentials-choose-user",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "reset-credential-email",
-          "requirement": "REQUIRED",
-          "priority": 20,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "reset-password",
-          "requirement": "REQUIRED",
-          "priority": 30,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        },
-        {
-          "authenticator": "reset-otp",
-          "requirement": "OPTIONAL",
-          "priority": 40,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    },
-    {
-      "id": "60a707b1-1ace-4852-ab0f-d755543e5ce5",
-      "alias": "saml ecp",
-      "description": "SAML ECP Profile Authentication Flow",
-      "providerId": "basic-flow",
-      "topLevel": true,
-      "builtIn": true,
-      "authenticationExecutions": [
-        {
-          "authenticator": "http-basic-authenticator",
-          "requirement": "REQUIRED",
-          "priority": 10,
-          "userSetupAllowed": false,
-          "autheticatorFlow": false
-        }
-      ]
-    }
-  ],
-  "authenticatorConfig": [
-    {
-      "id": "bb4eee3a-0624-4a06-8774-b3a2484f30fd",
-      "alias": "create unique user config",
-      "config": {
-        "require.password.update.after.registration": "false"
-      }
-    },
-    {
-      "id": "920d034a-5f7c-47c9-969e-d7f5cd8450dd",
-      "alias": "review profile config",
-      "config": {
-        "update.profile.on.first.login": "missing"
-      }
-    }
-  ],
-  "requiredActions": [
-    {
-      "alias": "CONFIGURE_TOTP",
-      "name": "Configure OTP",
-      "providerId": "CONFIGURE_TOTP",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 10,
-      "config": {}
-    },
-    {
-      "alias": "terms_and_conditions",
-      "name": "Terms and Conditions",
-      "providerId": "terms_and_conditions",
-      "enabled": false,
-      "defaultAction": false,
-      "priority": 20,
-      "config": {}
-    },
-    {
-      "alias": "UPDATE_PASSWORD",
-      "name": "Update Password",
-      "providerId": "UPDATE_PASSWORD",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 30,
-      "config": {}
-    },
-    {
-      "alias": "UPDATE_PROFILE",
-      "name": "Update Profile",
-      "providerId": "UPDATE_PROFILE",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 40,
-      "config": {}
-    },
-    {
-      "alias": "VERIFY_EMAIL",
-      "name": "Verify Email",
-      "providerId": "VERIFY_EMAIL",
-      "enabled": true,
-      "defaultAction": false,
-      "priority": 50,
-      "config": {}
-    }
-  ],
-  "browserFlow": "browser",
-  "registrationFlow": "registration",
-  "directGrantFlow": "direct grant",
-  "resetCredentialsFlow": "reset credentials",
-  "clientAuthenticationFlow": "clients",
-  "dockerAuthenticationFlow": "docker auth",
-  "attributes": {
-    "_browser_header.xXSSProtection": "1; mode=block",
-    "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains",
-    "_browser_header.xFrameOptions": "SAMEORIGIN",
-    "quickLoginCheckMilliSeconds": "1000",
-    "permanentLockout": "false",
-    "displayName": "Keycloak",
-    "_browser_header.xRobotsTag": "none",
-    "maxFailureWaitSeconds": "900",
-    "displayNameHtml": "<div class=\"kc-logo-text\"><span>Keycloak</span></div>",
-    "minimumQuickLoginWaitSeconds": "60",
-    "failureFactor": "30",
-    "maxDeltaTimeSeconds": "43200",
-    "_browser_header.xContentTypeOptions": "nosniff",
-    "offlineSessionMaxLifespan": "5184000",
-    "_browser_header.contentSecurityPolicyReportOnly": "",
-    "bruteForceProtected": "false",
-    "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
-    "offlineSessionMaxLifespanEnabled": "false",
-    "waitIncrementSeconds": "60"
-  },
-  "keycloakVersion": "6.0.1",
-  "userManagedAccessAllowed": false
-}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ddb848f..48e47fa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -468,7 +468,7 @@ under the License.
     <wicket.version>8.5.0</wicket.version>
     <wicket-jqueryui.version>8.3.0</wicket-jqueryui.version>
     <wicket-bootstrap.version>2.0.9</wicket-bootstrap.version>
-    <wicket-spring-boot.version>2.1.6</wicket-spring-boot.version>
+    <wicket-spring-boot.version>2.1.7</wicket-spring-boot.version>
     
     <ng-password-strength.version>0.2.1</ng-password-strength.version>
     <lodash.version>4.17.4</lodash.version>
@@ -1417,6 +1417,11 @@ under the License.
         <version>${wicket.version}</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.wicket</groupId>
+        <artifactId>wicket-native-websocket-javax</artifactId>
+        <version>${wicket.version}</version>
+      </dependency>
+      <dependency>
         <groupId>com.googlecode.wicket-jquery-ui</groupId>
         <artifactId>wicket-jquery-ui</artifactId>
         <version>${wicket-jqueryui.version}</version>
@@ -1442,11 +1447,6 @@ under the License.
         <version>${wicket-jqueryui.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.wicket</groupId>
-        <artifactId>wicket-native-websocket-javax</artifactId>
-        <version>${wicket.version}</version>
-      </dependency>
-      <dependency>
         <groupId>de.agilecoders.wicket</groupId>
         <artifactId>wicket-bootstrap-core</artifactId>
         <version>${wicket-bootstrap.version}</version>
@@ -2400,9 +2400,8 @@ under the License.
           <autoVersionSubmodules>true</autoVersionSubmodules>
           <tagNameFormat>syncope-@{project.version}</tagNameFormat>
         </configuration>
-      </plugin>      
+      </plugin>
     </plugins>
-    
   </build>
 
   <reporting>


Mime
View raw message