You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2020/01/02 16:41:56 UTC

[syncope] branch 2_1_X updated: [SYNCOPE-1531] Console support

This is an automated email from the ASF dual-hosted git repository.

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


The following commit(s) were added to refs/heads/2_1_X by this push:
     new d30308d  [SYNCOPE-1531] Console support
d30308d is described below

commit d30308d9df79b32e61ff22b97aec3d4fa43fe2a1
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Thu Jan 2 17:41:26 2020 +0100

    [SYNCOPE-1531] Console support
---
 .../client/console/SerializableSupplier.java       |  26 ++
 .../client/console/SyncopeConsoleSession.java      |  15 --
 .../syncope/client/console/commons/Constants.java  |   4 +
 .../notifications/MailTemplateDirectoryPanel.java  |   2 +-
 .../notifications/NotificationDirectoryPanel.java  |   2 +-
 .../console/panels/ActionDataTablePanel.java       |   7 +-
 .../client/console/panels/AnyDirectoryPanel.java   | 156 +++++++++---
 .../console/panels/AnyObjectDirectoryPanel.java    |   3 +-
 .../console/panels/ApplicationDirectoryPanel.java  |   2 +-
 .../client/console/panels/CSVConfPanel.java        | 106 ++++++++
 .../client/console/panels/DirectoryPanel.java      |   6 +-
 .../client/console/panels/GroupDirectoryPanel.java |   4 +-
 .../client/console/panels/ListViewPanel.java       |  15 +-
 .../client/console/panels/MembersTogglePanel.java  |   3 +-
 .../client/console/panels/RoleDirectoryPanel.java  |   4 +-
 .../client/console/panels/UserDirectoryPanel.java  |   2 +-
 .../console/policies/PolicyDirectoryPanel.java     |   4 +-
 .../console/reports/ReportExecutionDetails.java    |  62 ++---
 .../reports/ReportTemplateDirectoryPanel.java      |   2 +-
 .../console/rest/ReconciliationRestClient.java     |  35 +++
 .../console/topology/TopologyTogglePanel.java      |   8 +-
 ...loadBehavior.java => AjaxDownloadBehavior.java} |  35 ++-
 .../wicket/markup/html/form/ActionPanel.java       |  10 +-
 .../markup/html/form/AjaxCharacterFieldPanel.java  | 133 ++++++++++
 .../console/wizards/CSVPullWizardBuilder.java      | 277 +++++++++++++++++++++
 .../console/wizards/CSVPushWizardBuilder.java      | 135 ++++++++++
 .../client/console/wizards/WizardMgtPanel.java     |   4 +-
 .../client/console/wizards/any/ResultPage.java     |   8 +-
 .../resources/ItemTransformersTogglePanel.java     |   3 +-
 .../resources/JEXLTransformersTogglePanel.java     |   3 +-
 .../client/console/panels/AnyDirectoryPanel.html   |  30 +++
 .../console/panels/AnyDirectoryPanel.properties    |  20 ++
 .../panels/AnyDirectoryPanel_fr_CA.properties      |  20 ++
 .../console/panels/AnyDirectoryPanel_it.properties |  20 ++
 .../console/panels/AnyDirectoryPanel_ja.properties |  20 ++
 .../panels/AnyDirectoryPanel_pt_BR.properties      |  20 ++
 .../console/panels/AnyDirectoryPanel_ru.properties |  20 ++
 .../client/console/panels/CSVConfPanel.html        |  29 +++
 .../client/console/panels/CSVConfPanel.properties  |  23 ++
 .../console/panels/CSVConfPanel_fr_CA.properties   |  23 ++
 .../console/panels/CSVConfPanel_it.properties      |  23 ++
 .../console/panels/CSVConfPanel_ja.properties      |  23 ++
 .../console/panels/CSVConfPanel_pt_BR.properties   |  23 ++
 .../console/panels/CSVConfPanel_ru.properties      |  23 ++
 .../markup/html/form/AjaxCharacterFieldPanel.html  |  30 +++
 .../wizards/CSVPullWizardBuilder$Columns.html      |  36 +++
 .../CSVPullWizardBuilder$Columns.properties        |  19 ++
 .../CSVPullWizardBuilder$Columns_fr_CA.properties  |  19 ++
 .../CSVPullWizardBuilder$Columns_it.properties     |  19 ++
 .../CSVPullWizardBuilder$Columns_ja.properties     |  19 ++
 .../CSVPullWizardBuilder$Columns_pt_BR.properties  |  19 ++
 .../CSVPullWizardBuilder$Columns_ru.properties     |  19 ++
 .../wizards/CSVPullWizardBuilder$Details.html      |  29 +++
 .../CSVPullWizardBuilder$Details.properties        |  17 ++
 .../CSVPullWizardBuilder$Details_fr_CA.properties  |  17 ++
 .../CSVPullWizardBuilder$Details_it.properties     |  17 ++
 .../CSVPullWizardBuilder$Details_ja.properties     |  17 ++
 .../CSVPullWizardBuilder$Details_pt_BR.properties  |  17 ++
 .../CSVPullWizardBuilder$Details_ru.properties     |  17 ++
 .../wizards/CSVPullWizardBuilder$PullTask.html     |  32 +++
 .../CSVPullWizardBuilder$PullTask.properties       |  22 ++
 .../CSVPullWizardBuilder$PullTask_fr_CA.properties |  22 ++
 .../CSVPullWizardBuilder$PullTask_it.properties    |  22 ++
 .../CSVPullWizardBuilder$PullTask_ja.properties    |  22 ++
 .../CSVPullWizardBuilder$PullTask_pt_BR.properties |  22 ++
 .../CSVPullWizardBuilder$PullTask_ru.properties    |  22 ++
 .../wizards/CSVPushWizardBuilder$Details.html      |  25 ++
 .../wizards/CSVPushWizardBuilder$PushTask.html     |  30 +++
 .../CSVPushWizardBuilder$PushTask.properties       |  20 ++
 .../CSVPushWizardBuilder$PushTask_fr_CA.properties |  20 ++
 .../CSVPushWizardBuilder$PushTask_it.properties    |  20 ++
 .../CSVPushWizardBuilder$PushTask_ja.properties    |  20 ++
 .../CSVPushWizardBuilder$PushTask_pt_BR.properties |  20 ++
 .../CSVPushWizardBuilder$PushTask_ru.properties    |  20 ++
 .../client/console/wizards/WizardMgtPanel.html     |   6 +-
 .../syncope/common/rest/api/RESTHeaders.java       |   5 +
 .../common/rest/api/beans/AbstractCSVSpec.java     |   5 +-
 .../syncope/common/rest/api/beans/CSVPullSpec.java |   2 +
 .../syncope/common/rest/api/beans/CSVPushSpec.java |   2 +
 .../syncope/core/logic/ReconciliationLogic.java    |   2 +
 .../client/console/rest/BpmnProcessRestClient.java |  22 +-
 .../client/console/rest/SAML2IdPsRestClient.java   |  11 +-
 .../apache/syncope/fit/console/GroupsITCase.java   |   8 +-
 83 files changed, 1943 insertions(+), 163 deletions(-)

diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SerializableSupplier.java b/client/console/src/main/java/org/apache/syncope/client/console/SerializableSupplier.java
new file mode 100644
index 0000000..da3eb79
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SerializableSupplier.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+@FunctionalInterface
+public interface SerializableSupplier<T> extends Supplier<T>, Serializable {
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index 324b9ea..03c72ac 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -312,21 +312,6 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession {
         return serviceInstance;
     }
 
-    public <T> T getService(final MediaType mediaType, final Class<T> serviceClass) {
-        T service;
-
-        synchronized (clientFactory) {
-            SyncopeClientFactoryBean.ContentType preType = clientFactory.getContentType();
-
-            clientFactory.setContentType(SyncopeClientFactoryBean.ContentType.fromString(mediaType.toString()));
-            service = clientFactory.create(getJWT()).getService(serviceClass);
-
-            clientFactory.setContentType(preType);
-        }
-
-        return service;
-    }
-
     public BatchRequest batch() {
         return client.batch();
     }
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
index 0a2d7b3..ccf0f92 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
@@ -75,6 +75,10 @@ public final class Constants {
 
     public static final String ERROR = "error";
 
+    public static final String OUTER = "outer";
+
+    public static final String ACTION = "action";
+
     public static final String BEFORE_LOGOUT_PAGE = "beforeLogoutPage";
 
     public static final String PARAM_PASSWORD_RESET_TOKEN = "pwdResetToken";
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
index 2d13ff7..25e91a3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
@@ -62,7 +62,7 @@ public class MailTemplateDirectoryPanel
 
     private static final long serialVersionUID = -3789392431954221446L;
 
-    protected final BaseModal<String> utilityModal = new BaseModal<>("outer");
+    protected final BaseModal<String> utilityModal = new BaseModal<>(Constants.OUTER);
 
     public MailTemplateDirectoryPanel(final String id, final PageReference pageReference) {
         super(id, pageReference, true);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
index b3bd695..b09bed0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationDirectoryPanel.java
@@ -59,7 +59,7 @@ public class NotificationDirectoryPanel
 
     private static final long serialVersionUID = -3789392431954221446L;
 
-    protected final BaseModal<Serializable> utilityModal = new BaseModal<>("outer");
+    protected final BaseModal<Serializable> utilityModal = new BaseModal<>(Constants.OUTER);
 
     public NotificationDirectoryPanel(final String id, final PageReference pageRef) {
         super(id, pageRef, true);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ActionDataTablePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ActionDataTablePanel.java
index 17717c5..cff19eb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ActionDataTablePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ActionDataTablePanel.java
@@ -105,14 +105,12 @@ public class ActionDataTablePanel<T extends Serializable, S> extends DataTablePa
         }.setVisible(false).setEnabled(false));
     }
 
-    public void addAction(
-            final ActionLink<Serializable> action, final ActionType type, final String entitlements) {
+    public void addAction(final ActionLink<Serializable> action, final ActionType type, final String entitlements) {
         actionPanel.add(action, type, entitlements);
     }
 
     public void addCancelButton(final BaseModal<?> modal) {
-
-        final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+        AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
 
             private static final long serialVersionUID = -4804368561204623354L;
 
@@ -121,7 +119,6 @@ public class ActionDataTablePanel<T extends Serializable, S> extends DataTablePa
                 modal.close(target);
             }
         };
-
         cancel.setDefaultFormProcessing(false);
         batchForm.addOrReplace(cancel);
     }
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
index 05f7062..60980dc 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyDirectoryPanel.java
@@ -32,8 +32,10 @@ import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.AnyDataProvider;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
+import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.console.wicket.ajax.form.AjaxDownloadBehavior;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
@@ -41,6 +43,9 @@ import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.TokenColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.CSVPullWizardBuilder;
+import org.apache.syncope.client.console.wizards.CSVPushWizardBuilder;
 import org.apache.syncope.client.console.wizards.any.AnyWrapper;
 import org.apache.syncope.client.console.wizards.any.ResultPage;
 import org.apache.syncope.client.console.wizards.any.StatusPanel;
@@ -50,14 +55,22 @@ import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
+import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.IEvent;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.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.model.StringResourceModel;
 import org.apache.wicket.model.util.ListModel;
 import org.springframework.util.ReflectionUtils;
 
@@ -87,7 +100,7 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
      */
     protected final String type;
 
-    protected final BaseModal<Serializable> utilityModal = new BaseModal<>("outer");
+    protected final BaseModal<Serializable> utilityModal = new BaseModal<>(Constants.OUTER);
 
     protected AnyDirectoryPanel(final String id, final Builder<A, E> builder) {
         this(id, builder, true);
@@ -116,19 +129,6 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
         setWindowClosedReloadCallback(utilityModal);
 
         modal.size(Modal.Size.Large);
-        altDefaultModal.size(Modal.Size.Large);
-
-        this.pSchemaNames = new ArrayList<>();
-        AnyDirectoryPanelBuilder.class.cast(builder).getAnyTypeClassTOs().forEach(anyTypeClassTO -> {
-            this.pSchemaNames.addAll(anyTypeClassTO.getPlainSchemas());
-        });
-        this.dSchemaNames = new ArrayList<>();
-        AnyDirectoryPanelBuilder.class.cast(builder).getAnyTypeClassTOs().forEach(anyTypeClassTO -> {
-            this.dSchemaNames.addAll(anyTypeClassTO.getDerSchemas());
-        });
-
-        initResultTable();
-
         // change close callback in order to update header after model update
         modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
 
@@ -137,42 +137,133 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
             @Override
             public void onClose(final AjaxRequestTarget target) {
                 if (actionTogglePanel.isVisibleInHierarchy() && modal.getContent() instanceof ResultPage) {
-                    actionTogglePanel.updateHeader(
-                            target, ResultPage.class.cast(modal.getContent()).getItem());
+                    actionTogglePanel.updateHeader(target, ResultPage.class.cast(modal.getContent()).getItem());
                 }
                 modal.show(false);
             }
         });
+
+        altDefaultModal.size(Modal.Size.Large);
+
+        this.pSchemaNames = AnyDirectoryPanelBuilder.class.cast(builder).getAnyTypeClassTOs().stream().
+                flatMap(anyTypeClassTO -> anyTypeClassTO.getPlainSchemas().stream()).collect(Collectors.toList());
+
+        this.dSchemaNames = AnyDirectoryPanelBuilder.class.cast(builder).getAnyTypeClassTOs().stream().
+                flatMap(anyTypeClassTO -> anyTypeClassTO.getDerSchemas().stream()).collect(Collectors.toList());
+
+        initResultTable();
+
+        AjaxDownloadBehavior csvDownloadBehavior = new AjaxDownloadBehavior();
+        WebMarkupContainer csvEventSink = new WebMarkupContainer(Constants.OUTER) {
+
+            private static final long serialVersionUID = -957948639666058749L;
+
+            @Override
+            public void onEvent(final IEvent<?> event) {
+                if (event.getPayload() instanceof AjaxWizard.NewItemCancelEvent) {
+                    AjaxRequestTarget target = ((AjaxWizard.NewItemCancelEvent) event.getPayload()).getTarget();
+                    modal.close(target);
+                } else if (event.getPayload() instanceof AjaxWizard.NewItemFinishEvent) {
+                    AjaxWizard.NewItemFinishEvent<?> payload = (AjaxWizard.NewItemFinishEvent) event.getPayload();
+                    if (Constants.OPERATION_SUCCEEDED.equals(payload.getResult())) {
+                        AjaxRequestTarget target = payload.getTarget();
+
+                        if (csvDownloadBehavior.hasResponse()) {
+                            csvDownloadBehavior.initiate(target);
+                        }
+
+                        SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+
+                        target.add(container);
+                        modal.close(target);
+                    }
+                }
+            }
+        };
+        csvEventSink.add(csvDownloadBehavior);
+        addOuterObject(csvEventSink);
+        addInnerObject(new AjaxLink<Void>("csvPush") {
+
+            private static final long serialVersionUID = -817438685948164787L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                CSVPushSpec spec = csvPushSpec();
+                AnyQuery query = csvAnyQuery();
+
+                target.add(modal.setContent(new CSVPushWizardBuilder(spec, query, csvDownloadBehavior, pageRef).
+                        setEventSink(csvEventSink).
+                        build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT)));
+
+                modal.header(new StringResourceModel("csvPush", AnyDirectoryPanel.this, Model.of(spec)));
+                modal.show(true);
+            }
+        });
+        addInnerObject(new AjaxLink<Void>("csvPull") {
+
+            private static final long serialVersionUID = -817438685948164787L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                CSVPullSpec spec = csvPullSpec();
+
+                target.add(modal.setContent(new CSVPullWizardBuilder(spec, pageRef).
+                        setEventSink(csvEventSink).
+                        build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT)));
+
+                modal.header(new StringResourceModel("csvPull", AnyDirectoryPanel.this, Model.of(spec)));
+                modal.show(true);
+            }
+        });
+    }
+
+    protected CSVPushSpec csvPushSpec() {
+        CSVPushSpec spec = new CSVPushSpec.Builder(type).build();
+        spec.setFields(prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefDetailView(type)).
+                stream().filter(name -> !Constants.KEY_FIELD_NAME.equalsIgnoreCase(name)).
+                collect(Collectors.toList()));
+        spec.setPlainAttrs(
+                prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefPlainAttributeView(type)).
+                        stream().filter(name -> pSchemaNames.contains(name)).collect(Collectors.toList()));
+        spec.setDerAttrs(
+                prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefPlainAttributeView(type)).
+                        stream().filter(name -> dSchemaNames.contains(name)).collect(Collectors.toList()));
+        return spec;
+    }
+
+    protected CSVPullSpec csvPullSpec() {
+        CSVPullSpec spec = new CSVPullSpec();
+        spec.setAnyTypeKey(type);
+        spec.setDestinationRealm(realm);
+        return spec;
+    }
+
+    protected AnyQuery csvAnyQuery() {
+        return new AnyQuery.Builder().realm(realm).fiql(fiql).build();
     }
 
     @Override
     protected List<IColumn<A, String>> getColumns() {
-        final List<IColumn<A, String>> columns = new ArrayList<>();
-        final List<IColumn<A, String>> prefcolumns = new ArrayList<>();
-
+        List<IColumn<A, String>> columns = new ArrayList<>();
         columns.add(new KeyPropertyColumn<>(
                 new ResourceModel(Constants.KEY_FIELD_NAME, Constants.KEY_FIELD_NAME), Constants.KEY_FIELD_NAME));
 
+        List<IColumn<A, String>> prefcolumns = new ArrayList<>();
         prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefDetailView(type)).stream().
                 filter(name -> !Constants.KEY_FIELD_NAME.equalsIgnoreCase(name)).
-                forEachOrdered(name -> {
-                    addPropertyColumn(
-                            name,
-                            ReflectionUtils.findField(DisplayAttributesModalPanel.getTOClass(type), name),
-                            prefcolumns);
-                });
+                forEach(name -> addPropertyColumn(
+                name,
+                ReflectionUtils.findField(DisplayAttributesModalPanel.getTOClass(type), name),
+                prefcolumns));
 
         prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefPlainAttributeView(type)).stream().
                 filter(name -> pSchemaNames.contains(name)).
-                forEachOrdered(name -> {
-                    prefcolumns.add(new AttrColumn<>(name, SchemaType.PLAIN));
-                });
+                map(name -> prefcolumns.add(new AttrColumn<>(name, SchemaType.PLAIN)));
 
         prefMan.getList(getRequest(), DisplayAttributesModalPanel.getPrefDerivedAttributeView(type)).stream().
                 filter(name -> (dSchemaNames.contains(name))).
-                forEachOrdered(name -> {
-                    prefcolumns.add(new AttrColumn<>(name, SchemaType.DERIVED));
-                });
+                forEach(name -> prefcolumns.add(new AttrColumn<>(name, SchemaType.DERIVED)));
 
         // Add defaults in case of no selection
         if (prefcolumns.isEmpty()) {
@@ -183,7 +274,8 @@ public abstract class AnyDirectoryPanel<A extends AnyTO, E extends AbstractAnyRe
                         prefcolumns);
             }
 
-            prefMan.setList(getRequest(), getResponse(), DisplayAttributesModalPanel.getPrefDetailView(type),
+            prefMan.setList(
+                    getRequest(), getResponse(), DisplayAttributesModalPanel.getPrefDetailView(type),
                     Arrays.asList(getDefaultAttributeSelection()));
         }
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
index 40decfc..223e83c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDirectoryPanel.java
@@ -145,8 +145,7 @@ public class AnyObjectDirectoryPanel extends AnyDirectoryPanel<AnyObjectTO, AnyO
                     String.format("%s,%s", AnyEntitlement.READ.getFor(type), AnyEntitlement.UPDATE.getFor(type))).
                     setRealms(realm, model.getObject().getDynRealms());
 
-            panel.add(
-                    new ActionLink<AnyObjectTO>() {
+            panel.add(new ActionLink<AnyObjectTO>() {
 
                 private static final long serialVersionUID = -7978723352517770644L;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ApplicationDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ApplicationDirectoryPanel.java
index 0b57dde..c05e569 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ApplicationDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ApplicationDirectoryPanel.java
@@ -64,7 +64,7 @@ public class ApplicationDirectoryPanel extends
 
     private static final long serialVersionUID = -5491515010207202168L;
 
-    protected final BaseModal<PrivilegeTO> privilegeModal = new BaseModal<PrivilegeTO>("outer") {
+    protected final BaseModal<PrivilegeTO> privilegeModal = new BaseModal<PrivilegeTO>(Constants.OUTER) {
 
         private static final long serialVersionUID = 389935548143327858L;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/CSVConfPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/CSVConfPanel.java
new file mode 100644
index 0000000..e406155
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/CSVConfPanel.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCharacterFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wizards.CSVPullWizardBuilder;
+import org.apache.syncope.common.rest.api.beans.AbstractCSVSpec;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.validation.validator.StringValidator;
+
+public class CSVConfPanel extends Panel {
+
+    private static final long serialVersionUID = -1562409114958459620L;
+
+    public CSVConfPanel(final String id, final AbstractCSVSpec spec) {
+        super(id);
+
+        AjaxCharacterFieldPanel columnSeparator = new AjaxCharacterFieldPanel(
+                "columnSeparator", "columnSeparator", new PropertyModel<>(spec, "columnSeparator"));
+        columnSeparator.setChoices(Arrays.asList(',', ';', ' '));
+        columnSeparator.setRequired(true);
+        add(columnSeparator);
+
+        AjaxTextFieldPanel arrayElementSeparator = new AjaxTextFieldPanel(
+                "arrayElementSeparator", "arrayElementSeparator",
+                new PropertyModel<>(spec, "arrayElementSeparator"));
+        arrayElementSeparator.setChoices(Arrays.asList(";"));
+        arrayElementSeparator.setRequired(true);
+        arrayElementSeparator.addValidator(new StringValidator(1, 1));
+        add(arrayElementSeparator);
+
+        AjaxCharacterFieldPanel quoteChar = new AjaxCharacterFieldPanel(
+                "quoteChar", "quoteChar", new PropertyModel<>(spec, "quoteChar"));
+        quoteChar.setChoices(Arrays.asList('"'));
+        quoteChar.setRequired(true);
+        add(quoteChar);
+
+        AjaxCharacterFieldPanel escapeChar = new AjaxCharacterFieldPanel(
+                "escapeChar", "escapeChar", new PropertyModel<>(spec, "escapeChar"));
+        escapeChar.setRequired(false);
+        add(escapeChar);
+
+        AjaxDropDownChoicePanel<String> lineSeparator = new AjaxDropDownChoicePanel<>(
+                "lineSeparator", "lineSeparator", new PropertyModel<>(spec, "lineSeparator"), false);
+        lineSeparator.setChoices(Stream.of(CSVPullWizardBuilder.LineSeparator.values()).
+                map(CSVPullWizardBuilder.LineSeparator::name).collect(Collectors.toList()));
+        lineSeparator.setChoiceRenderer(new IChoiceRenderer<String>() {
+
+            private static final long serialVersionUID = 8551710814349123350L;
+
+            @Override
+            public Object getDisplayValue(final String object) {
+                return CSVPullWizardBuilder.LineSeparator.valueOf(object).name();
+            }
+
+            @Override
+            public String getIdValue(final String object, final int index) {
+                return object;
+            }
+
+            @Override
+            public String getObject(
+                    final String id, final IModel<? extends List<? extends String>> choices) {
+
+                return CSVPullWizardBuilder.LineSeparator.valueOf(id).getRepr();
+            }
+        });
+        lineSeparator.setRequired(true);
+        add(lineSeparator);
+
+        AjaxTextFieldPanel nullValue = new AjaxTextFieldPanel(
+                "nullValue", "nullValue", new PropertyModel<>(spec, "nullValue"));
+        nullValue.setRequired(false);
+        add(nullValue);
+
+        AjaxCheckBoxPanel allowComments = new AjaxCheckBoxPanel(
+                "allowComments", "allowComments", new PropertyModel<>(spec, "allowComments"), true);
+        add(allowComments);
+    }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
index f06b07e..399b202 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
@@ -104,9 +104,9 @@ public abstract class DirectoryPanel<
 
     protected String itemKeyFieldName = Constants.KEY_FIELD_NAME;
 
-    protected final BaseModal<W> altDefaultModal = new BaseModal<>("outer");
+    protected final BaseModal<W> altDefaultModal = new BaseModal<>(Constants.OUTER);
 
-    protected final BaseModal<W> displayAttributeModal = new BaseModal<>("outer");
+    protected final BaseModal<W> displayAttributeModal = new BaseModal<>(Constants.OUTER);
 
     protected ActionLinksTogglePanel<T> actionTogglePanel;
 
@@ -149,7 +149,7 @@ public abstract class DirectoryPanel<
         super(id, wizardInModal);
         setOutputMarkupId(true);
 
-        actionTogglePanel = new ActionLinksTogglePanel<>("outer", builder.getPageRef());
+        actionTogglePanel = new ActionLinksTogglePanel<>(Constants.OUTER, builder.getPageRef());
         addOuterObject(actionTogglePanel);
 
         addOuterObject(altDefaultModal);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
index f81c5fe..eb3a193 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupDirectoryPanel.java
@@ -75,9 +75,9 @@ public class GroupDirectoryPanel extends AnyDirectoryPanel<GroupTO, GroupRestCli
 
     private static final long serialVersionUID = -1100228004207271270L;
 
-    private final BaseModal<Serializable> typeExtensionsModal = new BaseModal<>("outer");
+    private final BaseModal<Serializable> typeExtensionsModal = new BaseModal<>(Constants.OUTER);
 
-    protected final BaseModal<Serializable> membersModal = new BaseModal<>("outer");
+    protected final BaseModal<Serializable> membersModal = new BaseModal<>(Constants.OUTER);
 
     protected final MembersTogglePanel templates;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
index 661c65f..f6a1a5d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
@@ -163,17 +163,17 @@ public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPan
 
             @Override
             protected void populateItem(final ListItem<T> beanItem) {
-                beanItem.add(new Check<>("check", beanItem.getModel(), checkGroup).setOutputMarkupId(true)
-                        .setOutputMarkupPlaceholderTag(true)
-                        .setVisible(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE
-                                || ListViewPanel.this.check.getObject() == CheckAvailability.DISABLED)
-                        .setEnabled(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE));
+                beanItem.add(new Check<>("check", beanItem.getModel(), checkGroup).setOutputMarkupId(true).
+                        setOutputMarkupPlaceholderTag(true).
+                        setVisible(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE
+                                || ListViewPanel.this.check.getObject() == CheckAvailability.DISABLED).
+                        setEnabled(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE));
 
                 final T bean = beanItem.getModelObject();
 
                 final ListView<String> fields = new ListView<String>("fields", toBeIncluded) {
 
-                    private static final long serialVersionUID = 1L;
+                    private static final long serialVersionUID = -9112553137618363167L;
 
                     @Override
                     protected void populateItem(final ListItem<String> fieldItem) {
@@ -230,7 +230,8 @@ public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPan
 
     /**
      * Use this to refresh the ListView with updated items (e.g. from callback methods)
-     * @param elements 
+     *
+     * @param elements
      */
     public void refreshList(final List<T> elements) {
         beans.setList(elements);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/MembersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembersTogglePanel.java
index b318090..002b7aa 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/MembersTogglePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembersTogglePanel.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
@@ -59,7 +60,7 @@ public abstract class MembersTogglePanel extends TogglePanel<Serializable> {
     };
 
     public MembersTogglePanel(final PageReference pageRef) {
-        super("outer", "groupMembers", pageRef);
+        super(Constants.OUTER, "groupMembers", pageRef);
 
         form = new Form<>("membersForm");
         addInnerObject(form);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
index be2bbeb..d31aa3a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
@@ -74,9 +74,9 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleWrapper, Role
 
     protected final AnyTypeRestClient anyTypeRestClient = new AnyTypeRestClient();
 
-    protected final BaseModal<String> utilityModal = new BaseModal<>("outer");
+    protected final BaseModal<String> utilityModal = new BaseModal<>(Constants.OUTER);
 
-    protected final BaseModal<Serializable> membersModal = new BaseModal<>("outer");
+    protected final BaseModal<Serializable> membersModal = new BaseModal<>(Constants.OUTER);
 
     protected RoleDirectoryPanel(final String id, final Builder builder) {
         super(id, builder);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
index b849abc..407be96 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserDirectoryPanel.java
@@ -66,7 +66,7 @@ public class UserDirectoryPanel extends AnyDirectoryPanel<UserTO, UserRestClient
 
     private static final long serialVersionUID = -1100228004207271270L;
 
-    protected final BaseModal<Serializable> wizardWrapperModal = new BaseModal<Serializable>("outer") {
+    protected final BaseModal<Serializable> wizardWrapperModal = new BaseModal<Serializable>(Constants.OUTER) {
 
         private static final long serialVersionUID = 389935548143327858L;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.java
index ad5dcae..a2bf636 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.java
@@ -65,7 +65,7 @@ public abstract class PolicyDirectoryPanel<T extends PolicyTO>
 
     private static final long serialVersionUID = 4984337552918213290L;
 
-    protected final BaseModal<T> ruleCompositionModal = new BaseModal<T>("outer") {
+    protected final BaseModal<T> ruleCompositionModal = new BaseModal<T>(Constants.OUTER) {
 
         private static final long serialVersionUID = 389935548143327858L;
 
@@ -77,7 +77,7 @@ public abstract class PolicyDirectoryPanel<T extends PolicyTO>
 
     };
 
-    protected final BaseModal<T> policySpecModal = new BaseModal<>("outer");
+    protected final BaseModal<T> policySpecModal = new BaseModal<>(Constants.OUTER);
 
     private final PolicyType type;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportExecutionDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportExecutionDetails.java
index 4311a1b..013e967 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportExecutionDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportExecutionDetails.java
@@ -18,12 +18,11 @@
  */
 package org.apache.syncope.client.console.reports;
 
-import org.apache.syncope.client.console.commons.HttpResourceStream;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.ExecutionRestClient;
 import org.apache.syncope.client.console.rest.ReportRestClient;
 import org.apache.syncope.client.console.tasks.ExecutionsDirectoryPanel;
-import org.apache.syncope.client.console.wicket.ajax.form.AbstractAjaxDownloadBehavior;
+import org.apache.syncope.client.console.wicket.ajax.form.AjaxDownloadBehavior;
 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.common.lib.to.ExecTO;
@@ -33,7 +32,6 @@ import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.model.IModel;
-import org.apache.wicket.util.resource.IResourceStream;
 
 /**
  * Modal window with report executions.
@@ -55,9 +53,11 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
         private static final long serialVersionUID = 5691719817252887541L;
 
+        private final ReportRestClient reportRestClient = new ReportRestClient();
+
         private final MultilevelPanel mlp;
 
-        private final AjaxExportDownloadBehavior downloadBehavior;
+        private final AjaxDownloadBehavior downloadBehavior;
 
         ReportExecutionDirectoryPanel(
                 final MultilevelPanel multiLevelPanelRef,
@@ -67,7 +67,7 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
             super(multiLevelPanelRef, key, executionRestClient, pageRef);
             this.mlp = multiLevelPanelRef;
 
-            this.downloadBehavior = new AjaxExportDownloadBehavior();
+            this.downloadBehavior = new AjaxDownloadBehavior();
             this.add(downloadBehavior);
         }
 
@@ -87,7 +87,8 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
                 @Override
                 public void onClick(final AjaxRequestTarget target, final ExecTO ignore) {
-                    downloadBehavior.setDetails(model.getObject().getKey(), ReportExecExportFormat.CSV);
+                    downloadBehavior.setResponse(() -> reportRestClient.exportExecutionResult(
+                            model.getObject().getKey(), ReportExecExportFormat.CSV));
                     downloadBehavior.initiate(target);
                 }
             }, ActionLink.ActionType.EXPORT_CSV, StandardEntitlement.REPORT_READ);
@@ -98,7 +99,8 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
                 @Override
                 public void onClick(final AjaxRequestTarget target, final ExecTO ignore) {
-                    downloadBehavior.setDetails(model.getObject().getKey(), ReportExecExportFormat.HTML);
+                    downloadBehavior.setResponse(() -> reportRestClient.exportExecutionResult(
+                            model.getObject().getKey(), ReportExecExportFormat.HTML));
                     downloadBehavior.initiate(target);
                 }
             }, ActionLink.ActionType.EXPORT_HTML, StandardEntitlement.REPORT_READ);
@@ -109,7 +111,8 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
                 @Override
                 public void onClick(final AjaxRequestTarget target, final ExecTO ignore) {
-                    downloadBehavior.setDetails(model.getObject().getKey(), ReportExecExportFormat.PDF);
+                    downloadBehavior.setResponse(() -> reportRestClient.exportExecutionResult(
+                            model.getObject().getKey(), ReportExecExportFormat.PDF));
                     downloadBehavior.initiate(target);
                 }
             }, ActionLink.ActionType.EXPORT_PDF, StandardEntitlement.REPORT_READ);
@@ -120,7 +123,8 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
                 @Override
                 public void onClick(final AjaxRequestTarget target, final ExecTO ignore) {
-                    downloadBehavior.setDetails(model.getObject().getKey(), ReportExecExportFormat.RTF);
+                    downloadBehavior.setResponse(() -> reportRestClient.exportExecutionResult(
+                            model.getObject().getKey(), ReportExecExportFormat.RTF));
                     downloadBehavior.initiate(target);
                 }
             }, ActionLink.ActionType.EXPORT_RTF, StandardEntitlement.REPORT_READ);
@@ -131,47 +135,11 @@ public class ReportExecutionDetails extends MultilevelPanel.SecondLevel {
 
                 @Override
                 public void onClick(final AjaxRequestTarget target, final ExecTO ignore) {
-                    downloadBehavior.setDetails(model.getObject().getKey(), ReportExecExportFormat.XML);
+                    downloadBehavior.setResponse(() -> reportRestClient.exportExecutionResult(
+                            model.getObject().getKey(), ReportExecExportFormat.XML));
                     downloadBehavior.initiate(target);
                 }
             }, ActionLink.ActionType.EXPORT_XML, StandardEntitlement.REPORT_READ);
         }
     }
-
-    private static class AjaxExportDownloadBehavior extends AbstractAjaxDownloadBehavior {
-
-        private static final long serialVersionUID = 3109256773218160485L;
-
-        private String execution;
-
-        private ReportExecExportFormat exportFormat;
-
-        private HttpResourceStream stream;
-
-        public AjaxExportDownloadBehavior setDetails(
-                final String execution, final ReportExecExportFormat exportFormat) {
-            this.execution = execution;
-            this.exportFormat = exportFormat;
-            this.stream = null;
-            return this;
-        }
-
-        private void createResourceStream() {
-            if (stream == null) {
-                stream = new HttpResourceStream(new ReportRestClient().exportExecutionResult(execution, exportFormat));
-            }
-        }
-
-        @Override
-        protected String getFileName() {
-            createResourceStream();
-            return stream == null ? null : stream.getFilename();
-        }
-
-        @Override
-        protected IResourceStream getResourceStream() {
-            createResourceStream();
-            return stream;
-        }
-    }
 }
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
index abd39f5..7ca33cc 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.java
@@ -63,7 +63,7 @@ public class ReportTemplateDirectoryPanel
 
     private static final long serialVersionUID = -3789392431954221446L;
 
-    protected final BaseModal<String> utilityModal = new BaseModal<>("outer");
+    protected final BaseModal<String> utilityModal = new BaseModal<>(Constants.OUTER);
 
     public ReportTemplateDirectoryPanel(final String id, final PageReference pageReference) {
         super(id, pageReference, true);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
index ed9bcdb..f523753 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
@@ -18,9 +18,20 @@
  */
 package org.apache.syncope.client.console.rest;
 
+import java.io.InputStream;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.client.Client;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.common.lib.to.ProvisioningReport;
 import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
 import org.apache.syncope.common.lib.to.ReconStatus;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
+import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
 import org.apache.syncope.common.rest.api.beans.ReconQuery;
 import org.apache.syncope.common.rest.api.service.ReconciliationService;
 
@@ -39,4 +50,28 @@ public class ReconciliationRestClient extends BaseRestClient {
     public void pull(final ReconQuery reconQuery, final PullTaskTO pullTask) {
         getService(ReconciliationService.class).pull(reconQuery, pullTask);
     }
+
+    public Response push(final AnyQuery anyQuery, final CSVPushSpec spec) {
+        ReconciliationService service = getService(ReconciliationService.class);
+        Client client = WebClient.client(service);
+        client.accept(RESTHeaders.TEXT_CSV);
+
+        Response response = service.push(anyQuery, spec);
+
+        SyncopeConsoleSession.get().resetClient(ReconciliationService.class);
+
+        return response;
+    }
+
+    public List<ProvisioningReport> pull(final CSVPullSpec spec, final InputStream csv) {
+        ReconciliationService service = getService(ReconciliationService.class);
+        Client client = WebClient.client(service);
+        client.type(RESTHeaders.TEXT_CSV);
+
+        List<ProvisioningReport> result = service.pull(spec, csv);
+
+        SyncopeConsoleSession.get().resetClient(ReconciliationService.class);
+
+        return result;
+    }
 }
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
index 40c8f16..05cd498 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
@@ -90,11 +90,11 @@ public class TopologyTogglePanel extends TogglePanel<Serializable> {
         modal.size(Modal.Size.Large);
         setFooterVisibility(false);
 
-        propTaskModal = new BaseModal<>("outer");
+        propTaskModal = new BaseModal<>(Constants.OUTER);
         propTaskModal.size(Modal.Size.Large);
         addOuterObject(propTaskModal);
 
-        schedTaskModal = new BaseModal<Serializable>("outer") {
+        schedTaskModal = new BaseModal<Serializable>(Constants.OUTER) {
 
             private static final long serialVersionUID = 389935548143327858L;
 
@@ -107,12 +107,12 @@ public class TopologyTogglePanel extends TogglePanel<Serializable> {
         schedTaskModal.size(Modal.Size.Large);
         addOuterObject(schedTaskModal);
 
-        provisionModal = new BaseModal<>("outer");
+        provisionModal = new BaseModal<>(Constants.OUTER);
         provisionModal.size(Modal.Size.Large);
         provisionModal.addSubmitButton();
         addOuterObject(provisionModal);
 
-        historyModal = new BaseModal<>("outer");
+        historyModal = new BaseModal<>(Constants.OUTER);
         historyModal.size(Modal.Size.Large);
         addOuterObject(historyModal);
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AjaxDownloadBehavior.java
similarity index 68%
rename from client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java
rename to client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AjaxDownloadBehavior.java
index 004f7c8..2072e9b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AjaxDownloadBehavior.java
@@ -18,6 +18,9 @@
  */
 package org.apache.syncope.client.console.wicket.ajax.form;
 
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.console.SerializableSupplier;
+import org.apache.syncope.client.console.commons.HttpResourceStream;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.behavior.AbstractAjaxBehavior;
 import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
@@ -26,11 +29,15 @@ import org.apache.wicket.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractAjaxDownloadBehavior extends AbstractAjaxBehavior {
+public class AjaxDownloadBehavior extends AbstractAjaxBehavior {
 
     private static final long serialVersionUID = 6833760760338614245L;
 
-    protected static final Logger LOG = LoggerFactory.getLogger(AbstractAjaxDownloadBehavior.class);
+    protected static final Logger LOG = LoggerFactory.getLogger(AjaxDownloadBehavior.class);
+
+    protected SerializableSupplier<Response> response;
+
+    protected HttpResourceStream stream;
 
     /**
      * Call this method to initiate the download.
@@ -54,7 +61,27 @@ public abstract class AbstractAjaxDownloadBehavior extends AbstractAjaxBehavior
         }
     }
 
-    protected abstract String getFileName();
+    public boolean hasResponse() {
+        return response != null;
+    }
+
+    public void setResponse(final SerializableSupplier<Response> response) {
+        this.response = response;
+    }
 
-    protected abstract IResourceStream getResourceStream();
+    private void createResourceStream() {
+        if (stream == null && response != null) {
+            stream = new HttpResourceStream(response.get());
+        }
+    }
+
+    protected String getFileName() {
+        createResourceStream();
+        return stream == null ? null : stream.getFilename();
+    }
+
+    protected IResourceStream getResourceStream() {
+        createResourceStream();
+        return stream;
+    }
 }
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
index a4d8775..e58789c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java
@@ -54,7 +54,7 @@ public final class ActionPanel<T extends Serializable> extends Panel {
     private final Action<T> action;
 
     public ActionPanel(final IModel<T> model, final Action<T> action) {
-        this("action", model, action);
+        this(Constants.ACTION, model, action);
     }
 
     public ActionPanel(final String componentId, final IModel<T> model, final Action<T> action) {
@@ -74,7 +74,7 @@ public final class ActionPanel<T extends Serializable> extends Panel {
 
         if (action.getLink() == null || action.getType() == ActionType.NOT_FOUND) {
             enabled = true;
-            actionLink = new IndicatingAjaxLink<Void>("action") {
+            actionLink = new IndicatingAjaxLink<Void>(Constants.ACTION) {
 
                 private static final long serialVersionUID = -7978723352517770644L;
 
@@ -90,13 +90,13 @@ public final class ActionPanel<T extends Serializable> extends Panel {
         } else if (action.getType() == ActionType.EXTERNAL_EDITOR) {
             enabled = action.getLink().isEnabled(obj);
             actionLink = new BookmarkablePageLink<>(
-                    "action", action.getLink().getPageClass(), action.getLink().getPageParameters()).
+                    Constants.ACTION, action.getLink().getPageClass(), action.getLink().getPageParameters()).
                     setPopupSettings(new VeilPopupSettings().setHeight(600).setWidth(800));
         } else {
             enabled = action.getLink().isEnabled(obj);
 
             actionLink = action.isOnConfirm()
-                    ? new IndicatingOnConfirmAjaxLink<Void>("action", enabled) {
+                    ? new IndicatingOnConfirmAjaxLink<Void>(Constants.ACTION, enabled) {
 
                 private static final long serialVersionUID = -7978723352517770644L;
 
@@ -112,7 +112,7 @@ public final class ActionPanel<T extends Serializable> extends Panel {
                             ? StringUtils.EMPTY : Constants.VEIL_INDICATOR_MARKUP_ID;
                 }
             }
-                    : new IndicatingAjaxLink<Void>("action") {
+                    : new IndicatingAjaxLink<Void>(Constants.ACTION) {
 
                 private static final long serialVersionUID = -7978723352517770644L;
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.java
new file mode 100644
index 0000000..38b1d27
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.java
@@ -0,0 +1,133 @@
+/*
+ * 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.wicket.markup.html.form;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAutoCompleteBehavior;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.validation.IValidator;
+
+public class AjaxCharacterFieldPanel extends FieldPanel<Character> implements Cloneable {
+
+    private static final long serialVersionUID = 238940918106696068L;
+
+    private Component questionMarkJexlHelp;
+
+    private List<Character> choices = Collections.emptyList();
+
+    public AjaxCharacterFieldPanel(final String id, final String name, final IModel<Character> model) {
+        this(id, name, model, true);
+    }
+
+    public AjaxCharacterFieldPanel(
+            final String id, final String name, final IModel<Character> model, final boolean enableOnChange) {
+        super(id, name, model);
+
+        questionMarkJexlHelp = Constants.getJEXLPopover(this, TooltipConfig.Placement.right);
+        add(questionMarkJexlHelp.setVisible(false));
+
+        final AutoCompleteSettings settings = new AutoCompleteSettings();
+        settings.setShowCompleteListOnFocusGain(true);
+        settings.setShowListOnEmptyInput(true);
+        settings.setCssClassName("custom-autocomplete-box");
+
+        field = new AutoCompleteTextField<Character>("textField", model, settings) {
+
+            private static final long serialVersionUID = -6648767303091874219L;
+
+            @Override
+            protected Iterator<Character> getChoices(final String input) {
+                return AjaxCharacterFieldPanel.this.getChoices(input);
+            }
+
+            @Override
+            protected AutoCompleteBehavior<Character> newAutoCompleteBehavior(
+                    final IAutoCompleteRenderer<Character> renderer, final AutoCompleteSettings settings) {
+                return new IndicatorAutoCompleteBehavior<Character>(renderer, settings) {
+
+                    private static final long serialVersionUID = 1070808433195962931L;
+
+                    @Override
+                    protected Iterator<Character> getChoices(final String input) {
+                        return AjaxCharacterFieldPanel.this.getChoices(input);
+                    }
+                };
+            }
+        };
+        add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
+
+        if (enableOnChange && !isReadOnly()) {
+            field.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                private static final long serialVersionUID = -1107858522700306810L;
+
+                @Override
+                protected void onUpdate(final AjaxRequestTarget target) {
+                    // nothing to do
+                }
+            });
+        }
+    }
+
+    public void addValidator(final IValidator<? super Character> validator) {
+        this.field.add(validator);
+    }
+
+    public void setChoices(final List<Character> choices) {
+        if (choices != null) {
+            this.choices = choices;
+        }
+    }
+
+    public FieldPanel<Character> enableJexlHelp() {
+        questionMarkJexlHelp.setVisible(true);
+        return this;
+    }
+
+    public FieldPanel<Character> enableJexlHelp(final String... jexlExamples) {
+        questionMarkJexlHelp = Constants.getJEXLPopover(this, TooltipConfig.Placement.bottom, jexlExamples);
+        addOrReplace(questionMarkJexlHelp.setVisible(true));
+        return this;
+    }
+
+    protected Iterator<Character> getChoices(final String input) {
+        return choices.stream().
+                filter(choice -> input != null && input.length() > 0 && input.toCharArray()[0] == choice).
+                iterator();
+    }
+
+    @Override
+    public FieldPanel<Character> clone() {
+        final AjaxCharacterFieldPanel panel = (AjaxCharacterFieldPanel) super.clone();
+        panel.setChoices(choices);
+        return panel;
+    }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java
new file mode 100644
index 0000000..f881bd1
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInputField;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.FileInputConfig;
+import java.io.ByteArrayInputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.CSVConfPanel;
+import org.apache.syncope.client.console.rest.ImplementationRestClient;
+import org.apache.syncope.client.console.rest.ReconciliationRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.types.ConflictResolutionAction;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
+import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
+import org.apache.wicket.event.IEventSink;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Radio;
+import org.apache.wicket.markup.html.form.RadioGroup;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class CSVPullWizardBuilder extends AjaxWizardBuilder<CSVPullSpec> {
+
+    private static final long serialVersionUID = -4049787433975145383L;
+
+    public enum LineSeparator {
+        LF("\n"),
+        CR("\r"),
+        CRLF("\r\n");
+
+        private final String repr;
+
+        LineSeparator(final String repr) {
+            this.repr = repr;
+        }
+
+        public String getRepr() {
+            return repr;
+        }
+
+        public static LineSeparator byRepr(final String repr) {
+            for (LineSeparator value : values()) {
+                if (value.getRepr().equals(repr)) {
+                    return value;
+                }
+            }
+            return null;
+        }
+    }
+
+    private final ReconciliationRestClient restClient = new ReconciliationRestClient();
+
+    private final Model<byte[]> csv = new Model<>();
+
+    public CSVPullWizardBuilder(final CSVPullSpec defaultItem, final PageReference pageRef) {
+        super(defaultItem, pageRef);
+    }
+
+    @Override
+    public CSVPullWizardBuilder setEventSink(final IEventSink eventSink) {
+        super.setEventSink(eventSink);
+        return this;
+    }
+
+    @Override
+    protected Serializable onApplyInternal(final CSVPullSpec modelObject) {
+        restClient.pull(modelObject, new ByteArrayInputStream(csv.getObject()));
+        return Constants.OPERATION_SUCCEEDED;
+    }
+
+    @Override
+    protected WizardModel buildModelSteps(final CSVPullSpec modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new Details(modelObject));
+        wizardModel.add(new Columns(modelObject));
+        wizardModel.add(new PullTask(modelObject));
+        return wizardModel;
+    }
+
+    public class Details extends WizardStep {
+
+        private static final long serialVersionUID = -4736870165235853919L;
+
+        public Details(final CSVPullSpec spec) {
+            FileInputConfig csvFile = new FileInputConfig();
+            csvFile.showUpload(false);
+            csvFile.showRemove(false);
+            csvFile.showPreview(false);
+            BootstrapFileInputField csvUpload =
+                    new BootstrapFileInputField("csvUpload", new ListModel<>(new ArrayList<>()), csvFile);
+            csvUpload.setRequired(true);
+            csvUpload.setOutputMarkupId(true);
+            csvUpload.add(new AjaxFormSubmitBehavior(Constants.ON_CHANGE) {
+
+                private static final long serialVersionUID = 5538299138211283825L;
+
+                @Override
+                protected void onSubmit(final AjaxRequestTarget target) {
+                    FileUpload uploadedFile = csvUpload.getFileUpload();
+                    if (uploadedFile != null) {
+                        csv.setObject(uploadedFile.getBytes());
+                    }
+                }
+            });
+            add(csvUpload);
+
+            add(new CSVConfPanel("csvconf", spec));
+        }
+    }
+
+    public class Columns extends WizardStep implements WizardModel.ICondition {
+
+        private static final long serialVersionUID = -4136764210454067728L;
+
+        private final CSVPullSpec spec;
+
+        private final ListModel<String> columnsModel = new ListModel<>();
+
+        public Columns(final CSVPullSpec spec) {
+            this.spec = spec;
+
+            RadioGroup<String> keyColumn = new RadioGroup<>("keyColumn", new PropertyModel<>(spec, "keyColumn"));
+            keyColumn.setOutputMarkupId(true);
+            keyColumn.setOutputMarkupPlaceholderTag(true);
+            keyColumn.setRenderBodyOnly(false);
+            keyColumn.setRequired(true);
+            add(keyColumn);
+
+            keyColumn.add(new ListView<String>("columns", columnsModel) {
+
+                private static final long serialVersionUID = -9112553137618363167L;
+
+                @Override
+                protected void populateItem(final ListItem<String> item) {
+                    item.add(new Label("column", item.getModelObject()));
+                    item.add(new Radio<>("key", new Model<>(item.getModelObject()), keyColumn));
+                    item.add(new AjaxCheckBox("ignore", new Model<>()) {
+
+                        private static final long serialVersionUID = -6139318907146065915L;
+
+                        @Override
+                        protected void onUpdate(final AjaxRequestTarget target) {
+                            if (spec.getIgnoreColumns().contains(item.getModelObject())) {
+                                spec.getIgnoreColumns().remove(item.getModelObject());
+                            } else {
+                                spec.getIgnoreColumns().add(item.getModelObject());
+                            }
+                        }
+                    });
+                }
+            }.setReuseItems(true));
+        }
+
+        @Override
+        public boolean evaluate() {
+            if (csv.getObject() != null) {
+                String header = StringUtils.substringBefore(new String(csv.getObject()), spec.getLineSeparator());
+                columnsModel.setObject(Stream.of(StringUtils.split(header, spec.getColumnSeparator())).
+                        map(value -> {
+                            String unquoted = value;
+                            if (unquoted.charAt(0) == spec.getQuoteChar()) {
+                                unquoted = unquoted.substring(1);
+                            }
+                            if (unquoted.charAt(unquoted.length() - 1) == spec.getQuoteChar()) {
+                                unquoted = unquoted.substring(0, unquoted.length() - 1);
+                            }
+                            return unquoted;
+                        }).collect(Collectors.toList()));
+            }
+
+            return true;
+        }
+    }
+
+    public class PullTask extends WizardStep {
+
+        private static final long serialVersionUID = -8954789648303078732L;
+
+        private final ImplementationRestClient implRestClient = new ImplementationRestClient();
+
+        private final IModel<List<String>> pullActions = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 4659376149825914247L;
+
+            @Override
+            protected List<String> load() {
+                return implRestClient.list(ImplementationType.PULL_ACTIONS).stream().
+                        map(EntityTO::getKey).sorted().collect(Collectors.toList());
+            }
+        };
+
+        private final IModel<List<String>> pullCorrelationRules = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 4659376149825914247L;
+
+            @Override
+            protected List<String> load() {
+                return implRestClient.list(ImplementationType.PULL_CORRELATION_RULE).stream().
+                        map(EntityTO::getKey).sorted().collect(Collectors.toList());
+            }
+        };
+
+        public PullTask(final CSVPullSpec spec) {
+            AjaxCheckBoxPanel remediation = new AjaxCheckBoxPanel(
+                    "remediation", "remediation", new PropertyModel<>(spec, "remediation"), false);
+            add(remediation);
+
+            AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
+                    "matchingRule", "matchingRule", new PropertyModel<>(spec, "matchingRule"), false);
+            matchingRule.setChoices(Arrays.asList(MatchingRule.values()));
+            add(matchingRule);
+
+            AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
+                    "unmatchingRule", "unmatchingRule", new PropertyModel<>(spec, "unmatchingRule"),
+                    false);
+            unmatchingRule.setChoices(Arrays.asList(UnmatchingRule.values()));
+            add(unmatchingRule);
+
+            AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
+                    build("actions", new PropertyModel<>(spec, "actions"), new ListModel<>(pullActions.getObject()));
+            add(actions);
+
+            AjaxDropDownChoicePanel<ConflictResolutionAction> conflictResolutionAction = new AjaxDropDownChoicePanel<>(
+                    "conflictResolutionAction", "conflictResolutionAction",
+                    new PropertyModel<>(spec, "conflictResolutionAction"), false);
+            conflictResolutionAction.setChoices(Arrays.asList(ConflictResolutionAction.values()));
+            conflictResolutionAction.setRequired(true);
+            add(conflictResolutionAction);
+
+            AjaxDropDownChoicePanel<String> pullCorrelationRule = new AjaxDropDownChoicePanel<>(
+                    "pullCorrelationRule", "pullCorrelationRule", new PropertyModel<>(spec, "pullCorrelationRule"),
+                    false);
+            pullCorrelationRule.setChoices(pullCorrelationRules);
+            add(pullCorrelationRule);
+        }
+    }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java
new file mode 100644
index 0000000..0a1fdd0
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.CSVConfPanel;
+import org.apache.syncope.client.console.rest.ImplementationRestClient;
+import org.apache.syncope.client.console.rest.ReconciliationRestClient;
+import org.apache.syncope.client.console.wicket.ajax.form.AjaxDownloadBehavior;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.event.IEventSink;
+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.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class CSVPushWizardBuilder extends AjaxWizardBuilder<CSVPushSpec> {
+
+    private static final long serialVersionUID = -8890710681835661962L;
+
+    private final ReconciliationRestClient restClient = new ReconciliationRestClient();
+
+    private final AnyQuery query;
+
+    private final AjaxDownloadBehavior downloadBehavior;
+
+    public CSVPushWizardBuilder(
+            final CSVPushSpec defaultItem,
+            final AnyQuery query,
+            final AjaxDownloadBehavior downloadBehavior,
+            final PageReference pageRef) {
+
+        super(defaultItem, pageRef);
+        this.query = query;
+        this.downloadBehavior = downloadBehavior;
+    }
+
+    @Override
+    public CSVPushWizardBuilder setEventSink(final IEventSink eventSink) {
+        super.setEventSink(eventSink);
+        return this;
+    }
+
+    @Override
+    protected Serializable onApplyInternal(final CSVPushSpec modelObject) {
+        downloadBehavior.setResponse(() -> restClient.push(query, modelObject));
+        return Constants.OPERATION_SUCCEEDED;
+    }
+
+    @Override
+    protected WizardModel buildModelSteps(final CSVPushSpec modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new Details(modelObject));
+        wizardModel.add(new PushTask(modelObject));
+        return wizardModel;
+    }
+
+    public class Details extends WizardStep {
+
+        private static final long serialVersionUID = -2368995286051427297L;
+
+        public Details(final CSVPushSpec spec) {
+            add(new CSVConfPanel("csvconf", spec));
+        }
+    }
+
+    public class PushTask extends WizardStep {
+
+        private static final long serialVersionUID = -2747583614435078452L;
+
+        private final ImplementationRestClient implRestClient = new ImplementationRestClient();
+
+        private final IModel<List<String>> pushActions = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 4659376149825914247L;
+
+            @Override
+            protected List<String> load() {
+                return implRestClient.list(ImplementationType.PUSH_ACTIONS).stream().
+                        map(EntityTO::getKey).sorted().collect(Collectors.toList());
+            }
+        };
+
+        public PushTask(final CSVPushSpec spec) {
+            AjaxCheckBoxPanel ignorePaging = new AjaxCheckBoxPanel(
+                    "ignorePaging", "ignorePaging", new PropertyModel<>(spec, "ignorePaging"), true);
+            add(ignorePaging);
+
+            AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
+                    "matchingRule", "matchingRule", new PropertyModel<>(spec, "matchingRule"), false);
+            matchingRule.setChoices(Arrays.asList(MatchingRule.values()));
+            add(matchingRule);
+
+            AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
+                    "unmatchingRule", "unmatchingRule", new PropertyModel<>(spec, "unmatchingRule"),
+                    false);
+            unmatchingRule.setChoices(Arrays.asList(UnmatchingRule.values()));
+            add(unmatchingRule);
+
+            AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
+                    build("actions", new PropertyModel<>(spec, "actions"), new ListModel<>(pushActions.getObject()));
+            add(actions);
+        }
+    }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
index 0e5bc89..4509f48 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
@@ -84,7 +84,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
     private final List<Component> outerObjects = new ArrayList<>();
 
-    protected final BaseModal<T> modal = new BaseModal<T>("outer") {
+    protected final BaseModal<T> modal = new BaseModal<T>(Constants.OUTER) {
 
         private static final long serialVersionUID = 389935548143327858L;
 
@@ -276,7 +276,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
     }
 
     /**
-     * Show exit butto sending ExitEvent paylad.
+     * Show exit button sending ExitEvent paylad.
      *
      * @return the current instance.
      */
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ResultPage.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ResultPage.java
index f74bc2e..1c96eb1 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ResultPage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ResultPage.java
@@ -20,6 +20,7 @@ package org.apache.syncope.client.console.wizards.any;
 
 import java.io.Serializable;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -43,9 +44,7 @@ public abstract class ResultPage<T extends Serializable> extends Panel implement
 
         add(customResultBody("customResultBody", item, result));
 
-        final ActionsPanel<T> panel = new ActionsPanel<>("action", null);
-        add(panel);
-
+        ActionsPanel<T> panel = new ActionsPanel<>(Constants.ACTION, null);
         panel.add(new ActionLink<T>() {
 
             private static final long serialVersionUID = 3257738274365467945L;
@@ -55,8 +54,7 @@ public abstract class ResultPage<T extends Serializable> extends Panel implement
                 closeAction(target);
             }
         }, ActionLink.ActionType.CLOSE, StringUtils.EMPTY).hideLabel();
-
-        panel.setRenderBodyOnly(true);
+        add(panel.setRenderBodyOnly(true));
     }
 
     protected abstract void closeAction(AjaxRequestTarget target);
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ItemTransformersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ItemTransformersTogglePanel.java
index ca5b038..cfc8ee7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ItemTransformersTogglePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ItemTransformersTogglePanel.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.TogglePanel;
 import org.apache.syncope.client.console.rest.ImplementationRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
@@ -48,7 +49,7 @@ public class ItemTransformersTogglePanel extends TogglePanel<Serializable> {
     private ItemTO item;
 
     public ItemTransformersTogglePanel(final WebMarkupContainer container, final PageReference pageRef) {
-        super("outer", "itemTransformersTogglePanel", pageRef);
+        super(Constants.OUTER, "itemTransformersTogglePanel", pageRef);
 
         final LoadableDetachableModel<List<String>> model = new LoadableDetachableModel<List<String>>() {
 
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
index f375a68..e99caf8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
@@ -20,6 +20,7 @@ package org.apache.syncope.client.console.wizards.resources;
 
 import java.io.Serializable;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.TogglePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.common.lib.to.ItemTO;
@@ -40,7 +41,7 @@ public class JEXLTransformersTogglePanel extends TogglePanel<Serializable> {
     private final AjaxTextFieldPanel pullJEXLTransformer;
 
     public JEXLTransformersTogglePanel(final WebMarkupContainer container, final PageReference pageRef) {
-        super("outer", "jexlTransformersTogglePanel", pageRef);
+        super(Constants.OUTER, "jexlTransformersTogglePanel", pageRef);
 
         Form<?> form = new Form<>("form");
         addInnerObject(form);
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.html
new file mode 100644
index 0000000..4466dfa
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.html
@@ -0,0 +1,30 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div style="float: left;padding-top: 15px;">
+      <a href="#" class="btn btn-primary btn-circle btn-lg" wicket:id="csvPush" wicket:message="title:csvPushTitle">
+        <i class="fa fa-download" aria-hidden="true"></i>
+      </a>
+      <a href="#" class="btn btn-primary btn-circle btn-lg" wicket:id="csvPull" wicket:message="title:csvPullTitle">
+        <i class="fa fa-upload" aria-hidden="true"></i>
+      </a>
+    </div>
+  </wicket:extend>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.properties
new file mode 100644
index 0000000..d65e32b
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Export current ${anyTypeKey} selection to CSV
+csvPull=Import ${anyTypeKey} from CSV into Realm ${destinationRealm}
+csvPushTitle=Export to CSV
+csvPullTitle=Import from CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_fr_CA.properties
new file mode 100644
index 0000000..3b7d66a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_fr_CA.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Exporter la s\u00e9lection actuelle de $ {anyTypeKey} vers CSV
+csvPull=Importer ${anyTypeKey} depuis CSV en Realm ${destinationRealm}
+csvPushTitle=Export to CSV
+csvPullTitle=Importer depuis CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_it.properties
new file mode 100644
index 0000000..7aba06c
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_it.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Esporta la selezione corrente di ${anyTypeKey} su CSV
+csvPull=Importa ${anyTypeKey} da CSV nel Realm ${destinationRealm}
+csvPushTitle=Esporta su CSV
+csvPullTitle=Importa da CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ja.properties
new file mode 100644
index 0000000..d65e32b
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ja.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Export current ${anyTypeKey} selection to CSV
+csvPull=Import ${anyTypeKey} from CSV into Realm ${destinationRealm}
+csvPushTitle=Export to CSV
+csvPullTitle=Import from CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_pt_BR.properties
new file mode 100644
index 0000000..d65e32b
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_pt_BR.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Export current ${anyTypeKey} selection to CSV
+csvPull=Import ${anyTypeKey} from CSV into Realm ${destinationRealm}
+csvPushTitle=Export to CSV
+csvPullTitle=Import from CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ru.properties
new file mode 100644
index 0000000..d65e32b
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/AnyDirectoryPanel_ru.properties
@@ -0,0 +1,20 @@
+# 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.
+csvPush=Export current ${anyTypeKey} selection to CSV
+csvPull=Import ${anyTypeKey} from CSV into Realm ${destinationRealm}
+csvPushTitle=Export to CSV
+csvPullTitle=Import from CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.html
new file mode 100644
index 0000000..3ba0a2a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.html
@@ -0,0 +1,29 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div wicket:id="columnSeparator">[columnSeparator]</div>
+    <div wicket:id="arrayElementSeparator">[arrayElementSeparator]</div>
+    <div wicket:id="quoteChar">[quoteChar]</div>
+    <div wicket:id="escapeChar">[escapeChar]</div>
+    <div wicket:id="lineSeparator">[lineSeparator]</div>
+    <div wicket:id="nullValue">[nullValue]</div>
+    <div wicket:id="allowComments">[allowComments]</div>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.properties
new file mode 100644
index 0000000..4e008ea
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=Column separator
+arrayElementSeparator=Array elements separator
+quoteChar=Quote character
+escapeChar=Escape character
+lineSeparator=Line separator
+nullValue=Null value
+allowComments=Comments allowed?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_fr_CA.properties
new file mode 100644
index 0000000..1d399ee
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_fr_CA.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=S\u00e9parateur de colonnes
+arrayElementSeparator=S\u00e9parateur d'\u00e9l\u00e9ments de tableau
+quoteChar=Caract\u00e8re de citation
+escapeChar=Caract\u00e8re d'\u00e9chappement
+lineSeparator=S\u00e9parateur de ligne
+nullValue=Valeur nulle
+allowComments=Commentaires autoris\u00e9s?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_it.properties
new file mode 100644
index 0000000..2633d79
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_it.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=Separatore di colonna
+arrayElementSeparator=Separatore di elenco
+quoteChar=Carattere di citazione
+escapeChar=Carattere di escape
+lineSeparator=Separatore di linea
+nullValue=Valore nullo
+allowComments=Permettere i commenti?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ja.properties
new file mode 100644
index 0000000..4e008ea
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ja.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=Column separator
+arrayElementSeparator=Array elements separator
+quoteChar=Quote character
+escapeChar=Escape character
+lineSeparator=Line separator
+nullValue=Null value
+allowComments=Comments allowed?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_pt_BR.properties
new file mode 100644
index 0000000..4e008ea
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_pt_BR.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=Column separator
+arrayElementSeparator=Array elements separator
+quoteChar=Quote character
+escapeChar=Escape character
+lineSeparator=Line separator
+nullValue=Null value
+allowComments=Comments allowed?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ru.properties
new file mode 100644
index 0000000..4e008ea
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/CSVConfPanel_ru.properties
@@ -0,0 +1,23 @@
+# 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.
+columnSeparator=Column separator
+arrayElementSeparator=Array elements separator
+quoteChar=Quote character
+escapeChar=Escape character
+lineSeparator=Line separator
+nullValue=Null value
+allowComments=Comments allowed?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
new file mode 100644
index 0000000..2c1b7bb
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
@@ -0,0 +1,30 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <wicket:enclosure child="field-label">
+      <label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
+      <span wicket:id="jexlInfo" class="glyphicon glyphicon-info-sign" style="cursor: pointer"></span>
+      <span wicket:id="externalAction"/>
+    </wicket:enclosure>
+    <fieldset class="input-group">
+      <input type="text" class="form-control" wicket:id="textField" placeholder=""/>
+    </fieldset>
+  </wicket:extend>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.html
new file mode 100644
index 0000000..6ebef23
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.html
@@ -0,0 +1,36 @@
+<!--
+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>
+    <table class="table table-hover">
+      <thead>
+        <th><wicket:message key="column"/></th>
+        <th><wicket:message key="key"/></th>
+        <th><wicket:message key="ignore"/></th>
+      </thead>
+      <tbody wicket:id="keyColumn">
+        <tr wicket:id="columns">
+          <td><span wicket:id="column"></span></td>
+          <td><input type="radio" wicket:id="key"></td>
+          <td><input type="checkbox" wicket:id="ignore"></td>
+        </tr>
+      </tbody>
+    </table>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.properties
new file mode 100644
index 0000000..462a14f
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Column name
+key=Is key column?
+ignore=Ignore?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_fr_CA.properties
new file mode 100644
index 0000000..6a7b6de
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_fr_CA.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Nom de colonne
+key=Est la colonne cl\u00e9?
+ignore=Ignorer?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_it.properties
new file mode 100644
index 0000000..255afa2
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_it.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Nome colonna
+key=Chiave?
+ignore=Da ignorare?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ja.properties
new file mode 100644
index 0000000..462a14f
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ja.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Column name
+key=Is key column?
+ignore=Ignore?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_pt_BR.properties
new file mode 100644
index 0000000..462a14f
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_pt_BR.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Column name
+key=Is key column?
+ignore=Ignore?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ru.properties
new file mode 100644
index 0000000..462a14f
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Columns_ru.properties
@@ -0,0 +1,19 @@
+# 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.
+column=Column name
+key=Is key column?
+ignore=Ignore?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.html
new file mode 100644
index 0000000..47873f8
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.html
@@ -0,0 +1,29 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="form-group">
+      <label><wicket:message key="csvFile"/></label>
+      <input wicket:id="csvUpload" type="file"/>
+    </div>
+    <div class="form-group">
+      <div wicket:id="csvconf"/>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.properties
new file mode 100644
index 0000000..5a4448a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=CSV File
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_fr_CA.properties
new file mode 100644
index 0000000..5c281d5
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_fr_CA.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=Fichier CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_it.properties
new file mode 100644
index 0000000..273d12c
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_it.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=File CSV
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ja.properties
new file mode 100644
index 0000000..5a4448a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ja.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=CSV File
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_pt_BR.properties
new file mode 100644
index 0000000..5a4448a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_pt_BR.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=CSV File
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ru.properties
new file mode 100644
index 0000000..5a4448a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$Details_ru.properties
@@ -0,0 +1,17 @@
+# 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.
+csvFile=CSV File
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.html
new file mode 100644
index 0000000..761b1f4
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.html
@@ -0,0 +1,32 @@
+<!--
+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="form-group">
+      <div wicket:id="remediation">[remediation]</div>
+      <div wicket:id="matchingRule">[matchingRule]</div>
+      <div wicket:id="unmatchingRule">[unmatchingRule]</div>
+      <div wicket:id="actions">[actions]</div>
+    </div>
+    <div class="form-group">
+      <div wicket:id="conflictResolutionAction">[conflictResolutionAction]</div>
+      <div wicket:id="pullCorrelationRule">[nullValue]</div>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.properties
new file mode 100644
index 0000000..5527723
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Remediation
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+conflictResolutionAction=Conflict resolution action
+pullCorrelationRule=Correlation rule
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_fr_CA.properties
new file mode 100644
index 0000000..c5e744a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_fr_CA.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Remediation
+matchingRule=R\u00e8gle de correspondance
+unmatchingRule=R\u00e8gle in\u00e9gal\u00e9e
+actions=Actions
+conflictResolutionAction=Action de r\u00e9solution de conflits
+pullCorrelationRule=R\u00e8gle de corr\u00e9lation
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties
new file mode 100644
index 0000000..02ad161
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Bonifiche
+matchingRule=Regola di matrching
+unmatchingRule=Regola di unmatching
+actions=Azioni
+conflictResolutionAction=Azione di Risoluzione Conflitti
+pullCorrelationRule=Regola di Correlazione
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ja.properties
new file mode 100644
index 0000000..5527723
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ja.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Remediation
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+conflictResolutionAction=Conflict resolution action
+pullCorrelationRule=Correlation rule
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_pt_BR.properties
new file mode 100644
index 0000000..5527723
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_pt_BR.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Remediation
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+conflictResolutionAction=Conflict resolution action
+pullCorrelationRule=Correlation rule
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ru.properties
new file mode 100644
index 0000000..5527723
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_ru.properties
@@ -0,0 +1,22 @@
+# 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.
+remediation=Remediation
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+conflictResolutionAction=Conflict resolution action
+pullCorrelationRule=Correlation rule
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$Details.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$Details.html
new file mode 100644
index 0000000..6628f18
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$Details.html
@@ -0,0 +1,25 @@
+<!--
+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="form-group">
+      <div wicket:id="csvconf"/>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.html
new file mode 100644
index 0000000..3773882
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.html
@@ -0,0 +1,30 @@
+<!--
+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="form-group">
+      <div wicket:id="ignorePaging">[ignorePaging]</div>
+    </div>
+    <div class="form-group">
+      <div wicket:id="matchingRule">[matchingRule]</div>
+      <div wicket:id="unmatchingRule">[unmatchingRule]</div>
+      <div wicket:id="actions">[actions]</div>
+    </div>
+  </wicket:panel>
+</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.properties
new file mode 100644
index 0000000..f269211
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+ignorePaging=Include all pages?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_fr_CA.properties
new file mode 100644
index 0000000..68e7e24
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_fr_CA.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=R\u00e8gle de correspondance
+unmatchingRule=R\u00e8gle in\u00e9gal\u00e9e
+actions=Actions
+ignorePaging=Inclure toutes les pages?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties
new file mode 100644
index 0000000..6dfeb3d
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=Regola di matrching
+unmatchingRule=Regola di unmatching
+actions=Azioni
+ignorePaging=Includere tutte le pagine?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ja.properties
new file mode 100644
index 0000000..f269211
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ja.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+ignorePaging=Include all pages?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_pt_BR.properties
new file mode 100644
index 0000000..f269211
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_pt_BR.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+ignorePaging=Include all pages?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ru.properties
new file mode 100644
index 0000000..f269211
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_ru.properties
@@ -0,0 +1,20 @@
+# 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.
+matchingRule=Matching rule
+unmatchingRule=Unmatching rule
+actions=Actions
+ignorePaging=Include all pages?
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
index 80736d2..995c7ea 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
@@ -42,11 +42,11 @@ under the License.
       <wicket:child/>
 
       <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">
+        <div class="modal-footer">
+          <a href="#" class="btn btn-default btn-circle btn-lg pull-left" wicket:id="exit">
             <i 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/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
index 0393466..34be920 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
@@ -73,6 +73,11 @@ public final class RESTHeaders {
     public static final String TEXT_CSV = "text/csv";
 
     /**
+     * Mediatype for text/csv, not defined in {@link javax.ws.rs.core.MediaType}.
+     */
+    public static final MediaType TEXT_CSV_TYPE = new MediaType("text", "csv");
+
+    /**
      * Mediatype for multipart/mixed, not defined in {@link javax.ws.rs.core.MediaType}.
      */
     public static final String MULTIPART_MIXED = "multipart/mixed";
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AbstractCSVSpec.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AbstractCSVSpec.java
index 7844335..81ba8f3 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AbstractCSVSpec.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AbstractCSVSpec.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.common.rest.api.beans;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import javax.validation.constraints.NotNull;
@@ -25,7 +26,9 @@ import javax.ws.rs.QueryParam;
 import org.apache.syncope.common.lib.types.MatchingRule;
 import org.apache.syncope.common.lib.types.UnmatchingRule;
 
-public abstract class AbstractCSVSpec {
+public abstract class AbstractCSVSpec implements Serializable {
+
+    private static final long serialVersionUID = 2253975790270165334L;
 
     protected abstract static class Builder<T extends AbstractCSVSpec, B extends Builder<T, B>> {
 
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPullSpec.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPullSpec.java
index 7bb8a2d..ac6d309 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPullSpec.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPullSpec.java
@@ -29,6 +29,8 @@ import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 
 public class CSVPullSpec extends AbstractCSVSpec {
 
+    private static final long serialVersionUID = -5079876176017613587L;
+
     public static class Builder extends AbstractCSVSpec.Builder<CSVPullSpec, Builder> {
 
         @Override
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPushSpec.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPushSpec.java
index 92b2196..7663010 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPushSpec.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/CSVPushSpec.java
@@ -25,6 +25,8 @@ import javax.ws.rs.QueryParam;
 
 public class CSVPushSpec extends AbstractCSVSpec {
 
+    private static final long serialVersionUID = -8198709720749169648L;
+
     public static class Builder extends AbstractCSVSpec.Builder<CSVPushSpec, Builder> {
 
         @Override
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
index c7a4dfe..a6566fa 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -489,6 +489,7 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
                     new StreamConnector(null, spec.getArrayElementSeparator(), null, writer),
                     pushTask);
         } catch (Exception e) {
+            LOG.error("Could not push to stream", e);
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
             sce.getElements().add(e.getMessage());
             throw sce;
@@ -540,6 +541,7 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
         } catch (NotFoundException e) {
             throw e;
         } catch (Exception e) {
+            LOG.error("Could not pull from stream", e);
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
             sce.getElements().add(e.getMessage());
             throw sce;
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
index 9e88431..909107d 100644
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
@@ -23,6 +23,7 @@ import java.util.List;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.client.Client;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.common.lib.to.BpmnProcess;
@@ -33,20 +34,29 @@ public class BpmnProcessRestClient extends BaseRestClient {
 
     private static final long serialVersionUID = 5049285686167071017L;
 
-    private BpmnProcessService getService(final MediaType mediaType) {
-        return SyncopeConsoleSession.get().getService(mediaType, BpmnProcessService.class);
-    }
-
     public List<BpmnProcess> getDefinitions() {
         return getService(BpmnProcessService.class).list();
     }
 
+    private BpmnProcessService getService(final MediaType mediaType) {
+        BpmnProcessService service = getService(BpmnProcessService.class);
+        Client client = WebClient.client(service);
+        client.type(mediaType);
+        return service;
+    }
+
     public InputStream getDefinition(final MediaType mediaType, final String key) {
         Response response = getService(mediaType).get(key);
+        SyncopeConsoleSession.get().resetClient(BpmnProcessService.class);
 
         return (InputStream) response.getEntity();
     }
 
+    public void setDefinition(final MediaType mediaType, final String key, final String definition) {
+        getService(mediaType).set(key, definition);
+        SyncopeConsoleSession.get().resetClient(BpmnProcessService.class);
+    }
+
     public byte[] getDiagram(final String key) {
         BpmnProcessService service = getService(BpmnProcessService.class);
         WebClient.client(service).accept(RESTHeaders.MEDIATYPE_IMAGE_PNG);
@@ -62,10 +72,6 @@ public class BpmnProcessRestClient extends BaseRestClient {
         return diagram;
     }
 
-    public void setDefinition(final MediaType mediaType, final String key, final String definition) {
-        getService(mediaType).set(key, definition);
-    }
-
     public void deleteDefinition(final String key) {
         getService(BpmnProcessService.class).delete(key);
     }
diff --git a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPsRestClient.java b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPsRestClient.java
index 06090a0..b7549d0 100644
--- a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPsRestClient.java
+++ b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPsRestClient.java
@@ -22,6 +22,8 @@ import java.io.InputStream;
 import java.util.List;
 import java.util.Set;
 import javax.ws.rs.core.MediaType;
+import org.apache.cxf.jaxrs.client.Client;
+import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.common.lib.to.SAML2IdPTO;
 import org.apache.syncope.common.rest.api.service.SAML2IdPService;
@@ -43,8 +45,13 @@ public class SAML2IdPsRestClient extends BaseRestClient {
     }
 
     public void importIdPs(final InputStream input) {
-        SyncopeConsoleSession.get().
-                getService(MediaType.APPLICATION_XML_TYPE, SAML2IdPService.class).importFromMetadata(input);
+        SAML2IdPService service = getService(SAML2IdPService.class);
+        Client client = WebClient.client(service);
+        client.type(MediaType.APPLICATION_XML);
+
+        service.importFromMetadata(input);
+
+        SyncopeConsoleSession.get().resetClient(SAML2IdPService.class);
     }
 
     public SAML2IdPTO read(final String key) {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java
index e47f9cd..e406116 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java
@@ -56,19 +56,19 @@ public class GroupsITCase extends AbstractConsoleITCase {
                 + "actions:actions:actionRepeater:2:action:action");
 
         FormTester formTester = TESTER.newFormTester(TAB_PANEL
-                + "outerObjectsRepeater:7:outer:container:content:togglePanelContainer:membersForm");
+                + "outerObjectsRepeater:8:outer:container:content:togglePanelContainer:membersForm");
 
         formTester.select("type:dropDownChoiceField", 0);
         formTester.submit("changeit");
 
         TESTER.assertModelValue(TAB_PANEL
-                + "outerObjectsRepeater:6:outer:dialog:header:header-label", "USER members of artDirector");
+                + "outerObjectsRepeater:7:outer:dialog:header:header-label", "USER members of artDirector");
         assertNotNull(findComponentByProp("username", TAB_PANEL
-                + "outerObjectsRepeater:6:outer:form:content:searchResult:container:content:"
+                + "outerObjectsRepeater:7:outer:form:content:searchResult:container:content:"
                 + "searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "puccini"));
 
         TESTER.executeAjaxEvent(TAB_PANEL
-                + "outerObjectsRepeater:6:outer:dialog:footer:buttons:0:button", Constants.ON_CLICK);
+                + "outerObjectsRepeater:7:outer:dialog:footer:buttons:0:button", Constants.ON_CLICK);
     }
 
     @Test