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 2018/06/07 07:22:33 UTC

[2/2] syncope git commit: [SYNCOPE-1295] New structured wizard to edit SCIM 2.0 configuration

[SYNCOPE-1295] New structured wizard to edit SCIM 2.0 configuration


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

Branch: refs/heads/2_0_X
Commit: a613585e903933f159d763c89c87e31b11cdc3e8
Parents: 06e5dcd
Author: skylark17 <ma...@tirasa.net>
Authored: Wed May 2 16:56:24 2018 +0200
Committer: skylark17 <ma...@tirasa.net>
Committed: Wed Jun 6 17:50:20 2018 +0200

----------------------------------------------------------------------
 .../init/ClassPathScanImplementationLookup.java |  35 +
 .../console/wizards/AbstractMappingPanel.java   |  37 -
 .../wizards/resources/ResourceMappingPanel.java |   7 +-
 .../wizards/OIDCProviderMappingPanel.java       |   3 +-
 .../console/wizards/SAML2IdPMappingPanel.java   |   3 +-
 .../syncope/client/console/pages/SCIMConf.java  | 137 ----
 .../client/console/pages/SCIMConfPage.java      | 109 +++
 .../panels/SCIMConfAccordionContainer.java      |  44 ++
 .../panels/SCIMConfEnterpriseUserPanel.java     | 235 +++++++
 .../console/panels/SCIMConfGeneralPanel.java    | 161 +++++
 .../client/console/panels/SCIMConfPanel.java    | 143 ++++
 .../client/console/panels/SCIMConfTabPanel.java |  62 ++
 .../console/panels/SCIMConfUserPanel.java       | 700 +++++++++++++++++++
 .../client/console/pages/SCIMConfPage.html      |  37 +
 .../console/pages/SCIMConfPage.properties       |  17 +
 .../console/pages/SCIMConfPage_it.properties    |  17 +
 .../console/pages/SCIMConfPage_pt_BR.properties |  17 +
 .../console/pages/SCIMConfPage_ru.properties    |  17 +
 .../panels/SCIMConfAccordionContainer.html      |  29 +
 .../panels/SCIMConfEnterpriseUserPanel.html     |  32 +
 .../console/panels/SCIMConfGeneralPanel.html    |  28 +
 .../client/console/panels/SCIMConfPanel.html    |  32 +
 .../console/panels/SCIMConfPanel.properties     |  21 +
 .../console/panels/SCIMConfPanel_it.properties  |  21 +
 .../panels/SCIMConfPanel_pt_BR.properties       |  21 +
 .../console/panels/SCIMConfPanel_ru.properties  |  21 +
 .../console/panels/SCIMConfUserPanel.html       |  81 +++
 .../syncope/common/lib/scim/SCIMConf.java       |  77 +-
 .../common/lib/scim/SCIMGeneralConf.java        | 104 +++
 .../syncope/core/logic/SCIMDataBinder.java      | 133 ++--
 .../apache/syncope/core/logic/SCIMLogic.java    |  12 +-
 .../core/logic/scim/SCIMConfManager.java        |   4 +-
 .../ext/scimv2/cxf/service/AbstractService.java |   4 +-
 33 files changed, 2075 insertions(+), 326 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java b/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
index d9ee460..6082d38 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
@@ -18,11 +18,16 @@
  */
 package org.apache.syncope.client.console.init;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.commons.collections4.ComparatorUtils;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.client.console.pages.BaseExtPage;
@@ -33,6 +38,9 @@ import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.panels.SSOLoginFormPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.preview.AbstractBinaryPreviewer;
 import org.apache.syncope.client.console.widgets.BaseExtWidget;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
@@ -46,6 +54,33 @@ public class ClassPathScanImplementationLookup {
 
     private static final String DEFAULT_BASE_PACKAGE = "org.apache.syncope.client.console";
 
+    public static final Set<String> USER_FIELD_NAMES = new HashSet<>();
+
+    public static final Set<String> GROUP_FIELD_NAMES = new HashSet<>();
+
+    public static final Set<String> ANY_OBJECT_FIELD_NAMES = new HashSet<>();
+
+    static {
+        initFieldNames(UserTO.class, USER_FIELD_NAMES);
+        initFieldNames(GroupTO.class, GROUP_FIELD_NAMES);
+        initFieldNames(AnyObjectTO.class, ANY_OBJECT_FIELD_NAMES);
+    }
+
+    private static void initFieldNames(final Class<?> entityClass, final Set<String> keys) {
+        List<Class<?>> classes = org.apache.commons.lang3.ClassUtils.getAllSuperclasses(entityClass);
+        classes.add(entityClass);
+        for (Class<?> clazz : classes) {
+            for (Field field : clazz.getDeclaredFields()) {
+                if (!Modifier.isStatic(field.getModifiers())
+                        && !Collection.class.isAssignableFrom(field.getType())
+                        && !Map.class.isAssignableFrom(field.getType())) {
+
+                    keys.add(field.getName());
+                }
+            }
+        }
+    }
+
     private List<Class<? extends BasePage>> pages;
 
     private List<Class<? extends AbstractBinaryPreviewer>> previewers;

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
index 38e5579..217c9e8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractMappingPanel.java
@@ -22,17 +22,10 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverBehavi
 import de.agilecoders.wicket.core.markup.html.bootstrap.components.PopoverConfig;
 import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
 import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang3.ClassUtils;
 import org.apache.syncope.client.console.commons.ConnIdSpecialName;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
@@ -47,10 +40,7 @@ import org.apache.syncope.client.console.widgets.JEXLTransformerWidget;
 import org.apache.syncope.client.console.widgets.ItemTransformerWidget;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
-import org.apache.syncope.common.lib.to.AnyObjectTO;
-import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.ItemTO;
-import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -71,33 +61,6 @@ public abstract class AbstractMappingPanel extends Panel {
 
     private static final long serialVersionUID = -8295587900937040104L;
 
-    protected static final Set<String> USER_FIELD_NAMES = new HashSet<>();
-
-    protected static final Set<String> GROUP_FIELD_NAMES = new HashSet<>();
-
-    protected static final Set<String> ANY_OBJECT_FIELD_NAMES = new HashSet<>();
-
-    static {
-        initFieldNames(UserTO.class, USER_FIELD_NAMES);
-        initFieldNames(GroupTO.class, GROUP_FIELD_NAMES);
-        initFieldNames(AnyObjectTO.class, ANY_OBJECT_FIELD_NAMES);
-    }
-
-    private static void initFieldNames(final Class<?> entityClass, final Set<String> keys) {
-        List<Class<?>> classes = ClassUtils.getAllSuperclasses(entityClass);
-        classes.add(entityClass);
-        for (Class<?> clazz : classes) {
-            for (Field field : clazz.getDeclaredFields()) {
-                if (!Modifier.isStatic(field.getModifiers())
-                        && !Collection.class.isAssignableFrom(field.getType())
-                        && !Map.class.isAssignableFrom(field.getType())) {
-
-                    keys.add(field.getName());
-                }
-            }
-        }
-    }
-
     /**
      * Any type rest client.
      */

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
index 6a36f62..19302b1 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.rest.ConnectorRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.AbstractMappingPanel;
@@ -152,15 +153,15 @@ public class ResourceMappingPanel extends AbstractMappingPanel {
 
             switch (provision.getAnyType()) {
                 case "USER":
-                    choices.addAll(USER_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
                     break;
 
                 case "GROUP":
-                    choices.addAll(GROUP_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.GROUP_FIELD_NAMES);
                     break;
 
                 default:
-                    choices.addAll(ANY_OBJECT_FIELD_NAMES);
+                    choices.addAll(ClassPathScanImplementationLookup.ANY_OBJECT_FIELD_NAMES);
             }
 
             for (AnyTypeClassTO anyTypeClassTO : anyTypeClassTOs) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java
----------------------------------------------------------------------
diff --git a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java
index d12965e..3308992 100644
--- a/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java
+++ b/ext/oidcclient/client-console/src/main/java/org/apache/syncope/client/console/wizards/OIDCProviderMappingPanel.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.console.wizards;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
@@ -87,7 +88,7 @@ public class OIDCProviderMappingPanel extends AbstractMappingPanel {
         toBeUpdated.setRequired(true);
         toBeUpdated.setEnabled(true);
 
-        List<String> choices = new ArrayList<>(USER_FIELD_NAMES);
+        List<String> choices = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
 
         for (AnyTypeClassTO anyTypeClassTO : anyTypeClassRestClient.list(
                 anyTypeRestClient.read(AnyTypeKind.USER.name()).getClasses())) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
index af13d8f..21e80a6 100644
--- a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
+++ b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
@@ -21,6 +21,7 @@ package org.apache.syncope.client.console.wizards;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
 import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
@@ -70,7 +71,7 @@ public class SAML2IdPMappingPanel extends AbstractMappingPanel {
         toBeUpdated.setRequired(true);
         toBeUpdated.setEnabled(true);
 
-        List<String> choices = new ArrayList<>(USER_FIELD_NAMES);
+        List<String> choices = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
 
         for (AnyTypeClassTO anyTypeClassTO : anyTypeClassRestClient.list(
                 anyTypeRestClient.read(AnyTypeKind.USER.name()).getClasses())) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java
deleted file mode 100644
index ac5a375..0000000
--- a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConf.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.pages;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.annotations.ExtPage;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.rest.SCIMConfRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel;
-import org.apache.syncope.common.lib.scim.SCIMComplexConf;
-import org.apache.syncope.common.lib.scim.SCIMEnterpriseUserConf;
-import org.apache.syncope.common.lib.scim.SCIMUserConf;
-import org.apache.syncope.common.lib.scim.SCIMUserNameConf;
-import org.apache.syncope.common.lib.scim.types.EmailCanonicalType;
-import org.apache.syncope.common.lib.scim.types.SCIMEntitlement;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
-import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.model.ResourceModel;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-
-@ExtPage(label = "SCIM 2.0", icon = "fa-cloud", listEntitlement = SCIMEntitlement.SCIM_CONF_GET, priority = 400)
-public class SCIMConf extends BaseExtPage {
-
-    private static final long serialVersionUID = 9128779230455599119L;
-
-    private static final ObjectMapper MAPPER = new ObjectMapper();
-
-    private final SCIMConfRestClient restClient = new SCIMConfRestClient();
-
-    public SCIMConf(final PageParameters parameters) {
-        super(parameters);
-
-        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
-
-        final BaseModal<String> modal = new BaseModal<>("modal");
-        modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                modal.show(false);
-            }
-        });
-        modal.size(Modal.Size.Large);
-        modal.addSubmitButton();
-        body.add(modal);
-
-        WebMarkupContainer content = new WebMarkupContainer("content");
-        content.setOutputMarkupId(true);
-        body.add(content);
-
-        String confString = "";
-        try {
-            org.apache.syncope.common.lib.scim.SCIMConf conf = restClient.get();
-            if (conf.getUserConf() == null) {
-                conf.setUserConf(new SCIMUserConf());
-            }
-            if (conf.getUserConf().getName() == null) {
-                conf.getUserConf().setName(new SCIMUserNameConf());
-            }
-            if (conf.getUserConf().getEmails().isEmpty()) {
-                conf.getUserConf().getEmails().add(new SCIMComplexConf<EmailCanonicalType>());
-            }
-
-            if (conf.getEnterpriseUserConf() == null) {
-                conf.setEnterpriseUserConf(new SCIMEnterpriseUserConf());
-            }
-
-            confString = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(conf);
-        } catch (Exception e) {
-            LOG.error("While reading SCIM configuration", e);
-            SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
-                    ? e.getClass().getName() : e.getMessage());
-        }
-        final Model<String> confModel = Model.of(confString);
-
-        content.add(new AjaxLink<Void>("edit") {
-
-            private static final long serialVersionUID = -4331619903296515985L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target) {
-                modal.header(new ResourceModel("editConf"));
-                modal.setContent(new JsonEditorPanel(modal, confModel, false, getPageReference()) {
-
-                    private static final long serialVersionUID = -8927036362466990179L;
-
-                    @Override
-                    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-                        try {
-                            restClient.set(MAPPER.readValue(
-                                    confModel.getObject(), org.apache.syncope.common.lib.scim.SCIMConf.class));
-
-                            SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
-                            modal.show(false);
-                            modal.close(target);
-                        } catch (Exception e) {
-                            LOG.error("While setting SCIM configuration", e);
-                            SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
-                                    ? e.getClass().getName() : e.getMessage());
-                        }
-                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-                    }
-                });
-                modal.show(true);
-                target.add(modal);
-            }
-        });
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java
new file mode 100644
index 0000000..4eded72
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/pages/SCIMConfPage.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.annotations.ExtPage;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.SCIMConfPanel;
+import org.apache.syncope.client.console.rest.SCIMConfRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wizards.any.ResultPage;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.types.SCIMEntitlement;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ExtPage(label = "SCIM 2.0", icon = "fa-cloud", listEntitlement = SCIMEntitlement.SCIM_CONF_GET, priority = 100)
+public class SCIMConfPage extends BaseExtPage {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfPage.class);
+
+    private static final long serialVersionUID = -8156063343062111770L;
+
+    private final SCIMConfRestClient restClient = new SCIMConfRestClient();
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private final WebMarkupContainer content;
+
+    public SCIMConfPage(final PageParameters parameters) {
+        super(parameters);
+
+        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+        content = new WebMarkupContainer("content");
+
+        content.add(new Label("body", "General"));
+        content.setOutputMarkupId(true);
+        body.add(content);
+
+        updateSCIMGeneralConfContent(restClient.get());
+    }
+
+    private WebMarkupContainer updateSCIMGeneralConfContent(final SCIMConf scimConf) {
+        if (scimConf == null) {
+            return content;
+        }
+        content.addOrReplace(new SCIMConfPanel("body", scimConf, SCIMConfPage.this.getPageReference()) {
+
+            private static final long serialVersionUID = 8221398624379357183L;
+
+            @Override
+            protected void setWindowClosedReloadCallback(final BaseModal<?> modal) {
+                modal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+                    private static final long serialVersionUID = 8804221891699487139L;
+
+                    @Override
+                    public void onClose(final AjaxRequestTarget target) {
+                        if (modal.getContent() instanceof ResultPage) {
+                            Serializable result = ResultPage.class.cast(modal.getContent()).getResult();
+                            try {
+                                restClient.set(MAPPER.readValue(result.toString(), SCIMConf.class));
+
+                                SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                                modal.show(false);
+                                target.add(content);
+                            } catch (Exception e) {
+                                LOG.error("While setting SCIM configuration", e);
+                                SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                                        ? e.getClass().getName() : e.getMessage());
+                            }
+                            ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                        }
+                    }
+                });
+            }
+
+        });
+
+        return content;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java
new file mode 100644
index 0000000..1a2d687
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfAccordionContainer.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class SCIMConfAccordionContainer extends Panel {
+
+    private static final long serialVersionUID = 8186681102688613299L;
+
+    SCIMConfAccordionContainer(final String id, final List<AjaxTextFieldPanel> fieldPanels) {
+        super(id);
+
+        add(new ListView<AjaxTextFieldPanel>("accordionContainer", fieldPanels) {
+
+            private static final long serialVersionUID = 4949588177564901031L;
+
+            @Override
+            protected void populateItem(final ListItem<AjaxTextFieldPanel> item) {
+                item.add(item.getModelObject());
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java
new file mode 100644
index 0000000..e127bbc
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfEnterpriseUserPanel.java
@@ -0,0 +1,235 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMEnterpriseUserConf;
+import org.apache.syncope.common.lib.scim.SCIMManagerConf;
+import org.apache.wicket.event.IEvent;
+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.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCIMConfEnterpriseUserPanel extends SCIMConfTabPanel {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfEnterpriseUserPanel.class);
+
+    private static final long serialVersionUID = -4183306437598820588L;
+
+    private final SCIMEnterpriseUserConf scimEnterpriseUserConf;
+
+    public SCIMConfEnterpriseUserPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        if (scimConf.getEnterpriseUserConf() == null) {
+            scimConf.setEnterpriseUserConf(new SCIMEnterpriseUserConf());
+        }
+        if (scimConf.getEnterpriseUserConf().getManager() == null) {
+            scimConf.getEnterpriseUserConf().setManager(new SCIMManagerConf());
+        }
+        scimEnterpriseUserConf = scimConf.getEnterpriseUserConf();
+
+        AjaxTextFieldPanel costCenterPanel =
+                new AjaxTextFieldPanel("costCenter", "costCenter",
+                        new PropertyModel<String>("costCenter", "costCenter") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getCostCenter();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setCostCenter(object);
+                    }
+
+                });
+        costCenterPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel departmentPanel =
+                new AjaxTextFieldPanel("department", "department",
+                        new PropertyModel<String>("department", "department") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getDepartment();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setDepartment(object);
+                    }
+
+                });
+        departmentPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel divisionPanel =
+                new AjaxTextFieldPanel("division", "division",
+                        new PropertyModel<String>("division", "division") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getDivision();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setDivision(object);
+                    }
+
+                });
+        divisionPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel employeeNumberPanel =
+                new AjaxTextFieldPanel("employeeNumber", "employeeNumber",
+                        new PropertyModel<String>("employeeNumber", "employeeNumber") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getEmployeeNumber();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setEmployeeNumber(object);
+                    }
+
+                });
+        employeeNumberPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel organizationPanel =
+                new AjaxTextFieldPanel("organization", "organization",
+                        new PropertyModel<String>("organization", "organization") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getOrganization();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.setOrganization(object);
+                    }
+
+                });
+        organizationPanel.setChoices(plainSchemaNames);
+
+        // manager
+        buildManagerAccordion();
+
+        add(costCenterPanel);
+        add(departmentPanel);
+        add(divisionPanel);
+        add(employeeNumberPanel);
+        add(organizationPanel);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+    }
+
+    private void buildManagerAccordion() {
+        final Accordion accordion = new Accordion("managerAccordion",
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("manager")) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildNameAccordionContent(panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+
+    }
+
+    private SCIMConfAccordionContainer buildNameAccordionContent(final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+
+        AjaxTextFieldPanel managerKeyPanel =
+                new AjaxTextFieldPanel("accordionContent", "manager.key",
+                        new PropertyModel<String>(scimEnterpriseUserConf.getManager(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getManager().getKey();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.getManager().setKey(object);
+                    }
+
+                });
+        managerKeyPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel managerDisplaNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "manager.displayName",
+                        new PropertyModel<String>(scimEnterpriseUserConf.getManager(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimEnterpriseUserConf.getManager().getDisplayName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimEnterpriseUserConf.getManager().setDisplayName(object);
+                    }
+
+                });
+        managerDisplaNamePanel.setChoices(plainSchemaNames);
+
+        panelList.add(managerKeyPanel);
+        panelList.add(managerDisplaNamePanel);
+        
+        add(new Label("managerLabel", Model.of("manager")));
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java
new file mode 100644
index 0000000..29f457c
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfGeneralPanel.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.Date;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDateTimeFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMGeneralConf;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class SCIMConfGeneralPanel extends SCIMConfTabPanel {
+
+    private static final long serialVersionUID = 2765863608539154422L;
+
+    public SCIMConfGeneralPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        final SCIMGeneralConf scimGeneralConf = scimConf.getGeneralConf();
+
+        AjaxDateTimeFieldPanel creationDatePanel =
+                new AjaxDateTimeFieldPanel("creationDate", "creationDate", new Model<Date>() {
+
+                    private static final long serialVersionUID = 7075312408615929880L;
+
+                    @Override
+                    public Date getObject() {
+                        return scimGeneralConf.getCreationDate();
+                    }
+
+                    @Override
+                    public void setObject(final Date object) {
+                        scimGeneralConf.setCreationDate(object);
+                    }
+
+                }, SyncopeConstants.DEFAULT_DATE_PATTERN);
+        creationDatePanel.setEnabled(false);
+
+        AjaxDateTimeFieldPanel lastChangeDatePanel =
+                new AjaxDateTimeFieldPanel("lastChangeDate", "lastChangeDate", new Model<Date>() {
+
+                    private static final long serialVersionUID = 7075312408615929880L;
+
+                    @Override
+                    public Date getObject() {
+                        return scimGeneralConf.getLastChangeDate();
+                    }
+
+                    @Override
+                    public void setObject(final Date object) {
+                        scimGeneralConf.setLastChangeDate(object);
+                    }
+
+                }, SyncopeConstants.DEFAULT_DATE_PATTERN);
+        lastChangeDatePanel.setEnabled(false);
+
+        AjaxTextFieldPanel bulkMaxOperationsPanel =
+                new AjaxTextFieldPanel("bulkMaxOperations", "bulkMaxOperations",
+                        new PropertyModel<String>("bulkMaxOperations", "bulkMaxOperations") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getBulkMaxOperations());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setBulkMaxOperations(Integer.parseInt(object));
+                    }
+
+                });
+        bulkMaxOperationsPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel bulkMaxMaxPayloadSizePanel =
+                new AjaxTextFieldPanel("bulkMaxMaxPayloadSize", "bulkMaxMaxPayloadSize",
+                        new PropertyModel<String>("bulkMaxMaxPayloadSize", "bulkMaxMaxPayloadSize") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getBulkMaxPayloadSize());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setBulkMaxPayloadSize(Integer.parseInt(object));
+                    }
+
+                });
+        bulkMaxMaxPayloadSizePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel filterMaxResultsPanel =
+                new AjaxTextFieldPanel("filterMaxResults", "filterMaxResults",
+                        new PropertyModel<String>("filterMaxResults", "filterMaxResults") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(scimGeneralConf.getFilterMaxResults());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimGeneralConf.setFilterMaxResults(Integer.parseInt(object));
+                    }
+
+                });
+        filterMaxResultsPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel eTagValuePanel =
+                new AjaxTextFieldPanel("eTagValue", "eTagValue",
+                        new PropertyModel<String>("eTagValue", "eTagValue") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimGeneralConf.getETagValue();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+
+                    }
+
+                });
+        eTagValuePanel.setEnabled(false);
+
+        add(creationDatePanel);
+        add(lastChangeDatePanel);
+        add(bulkMaxOperationsPanel);
+        add(bulkMaxMaxPayloadSizePanel);
+        add(filterMaxResultsPanel);
+        add(eTagValuePanel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java
new file mode 100644
index 0000000..d006bb1
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfPanel.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.commons.ITabComponent;
+import org.apache.syncope.client.console.rest.SCIMConfRestClient;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class SCIMConfPanel extends WizardMgtPanel<SCIMConf> {
+
+    private static final long serialVersionUID = -1100228004207271270L;
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfPanel.class);
+
+    private final SCIMConf scimConfTO;
+
+    private final SCIMConfRestClient scimConfRestClient = new SCIMConfRestClient();
+
+    public SCIMConfPanel(
+            final String id,
+            final SCIMConf scimConfTO,
+            final PageReference pageRef) {
+        super(id, true);
+
+        this.scimConfTO = scimConfTO;
+        this.pageRef = pageRef;
+
+        setPageRef(pageRef);
+
+        AjaxBootstrapTabbedPanel<ITab> tabbedPanel =
+                new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList());
+        tabbedPanel.setSelectedTab(0);
+        addInnerObject(tabbedPanel);
+
+        AjaxLink<String> saveButton = new AjaxLink<String>("saveButton") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                scimConfRestClient.set(SCIMConfPanel.this.scimConfTO);
+            }
+        };
+        addInnerObject(saveButton);
+
+        setShowResultPage(true);
+
+        modal.size(Modal.Size.Large);
+        setWindowClosedReloadCallback(modal);
+    }
+
+    private List<ITab> buildTabList() {
+        List<ITab> tabs = new ArrayList<>();
+
+        tabs.add(new ITabComponent(new Model<>(getString("tab1"))) {
+
+            private static final long serialVersionUID = -5861786415855103549L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new SCIMConfGeneralPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        tabs.add(new ITabComponent(
+                new Model<>(getString("tab2")), getString("tab2")) {
+
+            private static final long serialVersionUID = 1998052474181916792L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new SCIMConfUserPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        tabs.add(new ITabComponent(
+                new Model<>(getString("tab3")), getString("tab3")) {
+
+            private static final long serialVersionUID = 1998052474181916792L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new SCIMConfEnterpriseUserPanel(panelId, scimConfTO);
+            }
+
+            @Override
+            public boolean isVisible() {
+                return true;
+            }
+        });
+
+        return tabs;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Panel customResultBody(final String panelId, final SCIMConf item, final Serializable result) {
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java
new file mode 100644
index 0000000..12acbb2
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfTabPanel.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.to.SchemaTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class SCIMConfTabPanel extends Panel implements ModalPanel {
+
+    private static final long serialVersionUID = -4482885585790492795L;
+
+    protected final List<String> plainSchemaNames = getPlainSchemas();
+
+    public SCIMConfTabPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id);
+    }
+
+    private static List<String> getPlainSchemas() {
+        final List<String> names = new ArrayList<>(ClassPathScanImplementationLookup.USER_FIELD_NAMES);
+        names.addAll(CollectionUtils.collect(new SchemaRestClient().getSchemas(SchemaType.PLAIN, AnyTypeKind.USER),
+                new Transformer<SchemaTO, String>() {
+
+            @Override
+            public String transform(final SchemaTO input) {
+                return input.getKey();
+            }
+        }, new ArrayList<String>()));
+        names.remove("password");
+        Collections.sort(names);
+
+        return names;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java
new file mode 100644
index 0000000..ab5fbdb
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/java/org/apache/syncope/client/console/panels/SCIMConfUserPanel.java
@@ -0,0 +1,700 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
+import org.apache.syncope.common.lib.scim.SCIMComplexConf;
+import org.apache.syncope.common.lib.scim.SCIMConf;
+import org.apache.syncope.common.lib.scim.SCIMUserAddressConf;
+import org.apache.syncope.common.lib.scim.SCIMUserConf;
+import org.apache.syncope.common.lib.scim.SCIMUserNameConf;
+import org.apache.syncope.common.lib.scim.types.AddressCanonicalType;
+import org.apache.syncope.common.lib.scim.types.EmailCanonicalType;
+import org.apache.syncope.common.lib.scim.types.IMCanonicalType;
+import org.apache.syncope.common.lib.scim.types.PhoneNumberCanonicalType;
+import org.apache.syncope.common.lib.scim.types.PhotoCanonicalType;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+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.basic.Label;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCIMConfUserPanel extends SCIMConfTabPanel {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SCIMConfUserPanel.class);
+
+    private static final long serialVersionUID = 8747864142447220523L;
+
+    private final SCIMUserConf scimUserConf;
+
+    public SCIMConfUserPanel(
+            final String id,
+            final SCIMConf scimConf) {
+        super(id, scimConf);
+
+        if (scimConf.getUserConf() == null) {
+            scimConf.setUserConf(new SCIMUserConf());
+        }
+        if (scimConf.getUserConf().getName() == null) {
+            scimConf.getUserConf().setName(new SCIMUserNameConf());
+        }
+        scimUserConf = scimConf.getUserConf();
+
+        final AutoCompleteSettings settings = new AutoCompleteSettings();
+        settings.setShowCompleteListOnFocusGain(true);
+        settings.setShowListOnEmptyInput(true);
+        settings.setCssClassName("custom-autocomplete-box");
+
+        AjaxTextFieldPanel displayNamePanel =
+                new AjaxTextFieldPanel("displayName", "displayName",
+                        new PropertyModel<String>("displayName", "displayName") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getDisplayName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setDisplayName(object);
+                    }
+
+                });
+        displayNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel localePanel =
+                new AjaxTextFieldPanel("locale", "locale",
+                        new PropertyModel<String>("locale", "locale") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getLocale();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setLocale(object);
+                    }
+
+                });
+        localePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nickNamePanel =
+                new AjaxTextFieldPanel("nickName", "nickName",
+                        new PropertyModel<String>("nickName", "nickName") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getNickName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setNickName(object);
+                    }
+
+                });
+        nickNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel preferredLanguagePanel =
+                new AjaxTextFieldPanel("preferredLanguage", "preferredLanguage",
+                        new PropertyModel<String>("preferredLanguage", "preferredLanguage") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getPreferredLanguage();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setPreferredLanguage(object);
+                    }
+
+                });
+        preferredLanguagePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel profileUrlPanel =
+                new AjaxTextFieldPanel("profileUrl", "profileUrl",
+                        new PropertyModel<String>("profileUrl", "profileUrl") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getProfileUrl();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setProfileUrl(object);
+                    }
+
+                });
+        profileUrlPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel timezonePanel =
+                new AjaxTextFieldPanel("timezone", "timezone",
+                        new PropertyModel<String>("timezone", "timezone") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getTimezone();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setTimezone(object);
+                    }
+
+                });
+        timezonePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel titlePanel =
+                new AjaxTextFieldPanel("title", "title",
+                        new PropertyModel<String>("title", "title") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getTitle();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setTitle(object);
+                    }
+
+                });
+        titlePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel userTypePanel =
+                new AjaxTextFieldPanel("userType", "userType",
+                        new PropertyModel<String>("userType", "userType") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getUserType();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.setUserType(object);
+                    }
+
+                });
+        userTypePanel.setChoices(plainSchemaNames);
+
+        // name
+        buildNameAccordion();
+
+        // x509certificates
+        final AjaxTextFieldPanel x509CertificatesPanel = new AjaxTextFieldPanel("panel", "x509CertificatesPanel",
+                new Model<String>(null));
+        x509CertificatesPanel.setChoices(plainSchemaNames);
+        MultiFieldPanel<String> x509CertificatesMultiPanel = new MultiFieldPanel.Builder<>(
+                new ListModel<>(scimUserConf.getX509Certificates())).build(
+                "x509Certificates",
+                "x509Certificates",
+                x509CertificatesPanel);
+
+        // addresses
+        List<SCIMUserAddressConf> addresses = new ArrayList<>();
+        for (final AddressCanonicalType canonicalType : AddressCanonicalType.values()) {
+            SCIMUserAddressConf address = IterableUtils.find(scimUserConf.getAddresses(),
+                    new Predicate<SCIMUserAddressConf>() {
+
+                @Override
+                public boolean evaluate(final SCIMUserAddressConf object) {
+                    return object.getType().equals(canonicalType);
+                }
+            });
+
+            if (address == null) {
+                address = new SCIMUserAddressConf();
+                address.setType(canonicalType);
+            }
+            buildAddressAccordion(address, canonicalType);
+            addresses.add(address);
+        }
+        scimUserConf.getAddresses().clear();
+        scimUserConf.getAddresses().addAll(addresses);
+
+        // complex objects
+        buildComplexPanels(scimUserConf.getEmails(), "emailsAccordion", "emails", EmailCanonicalType.values());
+        buildComplexPanels(scimUserConf.getPhoneNumbers(), "phoneNumbersAccordion", "phoneNumbers",
+                PhoneNumberCanonicalType.values());
+        buildComplexPanels(scimUserConf.getIms(), "imsAccordion", "ims", IMCanonicalType.values());
+        buildComplexPanels(scimUserConf.getPhotos(), "photosAccordion", "photos", PhotoCanonicalType.values());
+
+        add(displayNamePanel);
+        add(localePanel);
+        add(nickNamePanel);
+        add(preferredLanguagePanel);
+        add(profileUrlPanel);
+        add(timezonePanel);
+        add(titlePanel);
+        add(userTypePanel);
+
+        add(x509CertificatesMultiPanel);
+
+        add(new Label("nameLabel", Model.of("name")));
+        add(new Label("addressesLabel", Model.of("addresses")));
+        add(new Label("emailsLabel", Model.of("emails")));
+        add(new Label("phoneNumbersLabel", Model.of("phoneNumbers")));
+        add(new Label("imsLabel", Model.of("ims")));
+        add(new Label("photosLabel", Model.of("photos")));
+
+    }
+
+    private <T extends Enum<?>> void buildComplexPanels(final List<SCIMComplexConf<T>> complexes,
+            final String basePanelId,
+            final String baseTabId,
+            final T[] canonicalTypes) {
+        List<SCIMComplexConf<T>> newElems = new ArrayList<>();
+        for (final T canonicalType : canonicalTypes) {
+            SCIMComplexConf<T> complex = IterableUtils.find(complexes,
+                    new Predicate<SCIMComplexConf<T>>() {
+
+                @Override
+                public boolean evaluate(final SCIMComplexConf<T> object) {
+                    return object.getType().equals(canonicalType);
+                }
+            });
+            if (complex == null) {
+                complex = new SCIMComplexConf<>();
+                complex.setType(canonicalType);
+            }
+            buildComplexAccordion(complex, basePanelId, baseTabId, canonicalType);
+            newElems.add(complex);
+        }
+        complexes.clear();
+        complexes.addAll(newElems);
+    }
+
+    private void buildNameAccordion() {
+        final Accordion accordion = new Accordion("nameAccordion",
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("name")) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildNameAccordionContent(panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private void buildAddressAccordion(final SCIMUserAddressConf address,
+            final AddressCanonicalType canonicalType) {
+        final Accordion accordion = new Accordion("addressesAccordion_" + address.getType().name(),
+                Collections.<ITab>singletonList(new AbstractTab(Model.of("address." + address.getType().name())) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildAddressAccordionContent(address, canonicalType, panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private <T extends Enum<?>> void buildComplexAccordion(final SCIMComplexConf<T> complex,
+            final String basePanelId,
+            final String baseTabId,
+            final T canonicalType) {
+        final Accordion accordion = new Accordion(basePanelId + "_" + complex.getType().name(),
+                Collections.<ITab>singletonList(
+                        new AbstractTab(Model.of(baseTabId + "." + complex.getType().name())) {
+
+                    private static final long serialVersionUID = -5861786415855103549L;
+
+                    @Override
+                    public WebMarkupContainer getPanel(final String panelId) {
+                        return buildComplexAccordionContent(complex, canonicalType, panelId);
+                    }
+
+                }), Model.of(-1)); // accordion closed at beginning
+        add(accordion.setOutputMarkupId(true));
+    }
+
+    private SCIMConfAccordionContainer buildNameAccordionContent(final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+
+        AjaxTextFieldPanel nameFamilyNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.familyName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getFamilyName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setFamilyName(object);
+                    }
+
+                });
+        nameFamilyNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameFormattedPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.formatted",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getFormatted();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setFormatted(object);
+                    }
+
+                });
+        nameFormattedPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameGivenNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.givenName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getGivenName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setGivenName(object);
+                    }
+
+                });
+        nameGivenNamePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameHonorificPrefixPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.honorificPrefix",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getHonorificPrefix();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setHonorificPrefix(object);
+                    }
+
+                });
+        nameHonorificPrefixPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameHonorificSuffixPanel =
+                new AjaxTextFieldPanel("accordionContent", "name.honorificSuffix",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getHonorificSuffix();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setHonorificSuffix(object);
+                    }
+
+                });
+        nameHonorificSuffixPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel nameMiddleNamePanel =
+                new AjaxTextFieldPanel("accordionContent", "name.middleName",
+                        new PropertyModel<String>(scimUserConf.getName(), "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return scimUserConf.getName().getMiddleName();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        scimUserConf.getName().setMiddleName(object);
+                    }
+
+                });
+        nameMiddleNamePanel.setChoices(plainSchemaNames);
+
+        panelList.add(nameFamilyNamePanel);
+        panelList.add(nameFormattedPanel);
+        panelList.add(nameGivenNamePanel);
+        panelList.add(nameHonorificPrefixPanel);
+        panelList.add(nameHonorificSuffixPanel);
+        panelList.add(nameMiddleNamePanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    private <T extends Enum<?>> SCIMConfAccordionContainer buildComplexAccordionContent(
+            final SCIMComplexConf<T> complex,
+            final T canonicalType,
+            final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+        final String fieldName = panelId + "." + canonicalType.name();
+
+        AjaxTextFieldPanel displayPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".display",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return complex.getDisplay();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setDisplay(object);
+                    }
+
+                });
+        displayPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel valuePanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".value",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return complex.getValue();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setValue(object);
+                    }
+
+                });
+        valuePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel primaryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".primary",
+                        new PropertyModel<String>(complex, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(complex.isPrimary());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        complex.setPrimary(Boolean.valueOf(object));
+                    }
+
+                });
+        primaryPanel.setChoices(Arrays.asList("true", "false"));
+
+        panelList.add(displayPanel);
+        panelList.add(valuePanel);
+        panelList.add(primaryPanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    private SCIMConfAccordionContainer buildAddressAccordionContent(final SCIMUserAddressConf address,
+            final AddressCanonicalType canonicalType,
+            final String panelId) {
+        final List<AjaxTextFieldPanel> panelList = new ArrayList<>();
+        final String fieldName = "addresses." + canonicalType.name();
+
+        AjaxTextFieldPanel addressCountryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".country",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getCountry();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setCountry(object);
+                    }
+
+                });
+        addressCountryPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressFormattedPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".formatted",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getFormatted();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setFormatted(object);
+                    }
+
+                });
+        addressFormattedPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressLocalityPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".locality",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getLocality();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setLocality(object);
+                    }
+
+                });
+        addressLocalityPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressRegionPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".region",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getRegion();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setRegion(object);
+                    }
+
+                });
+        addressRegionPanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressPostalCodePanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".postalCode",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return address.getPostalCode();
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setPostalCode(object);
+                    }
+
+                });
+        addressPostalCodePanel.setChoices(plainSchemaNames);
+
+        AjaxTextFieldPanel addressPrimaryPanel =
+                new AjaxTextFieldPanel("accordionContent", fieldName + ".primary",
+                        new PropertyModel<String>(address, "accordionContent") {
+
+                    private static final long serialVersionUID = -6427731218492117883L;
+
+                    @Override
+                    public String getObject() {
+                        return String.valueOf(address.isPrimary());
+                    }
+
+                    @Override
+                    public void setObject(final String object) {
+                        address.setPrimary(Boolean.valueOf(object));
+                    }
+
+                });
+        addressPrimaryPanel.setChoices(Arrays.asList("true", "false"));
+
+        panelList.add(addressCountryPanel);
+        panelList.add(addressFormattedPanel);
+        panelList.add(addressLocalityPanel);
+        panelList.add(addressRegionPanel);
+        panelList.add(addressPostalCodePanel);
+        panelList.add(addressPrimaryPanel);
+
+        return new SCIMConfAccordionContainer(panelId, panelList);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html
new file mode 100644
index 0000000..25a5a93
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.html
@@ -0,0 +1,37 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <section class="content-header">
+      <h1>&nbsp;</h1>
+      <ol class="breadcrumb">
+        <li><a wicket:id="dashboardBr"><i class="fa fa-dashboard"></i> <wicket:message key="dashboard"></wicket:message></a></li>
+        <li class="active"><wicket:message key="scimConfGeneral"></wicket:message></li>
+      </ol>
+    </section>
+
+    <section class="content" wicket:id="content">
+      <div class="box">
+        <div class="box-body">
+          <wicket:container wicket:id="body"/>
+        </div>
+      </div>
+    </section>
+  </wicket:extend>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties
new file mode 100644
index 0000000..cbcf4a3
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+scimConfGeneral=General

http://git-wip-us.apache.org/repos/asf/syncope/blob/a613585e/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties
----------------------------------------------------------------------
diff --git a/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties
new file mode 100644
index 0000000..cbcf4a3
--- /dev/null
+++ b/ext/scimv2/client-console/src/main/resources/org/apache/syncope/client/console/pages/SCIMConfPage_it.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+scimConfGeneral=General