You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by sk...@apache.org on 2019/11/04 15:38:18 UTC

[syncope] branch master updated: [SYNCOPE-957] Added new section in Admin Console for the Multiaccount feature

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

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


The following commit(s) were added to refs/heads/master by this push:
     new dd1ff82  [SYNCOPE-957] Added new section in Admin Console for the Multiaccount feature
dd1ff82 is described below

commit dd1ff8243199cb90ab9708ca371a98542fa1265c
Author: skylark17 <ma...@tirasa.net>
AuthorDate: Mon Nov 4 16:37:53 2019 +0100

    [SYNCOPE-957] Added new section in Admin Console for the Multiaccount feature
---
 ...DirectoryPanelAditionalActionLinksProvider.java |  21 +
 .../console/panels/ConnObjectListViewPanel.java    |  15 +-
 .../console/panels/LinkedAccountModalPanel.java    | 232 +++++++++++
 .../client/console/rest/ResourceRestClient.java    |  19 +-
 .../wizards/any/LinkedAccountCredentialsPanel.java | 125 ++++++
 .../wizards/any/LinkedAccountDetailsPanel.java     | 188 +++++++++
 .../wizards/any/LinkedAccountPlainAttrsPanel.java  | 255 ++++++++++++
 .../wizards/any/LinkedAccountPrivilegesPanel.java  |  66 +++
 .../wizards/any/LinkedAccountWizardBuilder.java    | 131 ++++++
 .../resources/ResourceConnCapabilitiesPanel.html   |   2 +-
 .../syncope/client/ui/commons/Constants.java       |   2 +
 .../markup/html/form/AbstractFieldPanel.java       |   2 +
 .../markup/html/form/AbstractMultiPanel.java       |   5 +
 .../commons/markup/html/form/AjaxPalettePanel.java |   6 +
 .../markup/html/form/AjaxSpinnerFieldPanel.java    |  15 +-
 .../ui/commons/wizards/AjaxWizardBuilder.java      |   4 +-
 .../ui/commons/wizards/any/EntityWrapper.java      |  35 ++
 .../commons/LinkedAccountPlainAttrProperty.java    | 100 +++++
 .../client/console/panels/ListViewPanel.java       |  13 +-
 .../wicket/markup/html/form/ActionLink.java        |   1 +
 .../wicket/markup/html/form/BinaryFieldPanel.java  |   7 +
 .../client/console/wizards/any/AbstractAttrs.java  | 140 +------
 .../wizards/any/AbstractAttrsWizardStep.java       | 453 +++++++++++++++++++++
 .../client/console/wizards/any/PlainAttrs.java     | 280 +------------
 .../wizards/any/TypeExtensionWizardBuilder.java    |   2 +-
 .../LinkedAccountModalPanel.html}                  |   6 +-
 ...operties => LinkedAccountModalPanel.properties} |   8 +-
 ...rties => LinkedAccountModalPanel_it.properties} |   8 +-
 ...rties => LinkedAccountModalPanel_ja.properties} |   8 +-
 ...es => LinkedAccountModalPanel_pt_BR.properties} |   8 +-
 ...rties => LinkedAccountModalPanel_ru.properties} |   8 +-
 .../console/panels/UserDirectoryPanel.properties   |   1 +
 .../panels/UserDirectoryPanel_it.properties        |   1 +
 .../panels/UserDirectoryPanel_ja.properties        |   1 +
 .../panels/UserDirectoryPanel_pt_BR.properties     |   1 +
 .../panels/UserDirectoryPanel_ru.properties        |   1 +
 .../markup/html/form/ActionsPanel.properties       |   4 +
 .../markup/html/form/ActionsPanel_it.properties    |   4 +
 .../markup/html/form/ActionsPanel_ja.properties    |   4 +
 .../markup/html/form/ActionsPanel_pt_BR.properties |   4 +
 .../markup/html/form/ActionsPanel_ru.properties    |   4 +
 .../client/console/wizards/any/AbstractAttrs.html  |   9 +-
 ...s.html => AbstractAttrsWizardStep$Schemas.html} |   9 +-
 ...ractAttrs.html => AbstractAttrsWizardStep.html} |   0
 .../any/LinkedAccountCredentialsPanel.html}        |  18 +-
 .../any/LinkedAccountCredentialsPanel.properties}  |   6 +-
 .../LinkedAccountCredentialsPanel_it.properties}   |   6 +-
 .../LinkedAccountCredentialsPanel_ja.properties}   |   6 +-
 ...LinkedAccountCredentialsPanel_pt_BR.properties} |   6 +-
 .../LinkedAccountCredentialsPanel_ru.properties}   |   6 +-
 .../wizards/any/LinkedAccountDetailsPanel.html}    |  18 +-
 .../any/LinkedAccountDetailsPanel.properties}      |   6 +-
 .../any/LinkedAccountDetailsPanel_it.properties}   |   6 +-
 .../any/LinkedAccountDetailsPanel_ja.properties}   |   6 +-
 .../LinkedAccountDetailsPanel_pt_BR.properties}    |   6 +-
 .../any/LinkedAccountDetailsPanel_ru.properties}   |   6 +-
 ...ttrs.html => LinkedAccountPlainAttrsPanel.html} |   9 +-
 .../wizards/any/LinkedAccountPrivilegesPanel.html} |  15 +-
 .../any/LinkedAccountPrivilegesPanel.properties}   |   4 +-
 .../LinkedAccountPrivilegesPanel_it.properties}    |   4 +-
 .../LinkedAccountPrivilegesPanel_ja.properties}    |   4 +-
 .../LinkedAccountPrivilegesPanel_pt_BR.properties} |   4 +-
 .../LinkedAccountPrivilegesPanel_ru.properties}    |   4 +-
 .../apache/syncope/fit/console/PoliciesITCase.java |   4 +-
 .../apache/syncope/fit/console/UsersITCase.java    |   2 +-
 65 files changed, 1846 insertions(+), 508 deletions(-)

diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAditionalActionLinksProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAditionalActionLinksProvider.java
index fd66565..11df282 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAditionalActionLinksProvider.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAditionalActionLinksProvider.java
@@ -20,6 +20,7 @@ package org.apache.syncope.client.console.commons;
 
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.syncope.client.console.panels.LinkedAccountModalPanel;
 import org.apache.syncope.client.console.status.AnyStatusModal;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.Action;
@@ -106,6 +107,26 @@ public class IdMAnyDirectoryPanelAditionalActionLinksProvider
         manageResources.setRealms(realm, modelObject.getDynRealms());
         actions.add(manageResources);
 
+        Action<UserTO> manageAccounts = new Action<>(new ActionLink<UserTO>() {
+
+            private static final long serialVersionUID = 8011039414597736111L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final UserTO ignore) {
+                modal.setFooterVisible(false);
+                target.add(modal.setContent(new LinkedAccountModalPanel(modal, modelObject, pageRef)));
+
+                modal.header(new Model<>(header));
+
+                modal.show(true);
+            }
+        }, ActionLink.ActionType.MANAGE_ACCOUNTS);
+        manageAccounts.setEntitlements(
+                String.format("%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.USER_UPDATE));
+        manageAccounts.setOnConfirm(false);
+        manageAccounts.setRealms(realm, modelObject.getDynRealms());
+        actions.add(manageAccounts);
+
         return actions;
     }
 
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java
index a996c7e..33462a3 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java
@@ -53,6 +53,7 @@ import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
 import org.apache.syncope.common.lib.types.MatchType;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
 import org.apache.syncope.common.rest.api.beans.ReconQuery;
 import org.apache.wicket.Component;
 import org.apache.wicket.PageReference;
@@ -152,7 +153,8 @@ public abstract class ConnObjectListViewPanel extends Panel {
                 if (StringUtils.equals(key, STATUS)) {
                     ReconStatus status = ReconciliationRestClient.status(
                             new ReconQuery.Builder(anyType, resource.getKey()).
-                            connObjectKeyValue(bean.getAttr(ConnIdSpecialName.UID).get().getValues().get(0)).build());
+                                    connObjectKeyValue(bean.getAttr(ConnIdSpecialName.UID).get().getValues().get(0)).
+                                    build());
 
                     return status.getOnSyncope() == null
                             ? StatusUtils.getLabel("field", "notfound icon", "Not found", Constants.NOT_FOUND_ICON)
@@ -283,12 +285,13 @@ public abstract class ConnObjectListViewPanel extends Panel {
             final String cookie,
             final String fiql) {
 
-        Pair<String, List<ConnObjectTO>> items = ResourceRestClient.listConnObjects(resource,
+        Pair<String, List<ConnObjectTO>> items = new ResourceRestClient().searchConnObjects(resource,
                 anyType,
-                SIZE,
-                cookie,
-                new SortParam<>(ConnIdSpecialName.UID, true),
-                fiql);
+                new ConnObjectTOQuery.Builder().
+                        size(SIZE).
+                        pagedResultsCookie(cookie).
+                        fiql(fiql),
+                new SortParam<>(ConnIdSpecialName.UID, true));
 
         nextPageCookie = items.getLeft();
         return items.getRight();
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java
new file mode 100644
index 0000000..a9680e3
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java
@@ -0,0 +1,232 @@
+/*
+ * 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 static org.apache.syncope.client.console.panels.AbstractModalPanel.LOG;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+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.wicket.markup.html.form.ActionLinksTogglePanel;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.client.console.wizards.any.LinkedAccountWizardBuilder;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.request.LinkedAccountUR;
+import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.StringResourceModel;
+
+public class LinkedAccountModalPanel extends AbstractModalPanel<Serializable> {
+
+    private static final long serialVersionUID = -4603032036433309900L;
+
+    private final LinkedAccountWizardBuilder wizard;
+
+    private final WizardMgtPanel<LinkedAccountTO> list;
+
+    private final AjaxLink<LinkedAccountTO> addAjaxLink;
+
+    protected ActionLinksTogglePanel<LinkedAccountTO> actionTogglePanel;
+
+    private UserRestClient userRestClient = new UserRestClient();
+
+    private final List<LinkedAccountTO> linkedAccountTOs;
+
+    @SuppressWarnings("unchecked")
+    public LinkedAccountModalPanel(
+            final BaseModal<?> modal,
+            final UserTO userTO,
+            final PageReference pageRef) {
+
+        super((BaseModal<Serializable>) modal, pageRef);
+
+        UserTO readUserTO = userRestClient.read(userTO.getKey());
+
+        setOutputMarkupId(true);
+
+        actionTogglePanel = new ActionLinksTogglePanel<>("toggle", pageRef);
+        add(actionTogglePanel);
+
+        wizard = new LinkedAccountWizardBuilder(readUserTO.getKey(), pageRef);
+
+        final ListViewPanel.Builder<LinkedAccountTO> builder = new ListViewPanel.Builder<LinkedAccountTO>(
+                LinkedAccountTO.class, pageRef) {
+
+            private static final long serialVersionUID = -5322423525438435153L;
+
+            @Override
+            protected LinkedAccountTO getActualItem(
+                    final LinkedAccountTO item, final List<LinkedAccountTO> list) {
+
+                return item == null
+                        ? null
+                        : list.stream().filter(
+                                in -> ((item.getKey() == null && in.getKey() == null)
+                                || (in.getKey() != null && in.getKey().
+                                equals(item.getKey())))).findAny().orElse(null);
+            }
+
+            @Override
+            protected void customActionCallback(final AjaxRequestTarget target) {
+                // change modal footer visibility
+                send(LinkedAccountModalPanel.this, Broadcast.BUBBLE, new BaseModal.ChangeFooterVisibilityEvent(target));
+            }
+
+            @Override
+            protected void customActionOnCancelCallback(final AjaxRequestTarget target) {
+                // change modal footer visibility
+                send(LinkedAccountModalPanel.this, Broadcast.BUBBLE, new BaseModal.ChangeFooterVisibilityEvent(target));
+            }
+
+            @Override
+            @SuppressWarnings("unchecked")
+            protected void customActionOnFinishCallback(final AjaxRequestTarget target) {
+                checkAddButton();
+
+                linkedAccountTOs.clear();
+                linkedAccountTOs.addAll(userRestClient.read(userTO.getKey()).getLinkedAccounts());
+                sortLinkedAccounts();
+
+                ListViewPanel.class.cast(list).refreshList(linkedAccountTOs);
+
+                // change modal footer visibility
+                send(LinkedAccountModalPanel.this, Broadcast.BUBBLE, new BaseModal.ChangeFooterVisibilityEvent(target));
+            }
+
+            @Override
+            protected ActionLinksTogglePanel<LinkedAccountTO> getTogglePanel() {
+                return actionTogglePanel;
+            }
+        };
+
+        linkedAccountTOs = new ArrayList<>(readUserTO.getLinkedAccounts());
+        sortLinkedAccounts();
+
+        builder.setItems(linkedAccountTOs);
+        builder.includes("connObjectKeyValue", "resource", "suspended");
+        builder.setReuseItem(false);
+        builder.withChecks(ListViewPanel.CheckAvailability.NONE);
+
+        builder.addAction(new ActionLink<LinkedAccountTO>() {
+
+            private static final long serialVersionUID = 2555747430358755813L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) {
+                try {
+                    send(LinkedAccountModalPanel.this, Broadcast.DEPTH,
+                            new AjaxWizard.NewItemActionEvent<>(linkedAccountTO, 1, target).setResourceModel(
+                                    new StringResourceModel("inner.edit.linkedAccount",
+                                            LinkedAccountModalPanel.this,
+                                            Model.of(linkedAccountTO))));
+                } catch (SyncopeClientException e) {
+                    LOG.error("While contacting linked account", e);
+                    SyncopeConsoleSession.get().error(
+                            StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+                    ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                }
+
+                send(LinkedAccountModalPanel.this, Broadcast.BREADTH,
+                        new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target));
+            }
+        }, ActionLink.ActionType.EDIT, IdRepoEntitlement.USER_READ).
+                addAction(new ActionLink<LinkedAccountTO>() {
+
+                    private static final long serialVersionUID = 2555747430358755813L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) {
+                        try {
+                            LinkedAccountUR linkedAccountPatch = new LinkedAccountUR.Builder().
+                                    operation(PatchOperation.DELETE).
+                                    linkedAccountTO(linkedAccountTO).build();
+                            linkedAccountPatch.setLinkedAccountTO(linkedAccountTO);
+                            UserUR patch = new UserUR();
+                            patch.setKey(readUserTO.getKey());
+                            patch.getLinkedAccounts().add(linkedAccountPatch);
+                            userRestClient.update(userRestClient.read(userTO.getKey()).getETagValue(), patch);
+                            linkedAccountTOs.remove(linkedAccountTO);
+
+                            SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                        } catch (Exception e) {
+                            LOG.error("While removing linked account {}", linkedAccountTO.getKey(), e);
+                            SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                                    ? e.getClass().getName() : e.getMessage());
+                        }
+
+                        checkAddButton();
+                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                        send(LinkedAccountModalPanel.this, Broadcast.DEPTH, new ListViewPanel.ListViewReload<>(target));
+                    }
+                }, ActionLink.ActionType.DELETE, IdRepoEntitlement.USER_UPDATE, true);
+
+        builder.addNewItemPanelBuilder(wizard);
+
+        list = builder.build("linkedAccountsList");
+        list.setOutputMarkupId(true);
+        list.setReadOnly(!SyncopeConsoleSession.get().owns(IdRepoEntitlement.USER_UPDATE));
+
+        addAjaxLink = new AjaxLink<LinkedAccountTO>("add") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                send(LinkedAccountModalPanel.this, Broadcast.BREADTH,
+                        new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target));
+
+                // this opens the wizard (set above) in CREATE mode
+                send(list, Broadcast.DEPTH, new AjaxWizard.NewItemActionEvent<>(new LinkedAccountTO(), target).
+                        setResourceModel(new StringResourceModel("inner.create.linkedAccount",
+                                LinkedAccountModalPanel.this)));
+            }
+        };
+        list.addOrReplaceInnerObject(addAjaxLink);
+        add(list);
+    }
+
+    private void sortLinkedAccounts() {
+        Collections.sort(linkedAccountTOs,
+                (o1, o2) -> AnyTypeRestClient.KEY_COMPARATOR.compare(
+                        o1.getConnObjectKeyValue(), o2.getConnObjectKeyValue()));
+    }
+
+    private void checkAddButton() {
+        addAjaxLink.setVisible(SyncopeConsoleSession.get().owns(IdRepoEntitlement.USER_UPDATE));
+    }
+
+}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
index 4174391..92f79f3 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java
@@ -55,26 +55,21 @@ public class ResourceRestClient extends BaseRestClient {
         return getService(ResourceService.class).readConnObject(resource, anyTypeKey, anyKey);
     }
 
-    public static Pair<String, List<ConnObjectTO>> listConnObjects(
+    public Pair<String, List<ConnObjectTO>> searchConnObjects(
             final String resource,
             final String anyTypeKey,
-            final int size,
-            final String pagedResultCookie,
-            final SortParam<String> sort,
-            final String fiql) {
-
-        ConnObjectTOQuery.Builder builder = new ConnObjectTOQuery.Builder().
-                pagedResultsCookie(pagedResultCookie).
-                size(size).
-                orderBy(toOrderBy(sort)).
-                fiql(fiql);
+            final ConnObjectTOQuery.Builder queryBuilder,
+            final SortParam<String> sortParam) {
 
         final List<ConnObjectTO> result = new ArrayList<>();
         String nextPageResultCookie = null;
 
         PagedConnObjectTOResult list;
         try {
-            list = getService(ResourceService.class).searchConnObjects(resource, anyTypeKey, builder.build());
+            if (sortParam != null) {
+                queryBuilder.orderBy(toOrderBy(sortParam));
+            }
+            list = getService(ResourceService.class).searchConnObjects(resource, anyTypeKey, queryBuilder.build());
             result.addAll(list.getResult());
             nextPageResultCookie = list.getPagedResultsCookie();
         } catch (Exception e) {
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.java
new file mode 100644
index 0000000..4ae7049
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.java
@@ -0,0 +1,125 @@
+/*
+ * 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.any;
+
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggle;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggleConfig;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.syncope.client.console.commons.LinkedAccountPlainAttrProperty;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class LinkedAccountCredentialsPanel extends WizardStep {
+
+    private static final long serialVersionUID = 5116461957402341603L;
+
+    public LinkedAccountCredentialsPanel(final LinkedAccountTO linkedAccountTO) {
+        super();
+        setOutputMarkupId(true);
+
+        AjaxTextFieldPanel usernameField = new AjaxTextFieldPanel(
+                "username",
+                "username",
+                new PropertyModel<>(linkedAccountTO, "username"),
+                false);
+        usernameField.setOutputMarkupId(true);
+        FieldPanel.class.cast(usernameField).setReadOnly(true);
+        LinkedAccountPlainAttrProperty property = new LinkedAccountPlainAttrProperty();
+        property.setOverridable(false);
+        property.setSchema("username");
+        property.getValues().add(linkedAccountTO.getUsername());
+        usernameField.showExternAction(checkboxToggle(property, usernameField));
+        add(usernameField);
+
+        AjaxPasswordFieldPanel passwordField = new AjaxPasswordFieldPanel(
+                "password",
+                "password",
+                new PropertyModel<>(linkedAccountTO, "password"));
+        passwordField.setOutputMarkupId(true);
+        passwordField.setRequired(true);
+        passwordField.setMarkupId("password");
+        FieldPanel.class.cast(passwordField).setReadOnly(true);
+        property = new LinkedAccountPlainAttrProperty();
+        property.setOverridable(false);
+        property.setSchema("password");
+        property.getValues().add(linkedAccountTO.getPassword());
+        passwordField.showExternAction(checkboxToggle(property, passwordField));
+        ((PasswordTextField) passwordField.getField()).setResetPassword(true);
+        add(passwordField);
+    }
+
+    private FormComponent<?> checkboxToggle(
+            final LinkedAccountPlainAttrProperty property, final FieldPanel<?> panel) {
+
+        final BootstrapToggleConfig config = new BootstrapToggleConfig().
+                withOnStyle(BootstrapToggleConfig.Style.success).
+                withOffStyle(BootstrapToggleConfig.Style.danger).
+                withSize(BootstrapToggleConfig.Size.mini);
+
+        return new BootstrapToggle("externalAction", new PropertyModel<Boolean>(property, "overridable"), config) {
+
+            private static final long serialVersionUID = -875219845189261873L;
+
+            @Override
+            protected CheckBox newCheckBox(final String id, final IModel<Boolean> model) {
+                final CheckBox checkBox = super.newCheckBox(id, model);
+                checkBox.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                    private static final long serialVersionUID = -1107858522700306810L;
+
+                    @Override
+                    protected void onUpdate(final AjaxRequestTarget target) {
+                        panel.setReadOnly(!model.getObject());
+                        target.add(panel);
+                    }
+                });
+                return checkBox;
+            }
+
+            @Override
+            protected IModel<String> getOnLabel() {
+                return Model.of("Override");
+            }
+
+            @Override
+            protected IModel<String> getOffLabel() {
+                return Model.of("Override?");
+            }
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+                tag.append("class", "overridable", " ");
+            }
+        };
+    }
+
+}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java
new file mode 100644
index 0000000..cccf7b8
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java
@@ -0,0 +1,188 @@
+/*
+ * 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.any;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.commons.ConnIdSpecialName;
+import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.ajax.attributes.ThrottlingSettings;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LinkedAccountDetailsPanel extends WizardStep {
+
+    private static final long serialVersionUID = 1221037007528732347L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(LinkedAccountDetailsPanel.class);
+
+    private static final int SEARCH_SIZE = 20;
+
+    private final ResourceRestClient resourceRestClient = new ResourceRestClient();
+
+    private ArrayList<String> connObjectKeyFieldValues;
+
+    public LinkedAccountDetailsPanel(final LinkedAccountTO linkedAccountTO) {
+        super();
+        setOutputMarkupId(true);
+
+        AjaxDropDownChoicePanel<String> dropdownResourceField = new AjaxDropDownChoicePanel<>(
+                "resource",
+                "resource",
+                new PropertyModel<>(linkedAccountTO, "resource"),
+                false);
+        dropdownResourceField.setChoices(resourceRestClient.list().stream().
+                filter(resource -> resource.getProvision(AnyTypeKind.USER.name()).isPresent()
+                && resource.getProvision(AnyTypeKind.USER.name()).get().getMapping() != null
+                && !resource.getProvision(AnyTypeKind.USER.name()).get().getMapping().getItems().isEmpty()).
+                map(resource -> resource.getKey()).
+                collect(Collectors.toList()));
+        dropdownResourceField.setOutputMarkupId(true);
+        dropdownResourceField.addRequiredLabel();
+        dropdownResourceField.setNullValid(false);
+        dropdownResourceField.setRequired(true);
+        add(dropdownResourceField);
+
+        final String connObjectKeyFieldId = "connObjectKeyValue";
+        AjaxTextFieldPanel connObjectKeyField = new AjaxTextFieldPanel(
+                "connObjectKeyValue",
+                "connObjectKeyValue",
+                new PropertyModel<>(linkedAccountTO, "connObjectKeyValue"),
+                false);
+        connObjectKeyField.setOutputMarkupId(true);
+        connObjectKeyField.addRequiredLabel();
+        connObjectKeyField.setChoices(Collections.<String>emptyList());
+        connObjectKeyField.setEnabled(false);
+        add(connObjectKeyField);
+
+        dropdownResourceField.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                boolean enabled = dropdownResourceField.getModelObject() != null
+                        && !dropdownResourceField.getModelObject().isEmpty();
+                connObjectKeyField.setEnabled(enabled);
+                if (enabled) {
+                    setConnObjectFieldChoices(connObjectKeyField, dropdownResourceField.getModelObject(), null);
+                }
+                target.add(connObjectKeyField);
+            }
+        });
+
+        connObjectKeyField.getField().setMarkupId(connObjectKeyFieldId);
+        connObjectKeyField.getField().add(new AjaxEventBehavior(Constants.ON_KEYDOWN) {
+
+            private static final long serialVersionUID = 3533589614190959822L;
+
+            @Override
+            protected void onEvent(final AjaxRequestTarget target) {
+                String searchTerm = connObjectKeyField.getField().getInput();
+                if (StringUtils.isNotBlank(searchTerm) && searchTerm.length() > 1) {
+                    setConnObjectFieldChoices(connObjectKeyField, dropdownResourceField.getModelObject(), searchTerm);
+
+                    // If elements are found, send an "arrow down" key event to open input autocomplete dropdown
+                    target.appendJavaScript(connObjectKeyFieldValues.isEmpty()
+                            ? "$('#" + connObjectKeyFieldId + "-autocomplete-container').hide();"
+                            : "var simulatedEvent = new KeyboardEvent('keydown', {keyCode: 40, which: 40}); "
+                            + "document.getElementById('" + connObjectKeyFieldId + "').dispatchEvent(simulatedEvent);");
+                }
+            }
+
+            @Override
+            protected void updateAjaxAttributes(final AjaxRequestAttributes attributes) {
+                super.updateAjaxAttributes(attributes);
+
+                AjaxCallListener listener = new AjaxCallListener() {
+
+                    private static final long serialVersionUID = 2208168001920794667L;
+
+                    @Override
+                    public CharSequence getPrecondition(final Component component) {
+                        // Eevaluates weather an ajax call will be executed or not.
+                        // If the key code is "arrow down" or "arrow up" do NOT trigger the event callback
+                        return "var keycode = Wicket.Event.keyCode(attrs.event); "
+                                + "if ((keycode == 40) || (keycode == 38)) {return false;} return true;";
+                    }
+                };
+                attributes.getAjaxCallListeners().add(listener);
+                attributes.setThrottlingSettings(new ThrottlingSettings("id", Duration.seconds(1.2), true));
+            }
+        });
+    }
+
+    private void setConnObjectFieldChoices(
+            final AjaxTextFieldPanel ajaxTextFieldPanel,
+            final String resource,
+            final String searchTerm) {
+
+        Set<String> choices = new HashSet<>();
+        String resourceRemoteKey = ConnIdSpecialName.NAME;
+        try {
+            resourceRemoteKey = resourceRestClient.read(resource).getProvision(AnyTypeKind.USER.name()).get().
+                    getMapping().getConnObjectKeyItem().getExtAttrName();
+        } catch (Exception ex) {
+            LOG.error("While reading mapping for resource {}", resource, ex);
+        }
+
+        ConnObjectTOQuery.Builder builder = new ConnObjectTOQuery.Builder().size(SEARCH_SIZE);
+        if (StringUtils.isNotBlank(searchTerm)) {
+            builder.fiql(SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
+                    is(resourceRemoteKey).equalTo(searchTerm + "*").query()).build();
+        }
+        Pair<String, List<ConnObjectTO>> items = resourceRestClient.searchConnObjects(resource,
+                AnyTypeKind.USER.name(),
+                builder,
+                new SortParam<>(resourceRemoteKey, true));
+
+        choices.addAll(items.getRight().stream().map(item -> {
+            return item.getAttr(ConnIdSpecialName.UID).get().getValues().get(0);
+        }).collect(Collectors.toSet()));
+
+        connObjectKeyFieldValues = new ArrayList<>(choices);
+        Collections.sort(connObjectKeyFieldValues);
+        ajaxTextFieldPanel.setChoices(connObjectKeyFieldValues);
+    }
+
+}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java
new file mode 100644
index 0000000..cac1afb
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java
@@ -0,0 +1,255 @@
+/*
+ * 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.any;
+
+import org.apache.syncope.client.ui.commons.wizards.any.EntityWrapper;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggle;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.checkbox.bootstraptoggle.BootstrapToggleConfig;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import org.apache.syncope.common.lib.EntityTOUtils;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.client.console.commons.LinkedAccountPlainAttrProperty;
+import org.apache.syncope.client.ui.commons.Constants;
+import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
+import org.apache.syncope.client.ui.commons.wicket.markup.html.bootstrap.tabs.Accordion;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.common.lib.Attr;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.FormComponent;
+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.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class LinkedAccountPlainAttrsPanel extends AbstractAttrsWizardStep<PlainSchemaTO> {
+
+    private static final long serialVersionUID = -6664931684253730934L;
+
+    private final LinkedAccountTO linkedAccountTO;
+
+    private final UserTO userTO;
+
+    private final Set<Attr> fixedAttrs = new HashSet<>();
+
+    private final List<LinkedAccountPlainAttrProperty> accountPlainAttrProperties = new ArrayList<>();
+
+    public <T extends AnyTO> LinkedAccountPlainAttrsPanel(
+            final EntityWrapper<LinkedAccountTO> modelObject,
+            final UserTO userTO) throws IllegalArgumentException {
+
+        super(userTO,
+                AjaxWizard.Mode.EDIT,
+                new AnyTypeRestClient().read(userTO.getType()).getClasses(),
+                FormLayoutInfoUtils.fetch(Arrays.asList(userTO.getType())).getLeft().getWhichPlainAttrs(),
+                modelObject);
+
+        this.linkedAccountTO = modelObject.getInnerObject();
+        this.fixedAttrs.addAll(this.linkedAccountTO.getPlainAttrs());
+        this.userTO = userTO;
+
+        add(new Accordion("plainSchemas", Collections.<ITab>singletonList(new AbstractTab(
+                new ResourceModel("attributes.accordion", "Plain Attributes")) {
+
+            private static final long serialVersionUID = -7078941093668723016L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new PlainSchemasOwn(panelId, schemas, attrs);
+            }
+        }), Model.of(0)).setOutputMarkupId(true));
+    }
+
+    @Override
+    protected FormComponent<?> checkboxToggle(
+            final Attr attrTO,
+            final AbstractFieldPanel<?> panel,
+            final boolean isMultivalue) {
+
+        LinkedAccountPlainAttrProperty property = accountPlainAttrProperties.stream().filter(
+                existingProperty -> {
+                    return existingProperty.getSchema().equals(attrTO.getSchema());
+                }).findFirst().orElseGet(() -> {
+                    LinkedAccountPlainAttrProperty newProperty = new LinkedAccountPlainAttrProperty();
+                    newProperty.setOverridable(linkedAccountTO.getPlainAttr(attrTO.getSchema()).isPresent());
+                    newProperty.setSchema(attrTO.getSchema());
+                    newProperty.getValues().addAll(attrTO.getValues());
+                    accountPlainAttrProperties.add(newProperty);
+                    return newProperty;
+                });
+
+        final BootstrapToggleConfig config = new BootstrapToggleConfig().
+                withOnStyle(BootstrapToggleConfig.Style.success).
+                withOffStyle(BootstrapToggleConfig.Style.danger).
+                withSize(BootstrapToggleConfig.Size.mini);
+
+        return new BootstrapToggle("externalAction", new PropertyModel<Boolean>(property, "overridable"), config) {
+
+            private static final long serialVersionUID = -875219845189261873L;
+
+            @Override
+            protected CheckBox newCheckBox(final String id, final IModel<Boolean> model) {
+                final CheckBox checkBox = super.newCheckBox(id, model);
+                checkBox.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                    private static final long serialVersionUID = -1107858522700306810L;
+
+                    @Override
+                    protected void onUpdate(final AjaxRequestTarget target) {
+                        if (isMultivalue) {
+                            MultiFieldPanel.class.cast(panel).setFormReadOnly(!model.getObject());
+                        } else {
+                            FieldPanel.class.cast(panel).setReadOnly(!model.getObject());
+                        }
+
+                        updateAccountPlainSchemas(property, model.getObject());
+                        target.add(panel);
+                    }
+                });
+                return checkBox;
+            }
+
+            @Override
+            protected IModel<String> getOnLabel() {
+                return Model.of("Override");
+            }
+
+            @Override
+            protected IModel<String> getOffLabel() {
+                return Model.of("Override?");
+            }
+
+            @Override
+            protected void onComponentTag(final ComponentTag tag) {
+                super.onComponentTag(tag);
+                tag.append("class", "overridable", " ");
+            }
+        };
+    }
+
+    private void updateAccountPlainSchemas(final LinkedAccountPlainAttrProperty property, final Boolean modelObject) {
+        Set<Attr> withoutCurrentSChema = new HashSet<>(linkedAccountTO.getPlainAttrs().stream().
+                filter(attr -> !attr.getSchema().equals(property.getSchema())).
+                collect(Collectors.toSet()));
+        linkedAccountTO.getPlainAttrs().clear();
+        linkedAccountTO.getPlainAttrs().addAll(withoutCurrentSChema);
+        if (modelObject) {
+            linkedAccountTO.getPlainAttrs().add(
+                    fixedAttrs.stream().filter(attrTO -> attrTO.getSchema().equals(property.getSchema())).findFirst().
+                            orElseGet(() -> new Attr.Builder(property.getSchema()).
+                            values(property.getValues()).build()));
+        }
+    }
+
+    @Override
+    protected SchemaType getSchemaType() {
+        return SchemaType.PLAIN;
+    }
+
+    @Override
+    protected void setAttrs() {
+        List<Attr> attrs = new ArrayList<>();
+        setFixedAttr(schemas.values());
+        Map<String, Attr> attrMap = EntityTOUtils.buildAttrMap(fixedAttrs);
+
+        attrs.addAll(schemas.values().stream().map(schema -> {
+            Attr attrTO = new Attr();
+            attrTO.setSchema(schema.getKey());
+            if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) {
+                attrTO.getValues().add("");
+            } else {
+                attrTO = attrMap.get(schema.getKey());
+            }
+            return attrTO;
+        }).collect(Collectors.toList()));
+
+        fixedAttrs.clear();
+        fixedAttrs.addAll(attrs);
+    }
+
+    @Override
+    protected List<Attr> getAttrsFromTO() {
+        return fixedAttrs.stream().sorted(attrComparator).collect(Collectors.toList());
+    }
+
+    private void setFixedAttr(final Collection<PlainSchemaTO> values) {
+        values.forEach(schema -> {
+            if (linkedAccountTO.getPlainAttr(schema.getKey()).isPresent()) {
+                fixedAttrs.add(linkedAccountTO.getPlainAttr(schema.getKey()).get());
+            } else if (userTO.getPlainAttr(schema.getKey()).isPresent()) {
+                fixedAttrs.add(userTO.getPlainAttr(schema.getKey()).get());
+            }
+        });
+    }
+
+    private class PlainSchemasOwn extends PlainSchemas<List<Attr>> {
+
+        private static final long serialVersionUID = -4730563859116024676L;
+
+        PlainSchemasOwn(
+                final String id,
+                final Map<String, PlainSchemaTO> schemas,
+                final IModel<List<Attr>> attrTOs) {
+
+            super(id, schemas, attrTOs);
+
+            add(new ListView<Attr>("schemas", attrTOs) {
+
+                private static final long serialVersionUID = 9101744072914090143L;
+
+                @Override
+                protected void populateItem(final ListItem<Attr> item) {
+                    Attr attrTO = item.getModelObject();
+                    final boolean isMultivalue = schemas.get(attrTO.getSchema()).isMultivalue();
+
+                    AbstractFieldPanel<?> panel = setPanel(
+                            schemas,
+                            item,
+                            !linkedAccountTO.getPlainAttr(attrTO.getSchema()).isPresent());
+
+                    panel.showExternAction(checkboxToggle(attrTO, panel, isMultivalue));
+                }
+            });
+        }
+    }
+
+}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java
new file mode 100644
index 0000000..c33351a
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java
@@ -0,0 +1,66 @@
+/*
+ * 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.any;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.syncope.client.console.rest.ApplicationRestClient;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class LinkedAccountPrivilegesPanel extends WizardStep {
+
+    private static final long serialVersionUID = 3388483585148725922L;
+
+    private final ApplicationRestClient applicationRestClient = new ApplicationRestClient();
+
+    public LinkedAccountPrivilegesPanel(final LinkedAccountTO linkedAccountTO) {
+        super();
+        setOutputMarkupId(true);
+
+        final LoadableDetachableModel<List<String>> availablePrivilges = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                return applicationRestClient.list().stream().
+                        flatMap(app -> app.getPrivileges().stream()).
+                        map(privilege -> privilege.getKey()).
+                        distinct().
+                        sorted().
+                        collect(Collectors.toList());
+            }
+        };
+        AjaxPalettePanel<String> privilegesPanel = new AjaxPalettePanel.Builder<String>().
+                setAllowOrder(true).
+                setAllowMoveAll(true).
+                build("privileges",
+                        new PropertyModel<>(linkedAccountTO, "privileges"),
+                        new ListModel<>(availablePrivilges.getObject()));
+        privilegesPanel.hideLabel();
+        privilegesPanel.setOutputMarkupId(true);
+        add(privilegesPanel);
+    }
+
+}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java
new file mode 100644
index 0000000..371ab09
--- /dev/null
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java
@@ -0,0 +1,131 @@
+/*
+ * 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.any;
+
+import org.apache.syncope.client.ui.commons.wizards.any.EntityWrapper;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal.ModalEvent;
+import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.common.lib.Attr;
+import org.apache.syncope.common.lib.request.LinkedAccountUR;
+import org.apache.syncope.common.lib.request.UserUR;
+import org.apache.syncope.common.lib.to.LinkedAccountTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.wizard.WizardModel;
+
+/**
+ * Accounts wizard builder.
+ */
+public class LinkedAccountWizardBuilder extends BaseAjaxWizardBuilder<LinkedAccountTO> {
+
+    private static final long serialVersionUID = -9142332740863374891L;
+
+    private final UserRestClient userRestClient = new UserRestClient();
+
+    private UserTO userTO;
+
+    private final String userKey;
+
+    public LinkedAccountWizardBuilder(final String userKey, final PageReference pageRef) {
+        super(new LinkedAccountTO(), pageRef);
+        this.userKey = userKey;
+        this.userTO = userRestClient.read(userKey);
+    }
+
+    @Override
+    public AjaxWizard<LinkedAccountTO> build(final String id, final AjaxWizard.Mode mode) {
+        this.userTO = userRestClient.read(userKey);
+        return super.build(id, mode);
+    }
+
+    @Override
+    protected WizardModel buildModelSteps(final LinkedAccountTO modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new LinkedAccountDetailsPanel(modelObject));
+        wizardModel.add(new LinkedAccountCredentialsPanel(modelObject));
+        wizardModel.add(new LinkedAccountPlainAttrsPanel(new EntityWrapper<>(modelObject), userTO));
+        wizardModel.add(new LinkedAccountPrivilegesPanel(modelObject));
+        return wizardModel;
+    }
+
+    @Override
+    protected Serializable onApplyInternal(final LinkedAccountTO modelObject) {
+        fixPlainAttrs(modelObject);
+
+        LinkedAccountUR linkedAccountPatch = new LinkedAccountUR.Builder().linkedAccountTO(modelObject).build();
+        linkedAccountPatch.setLinkedAccountTO(modelObject);
+        UserUR patch = new UserUR();
+        patch.setKey(userTO.getKey());
+        patch.getLinkedAccounts().add(linkedAccountPatch);
+        userRestClient.update(userTO.getETagValue(), patch);
+
+        return modelObject;
+    }
+
+    private void fixPlainAttrs(final LinkedAccountTO linkedAccountTO) {
+        Set<Attr> validAttrs = new HashSet<>(linkedAccountTO.getPlainAttrs().stream().
+                filter(attr -> !attr.getValues().isEmpty()).
+                collect(Collectors.toSet()));
+        linkedAccountTO.getPlainAttrs().clear();
+        linkedAccountTO.getPlainAttrs().addAll(validAttrs);
+    }
+
+    @Override
+    protected Serializable getCreateCustomPayloadEvent(final Serializable afterObject, final AjaxRequestTarget target) {
+        LinkedAccountTO linkedAccountTO = LinkedAccountTO.class.cast(afterObject);
+        return new CreateEvent(
+                linkedAccountTO.getConnObjectKeyValue(),
+                userTO,
+                target);
+    }
+
+    private static class CreateEvent extends ModalEvent {
+
+        private static final long serialVersionUID = 6416834092156281986L;
+
+        private final String key;
+
+        private final UserTO userTO;
+
+        CreateEvent(
+                final String key,
+                final UserTO userTO,
+                final AjaxRequestTarget target) {
+
+            super(target);
+            this.key = key;
+            this.userTO = userTO;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public UserTO getUserTO() {
+            return userTO;
+        }
+    }
+
+}
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
index e2da0f2..97c6734 100644
--- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
+++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
@@ -23,7 +23,7 @@ under the License.
     </div>
 
     <div class="form-group">
-      <span wicket:id="capabilities">[capabilitiesOverride]</span>
+      <span wicket:id="capabilities">[capabilities]</span>
     </div>
   </wicket:panel>
 </html>
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
index 579db02..4f3a090 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java
@@ -57,6 +57,8 @@ public final class Constants {
 
     public static final String ON_CHANGE = "change";
 
+    public static final String ON_KEYDOWN = "keydown";
+
     public static final String ON_BLUR = "blur";
 
     public static final String PNG_EXT = ".png";
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractFieldPanel.java
index f9c2878..30dfe7f 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractFieldPanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractFieldPanel.java
@@ -122,4 +122,6 @@ public abstract class AbstractFieldPanel<T> extends Panel {
     public String getName() {
         return this.name;
     }
+
+    public abstract AbstractFieldPanel<T> setReadOnly(boolean readOnly);
 }
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java
index e4eb01a..3079bf6 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java
@@ -205,4 +205,9 @@ public abstract class AbstractMultiPanel<INNER> extends AbstractFieldPanel<List<
         container.setEnabled(!readOnly);
         return this;
     }
+
+    public AbstractFieldPanel<List<INNER>> setFormReadOnly(final boolean readOnly) {
+        form.setEnabled(!readOnly);
+        return this;
+    }
 }
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPalettePanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPalettePanel.java
index 5af8052..818dd77 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPalettePanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPalettePanel.java
@@ -197,6 +197,12 @@ public class AjaxPalettePanel<T extends Serializable> extends AbstractFieldPanel
         target.add(palette);
     }
 
+    @Override
+    public AbstractFieldPanel<List<T>> setReadOnly(final boolean readOnly) {
+        palette.setEnabled(!readOnly);
+        return this;
+    }
+
     public static class Builder<T extends Serializable> implements Serializable {
 
         private static final long serialVersionUID = 991248996001040352L;
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java
index 3074dbf..acb92a3 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java
@@ -48,6 +48,8 @@ public final class AjaxSpinnerFieldPanel<T extends Number> extends FieldPanel<T>
 
     private final Options options;
 
+    private SpinnerBehavior behavior;
+
     private AjaxSpinnerFieldPanel(
             final String id,
             final String name,
@@ -64,7 +66,7 @@ public final class AjaxSpinnerFieldPanel<T extends Number> extends FieldPanel<T>
 
             @Override
             public JQueryUIBehavior newWidgetBehavior(final String selector) {
-                SpinnerBehavior behavior = new SpinnerBehavior(selector, new SpinnerAdapter());
+                behavior = new SpinnerBehavior(selector, new SpinnerAdapter());
                 behavior.setOptions(options);
                 return behavior;
             }
@@ -229,6 +231,17 @@ public final class AjaxSpinnerFieldPanel<T extends Number> extends FieldPanel<T>
         return panel;
     }
 
+    @Override
+    public FieldPanel<T> setReadOnly(final boolean readOnly) {
+        super.setReadOnly(readOnly);
+        AjaxSpinner.class.cast(field).setEnabled(!readOnly);
+        options.set("disabled", readOnly);
+        if (behavior != null) {
+            behavior.setOptions(options);
+        }
+        return this;
+    }
+
     public static class Builder<T extends Number> {
 
         private final Options options = new Options();
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
index 3aecf67..9a72010 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizardBuilder.java
@@ -88,7 +88,7 @@ public abstract class AjaxWizardBuilder<T extends Serializable> extends Abstract
         // get the specified item if available
         final T modelObject = newModelObject();
 
-        return new AjaxWizard<T>(id, modelObject, buildModelSteps(modelObject, new WizardModel()), mode, this.pageRef) {
+        return new AjaxWizard<T>(id, modelObject, buildModelSteps(modelObject, new WizardModel()), mode, pageRef) {
 
             private static final long serialVersionUID = 7770507663760640735L;
 
@@ -170,7 +170,7 @@ public abstract class AjaxWizardBuilder<T extends Serializable> extends Abstract
      * @return payload to be sent.
      */
     protected static Serializable getEditCustomPayloadEvent(final Serializable afterObject,
-                                                            final AjaxRequestTarget target) {
+            final AjaxRequestTarget target) {
         return null;
     }
 }
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java
new file mode 100644
index 0000000..6764049
--- /dev/null
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java
@@ -0,0 +1,35 @@
+/*
+ * 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.ui.commons.wizards.any;
+
+import org.apache.syncope.common.lib.to.EntityTO;
+
+public class EntityWrapper<T extends EntityTO> {
+
+    protected final T entityTO;
+
+    public EntityWrapper(final T entityTO) {
+        this.entityTO = entityTO;
+    }
+
+    public T getInnerObject() {
+        return entityTO;
+    }
+
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/LinkedAccountPlainAttrProperty.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/LinkedAccountPlainAttrProperty.java
new file mode 100644
index 0000000..3f0468a
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/LinkedAccountPlainAttrProperty.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+@XmlRootElement
+@XmlType
+public class LinkedAccountPlainAttrProperty implements Serializable, Comparable<LinkedAccountPlainAttrProperty> {
+
+    private static final long serialVersionUID = -5309050337675968950L;
+
+    private String schema;
+
+    private final List<String> values = new ArrayList<>();
+
+    private boolean overridable;
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(final String schema) {
+        this.schema = schema;
+    }
+
+    @XmlElementWrapper(name = "values")
+    @XmlElement(name = "value")
+    @JsonProperty("values")
+    public List<String> getValues() {
+        return values;
+    }
+
+    public boolean isOverridable() {
+        return overridable;
+    }
+
+    public void setOverridable(final boolean overridable) {
+        this.overridable = overridable;
+    }
+
+    @Override
+    public int compareTo(final LinkedAccountPlainAttrProperty connConfProperty) {
+        return ObjectUtils.compare(this.getSchema(), connConfProperty.getSchema());
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().
+                append(schema).
+                append(values).
+                append(overridable).
+                build();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final LinkedAccountPlainAttrProperty other = (LinkedAccountPlainAttrProperty) obj;
+        return new EqualsBuilder().
+                append(schema, other.schema).
+                append(values, other.values).
+                append(overridable, other.overridable).
+                build();
+    }
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
index 099d8a8..fbcd14b 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
@@ -227,6 +227,15 @@ 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
+     */
+    public void refreshList(final List<T> elements) {
+        beans.setList(elements);
+    }
+
     public void setCheckAvailability(final CheckAvailability check) {
         // used to perform selectable enabling check condition
         this.check.setObject(check);
@@ -384,8 +393,8 @@ public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPan
             LOG.debug("Field value {}", value);
 
             return Optional.ofNullable(value)
-                .map(o -> new Label("field", new ResourceModel(o.toString(), o.toString())))
-                .orElseGet(() -> new Label("field", StringUtils.EMPTY));
+                    .map(o -> new Label("field", new ResourceModel(o.toString(), o.toString())))
+                    .orElseGet(() -> new Label("field", StringUtils.EMPTY));
         }
 
         protected T getActualItem(final T item, final List<T> list) {
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index f37e91b..5416be7 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -97,6 +97,7 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
         MANAGE_RESOURCES("update"),
         MANAGE_USERS("update"),
         MANAGE_GROUPS("update"),
+        MANAGE_ACCOUNTS("update"),
         PROPAGATION_TASKS("read"),
         NOTIFICATION_TASKS("read"),
         ZOOM_IN("zoomin"),
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
index 4a98a4e..3d2a0c2 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
@@ -305,4 +305,11 @@ public class BinaryFieldPanel extends BaseBinaryFieldPanel {
     protected Integer getMaxUploadFileSizeMB() {
         return SyncopeWebApplication.get().getMaxUploadFileSizeMB();
     }
+
+    @Override
+    public FieldPanel<String> setReadOnly(final boolean readOnly) {
+        super.setReadOnly(readOnly);
+        fileUpload.setEnabled(!readOnly);
+        return this;
+    }
 }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
index 920afb3..c4638c3 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
@@ -18,84 +18,49 @@
  */
 package org.apache.syncope.client.console.wizards.any;
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.cxf.common.util.StringUtils;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.rest.GroupRestClient;
-import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
 import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
 import org.apache.syncope.common.lib.to.SchemaTO;
-import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.Attr;
 import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
-import org.apache.syncope.common.lib.types.SchemaType;
-import org.apache.wicket.PageReference;
 import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.core.util.lang.PropertyResolver;
-import org.apache.wicket.extensions.wizard.WizardModel.ICondition;
-import org.apache.wicket.extensions.wizard.WizardStep;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
-import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.util.ListModel;
 
-public abstract class AbstractAttrs<S extends SchemaTO> extends WizardStep implements ICondition {
+public abstract class AbstractAttrs<S extends SchemaTO> extends AbstractAttrsWizardStep<S> {
 
     private static final long serialVersionUID = -5387344116983102292L;
 
-    protected final Comparator<Attr> attrComparator = new AttrComparator();
-
-    private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
-
     private final GroupRestClient groupRestClient = new GroupRestClient();
 
-    protected final AnyTO anyTO;
-
-    private final List<String> whichAttrs;
-
-    protected final Map<String, S> schemas = new LinkedHashMap<>();
-
-    protected final Map<String, Map<String, S>> membershipSchemas = new LinkedHashMap<>();
-
-    protected final IModel<List<Attr>> attrs;
-
     protected final IModel<List<MembershipTO>> membershipTOs;
 
-    private final List<String> anyTypeClasses;
+    protected final Map<String, Map<String, S>> membershipSchemas = new LinkedHashMap<>();
 
     public AbstractAttrs(
             final AnyWrapper<?> modelObject,
             final List<String> anyTypeClasses,
             final List<String> whichAttrs) {
-        super();
-        this.anyTypeClasses = anyTypeClasses;
-        this.attrs = new ListModel<>(List.of());
-        this.membershipTOs = new ListModel<>(Collections.<MembershipTO>emptyList());
 
-        this.setOutputMarkupId(true);
+        super(modelObject.getInnerObject(), AjaxWizard.Mode.CREATE, anyTypeClasses, whichAttrs, null);
 
-        this.anyTO = modelObject.getInnerObject();
-        this.whichAttrs = whichAttrs;
-    }
+        this.membershipTOs = new ListModel<>(Collections.<MembershipTO>emptyList());
 
-    private List<Attr> loadAttrs() {
-        List<String> classes = new ArrayList<>(anyTypeClasses);
-        classes.addAll(AnyTypeClassRestClient.list(anyTO.getAuxClasses()).stream().
-                map(EntityTO::getKey).collect(Collectors.toList()));
-        setSchemas(classes);
-        setAttrs();
-        return AbstractAttrs.this.getAttrsFromTO();
+        this.setOutputMarkupId(true);
     }
 
     @SuppressWarnings("unchecked")
@@ -126,12 +91,6 @@ public abstract class AbstractAttrs<S extends SchemaTO> extends WizardStep imple
         return memberships;
     }
 
-    protected boolean reoderSchemas() {
-        return !whichAttrs.isEmpty();
-    }
-
-    protected abstract SchemaType getSchemaType();
-
     private void setSchemas(final String membership, final List<String> anyTypeClasses) {
         final Map<String, S> mscs;
 
@@ -144,28 +103,18 @@ public abstract class AbstractAttrs<S extends SchemaTO> extends WizardStep imple
         setSchemas(anyTypeClasses, mscs);
     }
 
-    private void setSchemas(final List<String> anyTypeClasses) {
-        setSchemas(anyTypeClasses, schemas);
-    }
-
-    private void setSchemas(final List<String> anyTypeClasses, final Map<String, S> scs) {
-        final List<S> allSchemas;
-        if (anyTypeClasses.isEmpty()) {
-            allSchemas = new ArrayList<>();
-        } else {
-            allSchemas = SchemaRestClient.getSchemas(getSchemaType(), null, anyTypeClasses.toArray(new String[] {}));
+    protected List<String> getMembershipAuxClasses(final MembershipTO membershipTO, final String anyType) {
+        try {
+            final GroupTO groupTO = groupRestClient.read(membershipTO.getGroupKey());
+            return groupTO.getTypeExtension(anyType).get().getAuxClasses();
+        } catch (Exception e) {
+            return List.of();
         }
+    }
 
-        scs.clear();
-
-        if (reoderSchemas()) {
-            // 1. remove attributes not selected for display
-            allSchemas.removeAll(allSchemas.stream().
-                    filter(schemaTO -> !whichAttrs.contains(schemaTO.getKey())).collect(Collectors.toSet()));
-        }
+    protected abstract void setAttrs(MembershipTO membershipTO);
 
-        allSchemas.forEach(schemaTO -> scs.put(schemaTO.getKey(), schemaTO));
-    }
+    protected abstract List<Attr> getAttrsFromTO(MembershipTO membershipTO);
 
     @Override
     public void renderHead(final IHeaderResponse response) {
@@ -178,23 +127,6 @@ public abstract class AbstractAttrs<S extends SchemaTO> extends WizardStep imple
         }
     }
 
-    protected abstract void setAttrs();
-
-    protected abstract void setAttrs(MembershipTO membershipTO);
-
-    protected abstract List<Attr> getAttrsFromTO();
-
-    protected abstract List<Attr> getAttrsFromTO(MembershipTO membershipTO);
-
-    protected List<String> getMembershipAuxClasses(final MembershipTO membershipTO, final String anyType) {
-        try {
-            final GroupTO groupTO = groupRestClient.read(membershipTO.getGroupKey());
-            return groupTO.getTypeExtension(anyType).get().getAuxClasses();
-        } catch (Exception e) {
-            return List.of();
-        }
-    }
-
     @Override
     public boolean evaluate() {
         this.attrs.setObject(loadAttrs());
@@ -202,46 +134,4 @@ public abstract class AbstractAttrs<S extends SchemaTO> extends WizardStep imple
         return !attrs.getObject().isEmpty() || !membershipTOs.getObject().isEmpty();
     }
 
-    public PageReference getPageReference() {
-        // SYNCOPE-1213
-        // default implementation does not require to pass page reference, override this method of want otherwise
-        return null;
-    }
-
-    private class AttrComparator implements Comparator<Attr>, Serializable {
-
-        private static final long serialVersionUID = -5105030477767941060L;
-
-        @Override
-        public int compare(final Attr left, final Attr right) {
-            if (left == null || StringUtils.isEmpty(left.getSchema())) {
-                return -1;
-            }
-            if (right == null || StringUtils.isEmpty(right.getSchema())) {
-                return 1;
-            } else if (AbstractAttrs.this.reoderSchemas()) {
-                int leftIndex = AbstractAttrs.this.whichAttrs.indexOf(left.getSchema());
-                int rightIndex = AbstractAttrs.this.whichAttrs.indexOf(right.getSchema());
-
-                if (leftIndex > rightIndex) {
-                    return 1;
-                } else if (leftIndex < rightIndex) {
-                    return -1;
-                } else {
-                    return 0;
-                }
-            } else {
-                return left.getSchema().compareTo(right.getSchema());
-            }
-        }
-    }
-
-    public static class Schemas extends Panel {
-
-        private static final long serialVersionUID = -2447602429647965090L;
-
-        public Schemas(final String id) {
-            super(id);
-        }
-    }
 }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
new file mode 100644
index 0000000..047628e
--- /dev/null
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
@@ -0,0 +1,453 @@
+/*
+ * 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.any;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.FastDateFormat;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import org.apache.syncope.client.ui.commons.SchemaUtils;
+import org.apache.syncope.client.ui.commons.ajax.markup.html.LabelInfo;
+import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.EncryptedFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
+import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
+import org.apache.syncope.client.ui.commons.wizards.any.EntityWrapper;
+import org.apache.syncope.common.lib.Attr;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.SchemaTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.wizard.WizardModel.ICondition;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+
+public abstract class AbstractAttrsWizardStep<S extends SchemaTO> extends WizardStep implements ICondition {
+
+    private static final long serialVersionUID = 8931397230194043674L;
+
+    protected final Comparator<Attr> attrComparator = new AttrComparator();
+
+    protected final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
+
+    protected final AnyTO anyTO;
+
+    protected AnyTO previousObject;
+
+    private final List<String> whichAttrs;
+
+    protected final Map<String, S> schemas = new LinkedHashMap<>();
+
+    protected final IModel<List<Attr>> attrs;
+
+    private final List<String> anyTypeClasses;
+
+    protected String fileKey = "";
+
+    protected final AjaxWizard.Mode mode;
+
+    public AbstractAttrsWizardStep(
+            final AnyTO anyTO,
+            final AjaxWizard.Mode mode,
+            final List<String> anyTypeClasses,
+            final List<String> whichAttrs,
+            final EntityWrapper<?> modelObject) {
+
+        super();
+        this.anyTypeClasses = anyTypeClasses;
+        this.attrs = new ListModel<>(Collections.<Attr>emptyList());
+
+        this.setOutputMarkupId(true);
+
+        this.mode = mode;
+        this.anyTO = anyTO;
+        this.whichAttrs = whichAttrs;
+    }
+
+    protected List<Attr> loadAttrs() {
+        List<String> classes = new ArrayList<>(anyTypeClasses);
+        classes.addAll(AnyTypeClassRestClient.list(anyTO.getAuxClasses()).stream().
+                map(EntityTO::getKey).collect(Collectors.toList()));
+        setSchemas(classes);
+        setAttrs();
+        return AbstractAttrsWizardStep.this.getAttrsFromTO();
+    }
+
+    protected boolean reoderSchemas() {
+        return !whichAttrs.isEmpty();
+    }
+
+    protected abstract SchemaType getSchemaType();
+
+    protected void setSchemas(final List<String> anyTypeClasses) {
+        setSchemas(anyTypeClasses, schemas);
+    }
+
+    protected void setSchemas(final List<String> anyTypeClasses, final Map<String, S> scs) {
+        final List<S> allSchemas;
+        if (anyTypeClasses.isEmpty()) {
+            allSchemas = new ArrayList<>();
+        } else {
+            allSchemas = SchemaRestClient.getSchemas(getSchemaType(), null, anyTypeClasses.toArray(new String[] {}));
+        }
+
+        scs.clear();
+
+        if (reoderSchemas()) {
+            // 1. remove attributes not selected for display
+            allSchemas.removeAll(allSchemas.stream().
+                    filter(schemaTO -> !whichAttrs.contains(schemaTO.getKey())).collect(Collectors.toSet()));
+        }
+
+        allSchemas.forEach(schemaTO -> scs.put(schemaTO.getKey(), schemaTO));
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        if (CollectionUtils.isEmpty(attrs.getObject())) {
+            response.render(OnDomReadyHeaderItem.forScript(
+                    String.format("$('#emptyPlaceholder').append(\"%s\"); $('#attributes').hide();",
+                            getString("attribute.empty.list"))));
+        }
+    }
+
+    protected abstract void setAttrs();
+
+    protected abstract List<Attr> getAttrsFromTO();
+
+    @Override
+    public boolean evaluate() {
+        this.attrs.setObject(loadAttrs());
+        return !attrs.getObject().isEmpty();
+    }
+
+    public PageReference getPageReference() {
+        // SYNCOPE-1213
+        // default implementation does not require to pass page reference, override this method of want otherwise
+        return null;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected FieldPanel getFieldPanel(final PlainSchemaTO schemaTO) {
+        final boolean required;
+        final boolean readOnly;
+        final AttrSchemaType type;
+        final boolean jexlHelp;
+
+        if (mode == AjaxWizard.Mode.TEMPLATE) {
+            required = false;
+            readOnly = false;
+            type = AttrSchemaType.String;
+            jexlHelp = true;
+        } else {
+            required = schemaTO.getMandatoryCondition().equalsIgnoreCase("true");
+            readOnly = schemaTO.isReadonly();
+            type = schemaTO.getType();
+            jexlHelp = false;
+
+        }
+
+        FieldPanel panel;
+        switch (type) {
+            case Boolean:
+                panel = new AjaxCheckBoxPanel(
+                        "panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                        new Model<>(),
+                        true);
+                panel.setRequired(required);
+                break;
+
+            case Date:
+                String datePattern = schemaTO.getConversionPattern() == null
+                        ? SyncopeConstants.DEFAULT_DATE_PATTERN
+                        : schemaTO.getConversionPattern();
+
+                if (datePattern.contains("H")) {
+                    panel = new AjaxDateTimeFieldPanel(
+                            "panel",
+                            schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                            new Model<>(),
+                            FastDateFormat.getInstance(datePattern));
+                } else {
+                    panel = new AjaxDateFieldPanel(
+                            "panel",
+                            schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                            new Model<>(),
+                            FastDateFormat.getInstance(datePattern));
+                }
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+
+                break;
+
+            case Enum:
+                panel = new AjaxDropDownChoicePanel<>("panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
+                ((AjaxDropDownChoicePanel<String>) panel).setChoices(SchemaUtils.getEnumeratedValues(schemaTO));
+
+                if (org.apache.commons.lang3.StringUtils.isNotBlank(schemaTO.getEnumerationKeys())) {
+                    ((AjaxDropDownChoicePanel) panel).setChoiceRenderer(new IChoiceRenderer<String>() {
+
+                        private static final long serialVersionUID = -3724971416312135885L;
+
+                        private final Map<String, String> valueMap = SchemaUtils.getEnumeratedKeyValues(schemaTO);
+
+                        @Override
+                        public String getDisplayValue(final String value) {
+                            return valueMap.get(value) == null ? value : valueMap.get(value);
+                        }
+
+                        @Override
+                        public String getIdValue(final String value, final int i) {
+                            return value;
+                        }
+
+                        @Override
+                        public String getObject(
+                                final String id, final IModel<? extends List<? extends String>> choices) {
+                            return id;
+                        }
+                    });
+                }
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Long:
+                panel = new AjaxSpinnerFieldPanel.Builder<Long>().enableOnChange().build(
+                        "panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                        Long.class,
+                        new Model<>());
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Double:
+                panel = new AjaxSpinnerFieldPanel.Builder<Double>().enableOnChange().step(0.1).build(
+                        "panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                        Double.class,
+                        new Model<>());
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Binary:
+                final PageReference pageRef = getPageReference();
+                panel = new BinaryFieldPanel(
+                        "panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
+                        new Model<>(),
+                        schemaTO.getMimeType(),
+                        fileKey) {
+
+                    private static final long serialVersionUID = -3268213909514986831L;
+
+                    @Override
+                    protected PageReference getPageReference() {
+                        return pageRef;
+                    }
+
+                };
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Encrypted:
+                panel = new EncryptedFieldPanel("panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            default:
+                panel = new AjaxTextFieldPanel("panel",
+                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
+
+                if (jexlHelp) {
+                    AjaxTextFieldPanel.class.cast(panel).enableJexlHelp();
+                }
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+        }
+
+        panel.setReadOnly(readOnly);
+
+        return panel;
+    }
+
+    protected FormComponent<?> checkboxToggle(
+            final Attr attr,
+            final AbstractFieldPanel<?> panel,
+            final boolean isMultivalue) {
+
+        // do nothing
+        return null;
+    }
+
+    private class AttrComparator implements Comparator<Attr>, Serializable {
+
+        private static final long serialVersionUID = -5105030477767941060L;
+
+        @Override
+        public int compare(final Attr left, final Attr right) {
+            if (left == null || StringUtils.isEmpty(left.getSchema())) {
+                return -1;
+            }
+            if (right == null || StringUtils.isEmpty(right.getSchema())) {
+                return 1;
+            } else if (AbstractAttrsWizardStep.this.reoderSchemas()) {
+                int leftIndex = AbstractAttrsWizardStep.this.whichAttrs.indexOf(left.getSchema());
+                int rightIndex = AbstractAttrsWizardStep.this.whichAttrs.indexOf(right.getSchema());
+
+                if (leftIndex > rightIndex) {
+                    return 1;
+                } else if (leftIndex < rightIndex) {
+                    return -1;
+                } else {
+                    return 0;
+                }
+            } else {
+                return left.getSchema().compareTo(right.getSchema());
+            }
+        }
+    }
+
+    public static class Schemas extends Panel {
+
+        private static final long serialVersionUID = -2447602429647965090L;
+
+        public Schemas(final String id) {
+            super(id);
+        }
+    }
+
+    protected abstract class PlainSchemas<T> extends Schemas {
+
+        private static final long serialVersionUID = 8315035592714180404L;
+
+        public PlainSchemas(
+                final String id,
+                final Map<String, PlainSchemaTO> schemas,
+                final IModel<T> attrs) {
+
+            super(id);
+        }
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        protected AbstractFieldPanel<?> setPanel(
+                final Map<String, PlainSchemaTO> schemas,
+                final ListItem<Attr> item,
+                final boolean setReadOnly) {
+
+            Attr attr = item.getModelObject();
+            final boolean isMultivalue = mode != AjaxWizard.Mode.TEMPLATE
+                    && schemas.get(attr.getSchema()).isMultivalue();
+
+            AbstractFieldPanel<?> panel = getFieldPanel(schemas.get(attr.getSchema()));
+            if (isMultivalue) {
+                // SYNCOPE-1476 set form as multipart to properly manage membership attributes
+                panel = new MultiFieldPanel.Builder<>(
+                        new PropertyModel<>(attr, "values")).build(
+                        "panel",
+                        attr.getSchema(),
+                        FieldPanel.class.cast(panel)).setFormAsMultipart(true);
+                // SYNCOPE-1215 the entire multifield panel must be readonly, not only its field
+                MultiFieldPanel.class.cast(panel).setReadOnly(schemas.get(attr.getSchema()).isReadonly());
+                MultiFieldPanel.class.cast(panel).setFormReadOnly(setReadOnly);
+            } else {
+                FieldPanel.class.cast(panel).setNewModel(attr.getValues()).setReadOnly(setReadOnly);
+            }
+            item.add(panel);
+
+            setExternalAction(attr, panel);
+
+            return panel;
+        }
+
+        protected void setExternalAction(final Attr attr, final AbstractFieldPanel<?> panel) {
+            Optional<Attr> prevAttr = previousObject == null
+                    ? Optional.empty()
+                    : previousObject.getPlainAttr(attr.getSchema());
+            if (previousObject != null
+                    && ((prevAttr.isEmpty() && attr.getValues().stream().anyMatch(StringUtils::isNotBlank))
+                    || (prevAttr.isPresent() && !ListUtils.isEqualList(
+                    prevAttr.get().getValues().stream().
+                            filter(StringUtils::isNotBlank).collect(Collectors.toList()),
+                    attr.getValues().stream().
+                            filter(StringUtils::isNotBlank).collect(Collectors.toList()))))) {
+
+                List<String> oldValues = prevAttr.isPresent()
+                        ? prevAttr.get().getValues()
+                        : List.of();
+                panel.showExternAction(new LabelInfo("externalAction", oldValues));
+            }
+        }
+    }
+
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
index 7727cb4..cd35090 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
@@ -25,29 +25,14 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
-import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateFieldPanel;
-import org.apache.syncope.client.ui.commons.SchemaUtils;
-import org.apache.syncope.client.ui.commons.ajax.markup.html.LabelInfo;
 import org.apache.syncope.client.ui.commons.wicket.markup.html.bootstrap.tabs.Accordion;
 import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.EncryptedFieldPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
 import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
 import org.apache.syncope.common.lib.EntityTOUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -55,20 +40,16 @@ import org.apache.syncope.common.lib.to.GroupableRelatableTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.SchemaType;
-import org.apache.wicket.PageReference;
 import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
 import org.apache.wicket.extensions.markup.html.tabs.ITab;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.form.IChoiceRenderer;
 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.ResourceModel;
 import org.apache.wicket.model.StringResourceModel;
 import org.apache.wicket.model.util.ListModel;
@@ -79,12 +60,6 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
 
     private static final long serialVersionUID = 552437609667518888L;
 
-    protected final AjaxWizard.Mode mode;
-
-    protected final AnyTO previousObject;
-
-    protected String fileKey = "";
-
     public <T extends AnyTO> PlainAttrs(
             final AnyWrapper<T> modelObject,
             final Form<?> form,
@@ -93,7 +68,6 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
             final List<String> whichPlainAttrs) throws IllegalArgumentException {
 
         super(modelObject, anyTypeClasses, whichPlainAttrs);
-        this.mode = mode;
 
         if (modelObject.getInnerObject() instanceof UserTO) {
             fileKey = UserTO.class.cast(modelObject.getInnerObject()).getUsername();
@@ -214,12 +188,12 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
         attrs.addAll(membershipSchemas.get(membershipTO.getGroupKey()).values().stream().
                 map(schema -> {
                     Attr attrTO = new Attr();
-            attrTO.setSchema(schema.getKey());
-            if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) {
-                attrTO.getValues().add(StringUtils.EMPTY);
-            } else {
-                attrTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
-            }
+                    attrTO.setSchema(schema.getKey());
+                    if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) {
+                        attrTO.getValues().add(StringUtils.EMPTY);
+                    } else {
+                        attrTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
+                    }
                     return attrTO;
                 }).collect(Collectors.toList()));
 
@@ -227,168 +201,27 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
         membershipTO.getPlainAttrs().addAll(attrs);
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    protected FieldPanel getFieldPanel(final PlainSchemaTO schemaTO) {
-        final boolean required;
-        final boolean readOnly;
-        final AttrSchemaType type;
-        final boolean jexlHelp;
-
-        if (mode == AjaxWizard.Mode.TEMPLATE) {
-            required = false;
-            readOnly = false;
-            type = AttrSchemaType.String;
-            jexlHelp = true;
-        } else {
-            required = schemaTO.getMandatoryCondition().equalsIgnoreCase("true");
-            readOnly = schemaTO.isReadonly();
-            type = schemaTO.getType();
-            jexlHelp = false;
-
-        }
-
-        FieldPanel panel;
-        switch (type) {
-            case Boolean:
-                panel = new AjaxCheckBoxPanel(
-                        "panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                        new Model<>(),
-                        true);
-                panel.setRequired(required);
-                break;
-
-            case Date:
-                String datePattern = schemaTO.getConversionPattern() == null
-                        ? SyncopeConstants.DEFAULT_DATE_PATTERN
-                        : schemaTO.getConversionPattern();
-
-                if (datePattern.contains("H")) {
-                    panel = new AjaxDateTimeFieldPanel(
-                            "panel",
-                            schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                            new Model<>(),
-                            FastDateFormat.getInstance(datePattern));
-                } else {
-                    panel = new AjaxDateFieldPanel(
-                            "panel",
-                            schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                            new Model<>(),
-                            FastDateFormat.getInstance(datePattern));
-                }
-
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-
-                break;
-
-            case Enum:
-                panel = new AjaxDropDownChoicePanel<>("panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
-                ((AjaxDropDownChoicePanel<String>) panel).setChoices(SchemaUtils.getEnumeratedValues(schemaTO));
-
-                if (StringUtils.isNotBlank(schemaTO.getEnumerationKeys())) {
-                    ((AjaxDropDownChoicePanel) panel).setChoiceRenderer(new IChoiceRenderer<String>() {
-
-                        private static final long serialVersionUID = -3724971416312135885L;
-
-                        private final Map<String, String> valueMap = SchemaUtils.getEnumeratedKeyValues(schemaTO);
-
-                        @Override
-                        public String getDisplayValue(final String value) {
-                            return valueMap.get(value) == null ? value : valueMap.get(value);
-                        }
-
-                        @Override
-                        public String getIdValue(final String value, final int i) {
-                            return value;
-                        }
-
-                        @Override
-                        public String getObject(
-                                final String id, final IModel<? extends List<? extends String>> choices) {
-                            return id;
-                        }
-                    });
-                }
-
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-                break;
-
-            case Long:
-                panel = new AjaxSpinnerFieldPanel.Builder<Long>().enableOnChange().build(
-                        "panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                        Long.class,
-                        new Model<>());
-
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-                break;
-
-            case Double:
-                panel = new AjaxSpinnerFieldPanel.Builder<Double>().enableOnChange().step(0.1).build(
-                        "panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                        Double.class,
-                        new Model<>());
-
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-                break;
-
-            case Binary:
-                final PageReference pageRef = getPageReference();
-                panel = new BinaryFieldPanel(
-                        "panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()),
-                        new Model<>(),
-                        schemaTO.getMimeType(),
-                        fileKey) {
-
-                    private static final long serialVersionUID = -3268213909514986831L;
-
-                    @Override
-                    protected PageReference getPageReference() {
-                        return pageRef;
-                    }
+    protected class PlainSchemasOwn extends PlainSchemas<List<Attr>> {
 
-                };
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-                break;
+        private static final long serialVersionUID = -4730563859116024676L;
 
-            case Encrypted:
-                panel = new EncryptedFieldPanel("panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
+        public PlainSchemasOwn(
+                final String id,
+                final Map<String, PlainSchemaTO> schemas,
+                final IModel<List<Attr>> attrTOs) {
 
-                if (required) {
-                    panel.addRequiredLabel();
-                }
-                break;
+            super(id, schemas, attrTOs);
 
-            default:
-                panel = new AjaxTextFieldPanel("panel",
-                        schemaTO.getLabel(SyncopeConsoleSession.get().getLocale()), new Model<>(), true);
+            add(new ListView<Attr>("schemas", attrTOs) {
 
-                if (jexlHelp) {
-                    AjaxTextFieldPanel.class.cast(panel).enableJexlHelp();
-                }
+                private static final long serialVersionUID = 9101744072914090143L;
 
-                if (required) {
-                    panel.addRequiredLabel();
+                @Override
+                protected void populateItem(final ListItem<Attr> item) {
+                    setPanel(schemas, item, false);
                 }
+            });
         }
-
-        panel.setReadOnly(readOnly);
-
-        return panel;
     }
 
     protected class PlainSchemasMemberships extends PlainSchemas<Attributable> {
@@ -442,79 +275,4 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
         }
     }
 
-    protected class PlainSchemasOwn extends PlainSchemas<List<Attr>> {
-
-        private static final long serialVersionUID = -4730563859116024676L;
-
-        public PlainSchemasOwn(
-                final String id,
-                final Map<String, PlainSchemaTO> schemas,
-                final IModel<List<Attr>> attrTOs) {
-
-            super(id, schemas, attrTOs);
-
-            add(new ListView<Attr>("schemas", attrTOs) {
-
-                private static final long serialVersionUID = 9101744072914090143L;
-
-                @Override
-                @SuppressWarnings({ "unchecked", "rawtypes" })
-                protected void populateItem(final ListItem<Attr> item) {
-                    Attr attrTO = item.getModelObject();
-
-                    AbstractFieldPanel<?> panel = getFieldPanel(schemas.get(attrTO.getSchema()));
-                    if (mode == AjaxWizard.Mode.TEMPLATE
-                            || !schemas.get(attrTO.getSchema()).isMultivalue()) {
-
-                        FieldPanel.class.cast(panel).setNewModel(attrTO.getValues());
-                    } else {
-                        // SYNCOPE-1476 set form as multipart to properly manage membership attributes
-                        panel = new MultiFieldPanel.Builder<>(
-                                new PropertyModel<>(attrTO, "values")).build(
-                                "panel",
-                                attrTO.getSchema(),
-                                FieldPanel.class.cast(panel)).setFormAsMultipart(true);
-                        // SYNCOPE-1215 the entire multifield panel must be readonly, not only its field
-                        ((MultiFieldPanel) panel).setReadOnly(schemas.get(attrTO.getSchema()).isReadonly());
-                    }
-                    item.add(panel);
-
-                    setExternalAction(attrTO, panel);
-                }
-            });
-        }
-    }
-
-    protected abstract class PlainSchemas<T> extends Schemas {
-
-        private static final long serialVersionUID = 8315035592714180404L;
-
-        public PlainSchemas(
-                final String id,
-                final Map<String, PlainSchemaTO> schemas,
-                final IModel<T> attrTOs) {
-
-            super(id);
-        }
-
-        protected void setExternalAction(final Attr attrTO, final AbstractFieldPanel<?> panel) {
-            Optional<Attr> prevAttr = previousObject == null
-                    ? Optional.empty()
-                    : previousObject.getPlainAttr(attrTO.getSchema());
-            if (previousObject != null
-                    && ((prevAttr.isEmpty() && attrTO.getValues().stream().anyMatch(StringUtils::isNotBlank))
-                    || (prevAttr.isPresent() && !ListUtils.isEqualList(
-                    prevAttr.get().getValues().stream().
-                            filter(StringUtils::isNotBlank).collect(Collectors.toList()),
-                    attrTO.getValues().stream().
-                            filter(StringUtils::isNotBlank).collect(Collectors.toList()))))) {
-
-                List<String> oldValues = prevAttr.isPresent()
-                        ? prevAttr.get().getValues()
-                        : List.of();
-                panel.showExternAction(new LabelInfo("externalAction", oldValues));
-            }
-        }
-    }
-
 }
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/TypeExtensionWizardBuilder.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/TypeExtensionWizardBuilder.java
index a62b5d7..66dce02 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/TypeExtensionWizardBuilder.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/TypeExtensionWizardBuilder.java
@@ -112,7 +112,7 @@ public class TypeExtensionWizardBuilder extends BaseAjaxWizardBuilder<TypeExtens
                     map(EntityTO::getKey).collect(Collectors.toList());
             AjaxPalettePanel<String> auxClassesPalette = new AjaxPalettePanel.Builder<String>().build(
                     "auxClasses.palette",
-                    new PropertyModel<List<String>>(typeExtensionTO, "auxClasses"),
+                    new PropertyModel<>(typeExtensionTO, "auxClasses"),
                     new ListModel<>(anyTypeClasses));
             add(auxClassesPalette.hideLabel().setOutputMarkupId(true));
         }
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.html
similarity index 89%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.html
index d0d803f..dd5288c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.html
@@ -18,9 +18,7 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-    <div id="emptyPlaceholder"/>
-    <div id="attributes">
-      <wicket:child/>
-    </div>
+    <span wicket:id="linkedAccountsList">[linkedAccountsList]</span>
+    <div wicket:id="toggle"/>
   </wicket:panel>
 </html>
\ No newline at end of file
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.properties
index ebae232..5f28a07 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Resource
+suspended=Suspended
+connObjectKeyValue=External key
+inner.edit.linkedAccount=Edit account
+inner.create.linkedAccount=Create account
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_it.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_it.properties
index ebae232..ce0bcf8 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_it.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Risorsa
+suspended=Sospeso
+connObjectKeyValue=Chiave esterna
+inner.edit.linkedAccount=Modifica account
+inner.create.linkedAccount=Crea account
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ja.properties
similarity index 74%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ja.properties
index ebae232..b825afb 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ja.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=\u8cc7\u6e90
+suspended=\u4e00\u6642\u505c\u6b62
+connObjectKeyValue=\u5916\u90e8\u30ad\u30fc
+inner.edit.linkedAccount=\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u7de8\u96c6
+inner.create.linkedAccount=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u4f5c\u6210\u3059\u308b
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_pt_BR.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_pt_BR.properties
index ebae232..62a2310 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_pt_BR.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Recurso
+suspended=Suspenso
+connObjectKeyValue=Chave externa
+inner.edit.linkedAccount=Editar conta
+inner.create.linkedAccount=Criar Conta
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ru.properties
similarity index 63%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ru.properties
index ebae232..8a337d3 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/LinkedAccountModalPanel_ru.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=\u0420\u0435\u0441\u0443\u0440\u0441
+suspended=\u043f\u043e\u0434\u0432\u0435\u0448\u0435\u043d\u043d\u044b\u0439
+connObjectKeyValue=\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043b\u044e\u0447
+inner.edit.linkedAccount=\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043a\u043a\u0430\u0443\u043d\u0442
+inner.create.linkedAccount=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
index ebae232..6acf5db 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
@@ -17,3 +17,4 @@
 any.edit=Edit ${anyTO.type} ${anyTO.username}
 any.propagation.tasks=Propagation tasks for ${type} ${username}
 any.notification.tasks=Notification tasks for ${type} ${username}
+linkedAccounts.title=Manage user accounts
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
index 1b03294..38fa14d 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_it.properties
@@ -17,3 +17,4 @@
 any.edit=Modifica ${anyTO.type} ${anyTO.username}
 any.propagation.tasks=Task di propagazione per ${type} ${username}
 any.notification.tasks=Task di notifica per ${type} ${username}
+linkedAccounts.title=Gestisci account utente
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
index c8baff6..9107368 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ja.properties
@@ -17,3 +17,4 @@
 any.edit=${anyTO.type} ${anyTO.username} \u3092\u7de8\u96c6
 any.propagation.tasks=${type} ${username} \u306e\u4f1d\u64ad\u30bf\u30b9\u30af
 any.notification.tasks=${type} ${username} \u306e\u901a\u77e5\u30bf\u30b9\u30af
+linkedAccounts.title=\u30e6\u30fc\u30b6\u30fc\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7ba1\u7406\u3059\u308b
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
index 9498b19..865e74d 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_pt_BR.properties
@@ -17,3 +17,4 @@
 any.edit=Alterar ${anyTO.type} ${anyTO.username}
 any.propagation.tasks=Propagation tasks for ${type} ${username}
 any.notification.tasks=Notification tasks for ${type} ${username}
+linkedAccounts.title=Gerenciar contas de usu\u00e1rio
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
index ad11a87..53e0e86 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel_ru.properties
@@ -18,3 +18,4 @@
 any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c ${anyTO.type} ${anyTO.username}
 any.propagation.tasks=\u0417\u0430\u0434\u0430\u0447\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f ${type} ${username}
 any.notification.tasks=\u0417\u0430\u0434\u0430\u0447\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0434\u043b\u044f ${type} ${username}
+linkedAccounts.title=\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u0447\u0435\u0442\u043d\u044b\u043c\u0438 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
index e5affd7..6831a2b 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
@@ -233,3 +233,7 @@ zoom_in.alt=zoom-in icon
 zoom_out.class=fa fa-search-minus
 zoom_out.title=zoom-out
 zoom_out.alt=zoom-out icon
+
+manage_accounts.class=fa fa-users
+manage_accounts.title=manage accounts
+manage_accounts.alt=manage accounts icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
index d0dbb16..2e13f6e 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
@@ -231,3 +231,7 @@ reconciliation_push.alt=reconciliation push icon
 reconciliation_pull.class=fa-chevron-circle-left
 reconciliation_pull.title=pull
 reconciliation_pull.alt=reconciliation pull icon
+
+manage_accounts.class=fa fa-users
+manage_accounts.title=gestisci account
+manage_accounts.alt=manage accounts icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
index 71156bd..33d593c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
@@ -231,3 +231,7 @@ reconciliation_push.alt=\u7167\u5408\u30d7\u30c3\u30b7\u30e5 icon
 reconciliation_pull.class=fa-chevron-circle-left
 reconciliation_pull.title=\u30d7\u30eb
 reconciliation_pull.alt=\u7167\u5408\u30d7\u30eb icon
+
+manage_accounts.class=fa fa-users
+manage_accounts.title=\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u7ba1\u7406\u3059\u308b
+manage_accounts.alt=\u30a2\u30ab\u30a6\u30f3\u30c8\u7ba1\u7406\u30a2\u30a4\u30b3\u30f3
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
index 4aedf76..7a61862 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
@@ -231,3 +231,7 @@ reconciliation_push.alt=reconciliation push icon
 reconciliation_pull.class=fa-chevron-circle-left
 reconciliation_pull.title=pull
 reconciliation_pull.alt=reconciliation pull icon
+
+manage_accounts.class=fa fa-users
+manage_accounts.title=manage accounts
+manage_accounts.alt=manage accounts icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
index e7fc2d3..d825127 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
@@ -231,3 +231,7 @@ reconciliation_push.alt=reconciliation push icon
 reconciliation_pull.class=fa-chevron-circle-left
 reconciliation_pull.title=pull
 reconciliation_pull.alt=reconciliation pull icon
+
+manage_accounts.class=fa fa-users
+manage_accounts.title=manage accounts
+manage_accounts.alt=manage accounts icon
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
index d0d803f..2c13529 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
@@ -17,10 +17,7 @@ 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 id="emptyPlaceholder"/>
-    <div id="attributes">
-      <wicket:child/>
-    </div>
-  </wicket:panel>
+  <wicket:extend>
+    <wicket:child/>
+  </wicket:extend>
 </html>
\ No newline at end of file
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep$Schemas.html
similarity index 83%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep$Schemas.html
index d0d803f..f62795a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep$Schemas.html
@@ -18,9 +18,12 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-    <div id="emptyPlaceholder"/>
-    <div id="attributes">
-      <wicket:child/>
+    <div wicket:id="schemas">
+      <div class="form-group">
+        <span wicket:id="panel">
+          [panel for dynamic input type markup]
+        </span>
+      </div>
     </div>
   </wicket:panel>
 </html>
\ No newline at end of file
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.html
similarity index 100%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.html
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.html
similarity index 68%
copy from client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.html
index e2da0f2..ed2f180 100644
--- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.html
@@ -19,11 +19,19 @@ under the License.
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
     <div class="form-group">
-      <span wicket:id="overrideCapabilities">[overrideCapabilities]</span>
-    </div>
-
-    <div class="form-group">
-      <span wicket:id="capabilities">[capabilitiesOverride]</span>
+      <div class="box">
+        <div class="box-header with-border">
+          <h3 class="box-title"><wicket:message key="title"/></h3>
+        </div>
+        <div class="box-body">
+          <div id="group-forum">
+            <span wicket:id="username">[username]</span>
+          </div>
+          <div id="group-forum">
+            <span wicket:id="password">[password]</span>
+          </div>
+        </div>
+      </div>
     </div>
   </wicket:panel>
 </html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.properties
index ebae232..387b986 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+username=Username
+password=Password
+title=Credentials
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_it.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_it.properties
index ebae232..c98ccb0 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_it.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+username=Username
+password=Password
+title=Credenziali
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ja.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ja.properties
index ebae232..6a73f2a 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ja.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+username=\u30e6\u30fc\u30b6\u30fc\u540d
+password=\u30d1\u30b9\u30ef\u30fc\u30c9
+title=\u8cc7\u683c\u60c5\u5831
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_pt_BR.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_pt_BR.properties
index ebae232..cbef682 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_pt_BR.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+username=Username
+password=Password
+title=Credenciais
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ru.properties
similarity index 78%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ru.properties
index ebae232..219c104 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountCredentialsPanel_ru.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+username=\u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f
+password=\u043f\u0430\u0440\u043e\u043b\u044c
+title=\u043f\u043e\u043b\u043d\u043e\u043c\u043e\u0447\u0438\u044f
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.html
similarity index 67%
copy from client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.html
index e2da0f2..f2087ab 100644
--- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.html
@@ -19,11 +19,19 @@ under the License.
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
     <div class="form-group">
-      <span wicket:id="overrideCapabilities">[overrideCapabilities]</span>
-    </div>
-
-    <div class="form-group">
-      <span wicket:id="capabilities">[capabilitiesOverride]</span>
+      <div class="box">
+        <div class="box-header with-border">
+          <h3 class="box-title"><wicket:message key="title"/></h3>
+        </div>
+        <div class="box-body">
+          <div id="group-forum">
+            <span wicket:id="resource">[resource]</span>
+          </div>
+          <div id="group-forum">
+            <span wicket:id="connObjectKeyValue">[connObjectKeyValue]</span>
+          </div>
+        </div>
+      </div>
     </div>
   </wicket:panel>
 </html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.properties
index ebae232..c820770 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Resource
+connObjectKeyValue=Value of the key of the object as on the external resource
+title=Details
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_it.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_it.properties
index ebae232..b098daf 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_it.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Risorsa
+connObjectKeyValue=Valore della chiave dell'oggetto come com'\u00e8 sulla risorsa esterna
+title=Dettagli
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ja.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ja.properties
index ebae232..03d0baa 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ja.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=\u8cc7\u6e90
+connObjectKeyValue=\u5916\u90e8\u30ea\u30bd\u30fc\u30b9\u4e0a\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30ad\u30fc\u306e\u5024
+title=\u8a73\u7d30
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_pt_BR.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_pt_BR.properties
index ebae232..9d1da54 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_pt_BR.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=Recurso
+connObjectKeyValue=Valor da chave do objeto como no recurso externo
+title=Detalhes
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ru.properties
similarity index 67%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ru.properties
index ebae232..bbaba52 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel_ru.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+resource=\u0420\u0435\u0441\u0443\u0440\u0441
+connObjectKeyValue=\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u0430\u043a \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0435
+title=\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.html
similarity index 86%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.html
index d0d803f..5310309 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AbstractAttrs.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.html
@@ -17,10 +17,7 @@ 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 id="emptyPlaceholder"/>
-    <div id="attributes">
-      <wicket:child/>
-    </div>
-  </wicket:panel>
+  <wicket:extend>
+    <div wicket:id="plainSchemas"/>
+  </wicket:extend>
 </html>
\ No newline at end of file
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.html
similarity index 74%
copy from client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.html
index e2da0f2..7a9b812 100644
--- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceConnCapabilitiesPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.html
@@ -19,11 +19,16 @@ under the License.
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
     <div class="form-group">
-      <span wicket:id="overrideCapabilities">[overrideCapabilities]</span>
-    </div>
-
-    <div class="form-group">
-      <span wicket:id="capabilities">[capabilitiesOverride]</span>
+      <div class="box">
+        <div class="box-header with-border">
+          <h3 class="box-title"><wicket:message key="title"/></h3>
+        </div>
+        <div class="box-body">
+          <div id="group-forum">
+            <span wicket:id="privileges">[privileges]</span>
+          </div>
+        </div>
+      </div>
     </div>
   </wicket:panel>
 </html>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.properties
index ebae232..5887b81 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.properties
@@ -14,6 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+title=Privileges
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_it.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_it.properties
index ebae232..8b9d8d5 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_it.properties
@@ -14,6 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+title=Privilegi
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ja.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ja.properties
index ebae232..c83d230 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ja.properties
@@ -14,6 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+title=\u7279\u5178
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_pt_BR.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_pt_BR.properties
index ebae232..2ef9db4 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_pt_BR.properties
@@ -14,6 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+title=Privil\u00e9gios
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ru.properties
similarity index 81%
copy from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
copy to client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ru.properties
index ebae232..4d83a4c 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/UserDirectoryPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel_ru.properties
@@ -14,6 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-any.edit=Edit ${anyTO.type} ${anyTO.username}
-any.propagation.tasks=Propagation tasks for ${type} ${username}
-any.notification.tasks=Notification tasks for ${type} ${username}
+title=\u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0438
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
index eeb654a..b29dce1 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
@@ -837,7 +837,7 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         UTILITY_UI.getTester().executeAjaxEvent(UTILITY_UI.getTester().getComponentFromLastRenderedPage(
                 "body:content:body:container:content:tabbedPanel:panel:searchResult:outerObjectsRepeater:"
-                + "1:outer:container:content:togglePanelContainer:container:actions:actions:actionRepeater:8:"
+                + "1:outer:container:content:togglePanelContainer:container:actions:actions:actionRepeater:9:"
                 + "action:action"), Constants.ON_CLICK);
 
         UTILITY_UI.getTester().assertInfoMessages("Operation successfully executed");
@@ -845,7 +845,7 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         component = UTILITY_UI.findComponentByProp("username",
                 "body:content:body:container:content:tabbedPanel:panel:searchResult:container:content:"
-                + ":searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "rossini_clone");
+                + "searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "rossini_clone");
         assertNull(component);
 
         // delete default policy
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
index 59ec6ea..daa617e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
@@ -582,7 +582,7 @@ public class UsersITCase extends AbstractConsoleITCase {
         UTILITY_UI.getTester().executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK);
         UTILITY_UI.getTester().assertComponent(TAB_PANEL
                 + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:"
-                + "actions:actions:actionRepeater:8:action:action", IndicatingOnConfirmAjaxLink.class);
+                + "actions:actions:actionRepeater:9:action:action", IndicatingOnConfirmAjaxLink.class);
     }
 
     @Test