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

[syncope] branch master updated: [SYNCOPE-1578] Adding auth support to SRA, with OIDC / OAUTH2 implementations, reviewing several details on WA and Core to make all functional (#206)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 278216e  [SYNCOPE-1578] Adding auth support to SRA, with OIDC / OAUTH2 implementations, reviewing several details on WA and Core to make all functional (#206)
278216e is described below

commit 278216e8b102d6accb5343c08d882d6f175374fa
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Thu Jul 16 10:47:58 2020 +0200

    [SYNCOPE-1578] Adding auth support to SRA, with OIDC / OAUTH2 implementations, reviewing several details on WA and Core to make all functional (#206)
---
 .travis.yml                                        |   3 +
 .../console/panels/SRARouteDirectoryPanel.java     |   6 +-
 .../client/console/wizards/WizardMgtPanel.html     |   2 +-
 .../apache/syncope/client/lib/SyncopeClient.java   |   9 +
 .../common/lib/auth/AbstractAuthModuleConf.java    |  14 -
 .../syncope/common/lib/auth/AuthModuleConf.java    |   7 -
 .../common/lib/auth/SyncopeAuthModuleConf.java     |  21 +-
 .../lib/policy/AbstractAccessPolicyConf.java       |  15 -
 .../lib/policy/AbstractAttrReleasePolicyConf.java  |  41 ---
 .../common/lib/policy/AbstractAuthPolicyConf.java  |  23 +-
 .../lib/policy/AbstractAuthPolicyCriteriaConf.java |  43 ---
 .../common/lib/policy/AccessPolicyConf.java        |   7 -
 .../lib/policy/AllowedAttrReleasePolicyConf.java   |   2 +-
 .../common/lib/policy/AttrReleasePolicyConf.java   |   7 -
 .../syncope/common/lib/policy/AuthPolicyConf.java  |   7 -
 .../common/lib/policy/AuthPolicyCriteriaConf.java  |   7 -
 .../lib/policy/DefaultAuthPolicyCriteriaConf.java  |   2 +-
 .../apache/syncope/common/lib/to/AuthModuleTO.java |  12 -
 .../apache/syncope/common/lib/to/OIDCJWKSTO.java   |  24 +-
 .../syncope/common/lib/to/client/OIDCRPTO.java     |  32 +--
 .../syncope/common/lib/types/AMEntitlement.java    |  10 +-
 ...outePredicateFactory.java => JWSAlgorithm.java} |  27 +-
 .../common/lib/types/SRARouteFilterFactory.java    |   6 +-
 .../common/lib/types/SRARoutePredicateFactory.java |   1 +
 .../syncope/common/lib/SerializationTest.java      |   1 -
 .../rest/api/service/AuthProfileService.java       |   4 +-
 ...DCJWKSConfService.java => OIDCJWKSService.java} |  18 +-
 ...nfService.java => SAML2IdPMetadataService.java} |   7 +-
 ...onfService.java => SAML2SPKeystoreService.java} |  12 +-
 ...onfService.java => SAML2SPMetadataService.java} |  22 +-
 .../common/rest/api/service/SRARouteService.java   |   4 +-
 .../service/wa/GoogleMfaAuthAccountService.java    |  67 +++--
 ...OIDCJWKSService.java => WAOIDCJWKSService.java} |  37 +--
 ...Service.java => WASAML2IdPMetadataService.java} |   4 +-
 ...eService.java => WASAML2SPKeystoreService.java} |  28 +-
 ...aService.java => WASAML2SPMetadataService.java} |  28 +-
 .../apache/syncope/core/logic/AuthModuleLogic.java |  14 +-
 .../apache/syncope/core/logic/OIDCJWKSLogic.java   |  34 +--
 .../apache/syncope/core/logic/SRARouteLogic.java   |  10 +-
 .../syncope/core/logic/wa/WAClientAppLogic.java    |   4 +-
 ...nfServiceImpl.java => OIDCJWKSServiceImpl.java} |   9 +-
 ...eImpl.java => SAML2IdPMetadataServiceImpl.java} |   4 +-
 ...ceImpl.java => SAML2SPKeystoreServiceImpl.java} |   4 +-
 ...ceImpl.java => SAML2SPMetadataServiceImpl.java} |   4 +-
 ...ServiceImpl.java => WAOIDCJWKSServiceImpl.java} |  23 +-
 ...mpl.java => WASAML2IdPMetadataServiceImpl.java} |   4 +-
 ...Impl.java => WASAML2SPKeystoreServiceImpl.java} |  16 +-
 ...Impl.java => WASAML2SPMetadataServiceImpl.java} |  14 +-
 .../persistence/api/entity/auth/AuthModule.java    |   8 +-
 .../core/persistence/api/entity/auth/OIDCRP.java   |   8 +-
 .../src/test/resources/domains/MasterContent.xml   |  52 ++--
 .../jpa/entity/auth/AbstractClientApp.java         |   2 +
 .../persistence/jpa/entity/auth/JPAAuthModule.java |  19 +-
 .../jpa/entity/auth/JPAAuthProfile.java            |  43 ++-
 .../persistence/jpa/entity/auth/JPAOIDCJWKS.java   |   7 +-
 .../persistence/jpa/entity/auth/JPAOIDCRP.java     |  31 +-
 .../jpa/entity/auth/JPASAML2IdPMetadata.java       |   5 -
 .../persistence/jpa/entity/auth/JPASAML2SP.java    |   9 -
 .../jpa/entity/auth/JPASAML2SPKeystore.java        |   7 +-
 .../jpa/entity/auth/JPASAML2SPMetadata.java        |   7 +-
 .../jpa/inner/AbstractClientAppTest.java           |   2 -
 .../core/persistence/jpa/inner/AuthModuleTest.java | 154 ++++------
 .../core/persistence/jpa/inner/PolicyTest.java     |   3 -
 .../src/test/resources/domains/MasterContent.xml   |  54 ++--
 .../provisioning/api/data/OIDCJWKSDataBinder.java  |   7 +-
 ...ntAppBinder.java => WAClientAppDataBinder.java} |   2 +-
 .../java/data/AuthModuleDataBinderImpl.java        |   6 +-
 .../java/data/ClientAppDataBinderImpl.java         |  30 +-
 .../java/data/OIDCJWKSDataBinderImpl.java          |  42 +--
 ...derImpl.java => WAClientAppDataBinderImpl.java} |  28 +-
 docker/sra/pom.xml                                 |  19 --
 docker/wa/src/main/resources/wa.properties         |   3 +-
 .../syncope/core/logic/NetworkServiceLogic.java    |   2 +
 .../api/service/NetworkServiceService.java         |   3 +-
 .../cxf/service/NetworkServiceServiceImpl.java     |  19 +-
 fit/core-reference/pom.xml                         |  18 ++
 .../org/apache/syncope/fit/AbstractITCase.java     |  99 ++-----
 .../syncope/fit/console/AbstractConsoleITCase.java |  17 +-
 .../fit/core/AbstractNotificationTaskITCase.java   |   2 +-
 .../apache/syncope/fit/core/AuthModuleITCase.java  | 137 ++++-----
 .../apache/syncope/fit/core/ClientAppITCase.java   |   7 +-
 .../syncope/fit/core/OIDCJWKSConfITCase.java       |  79 -----
 .../apache/syncope/fit/core/OIDCJWKSITCase.java    |  79 ++++-
 .../org/apache/syncope/fit/core/PolicyITCase.java  |   5 +-
 .../org/apache/syncope/fit/core/RealmITCase.java   |   2 -
 .../syncope/fit/core/SAML2IdPMetadataITCase.java   |  71 +++--
 .../syncope/fit/core/SAML2SPKeystoreITCase.java    |  69 +++--
 .../syncope/fit/core/SAML2SPMetadataITCase.java    |  65 +++--
 .../apache/syncope/fit/core/SRARouteITCase.java    |  30 +-
 .../apache/syncope/fit/core/WAClientAppITCase.java |  25 +-
 .../src/{main => test}/resources/logic.properties  |   0
 fit/wa-reference/pom.xml                           |  86 +++++-
 fit/wa-reference/src/main/resources/log4j2.xml     |   4 +
 fit/wa-reference/src/main/resources/wa.properties  |  10 +-
 .../org/apache/syncope/fit/sra/AbstractITCase.java | 319 +++++++++++++++++++++
 .../apache/syncope/fit/sra/OAUTH2SRAITCase.java    |  80 ++++++
 .../org/apache/syncope/fit/sra/OIDCSRAITCase.java  | 294 +++++++++++++++++++
 .../test/resources/application-oauth2.properties   |  15 +-
 .../src/test/resources/application-oidc.properties |   9 +-
 .../src/test/resources}/keymaster.properties       |   0
 .../src/{main => test}/resources/log4j2.xml        |  36 +--
 .../src/test/resources/test.properties             |   8 +-
 pom.xml                                            |   2 +-
 sra/pom.xml                                        | 116 +++-----
 .../java/org/apache/syncope/sra/RouteProvider.java |  82 +++++-
 .../org/apache/syncope/sra/SecurityConfig.java     |  78 ++++-
 ...cClientInitiatedServerLogoutSuccessHandler.java |   3 +-
 .../org/apache/syncope/sra/RouteProviderTest.java  |   2 +-
 .../resources/debug/application-debug.properties   |  20 +-
 .../src/test/resources/debug}/keymaster.properties |   0
 .../src/test/resources/debug}/log4j2.xml           |  48 ++--
 .../bootstrap/SyncopeWAPropertySourceLocator.java  | 188 ++++++------
 wa/starter/pom.xml                                 | 126 +-------
 .../wa/starter/config/SyncopeWAConfiguration.java  | 167 +++++------
 .../starter/mapping/AllowedAttrReleaseMapper.java  |  13 +-
 .../syncope/wa/starter/mapping/CASSPTOMapper.java  |  37 +--
 .../wa/starter/mapping/ClientAppMapper.java        |   4 +-
 .../wa/starter/mapping/DefaultAccessMapper.java    |   1 -
 .../wa/starter/mapping/DefaultAuthMapper.java      |  23 +-
 .../syncope/wa/starter/mapping/OIDCRPTOMapper.java | 103 +++++--
 .../starter/mapping/RegisteredServiceMapper.java   |  19 +-
 .../wa/starter/mapping/SAML2SPTOMapper.java        |  21 +-
 .../oidc/SyncopeWAOIDCJWKSGeneratorService.java    |  36 ++-
 .../pac4j/saml/SyncopeWASAML2ClientCustomizer.java |   6 +-
 .../SyncopeWASAML2ClientKeystoreGenerator.java     |  10 +-
 .../SyncopeWASAML2ClientMetadataGenerator.java     |   6 +-
 .../pac4j/saml/SyncopeWASAML2MetadataResolver.java |   6 +-
 .../metadata/RestfulSamlIdPMetadataGenerator.java  |   4 +-
 .../metadata/RestfulSamlIdPMetadataLocator.java    |   4 +-
 wa/starter/src/main/resources/wa.properties        |  10 +-
 .../org/apache/syncope/wa/starter/BasicTest.java   |   2 +-
 .../wa/starter/SyncopeWAServiceRegistryTest.java   |  45 ++-
 .../saml/SyncopeWASAML2ClientCustomizerTest.java   |  13 +-
 .../SyncopeWASAML2ClientKeystoreGeneratorTest.java |  13 +-
 .../SyncopeWASAML2ClientMetadataGeneratorTest.java |   7 +-
 .../saml/SyncopeWASAML2MetadataResolverTest.java   |   7 +-
 .../application-debug.properties}                  |   0
 .../resources/{dev => debug}/keymaster.properties  |   0
 .../src/test/resources/{dev => debug}/log4j2.xml   |   0
 .../test/resources/{dev => debug}/wa.properties    |   2 +-
 140 files changed, 2290 insertions(+), 1772 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index c2a2b81..f44f586 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -116,6 +116,9 @@ jobs:
     - stage: fit
       name: "Integration Tests: Tomcat / H2 / JSON Content-Type + Zookeeper"
       script: mvn -f fit/core-reference/pom.xml -P zookeeper-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Dianal.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true
+    - stage: fit
+      name: "Integration Tests: SRA and WA"
+      script: mvn -f fit/wa-reference/pom.xml verify -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Dianal.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true
       after_failure:
        - cat fit/core-reference/target/log/*
        - cat fit/core-reference/target/failsafe-reports/org.apache.syncope.fit.*-output.txt
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java
index d986b85..3c210bf 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java
@@ -126,7 +126,7 @@ public class SRARouteDirectoryPanel
                         new AjaxWizard.EditItemActionEvent<>(
                                 SRARouteRestClient.read(model.getObject().getKey()), target));
             }
-        }, ActionLink.ActionType.EDIT, AMEntitlement.GATEWAY_ROUTE_UPDATE);
+        }, ActionLink.ActionType.EDIT, AMEntitlement.SRA_ROUTE_UPDATE);
 
         panel.add(new ActionLink<SRARouteTO>() {
 
@@ -139,7 +139,7 @@ public class SRARouteDirectoryPanel
                 send(SRARouteDirectoryPanel.this, Broadcast.EXACT,
                         new AjaxWizard.EditItemActionEvent<>(clone, target));
             }
-        }, ActionLink.ActionType.CLONE, AMEntitlement.GATEWAY_ROUTE_CREATE);
+        }, ActionLink.ActionType.CLONE, AMEntitlement.SRA_ROUTE_CREATE);
 
         panel.add(new ActionLink<SRARouteTO>() {
 
@@ -158,7 +158,7 @@ public class SRARouteDirectoryPanel
                 }
                 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
             }
-        }, ActionLink.ActionType.DELETE, AMEntitlement.GATEWAY_ROUTE_DELETE, true);
+        }, ActionLink.ActionType.DELETE, AMEntitlement.SRA_ROUTE_DELETE, true);
 
         return panel;
     }
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
index fd804fc..acde277 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/WizardMgtPanel.html
@@ -41,7 +41,7 @@ under the License.
 
       <wicket:enclosure child="add">
         <div class="modal-footer" style="text-align: right">
-          <a href="#" class="btn btn-default btn-circle btn-lg pull-left" wicket:id="utility">
+          <a href="#" class="btn btn-success btn-circle btn-lg pull-left" wicket:id="utility">
             <i wicket:id="utilityIcon" class="fas fa-sign-out-alt"></i>
           </a>
           <a href="#" class="btn btn-success btn-circle btn-lg" wicket:id="add">
diff --git a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
index bf6ea23..6192fd4 100644
--- a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
+++ b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
@@ -136,6 +136,15 @@ public class SyncopeClient {
     }
 
     /**
+     * Gives the base address for REST calls.
+     *
+     * @return the base address for REST calls
+     */
+    public String getAddress() {
+        return restClientFactory.getAddress();
+    }
+
+    /**
      * Attempts to extend the lifespan of the JWT currently in use.
      */
     public void refresh() {
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java
index 089d24c..9a28b37 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AbstractAuthModuleConf.java
@@ -24,18 +24,4 @@ public abstract class AbstractAuthModuleConf implements BaseBean, AuthModuleConf
 
     private static final long serialVersionUID = 4153200197344709778L;
 
-    private String name;
-
-    public AbstractAuthModuleConf() {
-        setName(getClass().getName());
-    }
-
-    @Override
-    public final String getName() {
-        return name;
-    }
-
-    public final void setName(final String name) {
-        this.name = name;
-    }
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
index 35be339..9fbac72 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/AuthModuleConf.java
@@ -23,11 +23,4 @@ import org.apache.syncope.common.lib.BaseBean;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class")
 public interface AuthModuleConf extends BaseBean {
-
-    /**
-     * Given name of related authentication module instance.
-     *
-     * @return name of this authentication module instance
-     */
-    String getName();
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java
index f83ae24..0d0ecc4 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SyncopeAuthModuleConf.java
@@ -18,19 +18,13 @@
  */
 package org.apache.syncope.common.lib.auth;
 
+import org.apache.syncope.common.lib.SyncopeConstants;
+
 public class SyncopeAuthModuleConf extends AbstractAuthModuleConf {
 
     private static final long serialVersionUID = -3334329948161152222L;
 
-    /**
-     * Syncope domain used for authentication, etc.
-     */
-    private String domain = "Master";
-
-    /**
-     * Syncope instance URL primary used for REST.
-     */
-    private String url;
+    private String domain = SyncopeConstants.MASTER_DOMAIN;
 
     public String getDomain() {
         return domain;
@@ -39,13 +33,4 @@ public class SyncopeAuthModuleConf extends AbstractAuthModuleConf {
     public void setDomain(final String domain) {
         this.domain = domain;
     }
-
-    public String getUrl() {
-        return url;
-    }
-
-    public void setUrl(final String url) {
-        this.url = url;
-    }
-
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccessPolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccessPolicyConf.java
index f5ebb4e..84b88cb 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccessPolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccessPolicyConf.java
@@ -35,8 +35,6 @@ public abstract class AbstractAccessPolicyConf implements BaseBean, AccessPolicy
 
     private static final long serialVersionUID = 1153200197344709778L;
 
-    private String name;
-
     private boolean enabled = true;
 
     private boolean ssoEnabled = true;
@@ -46,19 +44,6 @@ public abstract class AbstractAccessPolicyConf implements BaseBean, AccessPolicy
     @JsonProperty("requiredAttrs")
     private final List<Attr> requiredAttrList = new ArrayList<>();
 
-    public AbstractAccessPolicyConf() {
-        setName(getClass().getName());
-    }
-
-    @Override
-    public final String getName() {
-        return name;
-    }
-
-    public final void setName(final String name) {
-        this.name = name;
-    }
-
     @Override
     public boolean isEnabled() {
         return enabled;
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAttrReleasePolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAttrReleasePolicyConf.java
deleted file mode 100644
index 5013c4b..0000000
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAttrReleasePolicyConf.java
+++ /dev/null
@@ -1,41 +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.common.lib.policy;
-
-import org.apache.syncope.common.lib.BaseBean;
-
-public abstract class AbstractAttrReleasePolicyConf implements BaseBean, AttrReleasePolicyConf {
-
-    private static final long serialVersionUID = 1153200197344709778L;
-
-    private String name;
-
-    public AbstractAttrReleasePolicyConf() {
-        setName(getClass().getName());
-    }
-
-    @Override
-    public final String getName() {
-        return name;
-    }
-
-    public final void setName(final String name) {
-        this.name = name;
-    }
-}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyConf.java
index 1a66800..3e51994 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyConf.java
@@ -18,24 +18,12 @@
  */
 package org.apache.syncope.common.lib.policy;
 
-import org.apache.syncope.common.lib.BaseBean;
-
-public abstract class AbstractAuthPolicyConf implements BaseBean, AuthPolicyConf {
+public abstract class AbstractAuthPolicyConf implements AuthPolicyConf {
 
     private static final long serialVersionUID = 9185127128182430142L;
 
-    private String name;
-
     private AuthPolicyCriteriaConf criteria;
 
-    public AbstractAuthPolicyConf() {
-        setName(getClass().getName());
-    }
-
-    public AbstractAuthPolicyConf(final String name) {
-        setName(name);
-    }
-
     @Override
     public AuthPolicyCriteriaConf getCriteria() {
         return criteria;
@@ -44,13 +32,4 @@ public abstract class AbstractAuthPolicyConf implements BaseBean, AuthPolicyConf
     public void setCriteria(final AuthPolicyCriteriaConf criteria) {
         this.criteria = criteria;
     }
-
-    @Override
-    public final String getName() {
-        return name;
-    }
-
-    public final void setName(final String name) {
-        this.name = name;
-    }
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyCriteriaConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyCriteriaConf.java
deleted file mode 100644
index 8f9bd14..0000000
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAuthPolicyCriteriaConf.java
+++ /dev/null
@@ -1,43 +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.common.lib.policy;
-
-public abstract class AbstractAuthPolicyCriteriaConf implements AuthPolicyCriteriaConf {
-
-    private static final long serialVersionUID = -6882164291962510245L;
-
-    private String name;
-
-    public AbstractAuthPolicyCriteriaConf() {
-        setName(getClass().getName());
-    }
-
-    public AbstractAuthPolicyCriteriaConf(final String name) {
-        setName(name);
-    }
-
-    @Override
-    public final String getName() {
-        return name;
-    }
-
-    public final void setName(final String name) {
-        this.name = name;
-    }
-}
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AccessPolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AccessPolicyConf.java
index da2e53c..2462ee8 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AccessPolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AccessPolicyConf.java
@@ -26,13 +26,6 @@ import org.apache.syncope.common.lib.BaseBean;
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class")
 public interface AccessPolicyConf extends BaseBean {
 
-    /**
-     * Give name of related access policy.
-     *
-     * @return name of this access policy
-     */
-    String getName();
-
     boolean isEnabled();
 
     boolean isSsoEnabled();
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AllowedAttrReleasePolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AllowedAttrReleasePolicyConf.java
index 889c302..d72149f 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AllowedAttrReleasePolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AllowedAttrReleasePolicyConf.java
@@ -21,7 +21,7 @@ package org.apache.syncope.common.lib.policy;
 import java.util.ArrayList;
 import java.util.List;
 
-public class AllowedAttrReleasePolicyConf extends AbstractAttrReleasePolicyConf implements AttrReleasePolicyConf {
+public class AllowedAttrReleasePolicyConf implements AttrReleasePolicyConf {
 
     private static final long serialVersionUID = -1969836661359025380L;
 
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AttrReleasePolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AttrReleasePolicyConf.java
index fbd8c2e..f16479c 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AttrReleasePolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AttrReleasePolicyConf.java
@@ -23,11 +23,4 @@ import org.apache.syncope.common.lib.BaseBean;
 
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class")
 public interface AttrReleasePolicyConf extends BaseBean {
-
-    /**
-     * Give name of related attr release policy.
-     *
-     * @return name of this attr release policy
-     */
-    String getName();
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyConf.java
index e8a0945..f1dcb13 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyConf.java
@@ -25,13 +25,6 @@ import org.apache.syncope.common.lib.BaseBean;
 public interface AuthPolicyConf extends BaseBean {
 
     /**
-     * Give name of related authentication policy instance.
-     *
-     * @return name of this authentication policy instance
-     */
-    String getName();
-
-    /**
      * Gets the policy criteria linked to this policy
      * to establish criteria for success.
      *
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyCriteriaConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyCriteriaConf.java
index 6597368..f228b5c 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyCriteriaConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/AuthPolicyCriteriaConf.java
@@ -31,11 +31,4 @@ import org.apache.syncope.common.lib.BaseBean;
  */
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class")
 public interface AuthPolicyCriteriaConf extends BaseBean {
-
-    /**
-     * Describe the name of the authentication policy criteria.
-     *
-     * @return name of this authentication policy instance
-     */
-    String getName();
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAuthPolicyCriteriaConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAuthPolicyCriteriaConf.java
index 4d0f4b6..d4ed27a 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAuthPolicyCriteriaConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAuthPolicyCriteriaConf.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.common.lib.policy;
 
-public class DefaultAuthPolicyCriteriaConf extends AbstractAuthPolicyCriteriaConf {
+public class DefaultAuthPolicyCriteriaConf implements AuthPolicyCriteriaConf {
 
     private static final long serialVersionUID = 3928807032588105869L;
 
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java
index 9d4d7f6..0fc1533 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/AuthModuleTO.java
@@ -32,8 +32,6 @@ public class AuthModuleTO implements EntityTO {
 
     private String key;
 
-    private String name;
-
     private String description;
 
     private AuthModuleConf conf;
@@ -51,14 +49,6 @@ public class AuthModuleTO implements EntityTO {
         this.key = key;
     }
 
-    public String getName() {
-        return name;
-    }
-
-    public void setName(final String name) {
-        this.name = name;
-    }
-
     public String getDescription() {
         return description;
     }
@@ -101,7 +91,6 @@ public class AuthModuleTO implements EntityTO {
         AuthModuleTO other = (AuthModuleTO) obj;
         return new EqualsBuilder().
                 append(key, other.key).
-                append(name, other.name).
                 append(description, other.description).
                 append(items, other.items).
                 append(conf, other.conf).
@@ -112,7 +101,6 @@ public class AuthModuleTO implements EntityTO {
     public int hashCode() {
         return new HashCodeBuilder().
                 append(key).
-                append(name).
                 append(description).
                 append(items).
                 append(conf).
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCJWKSTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCJWKSTO.java
index abbcbde..b5794df 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCJWKSTO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/OIDCJWKSTO.java
@@ -38,10 +38,12 @@ public class OIDCJWKSTO implements EntityTO {
         this.json = json;
     }
 
+    @Override
     public String getKey() {
         return key;
     }
 
+    @Override
     public void setKey(final String key) {
         this.key = key;
     }
@@ -49,10 +51,10 @@ public class OIDCJWKSTO implements EntityTO {
     @Override
     public int hashCode() {
         return new HashCodeBuilder()
-            .appendSuper(super.hashCode())
-            .append(key)
-            .append(json)
-            .toHashCode();
+                .appendSuper(super.hashCode())
+                .append(key)
+                .append(json)
+                .toHashCode();
     }
 
     @Override
@@ -68,18 +70,18 @@ public class OIDCJWKSTO implements EntityTO {
         }
         OIDCJWKSTO rhs = (OIDCJWKSTO) obj;
         return new EqualsBuilder()
-            .appendSuper(super.equals(obj))
-            .append(this.key, rhs.key)
-            .append(this.json, rhs.json)
-            .isEquals();
+                .appendSuper(super.equals(obj))
+                .append(this.key, rhs.key)
+                .append(this.json, rhs.json)
+                .isEquals();
     }
 
     @Override
     public String toString() {
         return new ToStringBuilder(this)
-            .append("key", key)
-            .append("json", json)
-            .toString();
+                .append("key", key)
+                .append("json", json)
+                .toString();
     }
 
     public static class Builder {
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/OIDCRPTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/OIDCRPTO.java
index fbecde7..2e2c3d5 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/OIDCRPTO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/client/OIDCRPTO.java
@@ -40,8 +40,6 @@ public class OIDCRPTO extends ClientAppTO {
 
     private boolean signIdToken;
 
-    private String jwks;
-
     private OIDCSubjectType subjectType;
 
     private final List<String> redirectUris = new ArrayList<>();
@@ -50,6 +48,8 @@ public class OIDCRPTO extends ClientAppTO {
 
     private final Set<String> supportedResponseTypes = new HashSet<>();
 
+    private String logoutUri;
+
     @JacksonXmlProperty(localName = "_class", isAttribute = true)
     @JsonProperty("_class")
     @Schema(name = "_class", required = true, example = "org.apache.syncope.common.lib.to.client.OIDCRPTO")
@@ -94,14 +94,6 @@ public class OIDCRPTO extends ClientAppTO {
         this.signIdToken = signIdToken;
     }
 
-    public String getJwks() {
-        return jwks;
-    }
-
-    public void setJwks(final String jwks) {
-        this.jwks = jwks;
-    }
-
     public OIDCSubjectType getSubjectType() {
         return subjectType;
     }
@@ -110,6 +102,14 @@ public class OIDCRPTO extends ClientAppTO {
         this.subjectType = subjectType;
     }
 
+    public String getLogoutUri() {
+        return logoutUri;
+    }
+
+    public void setLogoutUri(final String logoutUri) {
+        this.logoutUri = logoutUri;
+    }
+
     @Override
     public boolean equals(final Object obj) {
         if (obj == null) {
@@ -126,12 +126,12 @@ public class OIDCRPTO extends ClientAppTO {
                 .appendSuper(super.equals(obj))
                 .append(this.clientId, rhs.clientId)
                 .append(this.clientSecret, rhs.clientSecret)
+                .append(this.signIdToken, rhs.signIdToken)
+                .append(this.subjectType, rhs.subjectType)
                 .append(this.redirectUris, rhs.redirectUris)
                 .append(this.supportedGrantTypes, rhs.supportedGrantTypes)
                 .append(this.supportedResponseTypes, rhs.supportedResponseTypes)
-                .append(this.signIdToken, rhs.signIdToken)
-                .append(this.jwks, rhs.jwks)
-                .append(this.subjectType, rhs.subjectType)
+                .append(this.logoutUri, rhs.logoutUri)
                 .isEquals();
     }
 
@@ -141,12 +141,12 @@ public class OIDCRPTO extends ClientAppTO {
                 .appendSuper(super.hashCode())
                 .append(clientId)
                 .append(clientSecret)
+                .append(signIdToken)
+                .append(subjectType)
                 .append(redirectUris)
                 .append(supportedGrantTypes)
                 .append(supportedResponseTypes)
-                .append(signIdToken)
-                .append(jwks)
-                .append(subjectType)
+                .append(logoutUri)
                 .toHashCode();
     }
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
index 2885db4..d32468b 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
@@ -26,13 +26,13 @@ import java.util.TreeSet;
 
 public final class AMEntitlement {
 
-    public static final String GATEWAY_ROUTE_CREATE = "GATEWAY_ROUTE_CREATE";
+    public static final String SRA_ROUTE_CREATE = "SRA_ROUTE_CREATE";
 
-    public static final String GATEWAY_ROUTE_UPDATE = "GATEWAY_ROUTE_UPDATE";
+    public static final String SRA_ROUTE_UPDATE = "SRA_ROUTE_UPDATE";
 
-    public static final String GATEWAY_ROUTE_DELETE = "GATEWAY_ROUTE_DELETE";
+    public static final String SRA_ROUTE_DELETE = "SRA_ROUTE_DELETE";
 
-    public static final String GATEWAY_ROUTE_PUSH = "GATEWAY_ROUTE_PUSH";
+    public static final String SRA_ROUTE_PUSH = "SRA_ROUTE_PUSH";
 
     public static final String CLIENTAPP_READ = "CLIENTAPP_READ";
 
@@ -83,7 +83,7 @@ public final class AMEntitlement {
     public static final String GOOGLE_MFA_COUNT_TOKEN = "GOOGLE_MFA_COUNT_TOKEN";
 
     public static final String AUTH_PROFILE_DELETE = "AUTH_PROFILE_DELETE";
-    
+
     public static final String AUTH_PROFILE_READ = "AUTH_PROFILE_READ";
 
     public static final String AUTH_PROFILE_LIST = "AUTH_PROFILE_LIST";
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/JWSAlgorithm.java
similarity index 82%
copy from common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java
copy to common/am/lib/src/main/java/org/apache/syncope/common/lib/types/JWSAlgorithm.java
index 1a30f24..015a9d2 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/JWSAlgorithm.java
@@ -18,17 +18,20 @@
  */
 package org.apache.syncope.common.lib.types;
 
-public enum SRARoutePredicateFactory {
-    AFTER,
-    BEFORE,
-    BETWEEN,
-    COOKIE,
-    HEADER,
-    HOST,
-    METHOD,
-    PATH,
-    QUERY,
-    REMOTE_ADDR,
-    CUSTOM
+public enum JWSAlgorithm {
+    HS256,
+    HS384,
+    HS512,
+    RS256,
+    RS384,
+    RS512,
+    ES256,
+    ES384,
+    ES512,
+    PS256,
+    PS384,
+    PS512,
+    EdDSA,
+    ES256K;
 
 }
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARouteFilterFactory.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARouteFilterFactory.java
index af22d21..da3614e 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARouteFilterFactory.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARouteFilterFactory.java
@@ -22,15 +22,18 @@ public enum SRARouteFilterFactory {
     ADD_REQUEST_HEADER,
     ADD_REQUEST_PARAMETER,
     ADD_RESPONSE_HEADER,
+    DEDUPE_RESPONSE_HEADER,
     HYSTRIX,
     FALLBACK_HEADERS,
+    MAP_REQUEST_HEADER,
     PREFIX_PATH,
     PRESERVE_HOST_HEADER,
-    REDIRECT,
+    REDIRECT_TO,
     REMOVE_REQUEST_HEADER,
     REMOVE_RESPONSE_HEADER,
     REQUEST_RATE_LIMITER,
     REWRITE_PATH,
+    REWRITE_LOCATION,
     RETRY,
     SECURE_HEADERS,
     SET_PATH,
@@ -42,6 +45,7 @@ public enum SRARouteFilterFactory {
     STRIP_PREFIX,
     REQUEST_HEADER_TO_REQUEST_URI,
     SET_REQUEST_SIZE,
+    SET_REQUEST_HOST,
     LINK_REWRITE,
     CLIENT_CERTS_TO_REQUEST_HEADER,
     QUERY_PARAM_TO_REQUEST_HEADER,
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java
index 1a30f24..892fe8c 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/SRARoutePredicateFactory.java
@@ -29,6 +29,7 @@ public enum SRARoutePredicateFactory {
     PATH,
     QUERY,
     REMOTE_ADDR,
+    WEIGHT,
     CUSTOM
 
 }
diff --git a/common/am/lib/src/test/java/org/apache/syncope/common/lib/SerializationTest.java b/common/am/lib/src/test/java/org/apache/syncope/common/lib/SerializationTest.java
index 28ac120..cb23016 100644
--- a/common/am/lib/src/test/java/org/apache/syncope/common/lib/SerializationTest.java
+++ b/common/am/lib/src/test/java/org/apache/syncope/common/lib/SerializationTest.java
@@ -39,7 +39,6 @@ public abstract class SerializationTest {
 
         DefaultAccessPolicyConf conf = new DefaultAccessPolicyConf();
         conf.setEnabled(true);
-        conf.setName("TestAccessPolicyConf");
         conf.addRequiredAttr("cn", Set.of("admin", "Admin", "TheAdmin"));
         policy.setConf(conf);
 
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileService.java
index a2233b2..ce3cd97 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileService.java
@@ -35,9 +35,9 @@ import org.apache.syncope.common.lib.to.AuthProfileTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 
 /**
- * REST operations for SAML 2.0 SP metadata.
+ * REST operations for Auth profiles.
  */
-@Tag(name = "Auth Profiles")
+@Tag(name = "AuthProfiles")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSConfService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
similarity index 82%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSConfService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
index fbc8de7..e5287ff 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSConfService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/OIDCJWKSService.java
@@ -22,9 +22,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.OIDCJWKSTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -32,23 +29,24 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.OIDCJWKSTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 
-@Tag(name = "OIDC Json Web Keystore")
+@Tag(name = "OpenID Connect 1.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer")})
+    @SecurityRequirement(name = "Bearer") })
 @Path("oidc/jwks")
-public interface OIDCJWKSConfService extends JAXRSService {
+public interface OIDCJWKSService extends JAXRSService {
 
     @ApiResponse(responseCode = "204", description = "Operation was successful")
     @PUT
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void update(@NotNull OIDCJWKSTO jwksTO);
 
     @DELETE
     @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    Response delete();
+    void delete();
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataConfService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataService.java
similarity index 94%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataConfService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataService.java
index fafe273..5fad024 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataConfService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2IdPMetadataService.java
@@ -38,12 +38,12 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
 /**
  * REST operations for SAML 2.0 IdP metadata.
  */
-@Tag(name = "SAML 2.0 IdP Metadata")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
-@Path("saml2idp/conf/metadata")
-public interface SAML2IdPMetadataConfService extends JAXRSService {
+@Path("saml2idp/metadata")
+public interface SAML2IdPMetadataService extends JAXRSService {
 
     /**
      * Updates SAML 2.0 IdP metadata matching the given key.
@@ -59,5 +59,4 @@ public interface SAML2IdPMetadataConfService extends JAXRSService {
     @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void update(@NotNull SAML2IdPMetadataTO saml2IdPMetadataTO);
-
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreConfService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreService.java
similarity index 94%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreConfService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreService.java
index ffc169e..47c1162 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreConfService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPKeystoreService.java
@@ -26,25 +26,24 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 
 /**
  * REST operations for SAML 2.0 SP Keystore.
  */
-@Tag(name = "SAML 2.0 SP Keystore")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
-@Path("saml2sp/conf/keystore")
-public interface SAML2SPKeystoreConfService extends JAXRSService {
+@Path("saml2sp/keystore")
+public interface SAML2SPKeystoreService extends JAXRSService {
 
     /**
      * Updates SAML 2.0 SP keystore matching the given key.
@@ -60,5 +59,4 @@ public interface SAML2SPKeystoreConfService extends JAXRSService {
     @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void update(@NotNull SAML2SPKeystoreTO keystoreTO);
-
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataConfService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataService.java
similarity index 81%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataConfService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataService.java
index 227a0d0..f90c0f4 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataConfService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPMetadataService.java
@@ -26,25 +26,24 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 
 /**
  * REST operations for SAML 2.0 SP metadata.
  */
-@Tag(name = "SAML 2.0 SP Metadata")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer")})
-@Path("saml2sp/conf/metadata")
-public interface SAML2SPMetadataConfService extends JAXRSService {
+    @SecurityRequirement(name = "Bearer") })
+@Path("saml2sp/metadata")
+public interface SAML2SPMetadataService extends JAXRSService {
 
     /**
      * Updates SAML 2.0 SP metadata matching the given key.
@@ -52,13 +51,12 @@ public interface SAML2SPMetadataConfService extends JAXRSService {
      * @param metadataTO SAML2SPMetadata to replace existing SAML 2.0 SP metadata
      */
     @Parameter(name = "key", description = "SAML2SPMetadata's key", in = ParameterIn.PATH, schema =
-    @Schema(type = "string"))
+            @Schema(type = "string"))
     @ApiResponses(
-        @ApiResponse(responseCode = "204", description = "Operation was successful"))
+            @ApiResponse(responseCode = "204", description = "Operation was successful"))
     @PUT
     @Path("{key}")
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void update(@NotNull SAML2SPMetadataTO metadataTO);
-
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SRARouteService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SRARouteService.java
index 2838922..d10bf5a 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SRARouteService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SRARouteService.java
@@ -46,11 +46,11 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
 /**
  * REST operations for SRA routes.
  */
-@Tag(name = "SRARoutes")
+@Tag(name = "SRA Routes")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
-@Path("gatewayRoutes")
+@Path("sraRoutes")
 public interface SRARouteService extends JAXRSService {
 
     /**
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
index 3dbac81..bec5433 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthAccountService.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.common.rest.api.service.wa;
 
 import io.swagger.v3.oas.annotations.headers.Header;
@@ -26,11 +25,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.PagedResult;
-import org.apache.syncope.common.lib.types.GoogleMfaAuthAccount;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.JAXRSService;
-
+import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -42,85 +37,87 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-
-import java.util.List;
+import org.apache.syncope.common.lib.to.PagedResult;
+import org.apache.syncope.common.lib.types.GoogleMfaAuthAccount;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
 
 @Tag(name = "Google MFA Accounts")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer")})
+    @SecurityRequirement(name = "Bearer") })
 @Path("wa/gauth")
 public interface GoogleMfaAuthAccountService extends JAXRSService {
 
     @DELETE
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts/owners/${owner}")
     Response deleteAccountsFor(@NotNull @PathParam("owner") String owner);
 
     @DELETE
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts/${key}")
     Response deleteAccountBy(@NotNull @PathParam("key") String key);
 
     @DELETE
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts")
     Response deleteAll();
 
     @ApiResponses({
         @ApiResponse(responseCode = "201",
-            description = "GoogleMfaAuthAccount successfully created", headers = {
-            @Header(name = RESTHeaders.RESOURCE_KEY, schema =
-            @Schema(type = "string"),
-                description = "UUID generated for the entity created")})})
+                description = "GoogleMfaAuthAccount successfully created", headers = {
+                    @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                            @Schema(type = "string"),
+                            description = "UUID generated for the entity created") }) })
     @POST
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts")
     Response save(@NotNull GoogleMfaAuthAccount acct);
 
     @PUT
     @Path("accts")
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void update(@NotNull GoogleMfaAuthAccount acct);
 
     @GET
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts/owners/${owner}")
     List<GoogleMfaAuthAccount> findAccountsFor(@NotNull @PathParam("owner") String owner);
 
     @GET
     @Path("accts/{key}")
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     GoogleMfaAuthAccount findAccountBy(@NotNull @PathParam("key") String key);
 
     @GET
     @Path("accts/id/{id}")
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     GoogleMfaAuthAccount findAccountBy(@NotNull @PathParam("id") long id);
 
     @GET
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts/count")
     PagedResult<GoogleMfaAuthAccount> countAll();
 
     @GET
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts/count/{owner}")
     PagedResult<GoogleMfaAuthAccount> countFor(@NotNull @PathParam("owner") String owner);
 
     @GET
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Path("accts")
     List<GoogleMfaAuthAccount> list();
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/OIDCJWKSService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WAOIDCJWKSService.java
similarity index 59%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/OIDCJWKSService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WAOIDCJWKSService.java
index 6c28c9a..b3d511d 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/OIDCJWKSService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WAOIDCJWKSService.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.common.rest.api.service.wa;
 
 import io.swagger.v3.oas.annotations.headers.Header;
@@ -26,43 +25,49 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.validation.constraints.NotNull;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.service.JAXRSService;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
 
-@Tag(name = "OIDC Json Web Keystore")
+@Tag(name = "OpenID Connect 1.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer")})
+    @SecurityRequirement(name = "Bearer") })
 @Path("wa/oidc/jwks")
-public interface OIDCJWKSService extends JAXRSService {
+public interface WAOIDCJWKSService extends JAXRSService {
 
     @GET
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     OIDCJWKSTO get();
 
     @ApiResponses({
         @ApiResponse(responseCode = "201",
-            description = "JWKS successfully created", headers = {
-            @Header(name = RESTHeaders.RESOURCE_KEY, schema =
-            @Schema(type = "string"),
-                description = "UUID generated for the entity created"),
-            @Header(name = HttpHeaders.LOCATION, schema =
-            @Schema(type = "string"),
-                description = "URL of the entity created")}),
+                description = "JWKS successfully created", headers = {
+                    @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                            @Schema(type = "string"),
+                            description = "UUID generated for the entity created"),
+                    @Header(name = HttpHeaders.LOCATION, schema =
+                            @Schema(type = "string"),
+                            description = "URL of the entity created") }),
         @ApiResponse(responseCode = "409",
-            description = "JWKS already exists")})
+                description = "JWKS already exists") })
     @POST
-    @Consumes({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
-    Response set();
+    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    Response set(
+            @NotNull @QueryParam("size") @DefaultValue("2048") int size,
+            @NotNull @QueryParam("algorithm") @DefaultValue("RS256") JWSAlgorithm algorithm);
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2IdPMetadataService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2IdPMetadataService.java
similarity index 97%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2IdPMetadataService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2IdPMetadataService.java
index 00201b7..219abb0 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2IdPMetadataService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2IdPMetadataService.java
@@ -44,12 +44,12 @@ import org.apache.syncope.common.rest.api.service.JAXRSService;
 /**
  * REST operations for SAML 2.0 IdP metadata.
  */
-@Tag(name = "SAML 2.0 IdP Metadata")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
 @Path("wa/saml2idp/metadata")
-public interface SAML2IdPMetadataService extends JAXRSService {
+public interface WASAML2IdPMetadataService extends JAXRSService {
 
     /**
      * Returns a document outlining keys and metadata of Syncope as SAML 2.0 IdP.
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPKeystoreService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPKeystoreService.java
similarity index 84%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPKeystoreService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPKeystoreService.java
index 549af13..05e2021 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPKeystoreService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPKeystoreService.java
@@ -25,10 +25,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.JAXRSService;
-
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -40,16 +36,19 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
 
 /**
  * REST operations for SAML 2.0 IdP keystore.
  */
-@Tag(name = "SAML 2.0 SP Metadata Keystore")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
 @Path("wa/saml2sp/keystore")
-public interface SAML2SPKeystoreService extends JAXRSService {
+public interface WASAML2SPKeystoreService extends JAXRSService {
 
     /**
      * Returns a document outlining keystore for Syncope as SAML 2.0 SP.
@@ -80,18 +79,17 @@ public interface SAML2SPKeystoreService extends JAXRSService {
      */
     @ApiResponses({
         @ApiResponse(responseCode = "201",
-            description = "SAML2SPKeystoreTO successfully created", headers = {
-            @Header(name = RESTHeaders.RESOURCE_KEY, schema =
-            @Schema(type = "string"),
-                description = "UUID generated for the entity created"),
-            @Header(name = HttpHeaders.LOCATION, schema =
-            @Schema(type = "string"),
-                description = "URL of the entity created") }),
+                description = "SAML2SPKeystoreTO successfully created", headers = {
+                    @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                            @Schema(type = "string"),
+                            description = "UUID generated for the entity created"),
+                    @Header(name = HttpHeaders.LOCATION, schema =
+                            @Schema(type = "string"),
+                            description = "URL of the entity created") }),
         @ApiResponse(responseCode = "409",
-            description = "Metadata already existing") })
+                description = "Metadata already existing") })
     @POST
     @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     Response set(@NotNull SAML2SPKeystoreTO keystoreTO);
-
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPMetadataService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPMetadataService.java
similarity index 84%
rename from common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPMetadataService.java
rename to common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPMetadataService.java
index 24bb918..f3c84b2 100644
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/SAML2SPMetadataService.java
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPMetadataService.java
@@ -25,10 +25,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.JAXRSService;
-
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -40,16 +36,19 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
 
 /**
  * REST operations for SAML 2.0 SP metadata.
  */
-@Tag(name = "SAML 2.0 SP Metadata")
+@Tag(name = "SAML 2.0")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
     @SecurityRequirement(name = "Bearer") })
 @Path("wa/saml2sp/metadata")
-public interface SAML2SPMetadataService extends JAXRSService {
+public interface WASAML2SPMetadataService extends JAXRSService {
 
     /**
      * Returns a document outlining metadata for Syncope as SAML 2.0 SP.
@@ -80,18 +79,17 @@ public interface SAML2SPMetadataService extends JAXRSService {
      */
     @ApiResponses({
         @ApiResponse(responseCode = "201",
-            description = "SAML2SPMetadata successfully created", headers = {
-            @Header(name = RESTHeaders.RESOURCE_KEY, schema =
-            @Schema(type = "string"),
-                description = "UUID generated for the entity created"),
-            @Header(name = HttpHeaders.LOCATION, schema =
-            @Schema(type = "string"),
-                description = "URL of the entity created") }),
+                description = "SAML2SPMetadata successfully created", headers = {
+                    @Header(name = RESTHeaders.RESOURCE_KEY, schema =
+                            @Schema(type = "string"),
+                            description = "UUID generated for the entity created"),
+                    @Header(name = HttpHeaders.LOCATION, schema =
+                            @Schema(type = "string"),
+                            description = "URL of the entity created") }),
         @ApiResponse(responseCode = "409",
-            description = "Metadata already existing") })
+                description = "Metadata already existing") })
     @POST
     @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     Response set(@NotNull SAML2SPMetadataTO metadataTO);
-
 }
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java
index f8be20a..9cb29e8 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthModuleLogic.java
@@ -20,7 +20,6 @@ package org.apache.syncope.core.logic;
 
 import java.lang.reflect.Method;
 import java.util.List;
-import java.util.Objects;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
@@ -62,18 +61,7 @@ public class AuthModuleLogic extends AbstractTransactionalLogic<AuthModuleTO> {
     @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_LIST + "') or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
     @Transactional(readOnly = true)
     public List<AuthModuleTO> list() {
-        return authModuleDAO.findAll().stream().
-                filter(Objects::nonNull).
-                map(authModule -> {
-                    AuthModuleTO result = null;
-                    try {
-                        result = binder.getAuthModuleTO(authModule);
-                    } catch (NotFoundException e) {
-                        LOG.error("Authentication module '{}' not found", authModule.getName());
-                    }
-
-                    return result;
-                }).collect(Collectors.toList());
+        return authModuleDAO.findAll().stream().map(binder::getAuthModuleTO).collect(Collectors.toList());
     }
 
     @PreAuthorize("hasRole('" + AMEntitlement.AUTH_MODULE_READ + "')")
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
index 4212427..67a2767 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/OIDCJWKSLogic.java
@@ -16,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.core.logic;
 
-import org.apache.syncope.common.lib.SyncopeClientException;
+import java.lang.reflect.Method;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.lib.types.AMEntitlement;
-import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
+import org.apache.syncope.core.persistence.api.dao.DuplicateException;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.auth.OIDCJWKSDAO;
 import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
@@ -33,8 +33,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.lang.reflect.Method;
-
 @Component
 public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
 
@@ -44,8 +42,7 @@ public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
     @Autowired
     private OIDCJWKSDAO dao;
 
-    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_READ + "') "
-        + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_READ + "') or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
     @Transactional(readOnly = true)
     public OIDCJWKSTO get() {
         OIDCJWKS jwks = dao.get();
@@ -55,37 +52,36 @@ public class OIDCJWKSLogic extends AbstractTransactionalLogic<OIDCJWKSTO> {
         throw new NotFoundException("OIDC JWKS not found");
     }
 
-    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_CREATE + "') "
-        + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public OIDCJWKSTO set() {
+    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_CREATE + "') or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    public OIDCJWKSTO set(final int size, final JWSAlgorithm algorithm) {
         OIDCJWKS jwks = dao.get();
         if (jwks == null) {
-            return binder.get(dao.save(binder.create()));
+            return binder.get(dao.save(binder.create(size, algorithm)));
         }
-        throw SyncopeClientException.build(ClientExceptionType.EntityExists);
+        throw new DuplicateException("OIDC JWKS already set");
     }
 
     @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_UPDATE + "')")
     public OIDCJWKSTO update(final OIDCJWKSTO jwksTO) {
         OIDCJWKS jwks = dao.get();
         if (jwks == null) {
-            throw SyncopeClientException.build(ClientExceptionType.NotFound);
+            throw new NotFoundException("OIDC JWKS not found");
         }
         return binder.get(dao.save(binder.update(jwks, jwksTO)));
     }
 
+    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_DELETE + "')")
+    public void delete() {
+        dao.delete();
+    }
+
     @Override
     protected OIDCJWKSTO resolveReference(final Method method, final Object... args)
-        throws UnresolvedReferenceException {
+            throws UnresolvedReferenceException {
         OIDCJWKS jwks = dao.get();
         if (jwks == null) {
             throw new UnresolvedReferenceException();
         }
         return binder.get(jwks);
     }
-
-    @PreAuthorize("hasRole('" + AMEntitlement.OIDC_JWKS_DELETE + "')")
-    public void delete() {
-         dao.delete();
-    }
 }
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/SRARouteLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/SRARouteLogic.java
index 31643b8..e43b7c6 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/SRARouteLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/SRARouteLogic.java
@@ -72,7 +72,7 @@ public class SRARouteLogic extends AbstractTransactionalLogic<SRARouteTO> {
         return routeDAO.findAll().stream().map(binder::getSRARouteTO).collect(Collectors.toList());
     }
 
-    @PreAuthorize("hasRole('" + AMEntitlement.GATEWAY_ROUTE_CREATE + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.SRA_ROUTE_CREATE + "')")
     public SRARouteTO create(final SRARouteTO routeTO) {
         SRARoute route = entityFactory.newEntity(SRARoute.class);
         binder.getSRARoute(route, routeTO);
@@ -89,7 +89,7 @@ public class SRARouteLogic extends AbstractTransactionalLogic<SRARouteTO> {
         return binder.getSRARouteTO(route);
     }
 
-    @PreAuthorize("hasRole('" + AMEntitlement.GATEWAY_ROUTE_UPDATE + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.SRA_ROUTE_UPDATE + "')")
     public SRARouteTO update(final SRARouteTO routeTO) {
         SRARoute route = routeDAO.find(routeTO.getKey());
         if (route == null) {
@@ -101,7 +101,7 @@ public class SRARouteLogic extends AbstractTransactionalLogic<SRARouteTO> {
         return binder.getSRARouteTO(routeDAO.save(route));
     }
 
-    @PreAuthorize("hasRole('" + AMEntitlement.GATEWAY_ROUTE_DELETE + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.SRA_ROUTE_DELETE + "')")
     public SRARouteTO delete(final String key) {
         SRARoute route = routeDAO.find(key);
         if (route == null) {
@@ -113,13 +113,13 @@ public class SRARouteLogic extends AbstractTransactionalLogic<SRARouteTO> {
         return deleted;
     }
 
-    @PreAuthorize("hasRole('" + AMEntitlement.GATEWAY_ROUTE_PUSH + "')")
+    @PreAuthorize("hasRole('" + AMEntitlement.SRA_ROUTE_PUSH + "')")
     public void pushToSRA() {
         try {
             NetworkService sra = serviceOps.get(NetworkService.Type.SRA);
             HttpClient.newBuilder().build().send(
                     HttpRequest.newBuilder(URI.create(
-                            StringUtils.appendIfMissing(sra.getAddress(), "/") + "management/routes/refresh")).
+                            StringUtils.appendIfMissing(sra.getAddress(), "/") + "actuator/gateway/refresh")).
                             header(HttpHeaders.AUTHORIZATION,
                                     DefaultBasicAuthSupplier.getBasicAuthHeader(anonymousUser, anonymousKey)).
                             POST(HttpRequest.BodyPublishers.noBody()).build(),
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/wa/WAClientAppLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/wa/WAClientAppLogic.java
index 1bb6cd5..a1e6765 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/wa/WAClientAppLogic.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/wa/WAClientAppLogic.java
@@ -37,13 +37,13 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.core.provisioning.api.data.wa.WAClientAppBinder;
+import org.apache.syncope.core.provisioning.api.data.wa.WAClientAppDataBinder;
 
 @Component
 public class WAClientAppLogic {
 
     @Autowired
-    private WAClientAppBinder binder;
+    private WAClientAppDataBinder binder;
 
     @Autowired
     private SAML2SPDAO saml2spDAO;
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSConfServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
similarity index 82%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSConfServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
index a6a534b..39820ea 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSConfServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/OIDCJWKSServiceImpl.java
@@ -19,15 +19,13 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
-import org.apache.syncope.common.rest.api.service.OIDCJWKSConfService;
 import org.apache.syncope.core.logic.OIDCJWKSLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-
-import javax.ws.rs.core.Response;
+import org.apache.syncope.common.rest.api.service.OIDCJWKSService;
 
 @Service
-public class OIDCJWKSConfServiceImpl extends AbstractServiceImpl implements OIDCJWKSConfService {
+public class OIDCJWKSServiceImpl extends AbstractServiceImpl implements OIDCJWKSService {
 
     @Autowired
     private OIDCJWKSLogic logic;
@@ -38,8 +36,7 @@ public class OIDCJWKSConfServiceImpl extends AbstractServiceImpl implements OIDC
     }
 
     @Override
-    public Response delete() {
+    public void delete() {
         logic.delete();
-        return Response.noContent().build();
     }
 }
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataConfServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataServiceImpl.java
similarity index 91%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataConfServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataServiceImpl.java
index 12b6cb6..6db81ae 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataConfServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2IdPMetadataServiceImpl.java
@@ -19,13 +19,13 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
-import org.apache.syncope.common.rest.api.service.SAML2IdPMetadataConfService;
 import org.apache.syncope.core.logic.SAML2IdPMetadataLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.apache.syncope.common.rest.api.service.SAML2IdPMetadataService;
 
 @Service
-public class SAML2IdPMetadataConfServiceImpl extends AbstractServiceImpl implements SAML2IdPMetadataConfService {
+public class SAML2IdPMetadataServiceImpl extends AbstractServiceImpl implements SAML2IdPMetadataService {
 
     @Autowired
     private SAML2IdPMetadataLogic logic;
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreConfServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreServiceImpl.java
similarity index 91%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreConfServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreServiceImpl.java
index 43aaedf..0a670c3 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreConfServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPKeystoreServiceImpl.java
@@ -19,13 +19,13 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPKeystoreConfService;
 import org.apache.syncope.core.logic.SAML2SPKeystoreLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.apache.syncope.common.rest.api.service.SAML2SPKeystoreService;
 
 @Service
-public class SAML2SPKeystoreConfServiceImpl extends AbstractServiceImpl implements SAML2SPKeystoreConfService {
+public class SAML2SPKeystoreServiceImpl extends AbstractServiceImpl implements SAML2SPKeystoreService {
 
     @Autowired
     private SAML2SPKeystoreLogic logic;
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataConfServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataServiceImpl.java
similarity index 91%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataConfServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataServiceImpl.java
index 13f9239..93a87dc 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataConfServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPMetadataServiceImpl.java
@@ -19,13 +19,13 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPMetadataConfService;
 import org.apache.syncope.core.logic.SAML2SPMetadataLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.apache.syncope.common.rest.api.service.SAML2SPMetadataService;
 
 @Service
-public class SAML2SPMetadataConfServiceImpl extends AbstractServiceImpl implements SAML2SPMetadataConfService {
+public class SAML2SPMetadataServiceImpl extends AbstractServiceImpl implements SAML2SPMetadataService {
 
     @Autowired
     private SAML2SPMetadataLogic logic;
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/OIDCJWKSServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WAOIDCJWKSServiceImpl.java
similarity index 76%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/OIDCJWKSServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WAOIDCJWKSServiceImpl.java
index 19df5d4..fa3fb69 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/OIDCJWKSServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WAOIDCJWKSServiceImpl.java
@@ -16,23 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.core.rest.cxf.service.wa;
 
+import java.net.URI;
+import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.wa.OIDCJWKSService;
 import org.apache.syncope.core.logic.OIDCJWKSLogic;
 import org.apache.syncope.core.rest.cxf.service.AbstractServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-
-import javax.ws.rs.core.Response;
-
-import java.net.URI;
+import org.apache.syncope.common.rest.api.service.wa.WAOIDCJWKSService;
 
 @Service
-public class OIDCJWKSServiceImpl extends AbstractServiceImpl implements OIDCJWKSService {
+public class WAOIDCJWKSServiceImpl extends AbstractServiceImpl implements WAOIDCJWKSService {
+
     @Autowired
     private OIDCJWKSLogic logic;
 
@@ -42,12 +41,12 @@ public class OIDCJWKSServiceImpl extends AbstractServiceImpl implements OIDCJWKS
     }
 
     @Override
-    public Response set() {
-        OIDCJWKSTO jwks = logic.set();
+    public Response set(final int size, final JWSAlgorithm algorithm) {
+        OIDCJWKSTO jwks = logic.set(size, algorithm);
         URI location = uriInfo.getAbsolutePathBuilder().path(jwks.getKey()).build();
         return Response.created(location).
-            header(RESTHeaders.RESOURCE_KEY, jwks.getKey()).
-            entity(jwks).
-            build();
+                header(RESTHeaders.RESOURCE_KEY, jwks.getKey()).
+                entity(jwks).
+                build();
     }
 }
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2IdPMetadataServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2IdPMetadataServiceImpl.java
similarity index 91%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2IdPMetadataServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2IdPMetadataServiceImpl.java
index 6bc3dc2..cef4562 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2IdPMetadataServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2IdPMetadataServiceImpl.java
@@ -22,14 +22,14 @@ import java.net.URI;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.wa.SAML2IdPMetadataService;
 import org.apache.syncope.core.logic.SAML2IdPMetadataLogic;
 import org.apache.syncope.core.rest.cxf.service.AbstractServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2IdPMetadataService;
 
 @Service
-public class SAML2IdPMetadataServiceImpl extends AbstractServiceImpl implements SAML2IdPMetadataService {
+public class WASAML2IdPMetadataServiceImpl extends AbstractServiceImpl implements WASAML2IdPMetadataService {
 
     @Autowired
     private SAML2IdPMetadataLogic logic;
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPKeystoreServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPKeystoreServiceImpl.java
similarity index 83%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPKeystoreServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPKeystoreServiceImpl.java
index 852a701..64a6918 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPKeystoreServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPKeystoreServiceImpl.java
@@ -18,20 +18,18 @@
  */
 package org.apache.syncope.core.rest.cxf.service.wa;
 
+import java.net.URI;
+import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPKeystoreService;
 import org.apache.syncope.core.logic.SAML2SPKeystoreLogic;
 import org.apache.syncope.core.rest.cxf.service.AbstractServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-
-import javax.ws.rs.core.Response;
-
-import java.net.URI;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPKeystoreService;
 
 @Service
-public class SAML2SPKeystoreServiceImpl extends AbstractServiceImpl implements SAML2SPKeystoreService {
+public class WASAML2SPKeystoreServiceImpl extends AbstractServiceImpl implements WASAML2SPKeystoreService {
 
     @Autowired
     private SAML2SPKeystoreLogic logic;
@@ -48,10 +46,10 @@ public class SAML2SPKeystoreServiceImpl extends AbstractServiceImpl implements S
 
     @Override
     public Response set(final SAML2SPKeystoreTO keystoreTO) {
-        final SAML2SPKeystoreTO keystore = logic.set(keystoreTO);
+        SAML2SPKeystoreTO keystore = logic.set(keystoreTO);
         URI location = uriInfo.getAbsolutePathBuilder().path(keystore.getKey()).build();
         return Response.created(location).
-            header(RESTHeaders.RESOURCE_KEY, keystore.getKey()).
-            build();
+                header(RESTHeaders.RESOURCE_KEY, keystore.getKey()).
+                build();
     }
 }
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPMetadataServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPMetadataServiceImpl.java
similarity index 86%
rename from core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPMetadataServiceImpl.java
rename to core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPMetadataServiceImpl.java
index 3a8bf55..67fa859 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/SAML2SPMetadataServiceImpl.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPMetadataServiceImpl.java
@@ -18,20 +18,18 @@
  */
 package org.apache.syncope.core.rest.cxf.service.wa;
 
+import java.net.URI;
+import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.core.logic.SAML2SPMetadataLogic;
 import org.apache.syncope.core.rest.cxf.service.AbstractServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-
-import javax.ws.rs.core.Response;
-
-import java.net.URI;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
 
 @Service
-public class SAML2SPMetadataServiceImpl extends AbstractServiceImpl implements SAML2SPMetadataService {
+public class WASAML2SPMetadataServiceImpl extends AbstractServiceImpl implements WASAML2SPMetadataService {
 
     @Autowired
     private SAML2SPMetadataLogic logic;
@@ -51,7 +49,7 @@ public class SAML2SPMetadataServiceImpl extends AbstractServiceImpl implements S
         SAML2SPMetadataTO spMetadata = logic.set(metadataTO);
         URI location = uriInfo.getAbsolutePathBuilder().path(spMetadata.getKey()).build();
         return Response.created(location).
-            header(RESTHeaders.RESOURCE_KEY, spMetadata.getKey()).
-            build();
+                header(RESTHeaders.RESOURCE_KEY, spMetadata.getKey()).
+                build();
     }
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java
index 8ba362c..f2c7bf9 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/AuthModule.java
@@ -20,13 +20,9 @@ package org.apache.syncope.core.persistence.api.entity.auth;
 
 import java.util.List;
 import org.apache.syncope.common.lib.auth.AuthModuleConf;
-import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.ProvidedKeyEntity;
 
-public interface AuthModule extends Entity {
-
-    String getName();
-
-    void setName(String name);
+public interface AuthModule extends ProvidedKeyEntity {
 
     String getDescription();
 
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/OIDCRP.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/OIDCRP.java
index 0a72461..6ce0f82 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/OIDCRP.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/auth/OIDCRP.java
@@ -42,11 +42,11 @@ public interface OIDCRP extends ClientApp {
 
     void setSignIdToken(boolean signIdToken);
 
-    String getJwks();
-
-    void setJwks(String jwks);
-
     OIDCSubjectType getSubjectType();
 
     void setSubjectType(OIDCSubjectType subjectType);
+
+    String getLogoutUri();
+
+    void setLogoutUri(String logoutUri);
 }
diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
index f69dffb..ac39f7a 100644
--- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
@@ -61,27 +61,37 @@ under the License.
                      jsonConf='{"_class":"org.apache.syncope.common.lib.policy.AllowedAttrReleasePolicyConf","name":"DenyAttrReleasePolicyConf"}'/>
   
   <!-- Authentication modules -->
-  <AuthModule id="be456831-593d-4003-b273-4c3fb61700df" name="DefaultLDAPAuthModule" 
-              description="LDAP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.LDAPAuthModuleConf","name":"MyLDAPAuthModuleConf","userIdAttribute":"uid","bindCredential":"Password","ldapUrl":"ldap://localhost:1389","searchFilter":"cn={user}","baseDn":"dc=example,dc=org","subtreeSearch":true}'/>
-  <AuthModule id="4c3ed7e8-7008-11ea-bc55-0242ac130003" name="DefaultJDBCAuthModule"
-              description="JDBC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JDBCAuthModuleConf","name":"MyJDBCAuthModuleConf", "sql":"SELECT * FROM table WHERE name=?"}'/>
-  <AuthModule id="4c3ed4e6-7008-11ea-bc55-0242ac130003" name="DefaultGoogleMfaAuthModule"
-              description="Google Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf","name":"MyGoogleMfaAuthModuleConf","codeDigits":6,"issuer":"SyncopeTest", "label":"SyncopeTest", "timeStepSize":30, "windowSize":3}'/>
-  <AuthModule id="4c3ed8f6-7008-11ea-bc55-0242ac130003" name="DefaultOIDCAuthModule"
-              description="OIDC auth module"
-              jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","name":"MyOIDCAuthModuleConf", "discoveryUri":"https://accounts.google.com/.well-known/openid-configuration", "id":"client-id", "secret": "client-secret" }'/>
-  <AuthModule id="4c3ed9d2-7008-11ea-bc55-0242ac130003" name="DefaultSAML2IdPAuthModule"
-              description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","name":"MySAML2IdPAuthModuleConf", "keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"classpath:/idp-metadata.xml", "serviceProviderEntityId":"syncope:apache:org"}'/>
-  <AuthModule id="4c3edbbc-7008-11ea-bc55-0242ac130003" name="DefaultJaasAuthModule"
-              description="Jaas auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JaasAuthModuleConf","name":"MyJaasAuthModuleConf","realm":"SYNCOPE","kerberosRealmSystemProperty":"sample-value"}'/>
-  <AuthModule id="4c3edc98-7008-11ea-bc55-0242ac130003" name="DefaultStaticAuthModule"
-              description="Static auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.StaticAuthModuleConf","name":"MyStaticAuthModuleConf","users":{"user1": "testUserPassword123"}}'/>
-  <AuthModule id="4c3edd60-7008-11ea-bc55-0242ac130003" name="DefaultSyncopeAuthModule"
-              description="Syncope auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf","name":"MySyncopeAuthModuleConf","domain":"Master","url":"http://mydomain.com/syncope/rest"}'/>
-  <AuthModule id="07c528f3-63b4-4dc1-a4da-87f35b8bdec8" name="DefaultRadiusAuthModule"
-              description="Radius auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.RadiusAuthModuleConf","name":"MyRadiusAuthModuleConf","protocol":"MSCHAPv2","inetAddress":"1.2.3.4", "sharedSecret":"thesecret"}'/>
-  <AuthModule id="f6e1288d-50d9-45fe-82ee-597c42242205" name="DefaultU2FAuthModule"
-              description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","name":"MyU2FAuthModuleConf","expireDevices":40}'/>
+  <AuthModule id="DefaultLDAPAuthModule"
+              description="LDAP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.LDAPAuthModuleConf","userIdAttribute":"cn","bindDn": "cn=Directory Manager,dc=example,dc=org", "bindCredential":"Password","ldapUrl":"ldap://localhost:1389","searchFilter":"cn={user}","baseDn":"ou=people,dc=example,dc=org","subtreeSearch":true}'/>
+  <AuthModule id="DefaultJDBCAuthModule"
+              description="JDBC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JDBCAuthModuleConf","sql":"SELECT * FROM users_table WHERE name=?", "fieldPassword": "password"}'/>
+  <AuthModule id="DefaultGoogleMfaAuthModule"
+              description="Google Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf","codeDigits":6,"issuer":"SyncopeTest", "label":"SyncopeTest", "timeStepSize":30, "windowSize":3}'/>
+  <AuthModule id="DefaultOIDCAuthModule"
+              description="OIDC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","discoveryUri":"https://accounts.google.com/.well-known/openid-configuration", "id":"client-id", "secret": "client-secret" }'/>
+  <AuthModule id="DefaultSAML2IdPAuthModule"
+              description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"classpath:/idp-metadata.xml", "serviceProviderEntityId":"syncope:apache:org"}'/>
+  <AuthModule id="DefaultJaasAuthModule"
+              description="Jaas auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JaasAuthModuleConf","realm":"SYNCOPE","kerberosRealmSystemProperty":"sample-value", "loginConfigType": "JavaLoginConfig", "loginConfigurationFile": "file:/etc/jaas/login.conf"}'/>
+  <AuthModule id="DefaultStaticAuthModule"
+              description="Static auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.StaticAuthModuleConf","users":{"syncope1": "$cynop3"}}'/>
+  <AuthModule id="DefaultSyncopeAuthModule"
+              description="Syncope auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf","domain":"Master"}'/>
+  <AuthModule id="DefaultRadiusAuthModule"
+              description="Radius auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.RadiusAuthModuleConf","protocol":"PAP","inetAddress":"localhost", "sharedSecret":"testing123"}'/>
+  <AuthModule id="DefaultU2FAuthModule"
+              description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/>
+
+  <AuthModuleItem id="26678936-af09-48b8-a789-36af0918b87d" extAttrName="family_name" intAttrName="syncopeUserAttr_surname"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="a66ed3b1-07be-4a6e-aed3-b107be8a6e75" extAttrName="name" intAttrName="syncopeUserAttr_fullname"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="edc26674-fac5-4a60-8266-74fac5ca6020" extAttrName="given_name" intAttrName="syncopeUserAttr_firstname" 
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="520eeba7-e00a-4221-8eeb-a7e00aa22159" extAttrName="email" intAttrName="syncopeUserAttr_email"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="8360509b-7d8e-4796-aa79-3c5ccc8671e6" extAttrName="groups" intAttrName="syncopeUserMemberships"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
 
   <RelationshipType id="inclusion" description="Models the act that an object is included in another"/>
   <RelationshipType id="neighborhood" description="Models the act that an object is near another"/>
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/AbstractClientApp.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/AbstractClientApp.java
index 1027a1b..e5902e9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/AbstractClientApp.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/AbstractClientApp.java
@@ -59,10 +59,12 @@ public class AbstractClientApp extends AbstractGeneratedKeyEntity implements Cli
     @ManyToOne(fetch = FetchType.EAGER)
     private JPAAttrReleasePolicy attrReleasePolicy;
 
+    @Override
     public Long getClientAppId() {
         return clientAppId;
     }
 
+    @Override
     public void setClientAppId(final Long clientAppId) {
         this.clientAppId = clientAppId;
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java
index cbbb96b..f510721 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthModule.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.entity.auth;
 import java.util.ArrayList;
 import java.util.List;
 import javax.persistence.CascadeType;
-import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.Lob;
@@ -31,21 +30,17 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.auth.AuthModuleConf;
 import org.apache.syncope.core.persistence.api.entity.auth.AuthModule;
 import org.apache.syncope.core.persistence.api.entity.auth.AuthModuleItem;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractProvidedKeyEntity;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 
 @Entity
 @Table(name = JPAAuthModule.TABLE)
-public class JPAAuthModule extends AbstractGeneratedKeyEntity implements AuthModule {
+public class JPAAuthModule extends AbstractProvidedKeyEntity implements AuthModule {
 
     public static final String TABLE = "AuthModule";
 
     private static final long serialVersionUID = 5681033638234853077L;
 
-    @Column(unique = true, nullable = false)
-    private String name;
-
-    @Column(nullable = false)
     private String description;
 
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "authModule")
@@ -65,16 +60,6 @@ public class JPAAuthModule extends AbstractGeneratedKeyEntity implements AuthMod
     }
 
     @Override
-    public String getName() {
-        return name;
-    }
-
-    @Override
-    public void setName(final String name) {
-        this.name = name;
-    }
-
-    @Override
     public List<? extends AuthModuleItem> getItems() {
         return items;
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
index a830b1b..ab0b5d2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAAuthProfile.java
@@ -19,6 +19,13 @@
 package org.apache.syncope.core.persistence.jpa.entity.auth;
 
 import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import org.apache.syncope.common.lib.types.GoogleMfaAuthAccount;
 import org.apache.syncope.common.lib.types.GoogleMfaAuthToken;
 import org.apache.syncope.common.lib.types.U2FRegisteredDevice;
@@ -26,17 +33,9 @@ import org.apache.syncope.core.persistence.api.entity.auth.AuthProfile;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Lob;
-import javax.persistence.Table;
-import javax.persistence.UniqueConstraint;
-
-import java.util.ArrayList;
-import java.util.List;
-
 @Entity
-@Table(name = JPAAuthProfile.TABLE, uniqueConstraints = @UniqueConstraint(columnNames = {"owner"}))
+@Table(name = JPAAuthProfile.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner" }))
 public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthProfile {
 
     public static final String TABLE = "AuthProfile";
@@ -68,9 +67,9 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public List<GoogleMfaAuthToken> getGoogleMfaAuthTokens() {
         return googleMfaAuthTokens == null
-            ? new ArrayList<>(0)
-            : POJOHelper.deserialize(googleMfaAuthTokens, new TypeReference<List<GoogleMfaAuthToken>>() {
-        });
+                ? new ArrayList<>(0)
+                : POJOHelper.deserialize(googleMfaAuthTokens, new TypeReference<List<GoogleMfaAuthToken>>() {
+                });
     }
 
     @Override
@@ -81,9 +80,9 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public List<GoogleMfaAuthAccount> getGoogleMfaAuthAccounts() {
         return googleMfaAuthAccounts == null
-            ? new ArrayList<>(0)
-            : POJOHelper.deserialize(googleMfaAuthAccounts, new TypeReference<List<GoogleMfaAuthAccount>>() {
-        });
+                ? new ArrayList<>(0)
+                : POJOHelper.deserialize(googleMfaAuthAccounts, new TypeReference<List<GoogleMfaAuthAccount>>() {
+                });
     }
 
     @Override
@@ -94,7 +93,7 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public void add(final GoogleMfaAuthToken token) {
         checkType(token, GoogleMfaAuthToken.class);
-        final List<GoogleMfaAuthToken> tokens = getGoogleMfaAuthTokens();
+        List<GoogleMfaAuthToken> tokens = getGoogleMfaAuthTokens();
         tokens.add(token);
         setGoogleMfaAuthTokens(tokens);
     }
@@ -102,9 +101,9 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public List<U2FRegisteredDevice> getU2FRegisteredDevices() {
         return u2fRegisteredDevices == null
-            ? new ArrayList<>(0)
-            : POJOHelper.deserialize(u2fRegisteredDevices, new TypeReference<List<U2FRegisteredDevice>>() {
-        });
+                ? new ArrayList<>(0)
+                : POJOHelper.deserialize(u2fRegisteredDevices, new TypeReference<List<U2FRegisteredDevice>>() {
+                });
     }
 
     @Override
@@ -115,7 +114,7 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public void add(final GoogleMfaAuthAccount account) {
         checkType(account, GoogleMfaAuthAccount.class);
-        final List<GoogleMfaAuthAccount> accounts = getGoogleMfaAuthAccounts();
+        List<GoogleMfaAuthAccount> accounts = getGoogleMfaAuthAccounts();
         accounts.add(account);
         setGoogleMfaAuthAccounts(accounts);
     }
@@ -123,7 +122,7 @@ public class JPAAuthProfile extends AbstractGeneratedKeyEntity implements AuthPr
     @Override
     public void add(final U2FRegisteredDevice registration) {
         checkType(registration, U2FRegisteredDevice.class);
-        final List<U2FRegisteredDevice> records = getU2FRegisteredDevices();
+        List<U2FRegisteredDevice> records = getU2FRegisteredDevices();
         records.add(registration);
         setU2FRegisteredDevices(records);
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
index d01b038..0e12628 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCJWKS.java
@@ -18,13 +18,11 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.auth;
 
-import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
-
-import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Lob;
 import javax.persistence.Table;
+import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
 
 @Entity
 @Table(name = JPAOIDCJWKS.TABLE)
@@ -34,7 +32,6 @@ public class JPAOIDCJWKS extends AbstractGeneratedKeyEntity implements OIDCJWKS
 
     private static final long serialVersionUID = 47352617217394093L;
 
-    @Column
     @Lob
     private String json;
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCRP.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCRP.java
index a4f9a7b..dee84f4 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCRP.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPAOIDCRP.java
@@ -29,6 +29,8 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import org.apache.syncope.common.lib.types.OIDCSubjectType;
 import org.apache.syncope.core.persistence.api.entity.auth.OIDCRP;
 
@@ -43,16 +45,11 @@ public class JPAOIDCRP extends AbstractClientApp implements OIDCRP {
     @Column(unique = true, nullable = false)
     private String clientId;
 
-    @Column
     private String clientSecret;
 
-    @Column
     private boolean signIdToken;
 
-    @Column
-    private String jwks;
-
-    @Column
+    @Enumerated(EnumType.STRING)
     private OIDCSubjectType subjectType;
 
     @ElementCollection(fetch = FetchType.EAGER)
@@ -76,6 +73,8 @@ public class JPAOIDCRP extends AbstractClientApp implements OIDCRP {
             @JoinColumn(name = "client_id", referencedColumnName = "id"))
     private Set<String> supportedResponseTypes = new HashSet<>();
 
+    private String logoutUri;
+
     @Override
     public List<String> getRedirectUris() {
         return redirectUris;
@@ -112,16 +111,6 @@ public class JPAOIDCRP extends AbstractClientApp implements OIDCRP {
     }
 
     @Override
-    public String getJwks() {
-        return jwks;
-    }
-
-    @Override
-    public void setJwks(final String jwks) {
-        this.jwks = jwks;
-    }
-
-    @Override
     public OIDCSubjectType getSubjectType() {
         return subjectType;
     }
@@ -140,4 +129,14 @@ public class JPAOIDCRP extends AbstractClientApp implements OIDCRP {
     public Set<String> getSupportedResponseTypes() {
         return supportedResponseTypes;
     }
+
+    @Override
+    public String getLogoutUri() {
+        return logoutUri;
+    }
+
+    @Override
+    public void setLogoutUri(final String logoutUri) {
+        this.logoutUri = logoutUri;
+    }
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPMetadata.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPMetadata.java
index 1bb0130..6017f9a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPMetadata.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2IdPMetadata.java
@@ -37,23 +37,18 @@ public class JPASAML2IdPMetadata extends AbstractGeneratedKeyEntity implements S
     private String appliesTo;
 
     @Lob
-    @Column
     private String metadata;
 
     @Lob
-    @Column
     private String signingCertificate;
 
     @Lob
-    @Column
     private String signingKey;
 
     @Lob
-    @Column
     private String encryptionCertificate;
 
     @Lob
-    @Column
     private String encryptionKey;
 
     @Override
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SP.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SP.java
index a34f0e5..864df57 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SP.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SP.java
@@ -38,34 +38,25 @@ public class JPASAML2SP extends AbstractClientApp implements SAML2SP {
     @Column(nullable = false)
     private String metadataLocation;
 
-    @Column
     private String metadataSignatureLocation;
 
-    @Column
     private boolean signAssertions;
 
-    @Column
     private boolean signResponses;
 
-    @Column
     private boolean encryptionOptional;
 
-    @Column
     private boolean encryptAssertions;
 
     @Column(name = "reqAuthnContextClass")
     private String requiredAuthenticationContextClass;
 
-    @Column
     private SAML2SPNameId requiredNameIdFormat;
 
-    @Column
     private Integer skewAllowance;
 
-    @Column
     private String nameIdQualifier;
 
-    @Column
     private String assertionAudiences;
 
     @Column(name = "spNameIdQualifier")
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPKeystore.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPKeystore.java
index b7ef84c..5cefe7e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPKeystore.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPKeystore.java
@@ -18,13 +18,12 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.auth;
 
-import org.apache.syncope.core.persistence.api.entity.auth.SAML2SPKeystore;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Lob;
 import javax.persistence.Table;
+import org.apache.syncope.core.persistence.api.entity.auth.SAML2SPKeystore;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
 
 @Entity
 @Table(name = JPASAML2SPKeystore.TABLE)
@@ -38,7 +37,6 @@ public class JPASAML2SPKeystore extends AbstractGeneratedKeyEntity implements SA
     private String owner;
 
     @Lob
-    @Column
     private String keystore;
 
     @Override
@@ -60,5 +58,4 @@ public class JPASAML2SPKeystore extends AbstractGeneratedKeyEntity implements SA
     public void setOwner(final String name) {
         this.owner = name;
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPMetadata.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPMetadata.java
index e43e5ac..fa96b56 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPMetadata.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/auth/JPASAML2SPMetadata.java
@@ -18,13 +18,12 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.auth;
 
-import org.apache.syncope.core.persistence.api.entity.auth.SAML2SPMetadata;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Lob;
 import javax.persistence.Table;
+import org.apache.syncope.core.persistence.api.entity.auth.SAML2SPMetadata;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
 
 @Entity
 @Table(name = JPASAML2SPMetadata.TABLE)
@@ -38,7 +37,6 @@ public class JPASAML2SPMetadata extends AbstractGeneratedKeyEntity implements SA
     private String owner;
 
     @Lob
-    @Column
     private String metadata;
 
     @Override
@@ -60,5 +58,4 @@ public class JPASAML2SPMetadata extends AbstractGeneratedKeyEntity implements SA
     public void setOwner(final String name) {
         this.owner = name;
     }
-
 }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AbstractClientAppTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AbstractClientAppTest.java
index cb1e108..e31a537 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AbstractClientAppTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AbstractClientAppTest.java
@@ -40,7 +40,6 @@ public class AbstractClientAppTest extends AbstractTest {
         attrRelPolicy.setDescription("AttrRelPolicyTest");
 
         AllowedAttrReleasePolicyConf conf = new AllowedAttrReleasePolicyConf();
-        conf.setName("Example Attr Rel Policy for an application");
         conf.getAllowedAttrs().addAll(List.of("cn", "givenName"));
         attrRelPolicy.setConf(conf);
 
@@ -54,7 +53,6 @@ public class AbstractClientAppTest extends AbstractTest {
 
         DefaultAccessPolicyConf conf = new DefaultAccessPolicyConf();
         conf.setEnabled(true);
-        conf.setName("Example Access Policy for an application");
         conf.addRequiredAttr("attribute1", Set.of("value1", "value2"));
         conf.setSsoEnabled(false);
         accessPolicy.setConf(conf);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java
index 730a67e..876a0e0 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AuthModuleTest.java
@@ -53,101 +53,54 @@ public class AuthModuleTest extends AbstractTest {
     private AuthModuleDAO authModuleDAO;
 
     @Test
+    public void findAll() {
+        List<AuthModule> modules = authModuleDAO.findAll();
+        assertNotNull(modules);
+        assertFalse(modules.isEmpty());
+        assertTrue(modules.size() >= 10);
+    }
+
+    @Test
     public void find() {
-        AuthModule authModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModule authModule = authModuleDAO.find("DefaultLDAPAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof LDAPAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultJDBCAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof JDBCAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultGoogleMfaAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof GoogleMfaAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultOIDCAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof OIDCAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultSAML2IdPAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof SAML2IdPAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultJaasAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof JaasAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultStaticAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof StaticAuthModuleConf);
 
-        authModule = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
+        authModule = authModuleDAO.find("DefaultSyncopeAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof SyncopeAuthModuleConf);
 
-        authModule = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+        authModule = authModuleDAO.find("DefaultU2FAuthModule");
         assertNotNull(authModule);
+        assertTrue(authModule.getConf() instanceof U2FAuthModuleConf);
 
-        authModule = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
+        authModule = authModuleDAO.find("DefaultRadiusAuthModule");
         assertNotNull(authModule);
-
-        authModule = authModuleDAO.find(UUID.randomUUID().toString());
-        assertNull(authModule);
-    }
-
-    @Test
-    public void findAll() {
-        List<AuthModule> modules = authModuleDAO.findAll();
-        assertNotNull(modules);
-        assertFalse(modules.isEmpty());
-        assertTrue(modules.size() >= 10);
-    }
-
-    @Test
-    public void findByAuthModuleImpl() {
-        AuthModule ldapAuthModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
-        assertNotNull(ldapAuthModule);
-        AuthModule jdbcAuthModule = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
-        assertNotNull(jdbcAuthModule);
-        AuthModule googleMfaAuthModule = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
-        assertNotNull(googleMfaAuthModule);
-        AuthModule oidcAuthModule = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
-        assertNotNull(oidcAuthModule);
-        AuthModule saml2IdPAuthModule = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
-        assertNotNull(saml2IdPAuthModule);
-        AuthModule jaasAuthModule = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
-        assertNotNull(jaasAuthModule);
-        AuthModule staticAuthModule = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
-        assertNotNull(staticAuthModule);
-        AuthModule syncopeAuthModule = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
-        assertNotNull(syncopeAuthModule);
-        AuthModule radiusAuthModule = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
-        assertNotNull(radiusAuthModule);
-        AuthModule u2fAuthModule = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
-        assertNotNull(u2fAuthModule);
-
-        assertTrue(isSpecificConf(ldapAuthModule.getConf(), LDAPAuthModuleConf.class));
-        assertFalse(isSpecificConf(ldapAuthModule.getConf(), JDBCAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(jdbcAuthModule.getConf(), JDBCAuthModuleConf.class));
-        assertFalse(isSpecificConf(jdbcAuthModule.getConf(), GoogleMfaAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(googleMfaAuthModule.getConf(), GoogleMfaAuthModuleConf.class));
-        assertFalse(isSpecificConf(googleMfaAuthModule.getConf(), OIDCAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(oidcAuthModule.getConf(), OIDCAuthModuleConf.class));
-        assertFalse(isSpecificConf(oidcAuthModule.getConf(), SAML2IdPAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(saml2IdPAuthModule.getConf(), SAML2IdPAuthModuleConf.class));
-        assertFalse(isSpecificConf(saml2IdPAuthModule.getConf(), JaasAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(jaasAuthModule.getConf(), JaasAuthModuleConf.class));
-        assertFalse(isSpecificConf(jaasAuthModule.getConf(), StaticAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(staticAuthModule.getConf(), StaticAuthModuleConf.class));
-        assertFalse(isSpecificConf(staticAuthModule.getConf(), SyncopeAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(syncopeAuthModule.getConf(), SyncopeAuthModuleConf.class));
-        assertFalse(isSpecificConf(syncopeAuthModule.getConf(), RadiusAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(radiusAuthModule.getConf(), RadiusAuthModuleConf.class));
-        assertFalse(isSpecificConf(radiusAuthModule.getConf(), U2FAuthModuleConf.class));
-
-        assertTrue(isSpecificConf(u2fAuthModule.getConf(), U2FAuthModuleConf.class));
-        assertFalse(isSpecificConf(u2fAuthModule.getConf(), LDAPAuthModuleConf.class));
+        assertTrue(authModule.getConf() instanceof RadiusAuthModuleConf);
     }
 
     @Test
@@ -155,34 +108,34 @@ public class AuthModuleTest extends AbstractTest {
         List<AuthModule> authModules = authModuleDAO.findAll();
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), LDAPAuthModuleConf.class)
-                && authModule.getName().equals("DefaultLDAPAuthModule")));
+                && authModule.getKey().equals("DefaultLDAPAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), JDBCAuthModuleConf.class)
-                && authModule.getName().equals("DefaultJDBCAuthModule")));
+                && authModule.getKey().equals("DefaultJDBCAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), GoogleMfaAuthModuleConf.class)
-                && authModule.getName().equals("DefaultGoogleMfaAuthModule")));
+                && authModule.getKey().equals("DefaultGoogleMfaAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), OIDCAuthModuleConf.class)
-                && authModule.getName().equals("DefaultOIDCAuthModule")));
+                && authModule.getKey().equals("DefaultOIDCAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), SAML2IdPAuthModuleConf.class)
-                && authModule.getName().equals("DefaultSAML2IdPAuthModule")));
+                && authModule.getKey().equals("DefaultSAML2IdPAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), JaasAuthModuleConf.class)
-                && authModule.getName().equals("DefaultJaasAuthModule")));
+                && authModule.getKey().equals("DefaultJaasAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), StaticAuthModuleConf.class)
-                && authModule.getName().equals("DefaultStaticAuthModule")));
+                && authModule.getKey().equals("DefaultStaticAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), SyncopeAuthModuleConf.class)
-                && authModule.getName().equals("DefaultSyncopeAuthModule")));
+                && authModule.getKey().equals("DefaultSyncopeAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), RadiusAuthModuleConf.class)
-                && authModule.getName().equals("DefaultRadiusAuthModule")));
+                && authModule.getKey().equals("DefaultRadiusAuthModule")));
         assertTrue(authModules.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), U2FAuthModuleConf.class)
-                && authModule.getName().equals("DefaultU2FAuthModule")));
+                && authModule.getKey().equals("DefaultU2FAuthModule")));
     }
 
     @Test
@@ -257,7 +210,6 @@ public class AuthModuleTest extends AbstractTest {
     public void saveWithSyncopeModule() {
         SyncopeAuthModuleConf conf = new SyncopeAuthModuleConf();
         conf.setDomain("Master");
-        conf.setUrl("http://mydomain.com/syncope/rest");
 
         saveAuthModule("SyncopeAuthModuleTest", conf);
     }
@@ -291,7 +243,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithLDAPModule() {
-        AuthModule module = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModule module = authModuleDAO.find("DefaultLDAPAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         LDAPAuthModuleConf.class.cast(conf).setBaseDn("dc=example2,dc=org");
@@ -310,7 +262,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithJDBCModule() {
-        AuthModule module = authModuleDAO.find("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultJDBCAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         JDBCAuthModuleConf.class.cast(conf).setSql("SELECT * FROM otherTable WHERE name=?");
@@ -326,7 +278,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithGoogleMfaModule() {
-        AuthModule module = authModuleDAO.find("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultGoogleMfaAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         GoogleMfaAuthModuleConf.class.cast(conf).setLabel("newLabel");
@@ -342,7 +294,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithSAML2IdPModule() {
-        AuthModule module = authModuleDAO.find("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultSAML2IdPAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("newEntityId");
@@ -358,7 +310,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithOIDCModule() {
-        AuthModule module = authModuleDAO.find("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultOIDCAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         OIDCAuthModuleConf.class.cast(conf).setResponseType("newCode");
@@ -374,7 +326,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithJaasModule() {
-        AuthModule module = authModuleDAO.find("4c3edbbc-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultJaasAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         JaasAuthModuleConf.class.cast(conf).setRealm("SYNCOPE_NEW");
@@ -390,7 +342,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithStaticModule() {
-        AuthModule module = authModuleDAO.find("4c3edc98-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultStaticAuthModule");
         assertNotNull(module);
         assertEquals(1, StaticAuthModuleConf.class.cast(module.getConf()).getUsers().size());
         AuthModuleConf conf = module.getConf();
@@ -407,7 +359,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithRadiusModule() {
-        AuthModule module = authModuleDAO.find("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+        AuthModule module = authModuleDAO.find("DefaultRadiusAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         RadiusAuthModuleConf.class.cast(conf).setSocketTimeout(45);
@@ -423,7 +375,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithU2fModule() {
-        AuthModule module = authModuleDAO.find("f6e1288d-50d9-45fe-82ee-597c42242205");
+        AuthModule module = authModuleDAO.find("DefaultU2FAuthModule");
         assertNotNull(module);
         AuthModuleConf conf = module.getConf();
         U2FAuthModuleConf.class.cast(conf).setExpireDevices(24);
@@ -439,7 +391,7 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void updateWithSyncopeModule() {
-        AuthModule module = authModuleDAO.find("4c3edd60-7008-11ea-bc55-0242ac130003");
+        AuthModule module = authModuleDAO.find("DefaultSyncopeAuthModule");
         assertNotNull(module);
 
         AuthModuleConf conf = module.getConf();
@@ -456,18 +408,18 @@ public class AuthModuleTest extends AbstractTest {
 
     @Test
     public void delete() {
-        AuthModule authModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModule authModule = authModuleDAO.find("DefaultSyncopeAuthModule");
         assertNotNull(authModule);
 
-        authModuleDAO.delete("be456831-593d-4003-b273-4c3fb61700df");
+        authModuleDAO.delete("DefaultSyncopeAuthModule");
 
-        authModule = authModuleDAO.find("be456831-593d-4003-b273-4c3fb61700df");
+        authModule = authModuleDAO.find("DefaultSyncopeAuthModule");
         assertNull(authModule);
     }
 
-    private void saveAuthModule(final String name, final AuthModuleConf conf) {
+    private void saveAuthModule(final String key, final AuthModuleConf conf) {
         AuthModule module = entityFactory.newEntity(AuthModule.class);
-        module.setName(name);
+        module.setKey(key);
         module.setDescription("An authentication module");
         module.setConf(conf);
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
index 6301474..7a14685 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
@@ -192,7 +192,6 @@ public class PolicyTest extends AbstractTest {
 
         DefaultAccessPolicyConf conf = new DefaultAccessPolicyConf();
         conf.addRequiredAttr("cn", Set.of("syncope"));
-        conf.setName("AttrReleasePolicyAllowEverything");
         accessPolicy.setConf(conf);
 
         accessPolicy = policyDAO.save(accessPolicy);
@@ -210,7 +209,6 @@ public class PolicyTest extends AbstractTest {
         DefaultAuthPolicyConf authPolicyConf = new DefaultAuthPolicyConf();
         authPolicyConf.getAuthModules().addAll(List.of("LdapAuthentication1", "DatabaseAuthentication2"));
         DefaultAuthPolicyCriteriaConf criteria = new DefaultAuthPolicyCriteriaConf();
-        criteria.setName("DefaultConf");
         criteria.setAll(true);
         authPolicyConf.setCriteria(criteria);
         authPolicy.setConf(authPolicyConf);
@@ -229,7 +227,6 @@ public class PolicyTest extends AbstractTest {
 
         AllowedAttrReleasePolicyConf attrReleasePolicyConf = new AllowedAttrReleasePolicyConf();
         attrReleasePolicyConf.getAllowedAttrs().addAll(List.of("*"));
-        attrReleasePolicyConf.setName("AttrReleasePolicyAllowEverything");
         attrReleasePolicy.setConf(attrReleasePolicyConf);
 
         attrReleasePolicy = policyDAO.save(attrReleasePolicy);
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 225b40a..324c3be 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -61,27 +61,37 @@ under the License.
                      jsonConf='{"_class":"org.apache.syncope.common.lib.policy.AllowedAttrReleasePolicyConf","name":"DenyAttrReleasePolicyConf"}'/>
 
   <!-- Authentication modules -->
-  <AuthModule id="be456831-593d-4003-b273-4c3fb61700df" name="DefaultLDAPAuthModule"
-              description="LDAP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.LDAPAuthModuleConf","name":"MyLDAPAuthModuleConf","userIdAttribute":"cn","bindDn": "cn=Directory Manager,dc=example,dc=org", "bindCredential":"Password","ldapUrl":"ldap://localhost:1389","searchFilter":"cn={user}","baseDn":"ou=people,dc=example,dc=org","subtreeSearch":true}'/>
-  <AuthModule id="4c3ed7e8-7008-11ea-bc55-0242ac130003" name="DefaultJDBCAuthModule"
-              description="JDBC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JDBCAuthModuleConf","name":"MyJDBCAuthModuleConf", "sql":"SELECT * FROM users_table WHERE name=?", "fieldPassword": "password"}'/>
-  <AuthModule id="4c3ed4e6-7008-11ea-bc55-0242ac130003" name="DefaultGoogleMfaAuthModule"
-              description="Google Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf","name":"MyGoogleMfaAuthModuleConf","codeDigits":6,"issuer":"SyncopeTest", "label":"SyncopeTest", "timeStepSize":30, "windowSize":3}'/>
-  <AuthModule id="4c3ed8f6-7008-11ea-bc55-0242ac130003" name="DefaultOIDCAuthModule"
-              description="OIDC auth module"
-              jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","name":"MyOIDCAuthModuleConf", "discoveryUri":"https://accounts.google.com/.well-known/openid-configuration", "id":"client-id", "secret": "client-secret" }'/>
-  <AuthModule id="4c3ed9d2-7008-11ea-bc55-0242ac130003" name="DefaultSAML2IdPAuthModule"
-              description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","name":"MySAML2IdPAuthModuleConf", "keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"classpath:/idp-metadata.xml", "serviceProviderEntityId":"syncope:apache:org"}'/>
-  <AuthModule id="4c3edbbc-7008-11ea-bc55-0242ac130003" name="DefaultJaasAuthModule"
-              description="Jaas auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JaasAuthModuleConf","name":"MyJaasAuthModuleConf","realm":"SYNCOPE","kerberosRealmSystemProperty":"sample-value", "loginConfigType": "JavaLoginConfig", "loginConfigurationFile": "file:/etc/jaas/login.conf"}'/>
-  <AuthModule id="4c3edc98-7008-11ea-bc55-0242ac130003" name="DefaultStaticAuthModule"
-              description="Static auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.StaticAuthModuleConf","name":"MyStaticAuthModuleConf","users":{"syncope1": "$cynop3"}}'/>
-  <AuthModule id="4c3edd60-7008-11ea-bc55-0242ac130003" name="DefaultSyncopeAuthModule"
-              description="Syncope auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf","name":"MySyncopeAuthModuleConf","domain":"Master","url":"http://localhost:9080/syncope/rest"}'/>
-  <AuthModule id="07c528f3-63b4-4dc1-a4da-87f35b8bdec8" name="DefaultRadiusAuthModule"
-              description="Radius auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.RadiusAuthModuleConf","name":"MyRadiusAuthModuleConf","protocol":"PAP","inetAddress":"localhost", "sharedSecret":"testing123"}'/>
-  <AuthModule id="f6e1288d-50d9-45fe-82ee-597c42242205" name="DefaultU2FAuthModule"
-              description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","name":"MyU2FAuthModuleConf","expireDevices":40}'/>
+  <AuthModule id="DefaultLDAPAuthModule"
+              description="LDAP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.LDAPAuthModuleConf","userIdAttribute":"cn","bindDn": "cn=Directory Manager,dc=example,dc=org", "bindCredential":"Password","ldapUrl":"ldap://localhost:1389","searchFilter":"cn={user}","baseDn":"ou=people,dc=example,dc=org","subtreeSearch":true}'/>
+  <AuthModule id="DefaultJDBCAuthModule"
+              description="JDBC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JDBCAuthModuleConf","sql":"SELECT * FROM users_table WHERE name=?", "fieldPassword": "password"}'/>
+  <AuthModule id="DefaultGoogleMfaAuthModule"
+              description="Google Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf","codeDigits":6,"issuer":"SyncopeTest", "label":"SyncopeTest", "timeStepSize":30, "windowSize":3}'/>
+  <AuthModule id="DefaultOIDCAuthModule"
+              description="OIDC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","discoveryUri":"https://accounts.google.com/.well-known/openid-configuration", "id":"client-id", "secret": "client-secret" }'/>
+  <AuthModule id="DefaultSAML2IdPAuthModule"
+              description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"classpath:/idp-metadata.xml", "serviceProviderEntityId":"syncope:apache:org"}'/>
+  <AuthModule id="DefaultJaasAuthModule"
+              description="Jaas auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.JaasAuthModuleConf","realm":"SYNCOPE","kerberosRealmSystemProperty":"sample-value", "loginConfigType": "JavaLoginConfig", "loginConfigurationFile": "file:/etc/jaas/login.conf"}'/>
+  <AuthModule id="DefaultStaticAuthModule"
+              description="Static auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.StaticAuthModuleConf","users":{"syncope1": "$cynop3"}}'/>
+  <AuthModule id="DefaultSyncopeAuthModule"
+              description="Syncope auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf","domain":"Master"}'/>
+  <AuthModule id="DefaultRadiusAuthModule"
+              description="Radius auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.RadiusAuthModuleConf","protocol":"PAP","inetAddress":"localhost", "sharedSecret":"testing123"}'/>
+  <AuthModule id="DefaultU2FAuthModule"
+              description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/>
+
+  <AuthModuleItem id="26678936-af09-48b8-a789-36af0918b87d" extAttrName="family_name" intAttrName="syncopeUserAttr_surname"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="a66ed3b1-07be-4a6e-aed3-b107be8a6e75" extAttrName="name" intAttrName="syncopeUserAttr_fullname"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="edc26674-fac5-4a60-8266-74fac5ca6020" extAttrName="given_name" intAttrName="syncopeUserAttr_firstname" 
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="520eeba7-e00a-4221-8eeb-a7e00aa22159" extAttrName="email" intAttrName="syncopeUserAttr_email"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
+  <AuthModuleItem id="8360509b-7d8e-4796-aa79-3c5ccc8671e6" extAttrName="groups" intAttrName="syncopeUserMemberships"
+                  password="0" purpose="NONE" mandatoryCondition="false" connObjectKey="0" authModule_id="DefaultSyncopeAuthModule"/>
 
   <RelationshipType id="inclusion" description="Models the act that an object is included in another"/>
   <RelationshipType id="neighborhood" description="Models the act that an object is near another"/>
@@ -2466,7 +2476,7 @@ $$ }&#10;
   <SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's your mother's maiden name?"/>
 
   <SRARoute id="ec7bada2-3dd6-460c-8441-65521d005ffa" name="basic1" target="http://httpbin.org:80"
-            logout="0" csrf="1"
+            logout="0" csrf="1" routeType="PROTECTED"
             predicates="[{&quot;cond&quot;:null,&quot;factory&quot;:&quot;METHOD&quot;,&quot;args&quot;:&quot;GET&quot;}]"/>
 
   <SyncopeLogger logType="AUDIT" logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]" logLevel="DEBUG"/>
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
index 164c620..6a68e65 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/OIDCJWKSDataBinder.java
@@ -19,13 +19,14 @@
 package org.apache.syncope.core.provisioning.api.data;
 
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
 import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
 
 public interface OIDCJWKSDataBinder {
-    
+
     OIDCJWKSTO get(OIDCJWKS jwks);
 
-    OIDCJWKS create();
+    OIDCJWKS create(int size, JWSAlgorithm algorithm);
 
-    OIDCJWKS update(OIDCJWKS oidcjwks, OIDCJWKSTO jwksTO);
+    OIDCJWKS update(OIDCJWKS jwks, OIDCJWKSTO jwksTO);
 }
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppDataBinder.java
similarity index 96%
rename from core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppBinder.java
rename to core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppDataBinder.java
index c95f9a6..5cb03ad 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/wa/WAClientAppDataBinder.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.api.data.wa;
 import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apache.syncope.core.persistence.api.entity.auth.ClientApp;
 
-public interface WAClientAppBinder {
+public interface WAClientAppDataBinder {
 
     WAClientApp getWAClientApp(ClientApp clientApp);
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java
index 058e58d..23eaeae 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuthModuleDataBinderImpl.java
@@ -90,12 +90,13 @@ public class AuthModuleDataBinderImpl implements AuthModuleDataBinder {
 
     @Override
     public AuthModule create(final AuthModuleTO authModuleTO) {
-        return update(entityFactory.newEntity(AuthModule.class), authModuleTO);
+        AuthModule authModule = entityFactory.newEntity(AuthModule.class);
+        authModule.setKey(authModuleTO.getKey());
+        return update(authModule, authModuleTO);
     }
 
     @Override
     public AuthModule update(final AuthModule authModule, final AuthModuleTO authModuleTO) {
-        authModule.setName(authModuleTO.getName());
         authModule.setDescription(authModuleTO.getDescription());
         authModule.setConf(authModuleTO.getConf());
 
@@ -126,7 +127,6 @@ public class AuthModuleDataBinderImpl implements AuthModuleDataBinder {
     public AuthModuleTO getAuthModuleTO(final AuthModule authModule) {
         AuthModuleTO authModuleTO = new AuthModuleTO();
 
-        authModuleTO.setName(authModule.getName());
         authModuleTO.setKey(authModule.getKey());
         authModuleTO.setDescription(authModule.getDescription());
         authModuleTO.setConf(authModule.getConf());
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
index cc811fa..9fb5c44 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java
@@ -205,7 +205,6 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
         clientApp.setClientSecret(clientAppTO.getClientSecret());
         clientApp.setClientId(clientAppTO.getClientId());
         clientApp.setSignIdToken(clientAppTO.isSignIdToken());
-        clientApp.setJwks(clientAppTO.getJwks());
         clientApp.setSubjectType(clientAppTO.getSubjectType());
         clientApp.getRedirectUris().addAll(clientAppTO.getRedirectUris());
         clientApp.getSupportedGrantTypes().addAll(clientAppTO.getSupportedGrantTypes());
@@ -219,8 +218,12 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
                 clientApp.setAuthPolicy((AuthPolicy) policy);
             } else {
                 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
-                sce.getElements().add("Expected " + AuthPolicy.class.getSimpleName()
-                        + ", found " + policy.getClass().getSimpleName());
+                if (policy == null) {
+                    sce.getElements().add("Policy " + clientAppTO.getAuthPolicy() + " not found");
+                } else {
+                    sce.getElements().add("Expected " + AuthPolicy.class.getSimpleName()
+                            + ", found " + policy.getClass().getSimpleName());
+                }
                 throw sce;
             }
         }
@@ -233,8 +236,12 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
                 clientApp.setAccessPolicy((AccessPolicy) policy);
             } else {
                 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
-                sce.getElements().add("Expected " + AccessPolicy.class.getSimpleName()
-                        + ", found " + policy.getClass().getSimpleName());
+                if (policy == null) {
+                    sce.getElements().add("Policy " + clientAppTO.getAccessPolicy() + " not found");
+                } else {
+                    sce.getElements().add("Expected " + AccessPolicy.class.getSimpleName()
+                            + ", found " + policy.getClass().getSimpleName());
+                }
                 throw sce;
             }
         }
@@ -247,11 +254,17 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
                 clientApp.setAttrReleasePolicy((AttrReleasePolicy) policy);
             } else {
                 SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
-                sce.getElements().add("Expected " + AttrReleasePolicy.class.getSimpleName()
-                        + ", found " + policy.getClass().getSimpleName());
+                if (policy == null) {
+                    sce.getElements().add("Policy " + clientAppTO.getAttrReleasePolicy() + " not found");
+                } else {
+                    sce.getElements().add("Expected " + AttrReleasePolicy.class.getSimpleName()
+                            + ", found " + policy.getClass().getSimpleName());
+                }
                 throw sce;
             }
         }
+
+        clientApp.setLogoutUri(clientAppTO.getLogoutUri());
     }
 
     private static OIDCRPTO getClientAppTO(final OIDCRP clientApp) {
@@ -264,7 +277,6 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
         clientAppTO.setClientId(clientApp.getClientId());
         clientAppTO.setClientSecret(clientApp.getClientSecret());
         clientAppTO.setSignIdToken(clientApp.isSignIdToken());
-        clientAppTO.setJwks(clientApp.getJwks());
         clientAppTO.setSubjectType(clientApp.getSubjectType());
         clientAppTO.getRedirectUris().addAll(clientApp.getRedirectUris());
         clientAppTO.getSupportedGrantTypes().addAll(clientApp.getSupportedGrantTypes());
@@ -277,6 +289,8 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder {
         clientAppTO.setAttrReleasePolicy(clientApp.getAttrReleasePolicy() == null
                 ? null : clientApp.getAttrReleasePolicy().getKey());
 
+        clientAppTO.setLogoutUri(clientApp.getLogoutUri());
+
         return clientAppTO;
     }
 
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
index ed3010c..9b1aaee 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCJWKSDataBinderImpl.java
@@ -16,54 +16,62 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.core.provisioning.java.data;
 
-import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jose.jwk.KeyUse;
 import com.nimbusds.jose.jwk.RSAKey;
 import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
+import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.auth.OIDCJWKS;
 import org.apache.syncope.core.provisioning.api.data.OIDCJWKSDataBinder;
 import org.apache.syncope.core.spring.security.SecureRandomUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
 public class OIDCJWKSDataBinderImpl implements OIDCJWKSDataBinder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCJWKSDataBinder.class);
+
     @Autowired
     private EntityFactory entityFactory;
 
     @Override
     public OIDCJWKSTO get(final OIDCJWKS jwks) {
-        return new OIDCJWKSTO.Builder().
-            json(jwks.getJson()).
-            key(jwks.getKey()).
-            build();
+        return new OIDCJWKSTO.Builder().json(jwks.getJson()).key(jwks.getKey()).build();
     }
 
     @Override
-    public OIDCJWKS create() {
+    public OIDCJWKS create(final int size, final JWSAlgorithm algorithm) {
         try {
             OIDCJWKS jwks = entityFactory.newEntity(OIDCJWKS.class);
-            RSAKey jwk = new RSAKeyGenerator(2048)
-                .keyUse(KeyUse.SIGNATURE)
-                .keyID(SecureRandomUtils.generateRandomUUID().toString())
-                .algorithm(JWSAlgorithm.RS256)
-                .generate();
+            RSAKey jwk = new RSAKeyGenerator(size).
+                    keyUse(KeyUse.SIGNATURE).
+                    keyID(SecureRandomUtils.generateRandomUUID().toString()).
+                    algorithm(new com.nimbusds.jose.JWSAlgorithm(algorithm.name())).
+                    generate();
             jwks.setJson(new JWKSet(jwk).toJSONObject(false).toString());
             return jwks;
-        } catch (final Exception e) {
-            throw new RuntimeException("Unable to create OIDC JWKS", e);
+        } catch (JOSEException e) {
+            LOG.error("Could not create OIDC JWKS", e);
+
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown);
+            sce.getElements().add(e.getMessage());
+            throw sce;
         }
     }
 
     @Override
-    public OIDCJWKS update(final OIDCJWKS oidcjwks, final OIDCJWKSTO jwksTO) {
-        oidcjwks.setJson(jwksTO.getJson());
-        return oidcjwks;
+    public OIDCJWKS update(final OIDCJWKS jwks, final OIDCJWKSTO jwksTO) {
+        jwks.setJson(jwksTO.getJson());
+        return jwks;
     }
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppDataBinderImpl.java
similarity index 78%
rename from core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppBinderImpl.java
rename to core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppDataBinderImpl.java
index 1ed1418..d08d953 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/wa/WAClientAppDataBinderImpl.java
@@ -29,12 +29,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
-import org.apache.syncope.core.provisioning.api.data.wa.WAClientAppBinder;
+import org.apache.syncope.core.provisioning.api.data.wa.WAClientAppDataBinder;
 
 @Component
-public class WAClientAppBinderImpl implements WAClientAppBinder {
+public class WAClientAppDataBinderImpl implements WAClientAppDataBinder {
 
-    private static final Logger LOG = LoggerFactory.getLogger(WAClientAppBinder.class);
+    private static final Logger LOG = LoggerFactory.getLogger(WAClientAppDataBinder.class);
 
     @Autowired
     private ClientAppDataBinder clientAppDataBinder;
@@ -52,39 +52,39 @@ public class WAClientAppBinderImpl implements WAClientAppBinder {
             if (clientApp.getAuthPolicy() != null) {
                 authPolicyConf = clientApp.getAuthPolicy().getConf();
                 waClientApp.setAuthPolicyConf(clientApp.getAuthPolicy().getConf());
-            } else if (clientApp.getRealm().getAuthPolicy() != null) {
+            } else if (clientApp.getRealm() != null && clientApp.getRealm().getAuthPolicy() != null) {
                 authPolicyConf = clientApp.getRealm().getAuthPolicy().getConf();
                 waClientApp.setAuthPolicyConf(clientApp.getRealm().getAuthPolicy().getConf());
             }
 
             if (clientApp.getAccessPolicy() != null) {
                 waClientApp.setAccessPolicyConf(clientApp.getAccessPolicy().getConf());
-            } else if (clientApp.getRealm().getAccessPolicy() != null) {
+            } else if (clientApp.getRealm() != null && clientApp.getRealm().getAccessPolicy() != null) {
                 waClientApp.setAccessPolicyConf(clientApp.getRealm().getAccessPolicy().getConf());
             }
 
             if (clientApp.getAttrReleasePolicy() != null) {
                 waClientApp.setAttrReleasePolicyConf(clientApp.getAttrReleasePolicy().getConf());
-            } else if (clientApp.getRealm().getAttrReleasePolicy() != null) {
+            } else if (clientApp.getRealm() != null && clientApp.getRealm().getAttrReleasePolicy() != null) {
                 waClientApp.setAttrReleasePolicyConf(clientApp.getRealm().getAttrReleasePolicy().getConf());
             }
 
-            if (authPolicyConf instanceof DefaultAuthPolicyConf
-                    && !((DefaultAuthPolicyConf) authPolicyConf).getAuthModules().isEmpty()) {
-                ((DefaultAuthPolicyConf) authPolicyConf).getAuthModules().forEach(authModuleKey -> {
-                    AuthModule authModule = authModuleDAO.find(authModuleKey);
+            if (authPolicyConf instanceof DefaultAuthPolicyConf) {
+                ((DefaultAuthPolicyConf) authPolicyConf).getAuthModules().forEach(key -> {
+                    AuthModule authModule = authModuleDAO.find(key);
                     if (authModule == null) {
-                        LOG.warn("AuthModule " + authModuleKey + " not found");
+                        LOG.warn("AuthModule " + authModule + " not found");
                     } else {
-                        authModule.getItems().forEach(item -> waClientApp.getReleaseAttrs().put(
-                                item.getExtAttrName(), item.getIntAttrName()));
+                        authModule.getItems().
+                                forEach(item -> waClientApp.getReleaseAttrs().put(
+                                item.getIntAttrName(), item.getExtAttrName()));
                     }
                 });
             }
             if (waClientApp.getReleaseAttrs().isEmpty()) {
                 if (clientApp.getAttrReleasePolicy() != null) {
                     waClientApp.setAttrReleasePolicyConf(clientApp.getAttrReleasePolicy().getConf());
-                } else if (clientApp.getRealm().getAttrReleasePolicy() != null) {
+                } else if (clientApp.getRealm() != null && clientApp.getRealm().getAttrReleasePolicy() != null) {
                     waClientApp.setAttrReleasePolicyConf(clientApp.getRealm().getAttrReleasePolicy().getConf());
                 }
             }
diff --git a/docker/sra/pom.xml b/docker/sra/pom.xml
index 6a80959..b41c71f 100644
--- a/docker/sra/pom.xml
+++ b/docker/sra/pom.xml
@@ -59,25 +59,6 @@ under the License.
   <build>
     <plugins>
       <plugin>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-maven-plugin</artifactId>
-        <configuration>
-          <mainClass>org.apache.syncope.sra.SyncopeSRAApplication</mainClass>
-          <layout>ZIP</layout>
-        </configuration>
-        <executions>
-          <execution>
-            <goals>
-              <goal>repackage</goal>
-            </goals>
-            <configuration>
-              <outputDirectory>${project.build.outputDirectory}</outputDirectory>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
         <groupId>io.fabric8</groupId>
         <artifactId>docker-maven-plugin</artifactId>
         <configuration>
diff --git a/docker/wa/src/main/resources/wa.properties b/docker/wa/src/main/resources/wa.properties
index 1267324..eb69a87 100644
--- a/docker/wa/src/main/resources/wa.properties
+++ b/docker/wa/src/main/resources/wa.properties
@@ -22,12 +22,13 @@ useGZIPCompression=true
 # Conf directories
 conf.directory=${conf.directory}
 cas.standalone.configurationDirectory=${conf.directory}
-cas.authn.oidc.jwks.jwks-file=file:${conf.directory}/oidc.keystore
 
 cas.server.name=http://localhost:8080
 cas.server.prefix=${cas.server.name}/syncope-wa
 cas.server.scope=syncope.org
 
+cas.logout.follow-service-redirects=true
+
 cas.authn.saml-idp.entity-id=https://syncope.apache.org/saml
 
 # Disable access to the login endpoint
diff --git a/ext/self-keymaster/logic/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java b/ext/self-keymaster/logic/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java
index 554cb29..bd38741 100644
--- a/ext/self-keymaster/logic/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java
+++ b/ext/self-keymaster/logic/src/main/java/org/apache/syncope/core/logic/NetworkServiceLogic.java
@@ -72,6 +72,7 @@ public class NetworkServiceLogic extends AbstractTransactionalLogic<EntityTO> {
                 : list.get(RandomUtils.nextInt(0, list.size()));
     }
 
+    @PreAuthorize("@environment.getProperty('keymaster.username') == authentication.name and not(isAnonymous())")
     public void register(final NetworkService networkService) {
         unregister(networkService);
 
@@ -81,6 +82,7 @@ public class NetworkServiceLogic extends AbstractTransactionalLogic<EntityTO> {
         serviceDAO.save(service);
     }
 
+    @PreAuthorize("@environment.getProperty('keymaster.username') == authentication.name and not(isAnonymous())")
     public void unregister(final NetworkService networkService) {
         serviceDAO.findAll(networkService.getType()).stream().
                 filter(service -> service.getAddress().equals(networkService.getAddress())).
diff --git a/ext/self-keymaster/rest-api/src/main/java/org/apache/syncope/ext/self/keymaster/api/service/NetworkServiceService.java b/ext/self-keymaster/rest-api/src/main/java/org/apache/syncope/ext/self/keymaster/api/service/NetworkServiceService.java
index aade9af..d5fcd88 100644
--- a/ext/self-keymaster/rest-api/src/main/java/org/apache/syncope/ext/self/keymaster/api/service/NetworkServiceService.java
+++ b/ext/self-keymaster/rest-api/src/main/java/org/apache/syncope/ext/self/keymaster/api/service/NetworkServiceService.java
@@ -20,7 +20,6 @@ package org.apache.syncope.ext.self.keymaster.api.service;
 
 import java.io.Serializable;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -58,7 +57,7 @@ public interface NetworkServiceService extends Serializable {
     @POST
     @Consumes({ MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_JSON })
-    CompletableFuture<Response> action(
+    Response action(
             @NotNull NetworkService networkService,
             @QueryParam("action") Action action);
 }
diff --git a/ext/self-keymaster/rest-cxf/src/main/java/org/apache/syncope/ext/self/keymaster/cxf/service/NetworkServiceServiceImpl.java b/ext/self-keymaster/rest-cxf/src/main/java/org/apache/syncope/ext/self/keymaster/cxf/service/NetworkServiceServiceImpl.java
index e04c350..a026acc 100644
--- a/ext/self-keymaster/rest-cxf/src/main/java/org/apache/syncope/ext/self/keymaster/cxf/service/NetworkServiceServiceImpl.java
+++ b/ext/self-keymaster/rest-cxf/src/main/java/org/apache/syncope/ext/self/keymaster/cxf/service/NetworkServiceServiceImpl.java
@@ -19,13 +19,11 @@
 package org.apache.syncope.ext.self.keymaster.cxf.service;
 
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
 import org.apache.syncope.core.logic.NetworkServiceLogic;
 import org.apache.syncope.ext.self.keymaster.api.service.NetworkServiceService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Service;
 
 @Service
@@ -46,16 +44,13 @@ public class NetworkServiceServiceImpl implements NetworkServiceService {
         return logic.get(serviceType);
     }
 
-    @PreAuthorize("@environment.getProperty('keymaster.username') == authentication.name and not(isAnonymous())")
     @Override
-    public CompletableFuture<Response> action(final NetworkService networkService, final Action action) {
-        return CompletableFuture.supplyAsync(() -> {
-            if (action == Action.unregister) {
-                logic.unregister(networkService);
-            } else {
-                logic.register(networkService);
-            }
-            return Response.noContent().build();
-        });
+    public Response action(final NetworkService networkService, final Action action) {
+        if (action == Action.unregister) {
+            logic.unregister(networkService);
+        } else {
+            logic.register(networkService);
+        }
+        return Response.noContent().build();
     }
 }
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 25bcb63..251133f 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -237,6 +237,24 @@ under the License.
   <build>
     <plugins>
       <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>buildnumber-maven-plugin</artifactId>
+        <inherited>true</inherited>
+        <configuration>
+          <doCheck>false</doCheck>
+          <doUpdate>false</doUpdate>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>validate</phase>
+            <goals>
+              <goal>create</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <inherited>true</inherited>
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index a77e475..6c607c0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -67,8 +67,6 @@ import org.apache.syncope.common.lib.policy.PolicyTO;
 import org.apache.syncope.common.lib.request.AnyObjectCR;
 import org.apache.syncope.common.lib.request.GroupCR;
 import org.apache.syncope.common.lib.request.UserCR;
-import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
-import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
 import org.apache.syncope.common.lib.to.SchemaTO;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.Attr;
@@ -88,7 +86,6 @@ import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
 import org.apache.syncope.common.lib.policy.AuthPolicyTO;
-import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
 import org.apache.syncope.common.lib.to.client.ClientAppTO;
 import org.apache.syncope.common.lib.to.client.OIDCRPTO;
 import org.apache.syncope.common.lib.to.client.SAML2SPTO;
@@ -115,14 +112,8 @@ import org.apache.syncope.common.rest.api.service.ConnectorService;
 import org.apache.syncope.common.rest.api.service.DynRealmService;
 import org.apache.syncope.common.rest.api.service.LoggerService;
 import org.apache.syncope.common.rest.api.service.NotificationService;
-import org.apache.syncope.common.rest.api.service.OIDCJWKSConfService;
-import org.apache.syncope.common.rest.api.service.SAML2SPKeystoreConfService;
 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthAccountService;
 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthTokenService;
-import org.apache.syncope.common.rest.api.service.wa.OIDCJWKSService;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPKeystoreService;
-import org.apache.syncope.common.rest.api.service.SAML2SPMetadataConfService;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.common.rest.api.service.SAML2SPService;
 import org.apache.syncope.common.rest.api.service.PolicyService;
 import org.apache.syncope.common.rest.api.service.ReportService;
@@ -148,20 +139,21 @@ import org.apache.syncope.common.rest.api.service.UserSelfService;
 import org.apache.syncope.common.rest.api.service.UserService;
 import org.apache.syncope.common.rest.api.service.UserRequestService;
 import org.apache.syncope.common.rest.api.service.BpmnProcessService;
-import org.apache.syncope.common.rest.api.service.SAML2IdPMetadataConfService;
-import org.apache.syncope.common.rest.api.service.wa.SAML2IdPMetadataService;
+import org.apache.syncope.common.rest.api.service.OIDCJWKSService;
+import org.apache.syncope.common.rest.api.service.SAML2IdPMetadataService;
+import org.apache.syncope.common.rest.api.service.SAML2SPKeystoreService;
+import org.apache.syncope.common.rest.api.service.SAML2SPMetadataService;
+import org.apache.syncope.common.rest.api.service.SRARouteService;
 import org.apache.syncope.common.rest.api.service.UserWorkflowTaskService;
 import org.apache.syncope.common.rest.api.service.wa.U2FRegistrationService;
 import org.apache.syncope.fit.core.CoreITContext;
 import org.apache.syncope.fit.core.UserITCase;
-import org.identityconnectors.common.security.Encryptor;
 import org.junit.jupiter.api.BeforeAll;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
-import org.apache.syncope.common.rest.api.service.SRARouteService;
 
 @SpringJUnitConfig({ CoreITContext.class, SelfKeymasterClientContext.class, ZookeeperKeymasterClientContext.class })
 public abstract class AbstractITCase {
@@ -238,6 +230,8 @@ public abstract class AbstractITCase {
 
     protected static final String PRINTER = "PRINTER";
 
+    protected static final String OWNER = "Syncope";
+
     protected static final int MAX_WAIT_SECONDS = 50;
 
     protected static String ANONYMOUS_UNAME;
@@ -308,25 +302,13 @@ public abstract class AbstractITCase {
 
     protected static AuthModuleService authModuleService;
 
-    protected static SAML2SPMetadataService saml2SPMetadataService;
-
-    protected static SAML2SPMetadataConfService saml2SPMetadataConfService;
-
-    protected static SAML2SPKeystoreService saml2SPKeystoreService;
-
-    protected static SAML2SPKeystoreConfService saml2SPKeystoreConfService;
-
-    protected static SAML2IdPMetadataService saml2IdPMetadataService;
-
-    protected static SAML2IdPMetadataConfService saml2IdPMetadataConfService;
-
     protected static SecurityQuestionService securityQuestionService;
 
     protected static ImplementationService implementationService;
 
     protected static RemediationService remediationService;
 
-    protected static SRARouteService gatewayRouteService;
+    protected static SRARouteService sraRouteService;
 
     protected static CamelRouteService camelRouteService;
 
@@ -348,15 +330,19 @@ public abstract class AbstractITCase {
 
     protected static AuthProfileService authProfileService;
 
-    protected static OIDCJWKSService oidcJwksService;
+    protected static SAML2SPMetadataService saml2SPMetadataService;
+
+    protected static SAML2SPKeystoreService saml2SPKeystoreService;
+
+    protected static SAML2IdPMetadataService saml2IdPMetadataService;
 
-    protected static OIDCJWKSConfService oidcJwksConfService;
+    protected static OIDCJWKSService oidcJWKSService;
 
     protected static U2FRegistrationService u2FRegistrationService;
 
     @BeforeAll
     public static void securitySetup() {
-        try (InputStream propStream = Encryptor.class.getResourceAsStream("/security.properties")) {
+        try (InputStream propStream = AbstractITCase.class.getResourceAsStream("/security.properties")) {
             Properties props = new Properties();
             props.load(propStream);
 
@@ -366,7 +352,7 @@ public abstract class AbstractITCase {
             JWS_ALGORITHM = SignatureAlgorithm.valueOf(props.getProperty("jwsAlgorithm"));
             JWS_KEY = props.getProperty("jwsKey");
         } catch (Exception e) {
-            LOG.error("Could not read secretKey", e);
+            LOG.error("Could not read security.properties", e);
         }
 
         assertNotNull(ANONYMOUS_UNAME);
@@ -416,7 +402,7 @@ public abstract class AbstractITCase {
         securityQuestionService = adminClient.getService(SecurityQuestionService.class);
         implementationService = adminClient.getService(ImplementationService.class);
         remediationService = adminClient.getService(RemediationService.class);
-        gatewayRouteService = adminClient.getService(SRARouteService.class);
+        sraRouteService = adminClient.getService(SRARouteService.class);
         camelRouteService = adminClient.getService(CamelRouteService.class);
         saml2SpService = adminClient.getService(SAML2SPService.class);
         saml2IdPService = adminClient.getService(SAML2IdPService.class);
@@ -426,16 +412,12 @@ public abstract class AbstractITCase {
         clientAppService = adminClient.getService(ClientAppService.class);
         authModuleService = adminClient.getService(AuthModuleService.class);
         saml2SPMetadataService = adminClient.getService(SAML2SPMetadataService.class);
-        saml2SPMetadataConfService = adminClient.getService(SAML2SPMetadataConfService.class);
         saml2IdPMetadataService = adminClient.getService(SAML2IdPMetadataService.class);
-        saml2IdPMetadataConfService = adminClient.getService(SAML2IdPMetadataConfService.class);
         saml2SPKeystoreService = adminClient.getService(SAML2SPKeystoreService.class);
-        saml2SPKeystoreConfService = adminClient.getService(SAML2SPKeystoreConfService.class);
         googleMfaAuthTokenService = adminClient.getService(GoogleMfaAuthTokenService.class);
         googleMfaAuthAccountService = adminClient.getService(GoogleMfaAuthAccountService.class);
         authProfileService = adminClient.getService(AuthProfileService.class);
-        oidcJwksService = adminClient.getService(OIDCJWKSService.class);
-        oidcJwksConfService = adminClient.getService(OIDCJWKSConfService.class);
+        oidcJWKSService = adminClient.getService(OIDCJWKSService.class);
         u2FRegistrationService = adminClient.getService(U2FRegistrationService.class);
     }
 
@@ -628,7 +610,7 @@ public abstract class AbstractITCase {
     }
 
     @SuppressWarnings("unchecked")
-    protected <T extends PolicyTO> T createPolicy(final PolicyType type, final T policy) {
+    protected static <T extends PolicyTO> T createPolicy(final PolicyType type, final T policy) {
         Response response = policyService.create(type, policy);
         if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
             Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
@@ -651,40 +633,6 @@ public abstract class AbstractITCase {
         return getObject(response.getLocation(), AuthModuleService.class, authModule.getClass());
     }
 
-    @SuppressWarnings("unchecked")
-    protected SAML2IdPMetadataTO createSAML2IdPMetadata(final SAML2IdPMetadataTO saml2IdPMetadata) {
-        Response response = saml2IdPMetadataService.set(saml2IdPMetadata);
-        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
-            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
-            if (ex != null) {
-                throw (RuntimeException) ex;
-            }
-        }
-        return getObject(response.getLocation(), SAML2IdPMetadataService.class, saml2IdPMetadata.getClass());
-    }
-
-    protected SAML2SPMetadataTO createSAML2SPMetadata(final SAML2SPMetadataTO metadata) {
-        Response response = saml2SPMetadataService.set(metadata);
-        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
-            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
-            if (ex != null) {
-                throw (RuntimeException) ex;
-            }
-        }
-        return getObject(response.getLocation(), SAML2SPMetadataService.class, metadata.getClass());
-    }
-
-    protected SAML2SPKeystoreTO createSAML2SPKeystore(final SAML2SPKeystoreTO keystoreTO) {
-        Response response = saml2SPKeystoreService.set(keystoreTO);
-        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
-            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
-            if (ex != null) {
-                throw (RuntimeException) ex;
-            }
-        }
-        return getObject(response.getLocation(), SAML2SPKeystoreService.class, keystoreTO.getClass());
-    }
-
     protected ResourceTO createResource(final ResourceTO resourceTO) {
         Response response = resourceService.create(resourceTO);
         if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
@@ -809,7 +757,7 @@ public abstract class AbstractITCase {
         return object.get();
     }
 
-    protected OIDCRPTO buildOIDCRP() {
+    protected static OIDCRPTO buildOIDCRP() {
         AuthPolicyTO authPolicyTO = new AuthPolicyTO();
         authPolicyTO.setKey("AuthPolicyTest_" + getUUIDString());
         authPolicyTO.setDescription("Authentication Policy");
@@ -838,7 +786,7 @@ public abstract class AbstractITCase {
         return oidcrpTO;
     }
 
-    protected SAML2SPTO buildSAML2SP() {
+    protected static SAML2SPTO buildSAML2SP() {
         AuthPolicyTO authPolicyTO = new AuthPolicyTO();
         authPolicyTO.setKey("AuthPolicyTest_" + getUUIDString());
         authPolicyTO.setDescription("Authentication Policy");
@@ -884,19 +832,17 @@ public abstract class AbstractITCase {
         policy.setDescription("Test Authentication policy");
 
         DefaultAuthPolicyConf conf = new DefaultAuthPolicyConf();
-        conf.setName("TestAuthConf");
         conf.getAuthModules().add(authModuleKey);
         policy.setConf(conf);
 
         return policy;
     }
 
-    protected static AttrReleasePolicyTO buildAttributeReleasePolicyTO(final String policyName) {
+    protected static AttrReleasePolicyTO buildAttrReleasePolicyTO() {
         AttrReleasePolicyTO policy = new AttrReleasePolicyTO();
         policy.setDescription("Test Attribute Release policy");
 
         AllowedAttrReleasePolicyConf conf = new AllowedAttrReleasePolicyConf();
-        conf.setName("MyDefaultAttrReleasePolicyConf");
         conf.getAllowedAttrs().addAll(List.of("cn", "givenName"));
         policy.setConf(conf);
 
@@ -909,7 +855,6 @@ public abstract class AbstractITCase {
 
         DefaultAccessPolicyConf conf = new DefaultAccessPolicyConf();
         conf.setEnabled(true);
-        conf.setName("TestAccessPolicyConf");
         conf.addRequiredAttr("cn", Set.of("admin", "Admin", "TheAdmin"));
         policy.setConf(conf);
 
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
index 7edd289..8615b3b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AbstractConsoleITCase.java
@@ -38,8 +38,6 @@ import org.apache.syncope.common.keymaster.client.self.SelfKeymasterClientContex
 import org.apache.syncope.common.keymaster.client.zookeper.ZookeeperKeymasterClientContext;
 import org.apache.syncope.common.rest.api.service.SyncopeService;
 import org.apache.syncope.fit.ui.AbstractUITCase;
-import org.apache.wicket.IPageManagerProvider;
-import org.apache.wicket.mock.MockPageManager;
 import org.apache.wicket.util.tester.FormTester;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.jupiter.api.BeforeAll;
@@ -114,20 +112,7 @@ public abstract class AbstractConsoleITCase extends AbstractUITCase {
         ctx.register(SyncopeIdMConsoleContext.class);
         ctx.refresh();
 
-        TESTER = new WicketTester(ctx.getBean(SyncopeWebApplication.class)) {
-
-            // Remove this method when upgrading to Wicket 9.0.0-M6 - see WICKET-6766
-            @Override
-            protected IPageManagerProvider newTestPageManagerProvider() {
-                return () -> new MockPageManager() {
-
-                    @Override
-                    public boolean supportsVersioning() {
-                        return true;
-                    }
-                };
-            }
-        };
+        TESTER = new WicketTester(ctx.getBean(SyncopeWebApplication.class));
 
         SYNCOPE_SERVICE = new SyncopeClientFactoryBean().
                 setAddress(ADDRESS).create(ADMIN_UNAME, ADMIN_PWD).
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AbstractNotificationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AbstractNotificationTaskITCase.java
index 454c54f..d900cff 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AbstractNotificationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AbstractNotificationTaskITCase.java
@@ -41,7 +41,7 @@ public abstract class AbstractNotificationTaskITCase extends AbstractTaskITCase
     @BeforeAll
     public static void conf() {
         Properties props = new Properties();
-        try (InputStream propStream = ExceptionMapperITCase.class.getResourceAsStream("/test.properties")) {
+        try (InputStream propStream = AbstractNotificationTaskITCase.class.getResourceAsStream("/test.properties")) {
             props.load(propStream);
         } catch (Exception e) {
             LOG.error("Could not load /test.properties", e);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java
index ba5fc5a..2082339 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java
@@ -33,6 +33,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.auth.AuthModuleConf;
 import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf;
 import org.apache.syncope.common.lib.auth.JDBCAuthModuleConf;
@@ -65,14 +66,13 @@ public class AuthModuleITCase extends AbstractITCase {
 
     private static AuthModuleTO buildAuthModuleTO(final AuthModuleSupportedType type) {
         AuthModuleTO authModuleTO = new AuthModuleTO();
-        authModuleTO.setName("Test" + type + "AuthenticationModule" + getUUIDString());
+        authModuleTO.setKey("Test" + type + "AuthenticationModule" + getUUIDString());
         authModuleTO.setDescription("A test " + type + " Authentication Module");
 
         AuthModuleConf conf;
         switch (type) {
             case LDAP:
                 conf = new LDAPAuthModuleConf();
-                LDAPAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 LDAPAuthModuleConf.class.cast(conf).setBaseDn("dc=example,dc=org");
                 LDAPAuthModuleConf.class.cast(conf).setSearchFilter("cn={user}");
                 LDAPAuthModuleConf.class.cast(conf).setSubtreeSearch(true);
@@ -84,7 +84,6 @@ public class AuthModuleITCase extends AbstractITCase {
 
             case GOOGLE_MFA:
                 conf = new GoogleMfaAuthModuleConf();
-                GoogleMfaAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 GoogleMfaAuthModuleConf.class.cast(conf).setCodeDigits(6);
                 GoogleMfaAuthModuleConf.class.cast(conf).setIssuer("SyncopeTest");
                 GoogleMfaAuthModuleConf.class.cast(conf).setLabel("Syncope");
@@ -94,7 +93,6 @@ public class AuthModuleITCase extends AbstractITCase {
 
             case JAAS:
                 conf = new JaasAuthModuleConf();
-                JaasAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 JaasAuthModuleConf.class.cast(conf).setKerberosKdcSystemProperty("sample-value");
                 JaasAuthModuleConf.class.cast(conf).setKerberosRealmSystemProperty("sample-value");
                 JaasAuthModuleConf.class.cast(conf).setLoginConfigType("JavaLoginConfig");
@@ -104,7 +102,6 @@ public class AuthModuleITCase extends AbstractITCase {
 
             case JDBC:
                 conf = new JDBCAuthModuleConf();
-                JDBCAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 JDBCAuthModuleConf.class.cast(conf).setSql("SELECT * FROM table WHERE name=?");
                 JDBCAuthModuleConf.class.cast(conf).setFieldPassword("password");
                 JDBCAuthModuleConf.class.cast(conf).getPrincipalAttributeList().addAll(
@@ -113,7 +110,6 @@ public class AuthModuleITCase extends AbstractITCase {
 
             case OIDC:
                 conf = new OIDCAuthModuleConf();
-                OIDCAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 OIDCAuthModuleConf.class.cast(conf).setId("OIDCTestId");
                 OIDCAuthModuleConf.class.cast(conf).setDiscoveryUri("www.testurl.com");
                 OIDCAuthModuleConf.class.cast(conf).setUserIdAttribute("username");
@@ -123,27 +119,22 @@ public class AuthModuleITCase extends AbstractITCase {
 
             case SAML2_IDP:
                 conf = new SAML2IdPAuthModuleConf();
-                SAML2IdPAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("testEntityId");
                 SAML2IdPAuthModuleConf.class.cast(conf).setProviderName("testProviderName");
                 break;
 
             case SYNCOPE:
                 conf = new SyncopeAuthModuleConf();
-                SyncopeAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
-                SyncopeAuthModuleConf.class.cast(conf).setDomain("Master");
-                SyncopeAuthModuleConf.class.cast(conf).setUrl("http://mydomain.com/syncope/rest");
+                SyncopeAuthModuleConf.class.cast(conf).setDomain(SyncopeConstants.MASTER_DOMAIN);
                 break;
 
             case U2F:
                 conf = new U2FAuthModuleConf();
-                U2FAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 U2FAuthModuleConf.class.cast(conf).setExpireDevices(50);
                 break;
 
             case RADIUS:
                 conf = new RadiusAuthModuleConf();
-                RadiusAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 RadiusAuthModuleConf.class.cast(conf).setProtocol("MSCHAPv2");
                 RadiusAuthModuleConf.class.cast(conf).setInetAddress("1.2.3.4");
                 RadiusAuthModuleConf.class.cast(conf).setSharedSecret("xyz");
@@ -153,7 +144,6 @@ public class AuthModuleITCase extends AbstractITCase {
             case STATIC:
             default:
                 conf = new StaticAuthModuleConf();
-                StaticAuthModuleConf.class.cast(conf).setName("TestConf" + getUUIDString());
                 StaticAuthModuleConf.class.cast(conf).getUsers().put("user1", UUID.randomUUID().toString());
                 StaticAuthModuleConf.class.cast(conf).getUsers().put("user2", "user2Password123");
                 break;
@@ -173,6 +163,10 @@ public class AuthModuleITCase extends AbstractITCase {
         return authModuleTO;
     }
 
+    private static boolean isSpecificConf(final AuthModuleConf conf, final Class<? extends AuthModuleConf> clazz) {
+        return ClassUtils.isAssignable(clazz, conf.getClass());
+    }
+
     @Test
     public void list() {
         List<AuthModuleTO> authModuleTOs = authModuleService.list();
@@ -181,42 +175,41 @@ public class AuthModuleITCase extends AbstractITCase {
 
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), LDAPAuthModuleConf.class)
-                && authModule.getName().equals("DefaultLDAPAuthModule")));
+                && authModule.getKey().equals("DefaultLDAPAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), JDBCAuthModuleConf.class)
-                && authModule.getName().equals("DefaultJDBCAuthModule")));
+                && authModule.getKey().equals("DefaultJDBCAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), GoogleMfaAuthModuleConf.class)
-                && authModule.getName().equals("DefaultGoogleMfaAuthModule")));
+                && authModule.getKey().equals("DefaultGoogleMfaAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), OIDCAuthModuleConf.class)
-                && authModule.getName().equals("DefaultOIDCAuthModule")));
+                && authModule.getKey().equals("DefaultOIDCAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), SAML2IdPAuthModuleConf.class)
-                && authModule.getName().equals("DefaultSAML2IdPAuthModule")));
+                && authModule.getKey().equals("DefaultSAML2IdPAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), JaasAuthModuleConf.class)
-                && authModule.getName().equals("DefaultJaasAuthModule")));
+                && authModule.getKey().equals("DefaultJaasAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), StaticAuthModuleConf.class)
-                && authModule.getName().equals("DefaultStaticAuthModule")));
+                && authModule.getKey().equals("DefaultStaticAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), SyncopeAuthModuleConf.class)
-                && authModule.getName().equals("DefaultSyncopeAuthModule")));
+                && authModule.getKey().equals("DefaultSyncopeAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), U2FAuthModuleConf.class)
-                && authModule.getName().equals("DefaultU2FAuthModule")));
+                && authModule.getKey().equals("DefaultU2FAuthModule")));
         assertTrue(authModuleTOs.stream().anyMatch(
                 authModule -> isSpecificConf(authModule.getConf(), RadiusAuthModuleConf.class)
-                && authModule.getName().equals("DefaultRadiusAuthModule")));
+                && authModule.getKey().equals("DefaultRadiusAuthModule")));
     }
 
     @Test
     public void getLDAPAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultLDAPAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), LDAPAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), JDBCAuthModuleConf.class));
@@ -224,10 +217,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getJDBCAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultJDBCAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), JDBCAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), GoogleMfaAuthModuleConf.class));
@@ -235,10 +227,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getGoogleMfaAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultGoogleMfaAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), GoogleMfaAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), OIDCAuthModuleConf.class));
@@ -246,10 +237,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getOIDCAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultOIDCAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), OIDCAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class));
@@ -257,10 +247,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getSAML2IdPAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultSAML2IdPAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), SAML2IdPAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), JaasAuthModuleConf.class));
@@ -268,10 +257,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getJaasAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3edbbc-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultJaasAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), JaasAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), StaticAuthModuleConf.class));
@@ -279,10 +267,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getStaticAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3edc98-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultStaticAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), StaticAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), SyncopeAuthModuleConf.class));
@@ -290,10 +277,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getSyncopeAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("4c3edd60-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultSyncopeAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), SyncopeAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), RadiusAuthModuleConf.class));
@@ -301,10 +287,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getRadiusAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultRadiusAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), RadiusAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), U2FAuthModuleConf.class));
@@ -312,10 +297,9 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void getU2FAuthModule() {
-        AuthModuleTO authModuleTO = authModuleService.read("f6e1288d-50d9-45fe-82ee-597c42242205");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultU2FAuthModule");
 
         assertNotNull(authModuleTO);
-        assertTrue(StringUtils.isNotBlank(authModuleTO.getName()));
         assertTrue(StringUtils.isNotBlank(authModuleTO.getDescription()));
         assertTrue(isSpecificConf(authModuleTO.getConf(), U2FAuthModuleConf.class));
         assertFalse(isSpecificConf(authModuleTO.getConf(), LDAPAuthModuleConf.class));
@@ -323,12 +307,17 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void create() throws IOException {
-        EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> testCreate(type));
+        EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> {
+            AuthModuleTO authModuleTO = createAuthModule(buildAuthModuleTO(type));
+            assertNotNull(authModuleTO);
+            assertTrue(authModuleTO.getDescription().contains("A test " + type + " Authentication Module"));
+            assertEquals(2, authModuleTO.getItems().size());
+        });
     }
 
     @Test
     public void updateGoogleMfaAuthModule() {
-        AuthModuleTO googleMfaAuthModuleTO = authModuleService.read("4c3ed4e6-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO googleMfaAuthModuleTO = authModuleService.read("DefaultGoogleMfaAuthModule");
         assertNotNull(googleMfaAuthModuleTO);
 
         AuthModuleTO newGoogleMfaAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.GOOGLE_MFA);
@@ -351,7 +340,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateLDAPAuthModule() {
-        AuthModuleTO ldapAuthModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModuleTO ldapAuthModuleTO = authModuleService.read("DefaultLDAPAuthModule");
         assertNotNull(ldapAuthModuleTO);
 
         AuthModuleTO newLdapAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.LDAP);
@@ -374,7 +363,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateSAML2IdPAuthModule() {
-        AuthModuleTO saml2IdpAuthModuleTO = authModuleService.read("4c3ed9d2-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO saml2IdpAuthModuleTO = authModuleService.read("DefaultSAML2IdPAuthModule");
         assertNotNull(saml2IdpAuthModuleTO);
 
         AuthModuleTO newsaml2IdpAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.SAML2_IDP);
@@ -397,7 +386,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateOIDCAuthModule() {
-        AuthModuleTO oidcAuthModuleTO = authModuleService.read("4c3ed8f6-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO oidcAuthModuleTO = authModuleService.read("DefaultOIDCAuthModule");
         assertNotNull(oidcAuthModuleTO);
 
         AuthModuleTO newOIDCAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.OIDC);
@@ -420,7 +409,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateJDBCAuthModule() {
-        AuthModuleTO jdbcAuthModuleTO = authModuleService.read("4c3ed7e8-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO jdbcAuthModuleTO = authModuleService.read("DefaultJDBCAuthModule");
         assertNotNull(jdbcAuthModuleTO);
 
         AuthModuleTO newJDBCAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.JDBC);
@@ -443,7 +432,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateJaasAuthModule() {
-        AuthModuleTO jaasAuthModuleTO = authModuleService.read("4c3edbbc-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO jaasAuthModuleTO = authModuleService.read("DefaultJaasAuthModule");
         assertNotNull(jaasAuthModuleTO);
 
         AuthModuleTO newJaasAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.JAAS);
@@ -466,7 +455,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateStaticAuthModule() {
-        AuthModuleTO staticAuthModuleTO = authModuleService.read("4c3edc98-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO staticAuthModuleTO = authModuleService.read("DefaultStaticAuthModule");
         assertNotNull(staticAuthModuleTO);
 
         AuthModuleTO newStaticAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.STATIC);
@@ -490,7 +479,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateRadiusAuthModule() {
-        AuthModuleTO radiusAuthModuleTO = authModuleService.read("07c528f3-63b4-4dc1-a4da-87f35b8bdec8");
+        AuthModuleTO radiusAuthModuleTO = authModuleService.read("DefaultRadiusAuthModule");
         assertNotNull(radiusAuthModuleTO);
 
         AuthModuleTO newRadiusAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.RADIUS);
@@ -513,7 +502,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateU2fAuthModule() {
-        AuthModuleTO u2fAuthModuleTO = authModuleService.read("f6e1288d-50d9-45fe-82ee-597c42242205");
+        AuthModuleTO u2fAuthModuleTO = authModuleService.read("DefaultU2FAuthModule");
         assertNotNull(u2fAuthModuleTO);
 
         AuthModuleTO newU2fAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.U2F);
@@ -536,7 +525,7 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void updateSyncopeAuthModule() {
-        AuthModuleTO syncopeAuthModuleTO = authModuleService.read("4c3edd60-7008-11ea-bc55-0242ac130003");
+        AuthModuleTO syncopeAuthModuleTO = authModuleService.read("DefaultSyncopeAuthModule");
         assertNotNull(syncopeAuthModuleTO);
 
         AuthModuleTO newSyncopeAuthModuleTO = buildAuthModuleTO(AuthModuleSupportedType.SYNCOPE);
@@ -559,32 +548,18 @@ public class AuthModuleITCase extends AbstractITCase {
 
     @Test
     public void delete() throws IOException {
-        EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> testDelete(type));
-    }
-
-    private void testCreate(final AuthModuleSupportedType type) {
-        AuthModuleTO authModuleTO = createAuthModule(buildAuthModuleTO(type));
-        assertNotNull(authModuleTO);
-        assertTrue(authModuleTO.getName().contains("Test" + type + "AuthenticationModule"));
-        assertTrue(authModuleTO.getDescription().contains("A test " + type + " Authentication Module"));
-        assertEquals(2, authModuleTO.getItems().size());
-    }
-
-    private void testDelete(final AuthModuleSupportedType type) {
-        AuthModuleTO read = createAuthModule(buildAuthModuleTO(type));
-        assertNotNull(read);
-
-        authModuleService.delete(read.getKey());
-
-        try {
-            authModuleService.read(read.getKey());
-            fail("This should not happen");
-        } catch (SyncopeClientException e) {
-            assertNotNull(e);
-        }
-    }
-
-    private boolean isSpecificConf(final AuthModuleConf conf, final Class<? extends AuthModuleConf> clazz) {
-        return ClassUtils.isAssignable(clazz, conf.getClass());
+        EnumSet.allOf(AuthModuleSupportedType.class).forEach(type -> {
+            AuthModuleTO read = createAuthModule(buildAuthModuleTO(type));
+            assertNotNull(read);
+
+            authModuleService.delete(read.getKey());
+
+            try {
+                authModuleService.read(read.getKey());
+                fail("This should not happen");
+            } catch (SyncopeClientException e) {
+                assertNotNull(e);
+            }
+        });
     }
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
index ba6cf59..5de0634 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ClientAppITCase.java
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import java.util.UUID;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.policy.AccessPolicyTO;
@@ -36,8 +37,6 @@ import org.apache.syncope.common.lib.types.PolicyType;
 import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.Test;
 
-import java.util.UUID;
-
 public class ClientAppITCase extends AbstractITCase {
 
     @Test
@@ -187,7 +186,7 @@ public class ClientAppITCase extends AbstractITCase {
         }
     }
 
-    private CASSPTO buildCASSP() {
+    private static CASSPTO buildCASSP() {
         AuthPolicyTO authPolicyTO = new AuthPolicyTO();
         authPolicyTO.setKey("AuthPolicyTest_" + getUUIDString());
         authPolicyTO.setDescription("Authentication Policy");
@@ -210,6 +209,4 @@ public class ClientAppITCase extends AbstractITCase {
         casspTO.setAccessPolicy(accessPolicyTO.getKey());
         return casspTO;
     }
-
-
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSConfITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSConfITCase.java
deleted file mode 100644
index 8c1a70d..0000000
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSConfITCase.java
+++ /dev/null
@@ -1,79 +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.fit.core;
-
-import com.nimbusds.jose.jwk.JWKSet;
-import com.nimbusds.jose.jwk.KeyUse;
-import com.nimbusds.jose.jwk.RSAKey;
-import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.OIDCJWKSTO;
-import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.fit.AbstractITCase;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.function.Executable;
-import org.springframework.http.HttpStatus;
-
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.Response;
-
-import java.util.UUID;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class OIDCJWKSConfITCase extends AbstractITCase {
-
-    private static OIDCJWKSTO getCurrentJwksTO() {
-        try {
-            return oidcJwksService.get();
-        } catch (final SyncopeClientException e) {
-            if (e.getType() == ClientExceptionType.NotFound) {
-                Response response = oidcJwksService.set();
-                assertEquals(HttpStatus.CREATED.value(), response.getStatus());
-                return response.readEntity(new GenericType<OIDCJWKSTO>() {
-                });
-            }
-        }
-        throw new RuntimeException("Unable to locate current OIDC JWKS");
-    }
-
-    @Test
-    public void verifyJwks() throws Exception {
-        oidcJwksConfService.delete();
-
-        RSAKey jwk = new RSAKeyGenerator(2048)
-            .keyUse(KeyUse.SIGNATURE)
-            .keyID(UUID.randomUUID().toString())
-            .generate();
-        String json = new JWKSet(jwk).toString();
-
-        assertDoesNotThrow(new Executable() {
-            @Override
-            public void execute() {
-                OIDCJWKSTO currentTO = getCurrentJwksTO();
-                currentTO.setJson(json);
-                oidcJwksConfService.update(currentTO);
-            }
-        });
-        OIDCJWKSTO currentTO = getCurrentJwksTO();
-        assertEquals(json, currentTO.getJson());
-    }
-
-}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
index 931213f..d30d449 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/OIDCJWKSITCase.java
@@ -18,37 +18,94 @@
  */
 package org.apache.syncope.fit.core;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
+import org.apache.syncope.common.rest.api.service.wa.WAOIDCJWKSService;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.fit.AbstractITCase;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.springframework.http.HttpStatus;
 
-import javax.ws.rs.core.Response;
+public class OIDCJWKSITCase extends AbstractITCase {
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
+    private static WAOIDCJWKSService waOIDCJWKSService;
 
-public class OIDCJWKSITCase extends AbstractITCase {
+    @BeforeAll
+    public static void setup() {
+        assumeTrue(clientFactory.getContentType() == SyncopeClientFactoryBean.ContentType.JSON);
+
+        SyncopeClient anonymous = clientFactory.create(
+                new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY));
+        waOIDCJWKSService = anonymous.getService(WAOIDCJWKSService.class);
+    }
 
     @Test
-    public void verifyJwks() {
+    public void deleteGetSet() {
         try {
-            oidcJwksConfService.delete();
+            oidcJWKSService.delete();
 
-            oidcJwksService.get();
+            waOIDCJWKSService.get();
             fail("Should not locate an OIDC JWKS");
-        } catch (final SyncopeClientException e) {
+        } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
         }
-        Response response = oidcJwksService.set();
+
+        Response response = waOIDCJWKSService.set(2048, JWSAlgorithm.RS256);
         assertEquals(HttpStatus.CREATED.value(), response.getStatus());
         try {
-            oidcJwksService.set();
+            waOIDCJWKSService.set(2048, JWSAlgorithm.RS512);
             fail("Should not recreate an OIDC JWKS");
-        } catch (final SyncopeClientException e) {
+        } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.EntityExists, e.getType());
         }
     }
 
+    private static OIDCJWKSTO getCurrentJwksTO() {
+        try {
+            return waOIDCJWKSService.get();
+        } catch (final SyncopeClientException e) {
+            if (e.getType() == ClientExceptionType.NotFound) {
+                Response response = waOIDCJWKSService.set(2048, JWSAlgorithm.RS256);
+                assertEquals(HttpStatus.CREATED.value(), response.getStatus());
+                return waOIDCJWKSService.get();
+            }
+        }
+        throw new NotFoundException("Unable to locate current OIDC JWKS");
+    }
+
+    @Test
+    public void update() throws Exception {
+        oidcJWKSService.delete();
+
+        RSAKey jwk = new RSAKeyGenerator(2048)
+                .keyUse(KeyUse.SIGNATURE)
+                .keyID(UUID.randomUUID().toString())
+                .generate();
+        String json = new JWKSet(jwk).toString();
+
+        assertDoesNotThrow(() -> {
+            OIDCJWKSTO currentTO = getCurrentJwksTO();
+            currentTO.setJson(json);
+            oidcJWKSService.update(currentTO);
+        });
+        OIDCJWKSTO currentTO = getCurrentJwksTO();
+        assertEquals(json, currentTO.getJson());
+    }
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
index 45edfbf..6721fd2 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
@@ -267,9 +267,7 @@ public class PolicyITCase extends AbstractITCase {
 
     @Test
     public void updateAttrReleasePolicy() {
-        String policyName = "TestAttrReleasePolicy" + getUUIDString();
-        AttrReleasePolicyTO newPolicyTO = buildAttributeReleasePolicyTO(policyName);
-        newPolicyTO = createPolicy(PolicyType.ATTR_RELEASE, newPolicyTO);
+        AttrReleasePolicyTO newPolicyTO = createPolicy(PolicyType.ATTR_RELEASE, buildAttrReleasePolicyTO());
         assertNotNull(newPolicyTO);
 
         AllowedAttrReleasePolicyConf policyConf = (AllowedAttrReleasePolicyConf) newPolicyTO.getConf();
@@ -285,7 +283,6 @@ public class PolicyITCase extends AbstractITCase {
         assertTrue(policyConf.getAllowedAttrs().contains("cn"));
         assertTrue(policyConf.getAllowedAttrs().contains("postalCode"));
         assertTrue(policyConf.getAllowedAttrs().contains("givenName"));
-
     }
 
     @Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index 7abc702..efdb83a 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -256,7 +256,6 @@ public class RealmITCase extends AbstractITCase {
         // 1. create access policy
         DefaultAccessPolicyConf ruleConf = new DefaultAccessPolicyConf();
         ruleConf.setEnabled(true);
-        ruleConf.setName("TestAccessPolicyConf" + getUUIDString());
         ruleConf.addRequiredAttr("cn", Set.of("admin", "Admin", "TheAdmin"));
 
         AccessPolicyTO policy = new AccessPolicyTO();
@@ -298,7 +297,6 @@ public class RealmITCase extends AbstractITCase {
     public void deletingAttributeReleasePolicy() {
         // 1. create attribute release policy
         AllowedAttrReleasePolicyConf ruleConf = new AllowedAttrReleasePolicyConf();
-        ruleConf.setName("MyDefaultAttrReleasePolicyConf" + getUUIDString());
         ruleConf.getAllowedAttrs().addAll(List.of("cn", "givenName"));
 
         AttrReleasePolicyTO policy = new AttrReleasePolicyTO();
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2IdPMetadataITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2IdPMetadataITCase.java
index 2971cb7..a330df4 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2IdPMetadataITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2IdPMetadataITCase.java
@@ -18,26 +18,63 @@
  */
 package org.apache.syncope.fit.core;
 
+import static org.apache.syncope.fit.AbstractITCase.getObject;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.Test;
 import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2IdPMetadataService;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.platform.commons.util.StringUtils;
 
 public class SAML2IdPMetadataITCase extends AbstractITCase {
-    
-    private static final String APPLIES_TO = "Syncope";
+
+    private static WASAML2IdPMetadataService waSAML2IdPMetadataService;
+
+    @BeforeAll
+    public static void setup() {
+        assumeTrue(clientFactory.getContentType() == SyncopeClientFactoryBean.ContentType.JSON);
+
+        SyncopeClient anonymous = clientFactory.create(
+                new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY));
+        waSAML2IdPMetadataService = anonymous.getService(WASAML2IdPMetadataService.class);
+    }
+
+    private static void testIsValid(final SAML2IdPMetadataTO saml2IdPMetadataTO) {
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getAppliesTo()));
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getMetadata()));
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getEncryptionKey()));
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getEncryptionCertificate()));
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getSigningCertificate()));
+        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getSigningKey()));
+    }
+
+    private SAML2IdPMetadataTO createSAML2IdPMetadata(final SAML2IdPMetadataTO saml2IdPMetadata) {
+        Response response = waSAML2IdPMetadataService.set(saml2IdPMetadata);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), WASAML2IdPMetadataService.class, saml2IdPMetadata.getClass());
+    }
 
     private SAML2IdPMetadataTO createSAML2IdPMetadata() {
         SAML2IdPMetadataTO result = createSAML2IdPMetadata(new SAML2IdPMetadataTO.Builder().
-                appliesTo(APPLIES_TO).
+                appliesTo(OWNER).
                 metadata("testMetadata").
                 encryptionCertificate("testEncryptionCert").
                 encryptionKey("testEncryptionKey").
@@ -50,40 +87,31 @@ public class SAML2IdPMetadataITCase extends AbstractITCase {
         return result;
     }
 
-    private void testIsValid(final SAML2IdPMetadataTO saml2IdPMetadataTO) {
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getAppliesTo()));
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getMetadata()));
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getEncryptionKey()));
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getEncryptionCertificate()));
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getSigningCertificate()));
-        assertFalse(StringUtils.isBlank(saml2IdPMetadataTO.getSigningKey()));
-    }
-
     @Test
     public void read() {
-        SAML2IdPMetadataTO saml2IdPMetadataTO = null;
+        SAML2IdPMetadataTO saml2IdPMetadataTO;
         try {
-            saml2IdPMetadataTO = saml2IdPMetadataService.getByOwner(APPLIES_TO);
+            saml2IdPMetadataTO = waSAML2IdPMetadataService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             saml2IdPMetadataTO = createSAML2IdPMetadata();
         }
 
         assertNotNull(saml2IdPMetadataTO);
-        assertEquals(APPLIES_TO, saml2IdPMetadataTO.getAppliesTo());
+        assertEquals(OWNER, saml2IdPMetadataTO.getAppliesTo());
         testIsValid(saml2IdPMetadataTO);
     }
 
     @Test
     public void create() {
         try {
-            saml2IdPMetadataService.getByOwner(APPLIES_TO);
+            waSAML2IdPMetadataService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             createSAML2IdPMetadata();
         }
 
         try {
             createSAML2IdPMetadata(new SAML2IdPMetadataTO.Builder().
-                    appliesTo(APPLIES_TO).
+                    appliesTo(OWNER).
                     metadata("testMetadata").
                     build());
             fail("This should not happen");
@@ -94,20 +122,19 @@ public class SAML2IdPMetadataITCase extends AbstractITCase {
 
     @Test
     public void update() {
-        SAML2IdPMetadataTO saml2IdPMetadataTO = null;
+        SAML2IdPMetadataTO saml2IdPMetadataTO;
         try {
-            saml2IdPMetadataTO = saml2IdPMetadataService.getByOwner(APPLIES_TO);
+            saml2IdPMetadataTO = waSAML2IdPMetadataService.getByOwner(OWNER);
         } catch (NotFoundException e) {
             saml2IdPMetadataTO = createSAML2IdPMetadata();
         }
 
         assertNotNull(saml2IdPMetadataTO);
         saml2IdPMetadataTO.setEncryptionKey("newKey");
-        saml2IdPMetadataConfService.update(saml2IdPMetadataTO);
-        saml2IdPMetadataTO = saml2IdPMetadataService.getByOwner(saml2IdPMetadataTO.getAppliesTo());
+        saml2IdPMetadataService.update(saml2IdPMetadataTO);
+        saml2IdPMetadataTO = waSAML2IdPMetadataService.getByOwner(saml2IdPMetadataTO.getAppliesTo());
         assertNotNull(saml2IdPMetadataTO);
 
         assertEquals("newKey", saml2IdPMetadataTO.getEncryptionKey());
     }
-
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPKeystoreITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPKeystoreITCase.java
index cc7e40c..45abac3 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPKeystoreITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPKeystoreITCase.java
@@ -18,33 +18,65 @@
  */
 package org.apache.syncope.fit.core;
 
+import static org.apache.syncope.fit.AbstractITCase.getObject;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPKeystoreService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.fit.AbstractITCase;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.platform.commons.util.StringUtils;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.fail;
 
 public class SAML2SPKeystoreITCase extends AbstractITCase {
 
-    private static final String OWNER = "Syncope";
+    private static WASAML2SPKeystoreService waSAML2SPKeystoreService;
+
+    private static WASAML2SPMetadataService waSAML2SPMetadataService;
+
+    @BeforeAll
+    public static void setup() {
+        assumeTrue(clientFactory.getContentType() == SyncopeClientFactoryBean.ContentType.JSON);
+
+        SyncopeClient anonymous = clientFactory.create(
+                new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY));
+        waSAML2SPKeystoreService = anonymous.getService(WASAML2SPKeystoreService.class);
+        waSAML2SPMetadataService = anonymous.getService(WASAML2SPMetadataService.class);
+    }
 
     private static void testIsValid(final SAML2SPKeystoreTO keystoreTO) {
         assertFalse(StringUtils.isBlank(keystoreTO.getOwner()));
         assertFalse(StringUtils.isBlank(keystoreTO.getKeystore()));
     }
 
+    private SAML2SPKeystoreTO createSAML2SPKeystore(final SAML2SPKeystoreTO keystoreTO) {
+        Response response = waSAML2SPKeystoreService.set(keystoreTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), WASAML2SPKeystoreService.class, keystoreTO.getClass());
+    }
+
     private SAML2SPKeystoreTO createSAML2SPKeystore() {
         SAML2SPKeystoreTO result = createSAML2SPKeystore(new SAML2SPKeystoreTO.Builder().
-            owner(OWNER).
-            keystore("testkyStore").
-            build());
+                owner(OWNER).
+                keystore("testkyStore").
+                build());
         assertNotNull(result);
         testIsValid(result);
         return result;
@@ -54,7 +86,7 @@ public class SAML2SPKeystoreITCase extends AbstractITCase {
     public void read() {
         SAML2SPKeystoreTO keystoreTO;
         try {
-            keystoreTO = saml2SPKeystoreService.getByOwner(OWNER);
+            keystoreTO = waSAML2SPKeystoreService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             keystoreTO = createSAML2SPKeystore();
         }
@@ -66,16 +98,16 @@ public class SAML2SPKeystoreITCase extends AbstractITCase {
     @Test
     public void create() {
         try {
-            saml2SPMetadataService.getByOwner(OWNER);
+            waSAML2SPMetadataService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             createSAML2SPKeystore();
         }
 
         try {
             createSAML2SPKeystore(new SAML2SPKeystoreTO.Builder().
-                owner(OWNER).
-                keystore("testMetadata").
-                build());
+                    owner(OWNER).
+                    keystore("testMetadata").
+                    build());
             fail("This should not happen");
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.EntityExists, e.getType());
@@ -86,7 +118,7 @@ public class SAML2SPKeystoreITCase extends AbstractITCase {
     public void update() {
         SAML2SPKeystoreTO keystoreTO;
         try {
-            keystoreTO = saml2SPKeystoreService.getByOwner(OWNER);
+            keystoreTO = waSAML2SPKeystoreService.getByOwner(OWNER);
         } catch (NotFoundException e) {
             keystoreTO = createSAML2SPKeystore();
         }
@@ -94,11 +126,10 @@ public class SAML2SPKeystoreITCase extends AbstractITCase {
         keystoreTO.setKeystore("new-keystore");
         keystoreTO.setOwner("Syncope4");
 
-        saml2SPKeystoreConfService.update(keystoreTO);
-        keystoreTO = saml2SPKeystoreService.read(keystoreTO.getKey());
+        saml2SPKeystoreService.update(keystoreTO);
+        keystoreTO = waSAML2SPKeystoreService.read(keystoreTO.getKey());
         assertNotNull(keystoreTO);
         assertEquals("new-keystore", keystoreTO.getKeystore());
         assertEquals("Syncope4", keystoreTO.getOwner());
     }
-
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPMetadataITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPMetadataITCase.java
index 3fe0f0d..d697c2d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPMetadataITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPMetadataITCase.java
@@ -18,22 +18,50 @@
  */
 package org.apache.syncope.fit.core;
 
+import static org.apache.syncope.fit.AbstractITCase.getObject;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.lib.AnonymousAuthenticationHandler;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.fit.AbstractITCase;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.platform.commons.util.StringUtils;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.fail;
 
 public class SAML2SPMetadataITCase extends AbstractITCase {
 
-    private static final String OWNER = "Syncope";
+    private static WASAML2SPMetadataService waSAML2SPMetadataService;
+
+    @BeforeAll
+    public static void setup() {
+        assumeTrue(clientFactory.getContentType() == SyncopeClientFactoryBean.ContentType.JSON);
+
+        SyncopeClient anonymous = clientFactory.create(
+                new AnonymousAuthenticationHandler(ANONYMOUS_UNAME, ANONYMOUS_KEY));
+        waSAML2SPMetadataService = anonymous.getService(WASAML2SPMetadataService.class);
+    }
+
+    private SAML2SPMetadataTO createSAML2SPMetadata(final SAML2SPMetadataTO metadata) {
+        Response response = waSAML2SPMetadataService.set(metadata);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), WASAML2SPMetadataService.class, metadata.getClass());
+    }
 
     private static void testIsValid(final SAML2SPMetadataTO metadataTO) {
         assertFalse(StringUtils.isBlank(metadataTO.getOwner()));
@@ -42,9 +70,9 @@ public class SAML2SPMetadataITCase extends AbstractITCase {
 
     private SAML2SPMetadataTO createSAML2SPMetadata() {
         SAML2SPMetadataTO result = createSAML2SPMetadata(new SAML2SPMetadataTO.Builder().
-            owner(OWNER).
-            metadata("testMetadata").
-            build());
+                owner(OWNER).
+                metadata("testMetadata").
+                build());
         assertNotNull(result);
         testIsValid(result);
         return result;
@@ -54,7 +82,7 @@ public class SAML2SPMetadataITCase extends AbstractITCase {
     public void read() {
         SAML2SPMetadataTO metadataTO;
         try {
-            metadataTO = saml2SPMetadataService.getByOwner(OWNER);
+            metadataTO = waSAML2SPMetadataService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             metadataTO = createSAML2SPMetadata();
         }
@@ -66,16 +94,16 @@ public class SAML2SPMetadataITCase extends AbstractITCase {
     @Test
     public void create() {
         try {
-            saml2SPMetadataService.getByOwner(OWNER);
+            waSAML2SPMetadataService.getByOwner(OWNER);
         } catch (SyncopeClientException e) {
             createSAML2SPMetadata();
         }
 
         try {
             createSAML2SPMetadata(new SAML2SPMetadataTO.Builder().
-                owner(OWNER).
-                metadata("testMetadata").
-                build());
+                    owner(OWNER).
+                    metadata("testMetadata").
+                    build());
             fail("This should not happen");
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.EntityExists, e.getType());
@@ -86,7 +114,7 @@ public class SAML2SPMetadataITCase extends AbstractITCase {
     public void update() {
         SAML2SPMetadataTO metadataTO;
         try {
-            metadataTO = saml2SPMetadataService.getByOwner(OWNER);
+            metadataTO = waSAML2SPMetadataService.getByOwner(OWNER);
         } catch (NotFoundException e) {
             metadataTO = createSAML2SPMetadata();
         }
@@ -94,11 +122,10 @@ public class SAML2SPMetadataITCase extends AbstractITCase {
         metadataTO.setMetadata("new-metadata");
         metadataTO.setOwner("Syncope4");
 
-        saml2SPMetadataConfService.update(metadataTO);
-        metadataTO = saml2SPMetadataService.read(metadataTO.getKey());
+        saml2SPMetadataService.update(metadataTO);
+        metadataTO = waSAML2SPMetadataService.read(metadataTO.getKey());
         assertNotNull(metadataTO);
         assertEquals("new-metadata", metadataTO.getMetadata());
         assertEquals("Syncope4", metadataTO.getOwner());
     }
-
 }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SRARouteITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SRARouteITCase.java
index 45190bd..33a561a 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SRARouteITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SRARouteITCase.java
@@ -43,12 +43,12 @@ public class SRARouteITCase extends AbstractITCase {
 
     @Test
     public void read() {
-        SRARouteTO route = gatewayRouteService.read("ec7bada2-3dd6-460c-8441-65521d005ffa");
+        SRARouteTO route = sraRouteService.read("ec7bada2-3dd6-460c-8441-65521d005ffa");
         assertNotNull(route);
         assertEquals(1, route.getPredicates().size());
 
         try {
-            gatewayRouteService.read(UUID.randomUUID().toString());
+            sraRouteService.read(UUID.randomUUID().toString());
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
@@ -57,7 +57,7 @@ public class SRARouteITCase extends AbstractITCase {
 
     @Test
     public void findAll() {
-        List<SRARouteTO> routes = gatewayRouteService.list();
+        List<SRARouteTO> routes = sraRouteService.list();
         assertNotNull(routes);
         assertFalse(routes.isEmpty());
     }
@@ -72,27 +72,27 @@ public class SRARouteITCase extends AbstractITCase {
         route.getFilters().add(new SRARouteFilter.Builder().
                 factory(SRARouteFilterFactory.ADD_REQUEST_HEADER).args("X-Request-Foo, Bar").build());
 
-        int beforeCount = gatewayRouteService.list().size();
+        int beforeCount = sraRouteService.list().size();
 
-        Response response = gatewayRouteService.create(route);
+        Response response = sraRouteService.create(route);
         assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusInfo().getStatusCode());
         route = getObject(response.getLocation(), SRARouteService.class, SRARouteTO.class);
         assertNotNull(route);
         assertNotNull(route.getKey());
 
-        int afterCount = gatewayRouteService.list().size();
+        int afterCount = sraRouteService.list().size();
         assertEquals(afterCount, beforeCount + 1);
 
-        gatewayRouteService.delete(route.getKey());
+        sraRouteService.delete(route.getKey());
 
         try {
-            gatewayRouteService.read(route.getKey());
+            sraRouteService.read(route.getKey());
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
         }
 
-        int endCount = gatewayRouteService.list().size();
+        int endCount = sraRouteService.list().size();
         assertEquals(endCount, beforeCount);
     }
 
@@ -100,7 +100,7 @@ public class SRARouteITCase extends AbstractITCase {
     public void exceptions() {
         SRARouteTO route = new SRARouteTO();
         try {
-            gatewayRouteService.create(route);
+            sraRouteService.create(route);
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
@@ -108,18 +108,18 @@ public class SRARouteITCase extends AbstractITCase {
 
         route.setName("createException");
         try {
-            gatewayRouteService.create(route);
+            sraRouteService.create(route);
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.RequiredValuesMissing, e.getType());
         }
 
         route.setTarget(URI.create("http://httpbin.org:80"));
-        Response response = gatewayRouteService.create(route);
+        Response response = sraRouteService.create(route);
         assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusInfo().getStatusCode());
 
         try {
-            gatewayRouteService.create(route);
+            sraRouteService.create(route);
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.EntityExists, e.getType());
@@ -127,13 +127,13 @@ public class SRARouteITCase extends AbstractITCase {
 
         route.setKey(UUID.randomUUID().toString());
         try {
-            gatewayRouteService.update(route);
+            sraRouteService.update(route);
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
         }
         try {
-            gatewayRouteService.delete(route.getKey());
+            sraRouteService.delete(route.getKey());
             fail();
         } catch (SyncopeClientException e) {
             assertEquals(ClientExceptionType.NotFound, e.getType());
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/WAClientAppITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/WAClientAppITCase.java
index 4078360..81f99a7 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/WAClientAppITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/WAClientAppITCase.java
@@ -97,15 +97,11 @@ public class WAClientAppITCase extends AbstractITCase {
     public void readWithPolicies() {
         OIDCRPTO oidcrpto = buildOIDCRP();
 
-        AuthPolicyTO authPolicyTO = createPolicy(PolicyType.AUTH,
-                buildAuthPolicyTO("be456831-593d-4003-b273-4c3fb61700df"));
+        AuthPolicyTO authPolicyTO = createPolicy(PolicyType.AUTH, buildAuthPolicyTO("DefaultLDAPAuthModule"));
 
-        AccessPolicyTO accessPolicyTO = createPolicy(PolicyType.ACCESS,
-                buildAccessPolicyTO());
+        AccessPolicyTO accessPolicyTO = createPolicy(PolicyType.ACCESS, buildAccessPolicyTO());
 
-        String policyName = "TestAttrReleasePolicy" + getUUIDString();
-        AttrReleasePolicyTO attrReleasePolicyTO = createPolicy(PolicyType.ATTR_RELEASE,
-                buildAttributeReleasePolicyTO(policyName));
+        AttrReleasePolicyTO attrReleasePolicyTO = createPolicy(PolicyType.ATTR_RELEASE, buildAttrReleasePolicyTO());
 
         oidcrpto.setAuthPolicy(authPolicyTO.getKey());
         oidcrpto.setAccessPolicy(accessPolicyTO.getKey());
@@ -115,9 +111,6 @@ public class WAClientAppITCase extends AbstractITCase {
 
         WAClientApp waClientApp = waClientAppService.read(oidcrpto.getClientAppId(), null);
         assertNotNull(waClientApp);
-        assertEquals("TestAuthConf", waClientApp.getAuthPolicyConf().getName());
-        assertEquals("TestAccessPolicyConf", waClientApp.getAccessPolicyConf().getName());
-        assertEquals("MyDefaultAttrReleasePolicyConf", waClientApp.getAttrReleasePolicyConf().getName());
         assertTrue(waClientApp.getReleaseAttrs().isEmpty());
 
         // add items to the authentication module
@@ -125,13 +118,13 @@ public class WAClientAppITCase extends AbstractITCase {
         waClientApp = waClientAppService.read(oidcrpto.getClientAppId(), null);
         assertNotNull(waClientApp);
         assertFalse(waClientApp.getReleaseAttrs().isEmpty());
-        assertEquals("uid", waClientApp.getReleaseAttrs().get("username"));
-        assertEquals("cn", waClientApp.getReleaseAttrs().get("fullname"));
+        assertEquals("username", waClientApp.getReleaseAttrs().get("uid"));
+        assertEquals("fullname", waClientApp.getReleaseAttrs().get("cn"));
         removeItems();
     }
 
     private void addItems() {
-        AuthModuleTO authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultLDAPAuthModule");
 
         ItemTO keyMapping = new ItemTO();
         keyMapping.setIntAttrName("uid");
@@ -145,17 +138,17 @@ public class WAClientAppITCase extends AbstractITCase {
 
         authModuleService.update(authModuleTO);
 
-        authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        authModuleTO = authModuleService.read("DefaultLDAPAuthModule");
         assertFalse(authModuleTO.getItems().isEmpty());
     }
 
     private void removeItems() {
-        AuthModuleTO authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        AuthModuleTO authModuleTO = authModuleService.read("DefaultLDAPAuthModule");
         authModuleTO.getItems().clear();
 
         authModuleService.update(authModuleTO);
 
-        authModuleTO = authModuleService.read("be456831-593d-4003-b273-4c3fb61700df");
+        authModuleTO = authModuleService.read("DefaultLDAPAuthModule");
         assertTrue(authModuleTO.getItems().isEmpty());
     }
 }
diff --git a/fit/core-reference/src/main/resources/logic.properties b/fit/core-reference/src/test/resources/logic.properties
similarity index 100%
rename from fit/core-reference/src/main/resources/logic.properties
rename to fit/core-reference/src/test/resources/logic.properties
diff --git a/fit/wa-reference/pom.xml b/fit/wa-reference/pom.xml
index 5161b92..b609cbd 100644
--- a/fit/wa-reference/pom.xml
+++ b/fit/wa-reference/pom.xml
@@ -56,6 +56,12 @@ under the License.
 
     <!-- TEST -->
     <dependency>
+      <groupId>org.apache.syncope</groupId>
+      <artifactId>syncope-sra</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>com.h2database</groupId>
       <artifactId>h2</artifactId>
       <scope>test</scope>
@@ -89,6 +95,11 @@ under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.awaitility</groupId>
+      <artifactId>awaitility</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
@@ -122,7 +133,7 @@ under the License.
           <configuration>
             <properties>
               <cargo.jvmargs>
-                -Dspring.profiles.active=embedded
+                -Dspring.profiles.active=embedded 
                 -XX:+CMSClassUnloadingEnabled -Xmx1024m -Xms512m</cargo.jvmargs>
             </properties>
           </configuration>
@@ -136,25 +147,31 @@ under the License.
               </properties>
             </deployable>
             <deployable>
-              <location>${basedir}/../core-reference/target/syncope-fit-core-reference-${project.version}</location>
+              <groupId>org.apache.syncope.fit</groupId>
+              <artifactId>syncope-fit-core-reference</artifactId>
+              <type>war</type>
               <pingURL>http://localhost:${cargo.servlet.port}/syncope/index.html</pingURL>
               <pingTimeout>${cargo.deployable.ping.timeout}</pingTimeout>
               <properties>
                 <context>syncope</context>
               </properties>
             </deployable>
-<!--            <deployable>-->
-<!--              <location>${basedir}/../console-reference/target/syncope-fit-console-reference-${project.version}</location>-->
-<!--              <properties>-->
-<!--                <context>syncope-console</context>-->
-<!--              </properties>-->
-<!--            </deployable>-->
-<!--            <deployable>-->
-<!--              <location>${basedir}/../enduser-reference/target/syncope-fit-enduser-reference-${project.version}</location>-->
-<!--              <properties>-->
-<!--                <context>syncope-enduser</context>-->
-<!--              </properties>-->
-<!--            </deployable>-->
+            <deployable>
+              <groupId>org.apache.syncope.fit</groupId>
+              <artifactId>syncope-fit-console-reference</artifactId>
+              <type>war</type>
+              <properties>
+                <context>syncope-console</context>
+              </properties>
+            </deployable>
+            <deployable>
+              <groupId>org.apache.syncope.fit</groupId>
+              <artifactId>syncope-fit-enduser-reference</artifactId>
+              <type>war</type>
+              <properties>
+                <context>syncope-enduser</context>
+              </properties>
+            </deployable>
             <deployable>
               <location>${project.build.directory}/${project.build.finalName}</location>
               <properties>
@@ -163,10 +180,51 @@ under the License.
             </deployable>
           </deployables>
         </configuration>
+        <executions>
+          <execution>
+            <id>start-container</id>
+            <phase>pre-integration-test</phase>
+            <goals>
+              <goal>start</goal>
+            </goals>
+            <configuration>
+              <skip>${skipTests}</skip>
+            </configuration>
+          </execution>
+          <execution>
+            <id>stop-container</id>
+            <phase>post-integration-test</phase>
+            <goals>
+              <goal>stop</goal>
+            </goals>
+            <configuration>
+              <skip>${skipTests}</skip>
+            </configuration>
+          </execution>
+        </executions>
       </plugin>
       
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <inherited>true</inherited>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <inherited>true</inherited>
+        <executions>
+          <execution>
+            <id>verify</id>
+            <goals>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <configuration>
           <resourceIncludes>src/main/resources/**/*.properties</resourceIncludes>
diff --git a/fit/wa-reference/src/main/resources/log4j2.xml b/fit/wa-reference/src/main/resources/log4j2.xml
index e184c60..45979c0 100644
--- a/fit/wa-reference/src/main/resources/log4j2.xml
+++ b/fit/wa-reference/src/main/resources/log4j2.xml
@@ -44,6 +44,10 @@ under the License.
       <appender-ref ref="main"/>
     </asyncLogger>
 
+    <asyncLogger name="org.pac4j" additivity="false" level="ERROR">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+
     <asyncLogger name="org.springframework" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
diff --git a/fit/wa-reference/src/main/resources/wa.properties b/fit/wa-reference/src/main/resources/wa.properties
index c00cea1..fc6e2ca 100644
--- a/fit/wa-reference/src/main/resources/wa.properties
+++ b/fit/wa-reference/src/main/resources/wa.properties
@@ -22,18 +22,20 @@ useGZIPCompression=true
 # Conf directories
 conf.directory=${conf.directory}
 cas.standalone.configurationDirectory=${conf.directory}
-cas.authn.oidc.jwks.jwks-file=file:${conf.directory}/oidc.keystore
 
 cas.server.name=http://localhost:9080
 cas.server.prefix=${cas.server.name}/syncope-wa
 cas.server.scope=syncope.org
+cas.authn.syncope.url=http://localhost:9080/syncope/rest/
+
+cas.tgc.secure=false
+cas.logout.follow-service-redirects=true
 
 cas.authn.saml-idp.entity-id=https://syncope.apache.org/saml
 
 cas.authn.oidc.issuer=http://localhost:9080/syncope-wa/oidc/
-
-cas.authn.syncope.url=http://localhost:9080/syncope
-cas.tgc.secure=false
+cas.authn.oidc.id-token-signing-alg-values-supported=RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512,HS256,HS384,HS512
+cas.authn.oidc.user-info-signing-alg-values-supported=RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512,HS256,HS384,HS512
 
 # Disable access to the login endpoint
 # if no target application is specified.
diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractITCase.java
new file mode 100644
index 0000000..3a76fee
--- /dev/null
+++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractITCase.java
@@ -0,0 +1,319 @@
+/*
+ * 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.fit.sra;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.auth.SyncopeAuthModuleConf;
+import org.apache.syncope.common.lib.policy.AuthPolicyTO;
+import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
+import org.apache.syncope.common.lib.to.AuthModuleTO;
+import org.apache.syncope.common.lib.to.SRARouteTO;
+import org.apache.syncope.common.lib.to.client.OIDCRPTO;
+import org.apache.syncope.common.lib.types.ClientAppType;
+import org.apache.syncope.common.lib.types.OIDCSubjectType;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.common.lib.types.SRARouteFilter;
+import org.apache.syncope.common.lib.types.SRARouteFilterFactory;
+import org.apache.syncope.common.lib.types.SRARoutePredicate;
+import org.apache.syncope.common.lib.types.SRARoutePredicateFactory;
+import org.apache.syncope.common.lib.types.SRARouteType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AuthModuleService;
+import org.apache.syncope.common.rest.api.service.ClientAppService;
+import org.apache.syncope.common.rest.api.service.PolicyService;
+import org.apache.syncope.common.rest.api.service.SRARouteService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2IdPMetadataService;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractITCase {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(AbstractITCase.class);
+
+    protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    protected static final String EN_LANGUAGE = "en-US,en;q=0.5";
+
+    protected static final int PORT = 8080;
+
+    protected static final String ADMIN_UNAME = "admin";
+
+    protected static final String ADMIN_PWD = "password";
+
+    protected static final String CORE_ADDRESS = "http://localhost:9080/syncope/rest";
+
+    protected static final String WA_ADDRESS = "http://localhost:9080/syncope-wa";
+
+    protected static final String SRA_ADDRESS = "http://localhost:" + PORT;
+
+    protected static final String LOGGED_OUT_HEADER = "X-LOGGED-OUT";
+
+    protected static SyncopeClientFactoryBean clientFactory;
+
+    protected static SyncopeClient adminClient;
+
+    protected static AuthModuleService authModuleService;
+
+    protected static PolicyService policyService;
+
+    protected static ClientAppService clientAppService;
+
+    protected static SRARouteService sraRouteService;
+
+    private static Process SRA;
+
+    @BeforeAll
+    public static void restSetup() {
+        clientFactory = new SyncopeClientFactoryBean().setAddress(CORE_ADDRESS);
+        adminClient = clientFactory.create(ADMIN_UNAME, ADMIN_PWD);
+
+        authModuleService = adminClient.getService(AuthModuleService.class);
+        policyService = adminClient.getService(PolicyService.class);
+        clientAppService = adminClient.getService(ClientAppService.class);
+        sraRouteService = adminClient.getService(SRARouteService.class);
+
+    }
+
+    @BeforeAll
+    public static void waitForWARefresh() {
+        WASAML2IdPMetadataService samlIdPMetadataService = adminClient.getService(WASAML2IdPMetadataService.class);
+
+        await().atMost(50, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> {
+            boolean refreshed = false;
+            try {
+                samlIdPMetadataService.getByOwner("Syncope");
+                refreshed = true;
+            } catch (Exception e) {
+                // ignore
+            }
+            return refreshed;
+        });
+    }
+
+    @BeforeAll
+    public static void sraRouteSetup() {
+        sraRouteService.list().forEach(route -> sraRouteService.delete(route.getKey()));
+
+        SRARouteTO publicRoute = new SRARouteTO();
+        publicRoute.setName("public");
+        publicRoute.setTarget(URI.create("http://httpbin.org:80"));
+        publicRoute.setType(SRARouteType.PUBLIC);
+        publicRoute.setCsrf(false);
+        publicRoute.getPredicates().add(new SRARoutePredicate.Builder().
+                factory(SRARoutePredicateFactory.PATH).args("/public/{segment}").build());
+        publicRoute.getFilters().add(new SRARouteFilter.Builder().
+                factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
+
+        Response response = sraRouteService.create(publicRoute);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            fail("Could not create public SRA Route");
+        }
+
+        SRARouteTO protectedRoute = new SRARouteTO();
+        protectedRoute.setName("protected");
+        protectedRoute.setTarget(URI.create("http://httpbin.org:80"));
+        protectedRoute.setType(SRARouteType.PROTECTED);
+        protectedRoute.setCsrf(false);
+        protectedRoute.getPredicates().add(new SRARoutePredicate.Builder().
+                factory(SRARoutePredicateFactory.PATH).args("/protected/{segment}").build());
+        protectedRoute.getFilters().add(new SRARouteFilter.Builder().
+                factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
+
+        response = sraRouteService.create(protectedRoute);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            fail("Could not create protected SRA Route");
+        }
+
+        SRARouteTO logoutRoute = new SRARouteTO();
+        logoutRoute.setName("logout");
+        logoutRoute.setTarget(URI.create("http://httpbin.org:80"));
+        logoutRoute.setType(SRARouteType.PROTECTED);
+        logoutRoute.setLogout(true);
+        logoutRoute.getPredicates().add(new SRARoutePredicate.Builder().
+                factory(SRARoutePredicateFactory.PATH).args("/protected/logout").build());
+        logoutRoute.setOrder(-1);
+
+        response = sraRouteService.create(logoutRoute);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            fail("Could not create logout SRA Route");
+        }
+
+        SRARouteTO postLogout = new SRARouteTO();
+        postLogout.setName("postLogout");
+        postLogout.setTarget(URI.create("http://httpbin.org:80"));
+        postLogout.setType(SRARouteType.PUBLIC);
+        postLogout.getPredicates().add(new SRARoutePredicate.Builder().
+                factory(SRARoutePredicateFactory.PATH).args("/logout").build());
+        postLogout.getFilters().add(new SRARouteFilter.Builder().
+                factory(SRARouteFilterFactory.SET_STATUS).args("204").build());
+        postLogout.getFilters().add(new SRARouteFilter.Builder().
+                factory(SRARouteFilterFactory.SET_RESPONSE_HEADER).args(LOGGED_OUT_HEADER + ", true").build());
+        postLogout.setOrder(-10);
+
+        response = sraRouteService.create(postLogout);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            fail("Could not create logout SRA Route");
+        }
+    }
+
+    protected static void oidcClientAppSetup(
+            final String appName,
+            final String sraRegistrationId,
+            final Long clientAppId,
+            final String clientId,
+            final String clientSecret) {
+
+        AuthModuleTO syncopeAuthModule = authModuleService.list().stream().
+                filter(module -> module.getConf() instanceof SyncopeAuthModuleConf).
+                findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find Syncope Auth Module"));
+
+        AuthPolicyTO syncopeAuthPolicy = policyService.list(PolicyType.AUTH).stream().
+                map(AuthPolicyTO.class::cast).
+                filter(policy -> policy.getConf() instanceof DefaultAuthPolicyConf
+                && ((DefaultAuthPolicyConf) policy.getConf()).getAuthModules().contains(syncopeAuthModule.getKey())).
+                findFirst().
+                orElseGet(() -> {
+                    DefaultAuthPolicyConf policyConf = new DefaultAuthPolicyConf();
+                    policyConf.getAuthModules().add(syncopeAuthModule.getKey());
+
+                    AuthPolicyTO policy = new AuthPolicyTO();
+                    policy.setDescription("Syncope authentication");
+                    policy.setConf(policyConf);
+
+                    Response response = policyService.create(PolicyType.AUTH, policy);
+                    if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+                        fail("Could not create Syncope Auth Policy");
+                    }
+
+                    return policyService.read(PolicyType.AUTH, response.getHeaderString(RESTHeaders.RESOURCE_KEY));
+                });
+
+        OIDCRPTO clientApp = clientAppService.list(ClientAppType.OIDCRP).stream().
+                filter(app -> appName.equals(app.getName())).
+                map(OIDCRPTO.class::cast).
+                findFirst().
+                orElseGet(() -> {
+                    OIDCRPTO app = new OIDCRPTO();
+                    app.setName(appName);
+                    app.setClientAppId(clientAppId);
+                    app.setClientId(clientId);
+                    app.setClientSecret(clientSecret);
+
+                    Response response = clientAppService.create(ClientAppType.OIDCRP, app);
+                    if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+                        fail("Could not create OIDC Client App");
+                    }
+
+                    return clientAppService.read(
+                            ClientAppType.OIDCRP, response.getHeaderString(RESTHeaders.RESOURCE_KEY));
+                });
+
+        clientApp.setClientId(clientId);
+        clientApp.setClientSecret(clientSecret);
+        clientApp.setSubjectType(OIDCSubjectType.PUBLIC);
+        clientApp.getRedirectUris().add(SRA_ADDRESS + "/login/oauth2/code/" + sraRegistrationId);
+        clientApp.setAuthPolicy(syncopeAuthPolicy.getKey());
+        clientApp.setSignIdToken(true);
+        clientApp.setLogoutUri(SRA_ADDRESS + "/logout");
+
+        clientAppService.update(ClientAppType.OIDCRP, clientApp);
+        clientAppService.pushToWA();
+    }
+
+    protected static void doStartSRA(final String activeProfile)
+            throws IOException, InterruptedException, TimeoutException {
+
+        Properties props = new Properties();
+        try (InputStream propStream = AbstractITCase.class.getResourceAsStream("/test.properties")) {
+            props.load(propStream);
+        } catch (Exception e) {
+            fail("Could not load /test.properties", e);
+        }
+
+        String javaHome = props.getProperty("java.home");
+        assertNotNull(javaHome);
+
+        String sraJar = props.getProperty("sra.jar");
+        assertNotNull(sraJar);
+
+        String keymasterApiJar = props.getProperty("keymaster-api.jar");
+        assertNotNull(keymasterApiJar);
+
+        String keymasterClientJar = props.getProperty("keymaster-client.jar");
+        assertNotNull(keymasterClientJar);
+
+        String targetTestClasses = props.getProperty("targetTestClasses");
+        assertNotNull(targetTestClasses);
+
+        ProcessBuilder processBuilder = new ProcessBuilder(
+                javaHome + "/bin/java",
+                "-Dreactor.netty.http.server.accessLogEnabled=true",
+                "-jar", sraJar);
+        processBuilder.inheritIO();
+
+        Map<String, String> environment = processBuilder.environment();
+        environment.put("LOADER_PATH", targetTestClasses + "," + keymasterApiJar + "," + keymasterClientJar);
+        environment.put("SPRING_PROFILES_ACTIVE", activeProfile);
+
+        SRA = processBuilder.start();
+
+        await().atMost(30, TimeUnit.SECONDS).pollInterval(3, TimeUnit.SECONDS).until(() -> {
+            boolean connected = false;
+            try (Socket socket = new Socket()) {
+                socket.connect(new InetSocketAddress("0.0.0.0", PORT));
+                connected = socket.isConnected();
+            } catch (ConnectException e) {
+                // ignore
+            }
+            return connected;
+        });
+        assertTrue(WebClient.create(SRA_ADDRESS).get().getStatus() < 400);
+
+        sraRouteService.pushToSRA();
+    }
+
+    @AfterAll
+    public static void stopSRA() throws InterruptedException {
+        if (SRA != null) {
+            SRA.destroy();
+            SRA.waitFor();
+        }
+    }
+}
diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
new file mode 100644
index 0000000..a1288a4
--- /dev/null
+++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
@@ -0,0 +1,80 @@
+/*
+ * 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.fit.sra;
+
+import static org.apache.syncope.fit.sra.AbstractITCase.doStartSRA;
+import static org.apache.syncope.fit.sra.AbstractITCase.oidcClientAppSetup;
+import static org.apache.syncope.fit.sra.OIDCSRAITCase.CLIENT_ID;
+import static org.apache.syncope.fit.sra.OIDCSRAITCase.CLIENT_SECRET;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandles;
+import java.text.ParseException;
+import java.util.Properties;
+import java.util.concurrent.TimeoutException;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.junit.jupiter.api.BeforeAll;
+
+public class OAUTH2SRAITCase extends OIDCSRAITCase {
+
+    @BeforeAll
+    public static void startSRA() throws IOException, InterruptedException, TimeoutException {
+        assumeTrue(OAUTH2SRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
+
+        doStartSRA("oauth2");
+    }
+
+    @BeforeAll
+    public static void clientAppSetup() {
+        assumeTrue(OAUTH2SRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
+
+        Properties props = new Properties();
+        try (InputStream propStream = OAUTH2SRAITCase.class.getResourceAsStream("/application-oauth2.properties")) {
+            props.load(propStream);
+        } catch (Exception e) {
+            fail("Could not load /application-oauth2.properties", e);
+        }
+        CLIENT_ID = props.getProperty("am.oauth2.client.id");
+        assertNotNull(CLIENT_ID);
+        CLIENT_SECRET = props.getProperty("am.oauth2.client.secret");
+        assertNotNull(CLIENT_SECRET);
+        TOKEN_URI = props.getProperty("am.oauth2.tokenUri");
+        assertNotNull(TOKEN_URI);
+
+        oidcClientAppSetup(OAUTH2SRAITCase.class.getName(), "OAUTH2", 2L, CLIENT_ID, CLIENT_SECRET);
+    }
+
+    @Override
+    protected void checkLogout(final CloseableHttpResponse response) {
+        assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatusLine().getStatusCode());
+    }
+
+    @Override
+    protected void checkIdToken(final JsonNode json) throws ParseException {
+        assertFalse(json.has("id_token"));
+    }
+}
diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
new file mode 100644
index 0000000..079a13b
--- /dev/null
+++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
@@ -0,0 +1,294 @@
+/*
+ * 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.fit.sra;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandles;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.http.Consts;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class OIDCSRAITCase extends AbstractITCase {
+
+    protected static String CLIENT_ID;
+
+    protected static String CLIENT_SECRET;
+
+    protected static String TOKEN_URI;
+
+    @BeforeAll
+    public static void startSRA() throws IOException, InterruptedException, TimeoutException {
+        assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
+
+        doStartSRA("oidc");
+    }
+
+    @BeforeAll
+    public static void clientAppSetup() {
+        assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
+
+        Properties props = new Properties();
+        try (InputStream propStream = OIDCSRAITCase.class.getResourceAsStream("/application-oidc.properties")) {
+            props.load(propStream);
+        } catch (Exception e) {
+            fail("Could not load /application-oidc.properties", e);
+        }
+        CLIENT_ID = props.getProperty("am.oidc.client.id");
+        assertNotNull(CLIENT_ID);
+        CLIENT_SECRET = props.getProperty("am.oidc.client.secret");
+        assertNotNull(CLIENT_SECRET);
+        TOKEN_URI = WA_ADDRESS + "/oidc/accessToken";
+
+        oidcClientAppSetup(OIDCSRAITCase.class.getName(), "OIDC", 1L, CLIENT_ID, CLIENT_SECRET);
+    }
+
+    private ObjectNode checkResponse(final CloseableHttpResponse response, final String originalRequestURI)
+            throws IOException {
+
+        assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+
+        assertEquals(MediaType.APPLICATION_JSON, response.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+
+        JsonNode json = OBJECT_MAPPER.readTree(EntityUtils.toString(response.getEntity()));
+
+        ObjectNode args = (ObjectNode) json.get("args");
+        assertEquals("value1", args.get("key1").asText());
+
+        ArrayNode key2 = (ArrayNode) args.get("key2");
+        assertEquals("value2", key2.get(0).asText());
+        assertEquals("value3", key2.get(1).asText());
+
+        ObjectNode headers = (ObjectNode) json.get("headers");
+        assertEquals(MediaType.TEXT_HTML, headers.get(HttpHeaders.ACCEPT).asText());
+        assertEquals(EN_LANGUAGE, headers.get(HttpHeaders.ACCEPT_LANGUAGE).asText());
+        assertEquals("localhost:" + PORT, headers.get("X-Forwarded-Host").asText());
+
+        assertEquals(originalRequestURI, json.get("url").asText());
+
+        return headers;
+    }
+
+    protected void checkLogout(final CloseableHttpResponse response) {
+        assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
+        assertEquals("true", response.getFirstHeader(LOGGED_OUT_HEADER).getValue());
+    }
+
+    @Test
+    public void web() throws IOException {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        HttpClientContext context = HttpClientContext.create();
+        context.setCookieStore(new BasicCookieStore());
+
+        // 1. public
+        HttpGet get = new HttpGet(SRA_ADDRESS + "/public/get?key1=value1&key2=value2&key2=value3");
+        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        CloseableHttpResponse response = httpclient.execute(get, context);
+
+        ObjectNode headers = checkResponse(response, get.getURI().toASCIIString().replace("/public", ""));
+        assertFalse(headers.has(HttpHeaders.COOKIE));
+
+        // 2. protected
+        get = new HttpGet(SRA_ADDRESS + "/protected/get?key1=value1&key2=value2&key2=value3");
+        String originalRequestURI = get.getURI().toASCIIString();
+        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        response = httpclient.execute(get, context);
+        assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+
+        // 2a. redirected to WA login screen
+        String responseBody = EntityUtils.toString(response.getEntity());
+        int begin = responseBody.indexOf("name=\"execution\" value=\"");
+        assertNotEquals(-1, begin);
+        int end = responseBody.indexOf("\"/><input type=\"hidden\" name=\"_eventId\"");
+        assertNotEquals(-1, end);
+
+        String execution = responseBody.substring(begin + 24, end);
+        assertNotNull(execution);
+
+        List<NameValuePair> form = new ArrayList<>();
+        form.add(new BasicNameValuePair("_eventId", "submit"));
+        form.add(new BasicNameValuePair("execution", execution));
+        form.add(new BasicNameValuePair("username", "bellini"));
+        form.add(new BasicNameValuePair("password", "password"));
+        form.add(new BasicNameValuePair("geolocation", ""));
+
+        HttpPost post = new HttpPost(WA_ADDRESS + "/login");
+        post.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+        post.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        post.setEntity(new UrlEncodedFormEntity(form, Consts.UTF_8));
+        response = httpclient.execute(post, context);
+
+        // 2b. WA attribute consent screen
+        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+            responseBody = EntityUtils.toString(response.getEntity());
+            begin = responseBody.indexOf("name=\"execution\" value=\"");
+            assertNotEquals(-1, begin);
+            end = responseBody.indexOf("\"/><input type=\"hidden\" name=\"_eventId\"");
+            assertNotEquals(-1, end);
+
+            execution = responseBody.substring(begin + 24, end);
+            assertNotNull(execution);
+
+            form = new ArrayList<>();
+            form.add(new BasicNameValuePair("_eventId", "confirm"));
+            form.add(new BasicNameValuePair("execution", execution));
+            form.add(new BasicNameValuePair("option", "1"));
+            form.add(new BasicNameValuePair("reminder", "30"));
+            form.add(new BasicNameValuePair("reminderTimeUnit", "days"));
+
+            post = new HttpPost(WA_ADDRESS + "/login");
+            post.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+            post.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+            post.setEntity(new UrlEncodedFormEntity(form, Consts.UTF_8));
+            response = httpclient.execute(post, context);
+        }
+        assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusLine().getStatusCode());
+
+        // 2c. WA scope consent screen
+        get = new HttpGet(response.getLastHeader(HttpHeaders.LOCATION).getValue());
+        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        response = httpclient.execute(get, context);
+        assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+
+        responseBody = EntityUtils.toString(response.getEntity());
+
+        begin = responseBody.indexOf("name=\"allow\"");
+        assertNotEquals(-1, begin);
+        begin = responseBody.indexOf("href=\"", begin);
+        assertNotEquals(-1, begin);
+        end = responseBody.indexOf("\">", begin);
+        assertNotEquals(-1, end);
+
+        String allow = responseBody.substring(begin + 6, end).replace("&amp;", "&");
+        assertNotNull(allow);
+
+        // 2d. finally get requested content
+        get = new HttpGet(allow);
+        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
+        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        response = httpclient.execute(get, context);
+
+        headers = checkResponse(response, originalRequestURI.replace("/protected", ""));
+        assertTrue(headers.get(HttpHeaders.COOKIE).asText().contains("pac4jCsrfToken"));
+
+        // 3. logout
+        get = new HttpGet(SRA_ADDRESS + "/protected/logout");
+        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
+        response = httpclient.execute(get, context);
+        checkLogout(response);
+    }
+
+    protected void checkIdToken(final JsonNode json) throws ParseException {
+        SignedJWT idToken = SignedJWT.parse(json.get("id_token").asText());
+        assertNotNull(idToken);
+        JWTClaimsSet idTokenClaimsSet = idToken.getJWTClaimsSet();
+        assertEquals("verdi", idTokenClaimsSet.getStringClaim("preferred_username"));
+        assertEquals("verdi@syncope.org", idTokenClaimsSet.getStringClaim("email"));
+        assertEquals("Verdi", idTokenClaimsSet.getStringClaim("family_name"));
+        assertEquals("Giuseppe", idTokenClaimsSet.getStringClaim("given_name"));
+        assertEquals("Giuseppe Verdi", idTokenClaimsSet.getStringClaim("name"));
+        assertEquals(Set.of("root", "child", "citizen"), Set.of(idTokenClaimsSet.getStringArrayClaim("groups")));
+    }
+
+    @Test
+    public void rest() throws IOException, ParseException {
+        // 0. access public route
+        WebClient client = WebClient.create(SRA_ADDRESS + "/public/post").
+                accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
+        Response response = client.post(null);
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        // 1. obtain id and access tokens
+        Form form = new Form().
+                param("grant_type", "password").
+                param("client_id", CLIENT_ID).
+                param("client_secret", CLIENT_SECRET).
+                param("username", "verdi").
+                param("password", "password").
+                param("scope", "openid profile email address phone offline_access syncope");
+        response = WebClient.create(TOKEN_URI).post(form);
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertTrue(response.getHeaderString(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
+
+        JsonNode json = OBJECT_MAPPER.readTree(response.readEntity(String.class));
+
+        // 1a. verify id_token
+        checkIdToken(json);
+
+        // 1b. take access_token
+        String accessToken = json.get("access_token").asText();
+        assertNotNull(accessToken);
+
+        // 2. access protected route
+        client = WebClient.create(SRA_ADDRESS + "/protected/post").
+                authorization("Bearer " + accessToken).
+                accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
+        response = client.post(null);
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+
+        json = OBJECT_MAPPER.readTree(response.readEntity(String.class));
+
+        ObjectNode headers = (ObjectNode) json.get("headers");
+        assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.ACCEPT).asText());
+        assertEquals(MediaType.APPLICATION_JSON, headers.get(HttpHeaders.CONTENT_TYPE).asText());
+        assertEquals("localhost:" + PORT, headers.get("X-Forwarded-Host").asText());
+
+        assertEquals(client.getBaseURI().toASCIIString().replace("/protected", ""), json.get("url").asText());
+    }
+}
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/fit/wa-reference/src/test/resources/application-oauth2.properties
similarity index 61%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to fit/wa-reference/src/test/resources/application-oauth2.properties
index 033fe3b..eb8df47 100644
--- a/wa/starter/src/test/resources/dev/keymaster.properties
+++ b/fit/wa-reference/src/test/resources/application-oauth2.properties
@@ -14,6 +14,15 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-keymaster.address=http://localhost:9080/syncope/rest/keymaster
-keymaster.username=${anonymousUser}
-keymaster.password=${anonymousKey}
+am.type=OAUTH2
+am.oauth2.tokenUri=http://localhost:9080/syncope-wa/oauth2.0/accessToken
+am.oauth2.authorizationUri=http://localhost:9080/syncope-wa/oauth2.0/authorize
+am.oauth2.userInfoUri=http://localhost:9080/syncope-wa/oauth2.0/profile
+am.oauth2.userNameAttributeName=id
+am.oauth2.scopes=
+am.oauth2.jwkSetUri=
+am.oauth2.issuer=http://localhost:9080/syncope-wa
+am.oauth2.client.id=oauth2TestClientId
+am.oauth2.client.secret=oauth2TestClientSecret
+
+global.postLogout=http://localhost:8080/logout
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/fit/wa-reference/src/test/resources/application-oidc.properties
similarity index 79%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to fit/wa-reference/src/test/resources/application-oidc.properties
index 033fe3b..44bac5c 100644
--- a/wa/starter/src/test/resources/dev/keymaster.properties
+++ b/fit/wa-reference/src/test/resources/application-oidc.properties
@@ -14,6 +14,9 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-keymaster.address=http://localhost:9080/syncope/rest/keymaster
-keymaster.username=${anonymousUser}
-keymaster.password=${anonymousKey}
+am.type=OIDC
+am.oidc.configuration=http://localhost:9080/syncope-wa/oidc/
+am.oidc.client.id=oidcTestClientId
+am.oidc.client.secret=oidcTestClientSecret
+
+global.postLogout=http://localhost:8080/logout
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/fit/wa-reference/src/test/resources/keymaster.properties
similarity index 100%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to fit/wa-reference/src/test/resources/keymaster.properties
diff --git a/fit/wa-reference/src/main/resources/log4j2.xml b/fit/wa-reference/src/test/resources/log4j2.xml
similarity index 70%
copy from fit/wa-reference/src/main/resources/log4j2.xml
copy to fit/wa-reference/src/test/resources/log4j2.xml
index e184c60..0d20b7e 100644
--- a/fit/wa-reference/src/main/resources/log4j2.xml
+++ b/fit/wa-reference/src/test/resources/log4j2.xml
@@ -17,12 +17,10 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<configuration status="WARN">
-
+<configuration status="WARN" shutdownHook="disable">
   <appenders>
-
-    <RollingRandomAccessFile name="main" fileName="${log.directory}/wa.log"
-                             filePattern="${log.directory}/wa-%d{yyyy-MM-dd}.log.gz"
+    <RollingRandomAccessFile name="main" fileName="${log.directory}/wa-fit.log"
+                             filePattern="${log.directory}/wa-fit-%d{yyyy-MM-dd}.log.gz"
                              immediateFlush="false" append="true">
       <PatternLayout>
         <pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
@@ -32,37 +30,41 @@ under the License.
         <SizeBasedTriggeringPolicy size="250 MB"/>
       </Policies>
     </RollingRandomAccessFile>
-
   </appenders>
 
   <loggers>
-
-    <asyncLogger name="org.apereo.cas" additivity="false" level="INFO">
+    <asyncLogger name="org.apache.syncope.fit" additivity="false" level="DEBUG">
       <appender-ref ref="main"/>
     </asyncLogger>
-    <asyncLogger name="org.apereo.inspektr.audit.support" additivity="false" level="INFO">
+    
+    <asyncLogger name="org.springframework" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <asyncLogger name="org.springframework" additivity="false" level="INFO">
+    <asyncLogger name="org.apache.cxf" additivity="false" level="ERROR">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <asyncLogger name="org.apache.syncope.client.lib" additivity="false" level="OFF">
+    <asyncLogger name="org.apache.http" additivity="false" level="DEBUG">
       <appender-ref ref="main"/>
     </asyncLogger>
-    <asyncLogger name="org.apache.syncope.wa" additivity="false" level="INFO">
+
+    <asyncLogger name="io.netty" additivity="false" level="ERROR">
       <appender-ref ref="main"/>
     </asyncLogger>
-
-    <asyncLogger name="org.apache.cxf" additivity="false" level="ERROR">
+    <asyncLogger name="reactor.netty" additivity="false" level="ERROR">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+    <asyncLogger name="reactor.netty.http.server.AccessLog" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <root level="INFO">
+    <asyncLogger name="org.hibernate.validator" additivity="false" level="ERROR">
       <appender-ref ref="main"/>
+    </asyncLogger>
+
+    <root level="DEBUG">
+      <appenderRef ref="main"/>
     </root>
-  
   </loggers>
-  
 </configuration>
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/fit/wa-reference/src/test/resources/test.properties
similarity index 56%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to fit/wa-reference/src/test/resources/test.properties
index 033fe3b..44f0b1a 100644
--- a/wa/starter/src/test/resources/dev/keymaster.properties
+++ b/fit/wa-reference/src/test/resources/test.properties
@@ -14,6 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-keymaster.address=http://localhost:9080/syncope/rest/keymaster
-keymaster.username=${anonymousUser}
-keymaster.password=${anonymousKey}
+java.home=${java.home}
+sra.jar=${settings.localRepository}/org/apache/syncope/syncope-sra/${project.version}/syncope-sra-${project.version}.jar
+keymaster-api.jar=${settings.localRepository}/org/apache/syncope/ext/self-keymaster/syncope-ext-self-keymaster-rest-api/${project.version}/syncope-ext-self-keymaster-rest-api-${project.version}.jar
+keymaster-client.jar=${settings.localRepository}/org/apache/syncope/ext/self-keymaster/syncope-ext-self-keymaster-client/${project.version}/syncope-ext-self-keymaster-client-${project.version}.jar
+targetTestClasses=${project.build.testOutputDirectory}
diff --git a/pom.xml b/pom.xml
index fd0447e..dff2679 100644
--- a/pom.xml
+++ b/pom.xml
@@ -479,7 +479,7 @@ under the License.
 
     <antlr4.version>4.8-1</antlr4.version>
 
-    <curator.version>5.0.0</curator.version>
+    <curator.version>5.1.0</curator.version>
     <zookeeper.version>3.6.1</zookeeper.version>
 
     <testds.port>1389</testds.port>
diff --git a/sra/pom.xml b/sra/pom.xml
index 924baa5..ec6e970 100644
--- a/sra/pom.xml
+++ b/sra/pom.xml
@@ -72,6 +72,10 @@ under the License.
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-oauth2-client</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
+    </dependency>
 
     <dependency> 
       <groupId>org.springframework.session</groupId> 
@@ -176,8 +180,26 @@ under the License.
           </systemPropertyVariables>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <configuration>
+          <layout>ZIP</layout>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.outputDirectory}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
-    
+
     <resources>
       <resource>
         <directory>src/main/resources</directory>
@@ -218,118 +240,44 @@ under the License.
       <id>debug</id>
 
       <properties>
-        <skipTests>true</skipTests>
+        <maven.test.skip>true</maven.test.skip>
       </properties>
 
       <dependencies>
         <dependency>
-          <groupId>org.apache.syncope.common.keymaster</groupId>
-          <artifactId>syncope-common-keymaster-client-zookeeper</artifactId>
+          <groupId>org.apache.syncope.ext.self-keymaster</groupId>
+          <artifactId>syncope-ext-self-keymaster-client</artifactId>
           <version>${project.version}</version>
-          <scope>compile</scope>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-test</artifactId>
-          <scope>compile</scope>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.cxf</groupId>
-          <artifactId>cxf-rt-transports-http-netty-server</artifactId>
-          <scope>compile</scope>
-        </dependency>
-
-        <dependency>
-          <groupId>org.springframework.boot</groupId>
-          <artifactId>spring-boot-devtools</artifactId>
         </dependency>
       </dependencies>
 
       <build>
-        <defaultGoal>clean package io.fabric8:docker-maven-plugin:start spring-boot:run</defaultGoal>
+        <defaultGoal>clean spring-boot:run</defaultGoal>
 
         <plugins>
           <plugin>
-            <groupId>io.fabric8</groupId>
-            <artifactId>docker-maven-plugin</artifactId>
-            <configuration>
-              <images>
-                <image>
-                  <name>zookeeper:${zookeeper.version}</name>
-                  <run>
-                    <ports>
-                      <port>2181:2181</port>
-                    </ports>
-                    <volumes>
-                      <bind>
-                        <volume>${project.build.testOutputDirectory}/zoo.cfg:/conf/zoo.cfg</volume>
-                        <volume>${project.build.testOutputDirectory}/java.env:/conf/java.env</volume>
-                        <volume>${project.build.testOutputDirectory}/server-jaas.conf:/conf/server-jaas.conf</volume>
-                        <volume>${project.build.testOutputDirectory}/client-jaas.conf:/conf/client-jaas.conf</volume>
-                      </bind>
-                    </volumes>
-                  </run>
-                </image>
-              </images>
-            </configuration>
-          </plugin>
-
-          <plugin>
-            <groupId>org.codehaus.mojo</groupId>
-            <artifactId>build-helper-maven-plugin</artifactId>
-            <executions>
-              <execution>
-                <goals>
-                  <goal>add-source</goal>
-                </goals>
-                <configuration>
-                  <sources>
-                    <source>${basedir}/src/test/java</source>
-                  </sources>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <excludes>
-                <exclude>**/org/apache/syncope/sra/**Test.java</exclude>
-                <exclude>**/org/apache/syncope/sra/**Zookeeper*.java</exclude>
-              </excludes>
-            </configuration>
-          </plugin>
-
-          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
             <configuration>
-              <mainClass>org.apache.syncope.sra.SyncopeSRAApplication</mainClass>
               <systemPropertyVariables>
                 <reactor.netty.http.server.accessLogEnabled>true</reactor.netty.http.server.accessLogEnabled>
               </systemPropertyVariables>
               <jvmArguments>
-                -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
+                -Xdebug -Xrunjdwp:transport=dt_socket,address=8002,server=y,suspend=n
               </jvmArguments>
+              <profiles>
+                <profile>debug</profile>
+              </profiles>
             </configuration>
           </plugin>
         </plugins>
         
         <resources>
           <resource>
-            <directory>${basedir}/src/test/resources</directory>
+            <directory>${basedir}/src/test/resources/debug</directory>
             <filtering>true</filtering>
           </resource>
         </resources>
-
-        <testResources>
-          <testResource>
-            <directory>${basedir}/../common/keymaster/client-zookeeper/src/main/resources</directory>
-            <filtering>true</filtering>
-          </testResource>
-        </testResources>
       </build>
     </profile>
 
diff --git a/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java b/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
index bec1f07..e9048be 100644
--- a/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
+++ b/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
@@ -92,6 +92,11 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.unit.DataSize;
 import org.springframework.web.server.ServerWebExchange;
 import org.apache.syncope.common.rest.api.service.SRARouteService;
+import org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory;
+import org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory;
+import org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderGatewayFilterFactory;
+import org.springframework.cloud.gateway.filter.factory.SetRequestHostHeaderGatewayFilterFactory;
+import org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactory;
 
 @Component
 public class RouteProvider {
@@ -145,6 +150,18 @@ public class RouteProvider {
                         setValue(addResponseHeaderArgs[1].trim()));
                 break;
 
+            case DEDUPE_RESPONSE_HEADER:
+                String[] dedupeResponseHeaderArgs = gwfilter.getArgs().split(",");
+                filter = ctx.getBean(DedupeResponseHeaderGatewayFilterFactory.class).
+                        apply(c -> {
+                            c.setName(dedupeResponseHeaderArgs[0].trim());
+                            if (dedupeResponseHeaderArgs.length > 1) {
+                                c.setStrategy(DedupeResponseHeaderGatewayFilterFactory.Strategy.
+                                        valueOf(dedupeResponseHeaderArgs[1].trim()));
+                            }
+                        });
+                break;
+
             case HYSTRIX:
                 String[] hystrixArgs = gwfilter.getArgs().split(",");
                 filter = ctx.getBean(HystrixGatewayFilterFactory.class).
@@ -177,6 +194,13 @@ public class RouteProvider {
                         });
                 break;
 
+            case MAP_REQUEST_HEADER:
+                String[] mapRequestHeaderArgs = gwfilter.getArgs().split(",");
+                filter = ctx.getBean(MapRequestHeaderGatewayFilterFactory.class).
+                        apply(c -> c.setFromHeader(mapRequestHeaderArgs[0].trim()).
+                        setToHeader(mapRequestHeaderArgs[1].trim()));
+                break;
+
             case PREFIX_PATH:
                 filter = ctx.getBean(PrefixPathGatewayFilterFactory.class).
                         apply(c -> c.setPrefix(gwfilter.getArgs().trim()));
@@ -186,7 +210,7 @@ public class RouteProvider {
                 filter = ctx.getBean(PreserveHostHeaderGatewayFilterFactory.class).apply();
                 break;
 
-            case REDIRECT:
+            case REDIRECT_TO:
                 String[] redirectArgs = gwfilter.getArgs().split(",");
                 filter = ctx.getBean(RedirectToGatewayFilterFactory.class).
                         apply(redirectArgs[0].trim(), redirectArgs[1].trim());
@@ -231,11 +255,42 @@ public class RouteProvider {
                         setReplacement(rewritePathArgs[1].trim()));
                 break;
 
+            case REWRITE_LOCATION:
+                String[] rewriteLocationArgs = gwfilter.getArgs().split(",");
+                filter = ctx.getBean(RewriteLocationResponseHeaderGatewayFilterFactory.class).
+                        apply(c -> {
+                            c.setStripVersion(RewriteLocationResponseHeaderGatewayFilterFactory.StripVersion.
+                                    valueOf(rewriteLocationArgs[0].trim()));
+                            if (rewriteLocationArgs.length > 1) {
+                                c.setLocationHeaderName(rewriteLocationArgs[1].trim());
+                            }
+                            if (rewriteLocationArgs.length > 2) {
+                                c.setHostValue(rewriteLocationArgs[2].trim());
+                            }
+                            if (rewriteLocationArgs.length > 3) {
+                                c.setProtocols(rewriteLocationArgs[3].trim());
+                            }
+                        });
+                break;
+
+            case REWRITE_RESPONSE_HEADER:
+                String[] rewriteResponseHeaderArgs = gwfilter.getArgs().split(",");
+                filter = ctx.getBean(RewriteResponseHeaderGatewayFilterFactory.class).
+                        apply(c -> c.setReplacement(rewriteResponseHeaderArgs[2].trim()).
+                        setRegexp(rewriteResponseHeaderArgs[1].trim()).
+                        setName(rewriteResponseHeaderArgs[0].trim()));
+                break;
+
             case RETRY:
                 filter = ctx.getBean(RetryGatewayFilterFactory.class).
                         apply(c -> c.setRetries(Integer.valueOf(gwfilter.getArgs().trim())));
                 break;
 
+            case SAVE_SESSION:
+                filter = ctx.getBean(SaveSessionGatewayFilterFactory.class).apply(c -> {
+                });
+                break;
+
             case SECURE_HEADERS:
                 filter = ctx.getBean(SecureHeadersGatewayFilterFactory.class).apply(c -> {
                 });
@@ -260,24 +315,11 @@ public class RouteProvider {
                         setValue(setResponseHeaderArgs[1].trim()));
                 break;
 
-            case REWRITE_RESPONSE_HEADER:
-                String[] rewriteResponseHeaderArgs = gwfilter.getArgs().split(",");
-                filter = ctx.getBean(RewriteResponseHeaderGatewayFilterFactory.class).
-                        apply(c -> c.setReplacement(rewriteResponseHeaderArgs[2].trim()).
-                        setRegexp(rewriteResponseHeaderArgs[1].trim()).
-                        setName(rewriteResponseHeaderArgs[0].trim()));
-                break;
-
             case SET_STATUS:
                 filter = ctx.getBean(SetStatusGatewayFilterFactory.class).
                         apply(c -> c.setStatus(gwfilter.getArgs().trim()));
                 break;
 
-            case SAVE_SESSION:
-                filter = ctx.getBean(SaveSessionGatewayFilterFactory.class).apply(c -> {
-                });
-                break;
-
             case STRIP_PREFIX:
                 filter = ctx.getBean(StripPrefixGatewayFilterFactory.class).
                         apply(c -> c.setParts(Integer.valueOf(gwfilter.getArgs().trim())));
@@ -293,6 +335,11 @@ public class RouteProvider {
                         apply(c -> c.setMaxSize(DataSize.ofBytes(Long.valueOf(gwfilter.getArgs().trim()))));
                 break;
 
+            case SET_REQUEST_HOST:
+                filter = ctx.getBean(SetRequestHostHeaderGatewayFilterFactory.class).
+                        apply(c -> c.setHost(gwfilter.getArgs().trim()));
+                break;
+
             case LINK_REWRITE:
                 filter = ApplicationContextUtils.getOrCreateBean(
                         ctx,
@@ -422,6 +469,13 @@ public class RouteProvider {
                         applyAsync(c -> c.setSources(List.of(remoteAddrArgs)));
                 break;
 
+            case WEIGHT:
+                String[] weigthArgs = gwpredicate.getArgs().split(",");
+                predicate = ctx.getBean(WeightRoutePredicateFactory.class).
+                        applyAsync(c -> c.setGroup(weigthArgs[0].trim()).
+                        setWeight(Integer.valueOf(weigthArgs[1].trim())));
+                break;
+
             case CUSTOM:
                 String[] customArgs = gwpredicate.getArgs().split(";");
                 predicate = ApplicationContextUtils.getOrCreateBean(
diff --git a/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
index 159af5a..6347edc 100644
--- a/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
+++ b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
@@ -18,7 +18,11 @@
  */
 package org.apache.syncope.sra;
 
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.Map;
 import java.util.Objects;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
 import org.apache.syncope.sra.security.CsrfRouteMatcher;
 import org.apache.syncope.sra.security.LogoutRouteMatcher;
@@ -26,12 +30,14 @@ import org.apache.syncope.sra.security.OAuth2SecurityConfigUtils;
 import org.apache.syncope.sra.security.PublicRouteMatcher;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.cache.CacheManager;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.annotation.Order;
+import org.springframework.core.convert.converter.Converter;
 import org.springframework.core.env.Environment;
 import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
 import org.springframework.security.config.web.server.ServerHttpSecurity;
@@ -41,11 +47,17 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.client.registration.ClientRegistrations;
 import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
-import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.OAuth2TokenValidator;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtValidators;
+import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter;
+import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
+import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
 import org.springframework.security.web.server.SecurityWebFilterChain;
 import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
 import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
+import reactor.core.publisher.Mono;
 
 @EnableWebFluxSecurity
 @Configuration
@@ -87,7 +99,7 @@ public class SecurityConfig {
 
     @Bean
     @ConditionalOnProperty(name = AM_TYPE, havingValue = "OIDC")
-    public ReactiveClientRegistrationRepository oidcClientRegistrationRepository() {
+    public InMemoryReactiveClientRegistrationRepository oidcClientRegistrationRepository() {
         return new InMemoryReactiveClientRegistrationRepository(
                 ClientRegistrations.fromOidcIssuerLocation(env.getProperty("am.oidc.configuration")).
                         registrationId("OIDC").
@@ -97,8 +109,32 @@ public class SecurityConfig {
     }
 
     @Bean
+    @ConditionalOnMissingBean
+    @ConditionalOnProperty(name = AM_TYPE, havingValue = "OIDC")
+    public OAuth2TokenValidator<Jwt> oidcJWTValidator() {
+        return JwtValidators.createDefaultWithIssuer(env.getProperty("am.oidc.configuration"));
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public Converter<Map<String, Object>, Map<String, Object>> jwtClaimSetConverter() {
+        return MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap());
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    @ConditionalOnProperty(name = AM_TYPE, havingValue = "OIDC")
+    public ReactiveJwtDecoder oidcJWTDecoder() {
+        NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withJwkSetUri(
+                oidcClientRegistrationRepository().iterator().next().getProviderDetails().getJwkSetUri()).build();
+        jwtDecoder.setJwtValidator(oidcJWTValidator());
+        jwtDecoder.setClaimSetConverter(jwtClaimSetConverter());
+        return jwtDecoder;
+    }
+
+    @Bean
     @ConditionalOnProperty(name = AM_TYPE, havingValue = "OAUTH2")
-    public ReactiveClientRegistrationRepository oauth2ClientRegistrationRepository() {
+    public InMemoryReactiveClientRegistrationRepository oauth2ClientRegistrationRepository() {
         return new InMemoryReactiveClientRegistrationRepository(
                 ClientRegistration.withRegistrationId("OAUTH2").
                         redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}").
@@ -109,11 +145,44 @@ public class SecurityConfig {
                         clientId(env.getProperty("am.oauth2.client.id")).
                         clientSecret(env.getProperty("am.oauth2.client.secret")).
                         scope(env.getProperty("am.oauth2.scopes", String[].class)).
-                        authorizationGrantType(new AuthorizationGrantType(env.getProperty("am.oauth2.grantType"))).
+                        authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).
+                        jwkSetUri(env.getProperty("am.oauth2.jwkSetUri")).
                         build());
     }
 
     @Bean
+    @ConditionalOnMissingBean
+    @ConditionalOnProperty(name = AM_TYPE, havingValue = "OAUTH2")
+    public OAuth2TokenValidator<Jwt> oauth2JWTValidator() {
+        String issuer = env.getProperty("am.oauth2.issuer");
+        return issuer == null
+                ? JwtValidators.createDefault()
+                : JwtValidators.createDefaultWithIssuer(env.getProperty("am.oauth2.issuer"));
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    @ConditionalOnProperty(name = AM_TYPE, havingValue = "OAUTH2")
+    public ReactiveJwtDecoder oauth2JWTDecoder() {
+        String jwkSetUri = oauth2ClientRegistrationRepository().iterator().next().getProviderDetails().getJwkSetUri();
+        NimbusReactiveJwtDecoder jwtDecoder;
+        if (StringUtils.isBlank(jwkSetUri)) {
+            jwtDecoder = new NimbusReactiveJwtDecoder(jwt -> {
+                try {
+                    return Mono.just(jwt.getJWTClaimsSet());
+                } catch (ParseException e) {
+                    return Mono.error(e);
+                }
+            });
+        } else {
+            jwtDecoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri).build();
+        }
+        jwtDecoder.setJwtValidator(oauth2JWTValidator());
+        jwtDecoder.setClaimSetConverter(jwtClaimSetConverter());
+        return jwtDecoder;
+    }
+
+    @Bean
     @Order(1)
     @ConditionalOnProperty(name = AM_TYPE)
     public SecurityWebFilterChain routesSecurityFilterChain(
@@ -135,6 +204,7 @@ public class SecurityConfig {
             case OAUTH2:
                 OAuth2SecurityConfigUtils.forLogin(http, amType, ctx);
                 OAuth2SecurityConfigUtils.forLogout(builder, amType, cacheManager, logoutRouteMatcher, ctx);
+                http.oauth2ResourceServer().jwt().jwtDecoder(ctx.getBean(ReactiveJwtDecoder.class));
                 break;
 
             case SAML2:
diff --git a/sra/src/main/java/org/apache/syncope/sra/security/OidcClientInitiatedServerLogoutSuccessHandler.java b/sra/src/main/java/org/apache/syncope/sra/security/OidcClientInitiatedServerLogoutSuccessHandler.java
index 7709727..5ea8498 100644
--- a/sra/src/main/java/org/apache/syncope/sra/security/OidcClientInitiatedServerLogoutSuccessHandler.java
+++ b/sra/src/main/java/org/apache/syncope/sra/security/OidcClientInitiatedServerLogoutSuccessHandler.java
@@ -117,7 +117,8 @@ public class OidcClientInitiatedServerLogoutSuccessHandler
                     uri = route.get().getPostLogout();
                 }
 
-                return CACHE.put(routeId, Optional.ofNullable(uri));
+                CACHE.put(routeId, Optional.ofNullable(uri));
+                return CACHE.get(routeId);
             });
             if (routePostLogout.isPresent()) {
                 postLogout = routePostLogout.get();
diff --git a/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java b/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
index a5c0049..2cdc822 100644
--- a/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
+++ b/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
@@ -376,7 +376,7 @@ public class RouteProviderTest extends AbstractTest {
         route.setKey("redirect");
         route.setTarget(URI.create("http://localhost:" + wiremockPort));
         route.getFilters().add(new SRARouteFilter.Builder().
-                factory(SRARouteFilterFactory.REDIRECT).args("307,http://127.0.0.1:" + wiremockPort).build());
+                factory(SRARouteFilterFactory.REDIRECT_TO).args("307,http://127.0.0.1:" + wiremockPort).build());
 
         SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
         routeRefresher.refresh();
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/sra/src/test/resources/debug/application-debug.properties
similarity index 54%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to sra/src/test/resources/debug/application-debug.properties
index 033fe3b..5958ee8 100644
--- a/wa/starter/src/test/resources/dev/keymaster.properties
+++ b/sra/src/test/resources/debug/application-debug.properties
@@ -14,6 +14,20 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-keymaster.address=http://localhost:9080/syncope/rest/keymaster
-keymaster.username=${anonymousUser}
-keymaster.password=${anonymousKey}
+#am.type=OIDC
+#am.oidc.configuration=http://localhost:9080/syncope-wa/oidc/
+#am.oidc.client.id=oidcTestClientId
+#am.oidc.client.secret=oidcTestClientSecret
+
+am.type=OAUTH2
+am.oauth2.tokenUri=http://localhost:9080/syncope-wa/oauth2.0/accessToken
+am.oauth2.authorizationUri=http://localhost:9080/syncope-wa/oauth2.0/authorize
+am.oauth2.userInfoUri=http://localhost:9080/syncope-wa/oauth2.0/profile
+am.oauth2.userNameAttributeName=id
+am.oauth2.scopes=
+am.oauth2.jwkSetUri=
+am.oauth2.issuer=http://localhost:9080/syncope-wa
+am.oauth2.client.id=oauth2TestClientId
+am.oauth2.client.secret=oauth2TestClientSecret
+
+global.postLogout=http://localhost:8080/logout
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/sra/src/test/resources/debug/keymaster.properties
similarity index 100%
copy from wa/starter/src/test/resources/dev/keymaster.properties
copy to sra/src/test/resources/debug/keymaster.properties
diff --git a/fit/wa-reference/src/main/resources/log4j2.xml b/sra/src/test/resources/debug/log4j2.xml
similarity index 50%
copy from fit/wa-reference/src/main/resources/log4j2.xml
copy to sra/src/test/resources/debug/log4j2.xml
index e184c60..f7ac25d 100644
--- a/fit/wa-reference/src/main/resources/log4j2.xml
+++ b/sra/src/test/resources/debug/log4j2.xml
@@ -19,44 +19,42 @@ under the License.
 -->
 <configuration status="WARN">
 
-  <appenders>
-
-    <RollingRandomAccessFile name="main" fileName="${log.directory}/wa.log"
-                             filePattern="${log.directory}/wa-%d{yyyy-MM-dd}.log.gz"
-                             immediateFlush="false" append="true">
-      <PatternLayout>
-        <pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
-      </PatternLayout>
-      <Policies>
-        <TimeBasedTriggeringPolicy/>
-        <SizeBasedTriggeringPolicy size="250 MB"/>
-      </Policies>
-    </RollingRandomAccessFile>
-
-  </appenders>
-
+  <Properties>
+    <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
+    <Property name="LOG_LEVEL_PATTERN">%5p</Property>
+    <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
+    <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
+    <Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} %pid --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
+  </Properties>
+  <Appenders>
+    <Console name="main" target="SYSTEM_OUT" follow="true">
+      <PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
+    </Console>
+    <Console name="access" target="SYSTEM_OUT" follow="true">
+      <PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" />
+    </Console>
+  </Appenders>
+    
   <loggers>
 
-    <asyncLogger name="org.apereo.cas" additivity="false" level="INFO">
+    <asyncLogger name="org.apache.syncope.client.lib" additivity="false" level="OFF">
       <appender-ref ref="main"/>
     </asyncLogger>
-    <asyncLogger name="org.apereo.inspektr.audit.support" additivity="false" level="INFO">
+    <asyncLogger name="org.apache.syncope.sra" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <asyncLogger name="org.springframework" additivity="false" level="INFO">
+    <asyncLogger name="org.apache.cxf" additivity="false" level="ERROR">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <asyncLogger name="org.apache.syncope.client.lib" additivity="false" level="OFF">
-      <appender-ref ref="main"/>
-    </asyncLogger>
-    <asyncLogger name="org.apache.syncope.wa" additivity="false" level="INFO">
+    <asyncLogger name="org.springframework.cloud.gateway" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
 
-    <asyncLogger name="org.apache.cxf" additivity="false" level="ERROR">
-      <appender-ref ref="main"/>
+    <!-- Requires -Dreactor.netty.http.server.accessLogEnabled=true to work-->
+    <asyncLogger name="reactor.netty.http.server.AccessLog" additivity="false" level="INFO">
+      <appender-ref ref="access"/>
     </asyncLogger>
 
     <root level="INFO">
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
index ad9d115..a005c5a 100644
--- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/SyncopeWAPropertySourceLocator.java
@@ -18,7 +18,10 @@
  */
 package org.apache.syncope.wa.bootstrap;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import org.apereo.cas.configuration.CasConfigurationProperties;
@@ -53,7 +56,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
 import org.springframework.core.annotation.Order;
-import org.springframework.core.env.ConfigurableEnvironment;
 import org.springframework.core.env.Environment;
 import org.springframework.core.env.MapPropertySource;
 import org.springframework.core.env.PropertySource;
@@ -69,46 +71,44 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         this.waRestClient = waRestClient;
     }
 
-    private static void mapSyncopeAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        SyncopeAuthModuleConf conf = SyncopeAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final SyncopeAuthModuleConf conf,
+            final String address) {
 
         SyncopeAuthenticationProperties syncopeProps = new SyncopeAuthenticationProperties();
-        syncopeProps.setName(conf.getName());
+        syncopeProps.setName(authModule);
         syncopeProps.setDomain(conf.getDomain());
-        syncopeProps.setUrl(conf.getUrl());
+        syncopeProps.setUrl(StringUtils.substringBefore(address, "/rest"));
 
         casProperties.getAuthn().setSyncope(syncopeProps);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.syncope.";
     }
 
-    private static void mapStaticAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        StaticAuthModuleConf conf = StaticAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final StaticAuthModuleConf conf) {
 
         AcceptAuthenticationProperties staticProps = new AcceptAuthenticationProperties();
-        staticProps.setName(conf.getName());
+        staticProps.setName(authModule);
         String users = conf.getUsers().entrySet().stream().
                 map(entry -> entry.getKey() + "::" + entry.getValue()).
                 collect(Collectors.joining(","));
         staticProps.setUsers(users);
 
         casProperties.getAuthn().setAccept(staticProps);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.accept.";
     }
 
-    private static void mapLdapAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        LDAPAuthModuleConf conf = LDAPAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final LDAPAuthModuleConf conf) {
 
         LdapAuthenticationProperties ldapProps = new LdapAuthenticationProperties();
-        ldapProps.setName(conf.getName());
+        ldapProps.setName(authModule);
         ldapProps.setBaseDn(conf.getBaseDn());
         ldapProps.setBindCredential(conf.getBindCredential());
         ldapProps.setSearchFilter(conf.getSearchFilter());
@@ -118,17 +118,16 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         ldapProps.setPrincipalAttributeList(conf.getPrincipalAttributeList());
 
         casProperties.getAuthn().getLdap().add(ldapProps);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.ldap.";
     }
 
-    private static void mapGoogleMfaAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        GoogleMfaAuthModuleConf conf = GoogleMfaAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final GoogleMfaAuthModuleConf conf) {
 
         GoogleAuthenticatorMultifactorProperties props = new GoogleAuthenticatorMultifactorProperties();
-        props.setName(conf.getName());
+        props.setName(authModule);
         props.setIssuer(conf.getIssuer());
         props.setCodeDigits(conf.getCodeDigits());
         props.setLabel(conf.getLabel());
@@ -136,34 +135,32 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         props.setWindowSize(conf.getWindowSize());
 
         casProperties.getAuthn().getMfa().setGauth(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.mfa.gauth.";
     }
 
-    private static void mapU2fAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        U2FAuthModuleConf conf = U2FAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final U2FAuthModuleConf conf) {
 
         U2FMultifactorProperties props = new U2FMultifactorProperties();
-        props.setName(conf.getName());
+        props.setName(authModule);
         props.setExpireDevices(conf.getExpireDevices());
         props.setExpireDevicesTimeUnit(TimeUnit.valueOf(conf.getExpireDevicesTimeUnit()));
         props.setExpireRegistrations(conf.getExpireRegistrations());
         props.setExpireRegistrationsTimeUnit(TimeUnit.valueOf(conf.getExpireRegistrationsTimeUnit()));
 
         casProperties.getAuthn().getMfa().setU2f(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.mfa.u2f.";
     }
 
-    private static void mapJaasAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        JaasAuthModuleConf conf = JaasAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final JaasAuthModuleConf conf) {
 
         JaasAuthenticationProperties props = new JaasAuthenticationProperties();
-        props.setName(conf.getName());
+        props.setName(authModule);
         props.setLoginConfigType(conf.getLoginConfigType());
         props.setKerberosKdcSystemProperty(conf.getKerberosKdcSystemProperty());
         props.setKerberosRealmSystemProperty(conf.getKerberosRealmSystemProperty());
@@ -171,17 +168,16 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         props.setRealm(conf.getRealm());
 
         casProperties.getAuthn().getJaas().add(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.jaas.";
     }
 
-    private static void mapJdbcAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        JDBCAuthModuleConf conf = JDBCAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final JDBCAuthModuleConf conf) {
 
         QueryJdbcAuthenticationProperties props = new QueryJdbcAuthenticationProperties();
-        props.setName(conf.getName());
+        props.setName(authModule);
         props.setSql(conf.getSql());
         props.setFieldDisabled(conf.getFieldDisabled());
         props.setFieldExpired(conf.getFieldExpired());
@@ -194,21 +190,20 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         props.setPrincipalAttributeList(conf.getPrincipalAttributeList());
 
         casProperties.getAuthn().getJdbc().getQuery().add(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.jdbc.query.";
     }
 
-    private static void mapOidcAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        OIDCAuthModuleConf conf = OIDCAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final OIDCAuthModuleConf conf) {
 
         Pac4jGenericOidcClientProperties props = new Pac4jGenericOidcClientProperties();
         props.setId(conf.getId());
         props.setCustomParams(conf.getCustomParams());
         props.setDiscoveryUri(conf.getDiscoveryUri());
         props.setMaxClockSkew(conf.getMaxClockSkew());
-        props.setClientName(conf.getName());
+        props.setClientName(authModule);
         props.setPreferredJwsAlgorithm(conf.getPreferredJwsAlgorithm());
         props.setResponseMode(conf.getResponseMode());
         props.setResponseType(conf.getResponseType());
@@ -219,17 +214,16 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         client.setGeneric(props);
 
         casProperties.getAuthn().getPac4j().getOidc().add(client);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.pac4j.oidc.";
     }
 
-    private static void mapRadiusAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        RadiusAuthModuleConf conf = RadiusAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final RadiusAuthModuleConf conf) {
 
         RadiusProperties props = new RadiusProperties();
-        props.setName(conf.getName());
+        props.setName(authModule);
 
         props.getClient().setAccountingPort(conf.getAccountingPort());
         props.getClient().setAuthenticationPort(conf.getAuthenticationPort());
@@ -248,16 +242,16 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         props.getServer().setRetries(conf.getRetries());
 
         casProperties.getAuthn().setRadius(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.radius.";
     }
 
-    private static void mapSaml2IdPAuthModuleConf(
+    private static String mapAuthModule(
             final CasConfigurationProperties casProperties,
-            final AuthModuleConf authConf) {
-
-        SAML2IdPAuthModuleConf conf = SAML2IdPAuthModuleConf.class.cast(authConf);
+            final String authModule,
+            final SAML2IdPAuthModuleConf conf) {
 
         Pac4jSamlClientProperties props = new Pac4jSamlClientProperties();
+        props.setClientName(authModule);
         props.setAcceptedSkew(conf.getAcceptedSkew());
         props.setAssertionConsumerServiceIndex(conf.getAssertionConsumerServiceIndex());
         props.setAttributeConsumingServiceIndex(conf.getAttributeConsumingServiceIndex());
@@ -282,7 +276,7 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
                 : TriStateBoolean.valueOf(conf.getNameIdPolicyAllowCreate().toUpperCase()));
 
         casProperties.getAuthn().getPac4j().getSaml().add(props);
-        LOG.debug("Added {} to WA configuration", conf.getName());
+        return "cas.authn.pac4j.saml.";
     }
 
     @Override
@@ -294,50 +288,48 @@ public class SyncopeWAPropertySourceLocator implements PropertySourceLocator {
         }
 
         LOG.info("Bootstrapping WA configuration");
-        AuthModuleService authService = syncopeClient.getService(AuthModuleService.class);
+
         CasConfigurationProperties casProperties = new CasConfigurationProperties();
-        authService.list().forEach(authModuleTO -> {
+        List<String> filters = new ArrayList<>();
+
+        syncopeClient.getService(AuthModuleService.class).list().forEach(authModuleTO -> {
             AuthModuleConf authConf = authModuleTO.getConf();
-            LOG.debug("Mapping auth module {}:{} as conf {}",
-                    authModuleTO.getKey(), authModuleTO.getName(), authConf.getName());
+            LOG.debug("Mapping auth module {} ", authModuleTO.getKey());
+
             if (authConf instanceof LDAPAuthModuleConf) {
-                mapLdapAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof StaticAuthModuleConf) {
-                mapStaticAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof SyncopeAuthModuleConf) {
-                mapSyncopeAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof GoogleMfaAuthModuleConf) {
-                mapGoogleMfaAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof JaasAuthModuleConf) {
-                mapJaasAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof JDBCAuthModuleConf) {
-                mapJdbcAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof OIDCAuthModuleConf) {
-                mapOidcAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof RadiusAuthModuleConf) {
-                mapRadiusAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof SAML2IdPAuthModuleConf) {
-                mapSaml2IdPAuthModuleConf(casProperties, authConf);
-            }
-            if (authConf instanceof U2FAuthModuleConf) {
-                mapU2fAuthModuleConf(casProperties, authConf);
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (LDAPAuthModuleConf) authConf));
+            } else if (authConf instanceof StaticAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (StaticAuthModuleConf) authConf));
+            } else if (authConf instanceof SyncopeAuthModuleConf) {
+                filters.add(mapAuthModule(
+                        casProperties,
+                        authModuleTO.getKey(),
+                        (SyncopeAuthModuleConf) authConf,
+                        waRestClient.getSyncopeClient().getAddress()));
+            } else if (authConf instanceof GoogleMfaAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (GoogleMfaAuthModuleConf) authConf));
+            } else if (authConf instanceof JaasAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (JaasAuthModuleConf) authConf));
+            } else if (authConf instanceof JDBCAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (JDBCAuthModuleConf) authConf));
+            } else if (authConf instanceof OIDCAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (OIDCAuthModuleConf) authConf));
+            } else if (authConf instanceof RadiusAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (RadiusAuthModuleConf) authConf));
+            } else if (authConf instanceof SAML2IdPAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (SAML2IdPAuthModuleConf) authConf));
+            } else if (authConf instanceof U2FAuthModuleConf) {
+                filters.add(mapAuthModule(casProperties, authModuleTO.getKey(), (U2FAuthModuleConf) authConf));
             }
         });
 
-        Map<String, Object> properties = CasCoreConfigurationUtils.asMap(casProperties.withHolder());
+        Map<String, Object> properties = CasCoreConfigurationUtils.asMap(casProperties.withHolder()).
+                entrySet().stream().
+                filter(entry -> filters.stream().filter(Objects::nonNull).
+                anyMatch(prefix -> entry.getKey().startsWith(prefix))).
+                collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
         LOG.debug("Collected WA properties: {}", properties);
 
-        ConfigurableEnvironment.class.cast(environment).getPropertySources().
-                addLast(new MapPropertySource(getClass().getName(), properties));
-
-        return null;
+        return new MapPropertySource(getClass().getName(), properties);
     }
 }
diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml
index bb361aa..f62cf31 100644
--- a/wa/starter/pom.xml
+++ b/wa/starter/pom.xml
@@ -353,127 +353,6 @@ under the License.
       <id>debug</id>
 
       <properties>
-        <skipTests>true</skipTests>
-      </properties>
-
-      <dependencies>
-        <dependency>
-          <groupId>org.springframework.boot</groupId>
-          <artifactId>spring-boot-starter-undertow</artifactId>
-        </dependency>
-
-        <dependency>
-          <groupId>org.apache.syncope.common.keymaster</groupId>
-          <artifactId>syncope-common-keymaster-client-zookeeper</artifactId>
-          <version>${project.version}</version>
-        </dependency>
-        <dependency>
-          <groupId>org.apache.curator</groupId>
-          <artifactId>curator-test</artifactId>
-          <scope>compile</scope>
-        </dependency>
-
-        <dependency>
-          <groupId>org.springframework.boot</groupId>
-          <artifactId>spring-boot-devtools</artifactId>
-        </dependency>
-      </dependencies>
-
-      <build>
-        <defaultGoal>clean package io.fabric8:docker-maven-plugin:start spring-boot:run</defaultGoal>
-
-        <plugins>
-          <plugin>
-            <groupId>io.fabric8</groupId>
-            <artifactId>docker-maven-plugin</artifactId>
-            <configuration>
-              <images>
-                <image>
-                  <name>zookeeper:${zookeeper.version}</name>
-                  <run>
-                    <ports>
-                      <port>2181:2181</port>
-                    </ports>
-                    <volumes>
-                      <bind>
-                        <volume>${project.build.testOutputDirectory}/zoo.cfg:/conf/zoo.cfg</volume>
-                        <volume>${project.build.testOutputDirectory}/java.env:/conf/java.env</volume>
-                        <volume>${project.build.testOutputDirectory}/server-jaas.conf:/conf/server-jaas.conf</volume>
-                        <volume>${project.build.testOutputDirectory}/client-jaas.conf:/conf/client-jaas.conf</volume>
-                      </bind>
-                    </volumes>
-                  </run>
-                </image>
-              </images>
-            </configuration>
-          </plugin>
-
-          <plugin>
-            <groupId>org.codehaus.mojo</groupId>
-            <artifactId>build-helper-maven-plugin</artifactId>
-            <executions>
-              <execution>
-                <goals>
-                  <goal>add-source</goal>
-                </goals>
-                <configuration>
-                  <sources>
-                    <source>${basedir}/src/test/java</source>
-                  </sources>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <excludes>
-                <exclude>**/org/apache/syncope/wa/starter/**Test.java</exclude>
-                <exclude>**/org/apache/syncope/wa/starter/**Zookeeper*.java</exclude>
-              </excludes>
-            </configuration>
-          </plugin>
-
-          <plugin>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-maven-plugin</artifactId>
-            <configuration>
-              <mainClass>org.apache.syncope.wa.starter.SyncopeWAApplication</mainClass>
-              <jvmArguments>
-                -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
-              </jvmArguments>
-              <profiles>
-                <profile>debug</profile>
-              </profiles>
-            </configuration>
-          </plugin>
-        </plugins>
-
-        <resources>
-          <resource>
-            <directory>${basedir}/src/test/resources</directory>
-            <filtering>true</filtering>
-            <excludes>
-              <exclude>dev/**</exclude>
-            </excludes>
-          </resource>
-        </resources>
-
-        <testResources>
-          <testResource>
-            <directory>${basedir}/../../common/keymaster/client-zookeeper/src/main/resources</directory>
-            <filtering>true</filtering>
-          </testResource>
-        </testResources>
-      </build>
-    </profile>
-
-    <profile>
-      <id>dev</id>
-
-      <properties>
         <maven.test.skip>true</maven.test.skip>
       </properties>
 
@@ -498,12 +377,11 @@ under the License.
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
             <configuration>
-              <mainClass>org.apache.syncope.wa.starter.SyncopeWAApplication</mainClass>
               <jvmArguments>
                 -Xdebug -Xrunjdwp:transport=dt_socket,address=8001,server=y,suspend=n
               </jvmArguments>
               <profiles>
-                <profile>dev</profile>
+                <profile>debug</profile>
               </profiles>
             </configuration>
           </plugin>
@@ -511,7 +389,7 @@ under the License.
 
         <resources>
           <resource>
-            <directory>${basedir}/src/test/resources/dev</directory>
+            <directory>${basedir}/src/test/resources/debug</directory>
             <filtering>true</filtering>
           </resource>
         </resources>
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
index 9f09c50..c53c8fa 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/SyncopeWAConfiguration.java
@@ -18,33 +18,23 @@
  */
 package org.apache.syncope.wa.starter.config;
 
-import org.apereo.cas.adaptors.u2f.storage.U2FDeviceRepository;
-import org.apereo.cas.audit.AuditTrailExecutionPlanConfigurer;
-import org.apereo.cas.configuration.CasConfigurationProperties;
-import org.apereo.cas.configuration.model.support.mfa.u2f.U2FMultifactorProperties;
-import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
-import org.apereo.cas.otp.repository.credentials.OneTimeTokenCredentialRepository;
-import org.apereo.cas.otp.repository.token.OneTimeTokenRepository;
-import org.apereo.cas.services.ServiceRegistryExecutionPlanConfigurer;
-import org.apereo.cas.services.ServiceRegistryListener;
-import org.apereo.cas.support.pac4j.authentication.DelegatedClientFactoryCustomizer;
-import org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGenerator;
-import org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGeneratorConfigurationContext;
-import org.apereo.cas.support.saml.idp.metadata.locator.SamlIdPMetadataLocator;
-import org.apereo.cas.support.saml.idp.metadata.writer.SamlIdPCertificateAndKeyWriter;
-import org.apereo.cas.util.DateTimeUtils;
-import org.apereo.cas.util.crypto.CipherExecutor;
-
 import com.github.benmanes.caffeine.cache.Caffeine;
 import com.github.benmanes.caffeine.cache.LoadingCache;
-import com.warrenstrange.googleauth.IGoogleAuthenticator;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.info.Contact;
 import io.swagger.v3.oas.models.info.Info;
 import org.apache.commons.lang3.StringUtils;
+import com.warrenstrange.googleauth.IGoogleAuthenticator;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
 import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
 import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.apache.syncope.wa.starter.audit.SyncopeWAAuditTrailManager;
 import org.apache.syncope.wa.starter.gauth.credential.SyncopeWAGoogleMfaAuthCredentialRepository;
@@ -64,6 +54,22 @@ import org.apache.syncope.wa.starter.saml.idp.metadata.RestfulSamlIdPMetadataGen
 import org.apache.syncope.wa.starter.saml.idp.metadata.RestfulSamlIdPMetadataLocator;
 import org.apache.syncope.wa.starter.services.SyncopeWAServiceRegistry;
 import org.apache.syncope.wa.starter.u2f.SyncopeWAU2FDeviceRepository;
+import org.apereo.cas.adaptors.u2f.storage.U2FDeviceRepository;
+import org.apereo.cas.audit.AuditTrailExecutionPlanConfigurer;
+import org.apereo.cas.configuration.CasConfigurationProperties;
+import org.apereo.cas.configuration.model.support.mfa.u2f.U2FMultifactorProperties;
+import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
+import org.apereo.cas.otp.repository.credentials.OneTimeTokenCredentialRepository;
+import org.apereo.cas.otp.repository.token.OneTimeTokenRepository;
+import org.apereo.cas.services.ServiceRegistryExecutionPlanConfigurer;
+import org.apereo.cas.services.ServiceRegistryListener;
+import org.apereo.cas.support.pac4j.authentication.DelegatedClientFactoryCustomizer;
+import org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGenerator;
+import org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGeneratorConfigurationContext;
+import org.apereo.cas.support.saml.idp.metadata.locator.SamlIdPMetadataLocator;
+import org.apereo.cas.support.saml.idp.metadata.writer.SamlIdPCertificateAndKeyWriter;
+import org.apereo.cas.util.DateTimeUtils;
+import org.apereo.cas.util.crypto.CipherExecutor;
 import org.pac4j.core.client.Client;
 import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -72,15 +78,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
 
-@Configuration
 public class SyncopeWAConfiguration {
 
     @Autowired
@@ -91,62 +89,84 @@ public class SyncopeWAConfiguration {
     private ObjectProvider<SamlIdPCertificateAndKeyWriter> samlSelfSignedCertificateWriter;
 
     @Autowired
-    private ConfigurableApplicationContext applicationContext;
+    private ConfigurableApplicationContext ctx;
 
     @Autowired
     @Qualifier("serviceRegistryListeners")
     private Collection<ServiceRegistryListener> serviceRegistryListeners;
 
+    @Bean
+    public String version() {
+        return ctx.getEnvironment().getProperty("version");
+    }
+
+    @Bean
+    public OpenAPI casSwaggerOpenApi() {
+        return new OpenAPI().
+                info(new Info().
+                        title("Apache Syncope").
+                        description("Apache Syncope " + version()).
+                        contact(new Contact().
+                                name("The Apache Syncope community").
+                                email("dev@syncope.apache.org").
+                                url("http://syncope.apache.org")).
+                        version(version())).
+                schemaRequirement("BasicAuthentication",
+                        new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic")).
+                schemaRequirement("Bearer",
+                        new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT"));
+    }
+
     @ConditionalOnMissingBean
     @Bean
     public RegisteredServiceMapper registeredServiceMapper() {
         Map<String, AuthMapper> authPolicyConfMappers = new HashMap<>();
-        applicationContext.getBeansOfType(AuthMapper.class).forEach((name, bean) -> {
-            AuthMapFor authMapFor = applicationContext.findAnnotationOnBean(name, AuthMapFor.class);
+        ctx.getBeansOfType(AuthMapper.class).forEach((name, bean) -> {
+            AuthMapFor authMapFor = ctx.findAnnotationOnBean(name, AuthMapFor.class);
             if (authMapFor != null) {
                 authPolicyConfMappers.put(authMapFor.authPolicyConfClass().getName(), bean);
             }
         });
 
         Map<String, AccessMapper> accessPolicyConfMappers = new HashMap<>();
-        applicationContext.getBeansOfType(AccessMapper.class).forEach((name, bean) -> {
-            AccessMapFor accessMapFor = applicationContext.findAnnotationOnBean(name, AccessMapFor.class);
+        ctx.getBeansOfType(AccessMapper.class).forEach((name, bean) -> {
+            AccessMapFor accessMapFor = ctx.findAnnotationOnBean(name, AccessMapFor.class);
             if (accessMapFor != null) {
                 accessPolicyConfMappers.put(accessMapFor.accessPolicyConfClass().getName(), bean);
             }
         });
 
         Map<String, AttrReleaseMapper> attrReleasePolicyConfMappers = new HashMap<>();
-        applicationContext.getBeansOfType(AttrReleaseMapper.class).forEach((name, bean) -> {
+        ctx.getBeansOfType(AttrReleaseMapper.class).forEach((name, bean) -> {
             AttrReleaseMapFor attrReleaseMapFor =
-                applicationContext.findAnnotationOnBean(name, AttrReleaseMapFor.class);
+                    ctx.findAnnotationOnBean(name, AttrReleaseMapFor.class);
             if (attrReleaseMapFor != null) {
                 attrReleasePolicyConfMappers.put(attrReleaseMapFor.attrReleasePolicyConfClass().getName(), bean);
             }
         });
 
         Map<String, ClientAppMapper> clientAppTOMappers = new HashMap<>();
-        applicationContext.getBeansOfType(ClientAppMapper.class).forEach((name, bean) -> {
-            ClientAppMapFor clientAppMapFor = applicationContext.findAnnotationOnBean(name, ClientAppMapFor.class);
+        ctx.getBeansOfType(ClientAppMapper.class).forEach((name, bean) -> {
+            ClientAppMapFor clientAppMapFor = ctx.findAnnotationOnBean(name, ClientAppMapFor.class);
             if (clientAppMapFor != null) {
                 clientAppTOMappers.put(clientAppMapFor.clientAppClass().getName(), bean);
             }
         });
 
         return new RegisteredServiceMapper(
-            authPolicyConfMappers,
-            accessPolicyConfMappers,
-            attrReleasePolicyConfMappers,
-            clientAppTOMappers);
+                authPolicyConfMappers,
+                accessPolicyConfMappers,
+                attrReleasePolicyConfMappers,
+                clientAppTOMappers);
     }
 
     @Autowired
     @Bean
     public ServiceRegistryExecutionPlanConfigurer syncopeServiceRegistryConfigurer(
-        final WARestClient restClient, final RegisteredServiceMapper registeredServiceMapper) {
+            final WARestClient restClient, final RegisteredServiceMapper registeredServiceMapper) {
 
         SyncopeWAServiceRegistry registry = new SyncopeWAServiceRegistry(
-            restClient, registeredServiceMapper, applicationContext, serviceRegistryListeners);
+                restClient, registeredServiceMapper, ctx, serviceRegistryListeners);
         return plan -> plan.registerServiceRegistry(registry);
     }
 
@@ -154,13 +174,13 @@ public class SyncopeWAConfiguration {
     @Bean
     public SamlIdPMetadataGenerator samlIdPMetadataGenerator(final WARestClient restClient) {
         SamlIdPMetadataGeneratorConfigurationContext context =
-            SamlIdPMetadataGeneratorConfigurationContext.builder().
-                samlIdPMetadataLocator(samlIdPMetadataLocator(restClient)).
-                samlIdPCertificateAndKeyWriter(samlSelfSignedCertificateWriter.getObject()).
-                applicationContext(applicationContext).
-                casProperties(casProperties).
-                metadataCipherExecutor(CipherExecutor.noOpOfStringToString()).
-                build();
+                SamlIdPMetadataGeneratorConfigurationContext.builder().
+                        samlIdPMetadataLocator(samlIdPMetadataLocator(restClient)).
+                        samlIdPCertificateAndKeyWriter(samlSelfSignedCertificateWriter.getObject()).
+                        applicationContext(ctx).
+                        casProperties(casProperties).
+                        metadataCipherExecutor(CipherExecutor.noOpOfStringToString()).
+                        build();
         return new RestfulSamlIdPMetadataGenerator(context, restClient);
     }
 
@@ -170,49 +190,41 @@ public class SyncopeWAConfiguration {
         return new RestfulSamlIdPMetadataLocator(CipherExecutor.noOpOfStringToString(), restClient);
     }
 
-    @Bean
     @Autowired
+    @Bean
     public AuditTrailExecutionPlanConfigurer auditConfigurer(final WARestClient restClient) {
         return plan -> plan.registerAuditTrailManager(new SyncopeWAAuditTrailManager(restClient));
     }
 
     @Autowired
     @Bean
-    public DelegatedClientFactoryCustomizer<Client> delegatedClientCustomizer(final WARestClient restClient) {
+    public DelegatedClientFactoryCustomizer<Client<?>> delegatedClientCustomizer(final WARestClient restClient) {
         return new SyncopeWASAML2ClientCustomizer(restClient);
     }
 
-    @Bean
     @Autowired
+    @Bean
     public OneTimeTokenRepository oneTimeTokenAuthenticatorTokenRepository(final WARestClient restClient) {
-        return new SyncopeWAGoogleMfaAuthTokenRepository(restClient,
-            casProperties.getAuthn().getMfa().getGauth().getTimeStepSize());
+        return new SyncopeWAGoogleMfaAuthTokenRepository(
+                restClient, casProperties.getAuthn().getMfa().getGauth().getTimeStepSize());
     }
 
-    @Bean
     @Autowired
+    @Bean
     public OneTimeTokenCredentialRepository googleAuthenticatorAccountRegistry(
-        final IGoogleAuthenticator googleAuthenticatorInstance, final WARestClient restClient) {
+            final IGoogleAuthenticator googleAuthenticatorInstance, final WARestClient restClient) {
+
         return new SyncopeWAGoogleMfaAuthCredentialRepository(restClient, googleAuthenticatorInstance);
     }
 
-    @Bean
     @Autowired
-    public OidcJsonWebKeystoreGeneratorService oidcJsonWebKeystoreGeneratorService(final WARestClient restClient) {
-        return new SyncopeWAOIDCJWKSGeneratorService(restClient);
-    }
-
     @Bean
-    public OpenAPI casSwaggerOpenApi() {
-        return new OpenAPI()
-            .info(new Info()
-                .title("Apache Syncope")
-                .description("Apache Syncope " + version())
-                .contact(new Contact()
-                    .name("The Apache Syncope community")
-                    .email("dev@syncope.apache.org")
-                    .url("http://syncope.apache.org"))
-                .version(version()));
+    public OidcJsonWebKeystoreGeneratorService oidcJsonWebKeystoreGeneratorService(final WARestClient restClient) {
+        int size = ctx.getEnvironment().
+                getProperty("cas.authn.oidc.jwks.size", int.class, 2048);
+        JWSAlgorithm algorithm = ctx.getEnvironment().
+                getProperty("cas.authn.oidc.jwks.algorithm", JWSAlgorithm.class, JWSAlgorithm.RS256);
+        return new SyncopeWAOIDCJWKSGeneratorService(restClient, size, algorithm);
     }
 
     @Bean
@@ -220,11 +232,11 @@ public class SyncopeWAConfiguration {
     @RefreshScope
     public U2FDeviceRepository u2fDeviceRepository(final WARestClient restClient) {
         U2FMultifactorProperties u2f = casProperties.getAuthn().getMfa().getU2f();
-        final LocalDate expirationDate = LocalDate.now(ZoneId.systemDefault())
-            .minus(u2f.getExpireDevices(), DateTimeUtils.toChronoUnit(u2f.getExpireDevicesTimeUnit()));
-        final LoadingCache<String, String> requestStorage = Caffeine.newBuilder()
-            .expireAfterWrite(u2f.getExpireRegistrations(), u2f.getExpireRegistrationsTimeUnit())
-            .build(key -> StringUtils.EMPTY);
+        LocalDate expirationDate = LocalDate.now(ZoneId.systemDefault()).
+                minus(u2f.getExpireDevices(), DateTimeUtils.toChronoUnit(u2f.getExpireDevicesTimeUnit()));
+        LoadingCache<String, String> requestStorage = Caffeine.newBuilder().
+                expireAfterWrite(u2f.getExpireRegistrations(), u2f.getExpireRegistrationsTimeUnit()).
+                build(key -> StringUtils.EMPTY);
         return new SyncopeWAU2FDeviceRepository(requestStorage, restClient, expirationDate);
     }
 
@@ -237,9 +249,4 @@ public class SyncopeWAConfiguration {
     public KeymasterStop keymasterStop() {
         return new KeymasterStop(NetworkService.Type.WA);
     }
-
-    @Bean
-    public String version() {
-        return applicationContext.getEnvironment().getProperty("version");
-    }
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AllowedAttrReleaseMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AllowedAttrReleaseMapper.java
index bcb44c8..b243ba6 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AllowedAttrReleaseMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AllowedAttrReleaseMapper.java
@@ -31,16 +31,17 @@ public class AllowedAttrReleaseMapper implements AttrReleaseMapper {
 
     @Override
     public RegisteredServiceAttributeReleasePolicy build(final AttrReleasePolicyConf conf) {
+        AllowedAttrReleasePolicyConf aarpc = (AllowedAttrReleasePolicyConf) conf;
+
         RegisteredServiceAttributeReleasePolicy attributeReleasePolicy;
-        if (!((AllowedAttrReleasePolicyConf) conf).getAllowedAttrs().isEmpty()) {
-            attributeReleasePolicy = new ReturnAllowedAttributeReleasePolicy();
-            ((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).getAllowedAttributes().addAll(
-                    ((AllowedAttrReleasePolicyConf) conf).getAllowedAttrs());
-        } else {
+        if (aarpc.getAllowedAttrs().isEmpty()) {
             attributeReleasePolicy = new DenyAllAttributeReleasePolicy();
+        } else {
+            attributeReleasePolicy = new ReturnAllowedAttributeReleasePolicy();
+            ((ReturnAllowedAttributeReleasePolicy) attributeReleasePolicy).
+                    setAllowedAttributes((aarpc.getAllowedAttrs()));
         }
 
         return attributeReleasePolicy;
     }
-
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java
index d5b870d..d8870cc 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/CASSPTOMapper.java
@@ -18,14 +18,13 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
+import org.apache.syncope.common.lib.to.client.CASSPTO;
+import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.RegexRegisteredService;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
 import org.apereo.cas.services.RegisteredServiceAuthenticationPolicy;
-
-import org.apache.syncope.common.lib.to.client.CASSPTO;
-import org.apache.syncope.common.lib.to.client.ClientAppTO;
 import org.springframework.stereotype.Component;
 
 @ClientAppMapFor(clientAppClass = CASSPTO.class)
@@ -34,24 +33,30 @@ public class CASSPTOMapper implements ClientAppMapper {
 
     @Override
     public RegisteredService build(
-        final ClientAppTO clientAppTO,
-        final RegisteredServiceAuthenticationPolicy authPolicy,
-        final RegisteredServiceAccessStrategy accessStrategy,
-        final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy) {
+            final WAClientApp clientApp,
+            final RegisteredServiceAuthenticationPolicy authenticationPolicy,
+            final RegisteredServiceAccessStrategy accessStrategy,
+            final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy) {
 
-        CASSPTO rp = CASSPTO.class.cast(clientAppTO);
+        CASSPTO cas = CASSPTO.class.cast(clientApp.getClientAppTO());
 
         RegexRegisteredService service = new RegexRegisteredService();
 
-        service.setServiceId(rp.getServiceId());
-        service.setId(rp.getClientAppId());
-        service.setName(rp.getName());
-        service.setDescription(rp.getDescription());
-        service.setAccessStrategy(accessStrategy);
-        service.setAuthenticationPolicy(authPolicy);
-        service.setAttributeReleasePolicy(attributeReleasePolicy);
+        service.setServiceId(cas.getServiceId());
+        service.setId(cas.getClientAppId());
+        service.setName(cas.getName());
+        service.setDescription(cas.getDescription());
+
+        if (authenticationPolicy != null) {
+            service.setAuthenticationPolicy(authenticationPolicy);
+        }
+        if (accessStrategy != null) {
+            service.setAccessStrategy(accessStrategy);
+        }
+        if (attributeReleasePolicy != null) {
+            service.setAttributeReleasePolicy(attributeReleasePolicy);
+        }
 
         return service;
     }
-
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
index b783136..a7945ac 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/ClientAppMapper.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
-import org.apache.syncope.common.lib.to.client.ClientAppTO;
+import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
@@ -27,7 +27,7 @@ import org.apereo.cas.services.RegisteredServiceAuthenticationPolicy;
 public interface ClientAppMapper {
 
     RegisteredService build(
-            ClientAppTO clientAppTO,
+            WAClientApp clientApp,
             RegisteredServiceAuthenticationPolicy authPolicy,
             RegisteredServiceAccessStrategy accessStrategy,
             RegisteredServiceAttributeReleasePolicy attributeReleasePolicy);
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
index 323b3b1..26832dc 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAccessMapper.java
@@ -35,5 +35,4 @@ public class DefaultAccessMapper implements AccessMapper {
         accessStrategy.getRequiredAttributes().putAll(conf.getRequiredAttrs());
         return accessStrategy;
     }
-
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
index 10945e7..c79acd8 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultAuthMapper.java
@@ -34,16 +34,23 @@ public class DefaultAuthMapper implements AuthMapper {
     @Override
     public RegisteredServiceAuthenticationPolicy build(final AuthPolicyConf conf) {
         DefaultRegisteredServiceAuthenticationPolicy authPolicy = new DefaultRegisteredServiceAuthenticationPolicy();
-        AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria criteria =
-                new AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria();
-        criteria.setTryAll(((DefaultAuthPolicyCriteriaConf) conf.getCriteria()).isAll());
-        authPolicy.setCriteria(criteria);
 
-        if (conf instanceof DefaultAuthPolicyConf && !((DefaultAuthPolicyConf) conf).getAuthModules().isEmpty()) {
-            authPolicy.setRequiredAuthenticationHandlers(
-                    new HashSet<>(((DefaultAuthPolicyConf) conf).getAuthModules()));
+        if (conf.getCriteria() instanceof DefaultAuthPolicyCriteriaConf) {
+            DefaultAuthPolicyCriteriaConf policyCriteriaConf = (DefaultAuthPolicyCriteriaConf) conf.getCriteria();
+
+            AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria criteria =
+                    new AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria();
+            criteria.setTryAll(policyCriteriaConf.isAll());
+            authPolicy.setCriteria(criteria);
+        }
+
+        if (conf instanceof DefaultAuthPolicyConf) {
+            DefaultAuthPolicyConf policyConf = (DefaultAuthPolicyConf) conf;
+            if (!policyConf.getAuthModules().isEmpty()) {
+                authPolicy.setRequiredAuthenticationHandlers(new HashSet<>(policyConf.getAuthModules()));
+            }
         }
+
         return authPolicy;
     }
-
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPTOMapper.java
index a14923e..63b8e2f 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/OIDCRPTOMapper.java
@@ -19,49 +19,118 @@
 package org.apache.syncope.wa.starter.mapping;
 
 import java.util.HashSet;
-import org.apache.syncope.common.lib.to.client.ClientAppTO;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.apache.syncope.common.lib.to.client.OIDCRPTO;
+import org.apache.syncope.common.lib.wa.WAClientApp;
+import org.apereo.cas.configuration.CasConfigurationProperties;
+import org.apereo.cas.oidc.claims.OidcAddressScopeAttributeReleasePolicy;
+import org.apereo.cas.oidc.claims.OidcCustomScopeAttributeReleasePolicy;
+import org.apereo.cas.oidc.claims.OidcEmailScopeAttributeReleasePolicy;
+import org.apereo.cas.oidc.claims.OidcPhoneScopeAttributeReleasePolicy;
+import org.apereo.cas.oidc.claims.OidcProfileScopeAttributeReleasePolicy;
+import org.apereo.cas.services.ChainingAttributeReleasePolicy;
 import org.apereo.cas.services.OidcRegisteredService;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
 import org.apereo.cas.services.RegisteredServiceAuthenticationPolicy;
+import org.apereo.cas.services.ReturnMappedAttributeReleasePolicy;
+import org.apereo.cas.util.spring.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
 import org.springframework.stereotype.Component;
 
 @ClientAppMapFor(clientAppClass = OIDCRPTO.class)
 @Component
 public class OIDCRPTOMapper implements ClientAppMapper {
 
+    private static final Logger LOG = LoggerFactory.getLogger(OIDCRPTOMapper.class);
+
+    public static final String CUSTOM_SCOPE = "syncope";
+
     @Override
     public RegisteredService build(
-            final ClientAppTO clientAppTO,
-            final RegisteredServiceAuthenticationPolicy authPolicy,
+            final WAClientApp clientApp,
+            final RegisteredServiceAuthenticationPolicy authenticationPolicy,
             final RegisteredServiceAccessStrategy accessStrategy,
             final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy) {
 
-        OIDCRPTO rp = OIDCRPTO.class.cast(clientAppTO);
+        OIDCRPTO rp = OIDCRPTO.class.cast(clientApp.getClientAppTO());
 
         OidcRegisteredService service = new OidcRegisteredService();
-
-        String redirectURIs = String.join("|", rp.getRedirectUris());
-        service.setServiceId(redirectURIs);
+        service.setServiceId(Stream.concat(rp.getRedirectUris().stream(), Stream.of(rp.getLogoutUri())).
+                filter(Objects::nonNull).
+                collect(Collectors.joining("|")));
         service.setId(rp.getClientAppId());
         service.setName(rp.getName());
         service.setDescription(rp.getDescription());
-        service.setAccessStrategy(accessStrategy);
-        service.setAuthenticationPolicy(authPolicy);
-        service.setAttributeReleasePolicy(attributeReleasePolicy);
-
+        service.setRedirectUrl(service.getServiceId());
         service.setClientId(rp.getClientId());
         service.setClientSecret(rp.getClientSecret());
         service.setSignIdToken(rp.isSignIdToken());
-        service.setJwks(rp.getJwks());
-        service.setSubjectType(rp.getSubjectType().name());
-        service.setRedirectUrl(redirectURIs);
-        service.setSupportedGrantTypes((HashSet<String>) rp.getSupportedGrantTypes());
-        service.setSupportedResponseTypes((HashSet<String>) rp.getSupportedResponseTypes());
+        if (!service.isSignIdToken()) {
+            service.setIdTokenSigningAlg("none");
+        }
+        service.setJwtAccessToken(true);
+        service.setSupportedGrantTypes(new HashSet<>(rp.getSupportedGrantTypes()));
+        service.setSupportedResponseTypes(new HashSet<>(rp.getSupportedResponseTypes()));
+        if (rp.getSubjectType() != null) {
+            service.setSubjectType(rp.getSubjectType().name());
+        }
+        service.setLogoutUrl(rp.getLogoutUri());
+
+        if (authenticationPolicy != null) {
+            service.setAuthenticationPolicy(authenticationPolicy);
+        }
+        if (accessStrategy != null) {
+            service.setAccessStrategy(accessStrategy);
+        }
+        if (attributeReleasePolicy != null) {
+            ChainingAttributeReleasePolicy chain = new ChainingAttributeReleasePolicy();
+            if (attributeReleasePolicy instanceof ReturnMappedAttributeReleasePolicy) {
+                chain.addPolicy(attributeReleasePolicy);
+            } else {
+                chain.addPolicy(new ReturnMappedAttributeReleasePolicy(clientApp.getReleaseAttrs()));
+                chain.addPolicy(attributeReleasePolicy);
+            }
+
+            chain.addPolicy(new OidcProfileScopeAttributeReleasePolicy());
+            chain.addPolicy(new OidcEmailScopeAttributeReleasePolicy());
+            chain.addPolicy(new OidcAddressScopeAttributeReleasePolicy());
+            chain.addPolicy(new OidcPhoneScopeAttributeReleasePolicy());
+
+            Set<String> customClaims = clientApp.getReleaseAttrs().values().stream().
+                    map(Objects::toString).collect(Collectors.toCollection(HashSet::new));
+            customClaims.removeAll(OidcProfileScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+            customClaims.removeAll(OidcEmailScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+            customClaims.removeAll(OidcAddressScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+            customClaims.removeAll(OidcPhoneScopeAttributeReleasePolicy.ALLOWED_CLAIMS);
+            if (!customClaims.isEmpty()) {
+                ApplicationContext ctx = ApplicationContextProvider.getApplicationContext();
+                if (ctx == null) {
+                    LOG.warn("Could not locate the application context to add custom claims {}", customClaims);
+                } else {
+                    CasConfigurationProperties properties = ctx.getBean(CasConfigurationProperties.class);
+                    List<String> supportedClaims = properties.getAuthn().getOidc().getClaims();
+                    if (!supportedClaims.containsAll(customClaims)) {
+                        properties.getAuthn().getOidc().setClaims(
+                                Stream.concat(supportedClaims.stream(), customClaims.stream()).
+                                        distinct().collect(Collectors.toList()));
+                    }
+
+                    chain.addPolicy(new OidcCustomScopeAttributeReleasePolicy(
+                            CUSTOM_SCOPE, customClaims.stream().collect(Collectors.toList())));
+                }
+            }
+
+            service.setAttributeReleasePolicy(chain);
+        }
 
         return service;
     }
-
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
index 3a31009..af7c9e4 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/RegisteredServiceMapper.java
@@ -21,7 +21,6 @@ package org.apache.syncope.wa.starter.mapping;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.syncope.common.lib.wa.WAClientApp;
-import org.apereo.cas.services.DenyAllAttributeReleasePolicy;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
@@ -69,20 +68,20 @@ public class RegisteredServiceMapper {
 
         RegisteredServiceAttributeReleasePolicy attributeReleasePolicy = null;
         if (!clientApp.getReleaseAttrs().isEmpty()) {
-            attributeReleasePolicy = new ReturnMappedAttributeReleasePolicy(clientApp.getReleaseAttrs());
-        } else if (clientApp.getAttrReleasePolicyConf() != null) {
-            AttrReleaseMapper attrReleasePolicyConfMapper =
-                    attrReleasePolicyConfMappers.get(clientApp.getAttrReleasePolicyConf().getClass().getName());
-            attributeReleasePolicy = Optional.ofNullable(attrReleasePolicyConfMapper).
-                    map(mapper -> mapper.build(clientApp.getAttrReleasePolicyConf())).orElse(null);
-        } else {
-            attributeReleasePolicy = new DenyAllAttributeReleasePolicy();
+            if (clientApp.getAttrReleasePolicyConf() == null) {
+                attributeReleasePolicy = new ReturnMappedAttributeReleasePolicy(clientApp.getReleaseAttrs());
+            } else {
+                AttrReleaseMapper attrReleasePolicyConfMapper =
+                        attrReleasePolicyConfMappers.get(clientApp.getAttrReleasePolicyConf().getClass().getName());
+                attributeReleasePolicy = Optional.ofNullable(attrReleasePolicyConfMapper).
+                        map(mapper -> mapper.build(clientApp.getAttrReleasePolicyConf())).orElse(null);
+            }
         }
 
         ClientAppMapper clientAppMapper = clientAppTOMappers.get(clientApp.getClientAppTO().getClass().getName());
         if (clientAppMapper == null) {
             return null;
         }
-        return clientAppMapper.build(clientApp.getClientAppTO(), authPolicy, accessStrategy, attributeReleasePolicy);
+        return clientAppMapper.build(clientApp, authPolicy, accessStrategy, attributeReleasePolicy);
     }
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPTOMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPTOMapper.java
index 170bb28..f266dd2 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPTOMapper.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/SAML2SPTOMapper.java
@@ -18,8 +18,8 @@
  */
 package org.apache.syncope.wa.starter.mapping;
 
-import org.apache.syncope.common.lib.to.client.ClientAppTO;
 import org.apache.syncope.common.lib.to.client.SAML2SPTO;
+import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.RegisteredServiceAccessStrategy;
 import org.apereo.cas.services.RegisteredServiceAttributeReleasePolicy;
@@ -33,12 +33,12 @@ public class SAML2SPTOMapper implements ClientAppMapper {
 
     @Override
     public RegisteredService build(
-            final ClientAppTO clientAppTO,
-            final RegisteredServiceAuthenticationPolicy authPolicy,
+            final WAClientApp clientApp,
+            final RegisteredServiceAuthenticationPolicy authenticationPolicy,
             final RegisteredServiceAccessStrategy accessStrategy,
             final RegisteredServiceAttributeReleasePolicy attributeReleasePolicy) {
 
-        SAML2SPTO sp = SAML2SPTO.class.cast(clientAppTO);
+        SAML2SPTO sp = SAML2SPTO.class.cast(clientApp.getClientAppTO());
 
         SamlRegisteredService service = new SamlRegisteredService();
 
@@ -46,9 +46,6 @@ public class SAML2SPTOMapper implements ClientAppMapper {
         service.setId(sp.getClientAppId());
         service.setName(sp.getName());
         service.setDescription(sp.getDescription());
-        service.setAccessStrategy(accessStrategy);
-        service.setAuthenticationPolicy(authPolicy);
-        service.setAttributeReleasePolicy(attributeReleasePolicy);
 
         service.setMetadataLocation(sp.getMetadataLocation());
         service.setMetadataSignatureLocation(sp.getMetadataSignatureLocation());
@@ -63,6 +60,16 @@ public class SAML2SPTOMapper implements ClientAppMapper {
         service.setAssertionAudiences(sp.getAssertionAudiences());
         service.setServiceProviderNameIdQualifier(sp.getServiceProviderNameIdQualifier());
 
+        if (authenticationPolicy != null) {
+            service.setAuthenticationPolicy(authenticationPolicy);
+        }
+        if (accessStrategy != null) {
+            service.setAccessStrategy(accessStrategy);
+        }
+        if (attributeReleasePolicy != null) {
+            service.setAttributeReleasePolicy(attributeReleasePolicy);
+        }
+
         return service;
     }
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
index 346f504..3dbea1a 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/oidc/SyncopeWAOIDCJWKSGeneratorService.java
@@ -16,29 +16,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.wa.starter.oidc;
 
-import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
-
+import java.nio.charset.StandardCharsets;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.OIDCJWKSTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.rest.api.service.wa.OIDCJWKSService;
+import org.apache.syncope.common.lib.types.JWSAlgorithm;
+import org.apache.syncope.common.rest.api.service.wa.WAOIDCJWKSService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
+import org.apereo.cas.oidc.jwks.OidcJsonWebKeystoreGeneratorService;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
 
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.Response;
-
-import java.nio.charset.StandardCharsets;
-
 public class SyncopeWAOIDCJWKSGeneratorService implements OidcJsonWebKeystoreGeneratorService {
+
     private final WARestClient waRestClient;
 
-    public SyncopeWAOIDCJWKSGeneratorService(final WARestClient restClient) {
+    private final int size;
+
+    private final JWSAlgorithm algorithm;
+
+    public SyncopeWAOIDCJWKSGeneratorService(
+            final WARestClient restClient, final int size, final JWSAlgorithm algorithm) {
+
         this.waRestClient = restClient;
+        this.size = size;
+        this.algorithm = algorithm;
     }
 
     @Override
@@ -47,19 +53,19 @@ public class SyncopeWAOIDCJWKSGeneratorService implements OidcJsonWebKeystoreGen
             throw new RuntimeException("Syncope core is not yet ready");
         }
 
-        OIDCJWKSService service = waRestClient.getSyncopeClient().
-            getService(OIDCJWKSService.class);
+        WAOIDCJWKSService service = waRestClient.getSyncopeClient().getService(WAOIDCJWKSService.class);
         try {
-            Response response = service.set();
+            Response response = service.set(size, algorithm);
             OIDCJWKSTO jwksTO = response.readEntity(new GenericType<OIDCJWKSTO>() {
             });
             return new ByteArrayResource(jwksTO.getJson().getBytes(StandardCharsets.UTF_8), "OIDC JWKS");
-        } catch (final SyncopeClientException e) {
+        } catch (SyncopeClientException e) {
             if (e.getType() == ClientExceptionType.EntityExists) {
                 OIDCJWKSTO jwksTO = service.get();
                 return new ByteArrayResource(jwksTO.getJson().getBytes(StandardCharsets.UTF_8), "OIDC JWKS");
             }
+
+            throw new RuntimeException("Unable to determine OIDC JWKS resource", e);
         }
-        throw new RuntimeException("Unable to determine OIDC JWKS resource");
     }
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizer.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizer.java
index 0dfc403..704cdb1 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizer.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizer.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.syncope.wa.starter.pac4j.saml;
 
 import org.apereo.cas.support.pac4j.authentication.DelegatedClientFactoryCustomizer;
@@ -28,7 +27,8 @@ import org.pac4j.saml.config.SAML2Configuration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SyncopeWASAML2ClientCustomizer implements DelegatedClientFactoryCustomizer<Client> {
+public class SyncopeWASAML2ClientCustomizer implements DelegatedClientFactoryCustomizer<Client<?>> {
+
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeWASAML2ClientCustomizer.class);
 
     private final WARestClient restClient;
@@ -38,7 +38,7 @@ public class SyncopeWASAML2ClientCustomizer implements DelegatedClientFactoryCus
     }
 
     @Override
-    public void customize(final Client client) {
+    public void customize(final Client<?> client) {
         if (client instanceof SAML2Client) {
             LOG.debug("Customizing SAML2 client {}", client.getName());
             final SAML2Client saml2Client = (SAML2Client) client;
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGenerator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGenerator.java
index 77f84f6..bb7dfad 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGenerator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGenerator.java
@@ -22,7 +22,6 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPKeystoreService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.pac4j.saml.client.SAML2Client;
 import org.pac4j.saml.metadata.keystore.BaseSAML2KeystoreGenerator;
@@ -38,6 +37,7 @@ import java.security.KeyStore;
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
 import java.util.Base64;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPKeystoreService;
 
 public class SyncopeWASAML2ClientKeystoreGenerator extends BaseSAML2KeystoreGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeWASAML2ClientKeystoreGenerator.class);
@@ -67,8 +67,8 @@ public class SyncopeWASAML2ClientKeystoreGenerator extends BaseSAML2KeystoreGene
             String encodedKeystore = Base64.getEncoder().encodeToString(out.toByteArray());
             LOG.debug("Encoded keystore {}", encodedKeystore);
 
-            SAML2SPKeystoreService keystoreService = restClient.getSyncopeClient().
-                getService(SAML2SPKeystoreService.class);
+            WASAML2SPKeystoreService keystoreService = restClient.getSyncopeClient().
+                getService(WASAML2SPKeystoreService.class);
 
             SAML2SPKeystoreTO keystoreTO = new SAML2SPKeystoreTO.Builder().
                 keystore(encodedKeystore).
@@ -94,8 +94,8 @@ public class SyncopeWASAML2ClientKeystoreGenerator extends BaseSAML2KeystoreGene
     @Override
     public InputStream retrieve() throws Exception {
         try {
-            SAML2SPKeystoreService keystoreService = restClient.getSyncopeClient().
-                getService(SAML2SPKeystoreService.class);
+            WASAML2SPKeystoreService keystoreService = restClient.getSyncopeClient().
+                getService(WASAML2SPKeystoreService.class);
             SAML2SPKeystoreTO keystoreTO = keystoreService.getByOwner(saml2Client.getName());
             LOG.debug("Retrieved keystore {}", keystoreTO);
             byte[] decode = Base64.getDecoder().decode(keystoreTO.getKeystore());
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGenerator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGenerator.java
index 9ba283c..a05d77f 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGenerator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGenerator.java
@@ -22,7 +22,6 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.opensaml.saml.metadata.resolver.impl.AbstractBatchMetadataResolver;
 import org.pac4j.saml.client.SAML2Client;
@@ -32,6 +31,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.core.io.Resource;
 
 import javax.ws.rs.core.Response;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
 
 public class SyncopeWASAML2ClientMetadataGenerator extends BaseSAML2MetadataGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeWASAML2ClientMetadataGenerator.class);
@@ -52,8 +52,8 @@ public class SyncopeWASAML2ClientMetadataGenerator extends BaseSAML2MetadataGene
 
     @Override
     public boolean storeMetadata(final String metadata, final Resource resource, final boolean force) throws Exception {
-        SAML2SPMetadataService metadataService = restClient.getSyncopeClient().
-            getService(SAML2SPMetadataService.class);
+        WASAML2SPMetadataService metadataService = restClient.getSyncopeClient().
+            getService(WASAML2SPMetadataService.class);
         SAML2SPMetadataTO metadataTO = new SAML2SPMetadataTO.Builder().
             metadata(metadata).
             owner(saml2Client.getName()).
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolver.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolver.java
index da71d2a..f293291 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolver.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolver.java
@@ -21,7 +21,6 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver;
 import org.pac4j.saml.client.SAML2Client;
@@ -29,6 +28,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.nio.charset.StandardCharsets;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
 
 public class SyncopeWASAML2MetadataResolver extends AbstractReloadingMetadataResolver {
     private static final Logger LOG = LoggerFactory.getLogger(SyncopeWASAML2MetadataResolver.class);
@@ -50,8 +50,8 @@ public class SyncopeWASAML2MetadataResolver extends AbstractReloadingMetadataRes
     @Override
     protected byte[] fetchMetadata() throws ResolverException {
         try {
-            SAML2SPMetadataService metadataService = restClient.getSyncopeClient().
-                getService(SAML2SPMetadataService.class);
+            WASAML2SPMetadataService metadataService = restClient.getSyncopeClient().
+                getService(WASAML2SPMetadataService.class);
             SAML2SPMetadataTO metadataTO = metadataService.getByOwner(saml2Client.getName());
             return metadataTO.getMetadata().getBytes(StandardCharsets.UTF_8);
         } catch (final Exception e) {
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataGenerator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataGenerator.java
index dd33e68..9719676 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataGenerator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataGenerator.java
@@ -21,7 +21,6 @@ package org.apache.syncope.wa.starter.saml.idp.metadata;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2IdPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.apereo.cas.support.saml.idp.metadata.generator.BaseSamlIdPMetadataGenerator;
 import org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGeneratorConfigurationContext;
@@ -32,6 +31,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
 import javax.ws.rs.core.Response;
 import java.util.Optional;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2IdPMetadataService;
 
 public class RestfulSamlIdPMetadataGenerator extends BaseSamlIdPMetadataGenerator {
 
@@ -68,7 +68,7 @@ public class RestfulSamlIdPMetadataGenerator extends BaseSamlIdPMetadataGenerato
         SyncopeClient client = getSyncopeClient();
         Response response = null;
         try {
-            response = client.getService(SAML2IdPMetadataService.class).set(metadataTO);
+            response = client.getService(WASAML2IdPMetadataService.class).set(metadataTO);
         } catch (Exception ex) {
             LOG.warn("While generating SAML2 IdP metadata document", ex);
         }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
index eb2c220..f00bba5 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/metadata/RestfulSamlIdPMetadataLocator.java
@@ -22,7 +22,6 @@ import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2IdPMetadataTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.rest.api.service.wa.SAML2IdPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.apereo.cas.support.saml.idp.metadata.locator.AbstractSamlIdPMetadataLocator;
 import org.apereo.cas.support.saml.services.SamlRegisteredService;
@@ -31,6 +30,7 @@ import org.apereo.cas.util.crypto.CipherExecutor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.util.Optional;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2IdPMetadataService;
 
 public class RestfulSamlIdPMetadataLocator extends AbstractSamlIdPMetadataLocator {
 
@@ -58,7 +58,7 @@ public class RestfulSamlIdPMetadataLocator extends AbstractSamlIdPMetadataLocato
     public SamlIdPMetadataDocument fetchInternal(final Optional<SamlRegisteredService> registeredService) {
         try {
             LOG.info("Locating SAML2 IdP metadata document");
-            SAML2IdPMetadataTO saml2IdPMetadataTO = getSyncopeClient().getService(SAML2IdPMetadataService.class).
+            SAML2IdPMetadataTO saml2IdPMetadataTO = getSyncopeClient().getService(WASAML2IdPMetadataService.class).
                 getByOwner(getAppliesToFor(registeredService));
 
             if (saml2IdPMetadataTO == null) {
diff --git a/wa/starter/src/main/resources/wa.properties b/wa/starter/src/main/resources/wa.properties
index 6f2df05..eb69a87 100644
--- a/wa/starter/src/main/resources/wa.properties
+++ b/wa/starter/src/main/resources/wa.properties
@@ -21,13 +21,14 @@ useGZIPCompression=true
 
 # Conf directories
 conf.directory=${conf.directory}
-cas.standalone.configuration-directory=${conf.directory}
-cas.authn.oidc.jwks.jwks-file=file:${conf.directory}/oidc.keystore
+cas.standalone.configurationDirectory=${conf.directory}
 
 cas.server.name=http://localhost:8080
 cas.server.prefix=${cas.server.name}/syncope-wa
 cas.server.scope=syncope.org
 
+cas.logout.follow-service-redirects=true
+
 cas.authn.saml-idp.entity-id=https://syncope.apache.org/saml
 
 # Disable access to the login endpoint
@@ -49,3 +50,8 @@ cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
 
 spring.security.user.name=${anonymousUser}
 spring.security.user.password=${anonymousKey}
+
+springdoc.show-actuator=true
+springdoc.model-and-view-allowed=true
+springdoc.writer-with-default-pretty-printer=true
+springdoc.swagger-ui.displayRequestDuration=true
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/BasicTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/BasicTest.java
index 938f850..ec8b238 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/BasicTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/BasicTest.java
@@ -88,7 +88,7 @@ public class BasicTest extends AbstractTest {
         // 3. check authentication results
         assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
 
-        Header[] cookie = response.getHeaders("Set-Cookie");
+        Header[] cookie = response.getHeaders(HttpHeaders.SET_COOKIE);
         assertNotNull(cookie);
         assertTrue(cookie.length > 0);
         assertEquals(1, Stream.of(cookie).filter(item -> item.getValue().startsWith("TGC")).count());
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
index c69fcdb..d86d588 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeWAServiceRegistryTest.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.wa.starter;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -41,11 +40,10 @@ import org.apache.syncope.common.lib.wa.WAClientApp;
 import org.apache.syncope.common.rest.api.service.wa.WAClientAppService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.apereo.cas.services.AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria;
-import org.apereo.cas.services.DenyAllAttributeReleasePolicy;
+import org.apereo.cas.services.ChainingAttributeReleasePolicy;
 import org.apereo.cas.services.OidcRegisteredService;
 import org.apereo.cas.services.RegisteredService;
 import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy;
-import org.apereo.cas.services.ReturnMappedAttributeReleasePolicy;
 import org.apereo.cas.services.ServicesManager;
 import org.apereo.cas.support.saml.services.SamlRegisteredService;
 import org.apereo.cas.util.RandomUtils;
@@ -89,9 +87,11 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         return saml2spto;
     }
 
-    private static void addAttributes(final boolean withReleaseAttributes,
+    private static void addAttributes(
+            final boolean withReleaseAttributes,
             final boolean withAttrReleasePolicy,
             final WAClientApp waClientApp) {
+
         DefaultAuthPolicyConf authPolicyConf = new DefaultAuthPolicyConf();
         DefaultAuthPolicyCriteriaConf criteria = new DefaultAuthPolicyCriteriaConf();
         criteria.setAll(true);
@@ -136,7 +136,7 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         waClientApp.setClientAppTO(buildOIDCRP());
         Long clientAppId = waClientApp.getClientAppTO().getClientAppId();
         addAttributes(true, true, waClientApp);
-        
+
         SyncopeCoreTestingServer.APPS.add(waClientApp);
         List<WAClientApp> apps = service.list();
         assertEquals(1, apps.size());
@@ -151,18 +151,15 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         RegisteredService found = servicesManager.findServiceBy(clientAppId);
         assertNotNull(found);
         assertTrue(found instanceof OidcRegisteredService);
-        OidcRegisteredService oidcRegisteredService = OidcRegisteredService.class.cast(found);
+        OidcRegisteredService oidc = OidcRegisteredService.class.cast(found);
         OIDCRPTO oidcrpto = OIDCRPTO.class.cast(waClientApp.getClientAppTO());
-        assertEquals("uri1|uri2", oidcRegisteredService.getServiceId());
-        assertEquals(oidcrpto.getClientId(), oidcRegisteredService.getClientId());
-        assertEquals(oidcrpto.getClientSecret(), oidcRegisteredService.getClientSecret());
-        assertTrue(oidcRegisteredService.getAuthenticationPolicy().getRequiredAuthenticationHandlers().
-                contains("TestAuthModule"));
-        assertTrue(((AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria) oidcRegisteredService.
+        assertEquals("uri1|uri2", oidc.getServiceId());
+        assertEquals(oidcrpto.getClientId(), oidc.getClientId());
+        assertEquals(oidcrpto.getClientSecret(), oidc.getClientSecret());
+        assertTrue(oidc.getAuthenticationPolicy().getRequiredAuthenticationHandlers().contains("TestAuthModule"));
+        assertTrue(((AnyAuthenticationHandlerRegisteredServiceAuthenticationPolicyCriteria) oidc.
                 getAuthenticationPolicy().getCriteria()).isTryAll());
-        assertTrue(oidcRegisteredService.getAttributeReleasePolicy() instanceof ReturnMappedAttributeReleasePolicy);
-        assertFalse(oidcRegisteredService.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy);
-        assertFalse(oidcRegisteredService.getAttributeReleasePolicy() instanceof DenyAllAttributeReleasePolicy);
+        assertTrue(oidc.getAttributeReleasePolicy() instanceof ChainingAttributeReleasePolicy);
 
         // 5. more client with different attributes 
         waClientApp = new WAClientApp();
@@ -179,16 +176,13 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
 
         found = servicesManager.findServiceBy(clientAppId);
         assertTrue(found instanceof SamlRegisteredService);
-        SamlRegisteredService samlRegisteredService = SamlRegisteredService.class.cast(found);
+        SamlRegisteredService saml = SamlRegisteredService.class.cast(found);
         SAML2SPTO samlspto = SAML2SPTO.class.cast(waClientApp.getClientAppTO());
-        assertEquals(samlspto.getMetadataLocation(), samlRegisteredService.getMetadataLocation());
-        assertEquals(samlspto.getEntityId(), samlRegisteredService.getServiceId());
-        assertTrue(samlRegisteredService.getAuthenticationPolicy().getRequiredAuthenticationHandlers().
-                contains("TestAuthModule"));
+        assertEquals(samlspto.getMetadataLocation(), saml.getMetadataLocation());
+        assertEquals(samlspto.getEntityId(), saml.getServiceId());
+        assertTrue(saml.getAuthenticationPolicy().getRequiredAuthenticationHandlers().contains("TestAuthModule"));
         assertNotNull(found.getAccessStrategy());
-        assertFalse(samlRegisteredService.getAttributeReleasePolicy() instanceof ReturnMappedAttributeReleasePolicy);
-        assertTrue(samlRegisteredService.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy);
-        assertFalse(samlRegisteredService.getAttributeReleasePolicy() instanceof DenyAllAttributeReleasePolicy);
+        assertTrue(saml.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy);
 
         waClientApp = new WAClientApp();
         waClientApp.setClientAppTO(buildSAML2SP());
@@ -203,9 +197,6 @@ public class SyncopeWAServiceRegistryTest extends AbstractTest {
         assertEquals(5, load.size());
 
         found = servicesManager.findServiceBy(clientAppId);
-        assertFalse(found.getAttributeReleasePolicy() instanceof ReturnMappedAttributeReleasePolicy);
-        assertFalse(found.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy);
-        assertTrue(found.getAttributeReleasePolicy() instanceof DenyAllAttributeReleasePolicy);
-
+        assertTrue(found.getAttributeReleasePolicy() instanceof ReturnAllowedAttributeReleasePolicy);
     }
 }
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizerTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizerTest.java
index f752fdd..339f6ec5 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizerTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientCustomizerTest.java
@@ -23,8 +23,6 @@ import org.apache.commons.io.IOUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPKeystoreService;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.pac4j.saml.client.SAML2Client;
@@ -41,6 +39,9 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPKeystoreService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
+
 public class SyncopeWASAML2ClientCustomizerTest extends BaseSyncopeWASAML2ClientTest {
 
     @Test
@@ -50,7 +51,7 @@ public class SyncopeWASAML2ClientCustomizerTest extends BaseSyncopeWASAML2Client
             .keystore(getKeystoreAsString())
             .owner("CAS")
             .build();
-        SAML2SPKeystoreService saml2SPKeystoreService = mock(SAML2SPKeystoreService.class);
+        WASAML2SPKeystoreService saml2SPKeystoreService = mock(WASAML2SPKeystoreService.class);
         when(saml2SPKeystoreService.getByOwner(anyString())).thenReturn(keystoreTO);
         when(saml2SPKeystoreService.set(any())).thenReturn(Response.created(new URI("http://localhost:9080/syncop-wa")).build());
 
@@ -59,15 +60,15 @@ public class SyncopeWASAML2ClientCustomizerTest extends BaseSyncopeWASAML2Client
             .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(), StandardCharsets.UTF_8))
             .build();
 
-        SAML2SPMetadataService saml2SPMetadataService = mock(SAML2SPMetadataService.class);
+        WASAML2SPMetadataService saml2SPMetadataService = mock(WASAML2SPMetadataService.class);
         when(saml2SPMetadataService.getByOwner(anyString())).thenReturn(metadataTO);
         when(saml2SPMetadataService.set(any())).thenReturn(Response.created(new URI("http://localhost:9080/syncop-wa")).build());
 
         WARestClient restClient = mock(WARestClient.class);
 
         SyncopeClient syncopeClient = mock(SyncopeClient.class);
-        when(syncopeClient.getService(SAML2SPKeystoreService.class)).thenReturn(saml2SPKeystoreService);
-        when(syncopeClient.getService(SAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
+        when(syncopeClient.getService(WASAML2SPKeystoreService.class)).thenReturn(saml2SPKeystoreService);
+        when(syncopeClient.getService(WASAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
         when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
 
         SyncopeWASAML2ClientCustomizer customizer = new SyncopeWASAML2ClientCustomizer(restClient);
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGeneratorTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGeneratorTest.java
index 8c50d22..e609994 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGeneratorTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientKeystoreGeneratorTest.java
@@ -24,8 +24,6 @@ import org.apache.syncope.client.lib.SyncopeClient;
 
 import org.apache.syncope.common.lib.to.SAML2SPKeystoreTO;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPKeystoreService;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.function.Executable;
@@ -46,6 +44,9 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPKeystoreService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
+
 public class SyncopeWASAML2ClientKeystoreGeneratorTest extends BaseSyncopeWASAML2ClientTest {
     private static WARestClient getWaRestClient(final Response response) throws Exception {
         WARestClient restClient = mock(WARestClient.class);
@@ -54,7 +55,7 @@ public class SyncopeWASAML2ClientKeystoreGeneratorTest extends BaseSyncopeWASAML
             .keystore(getKeystoreAsString())
             .owner("CAS")
             .build();
-        SAML2SPKeystoreService saml2SPKeystoreService = mock(SAML2SPKeystoreService.class);
+        WASAML2SPKeystoreService saml2SPKeystoreService = mock(WASAML2SPKeystoreService.class);
         when(saml2SPKeystoreService.getByOwner(anyString())).thenReturn(keystoreTO);
         when(saml2SPKeystoreService.set(any())).thenReturn(response);
 
@@ -63,14 +64,14 @@ public class SyncopeWASAML2ClientKeystoreGeneratorTest extends BaseSyncopeWASAML
             .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(), StandardCharsets.UTF_8))
             .build();
 
-        SAML2SPMetadataService saml2SPMetadataService = mock(SAML2SPMetadataService.class);
+        WASAML2SPMetadataService saml2SPMetadataService = mock(WASAML2SPMetadataService.class);
         when(saml2SPMetadataService.getByOwner(anyString())).thenReturn(metadataTO);
         when(saml2SPMetadataService.set(any())).thenReturn(response);
 
         SyncopeClient syncopeClient = mock(SyncopeClient.class);
 
-        when(syncopeClient.getService(SAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
-        when(syncopeClient.getService(SAML2SPKeystoreService.class)).thenReturn(saml2SPKeystoreService);
+        when(syncopeClient.getService(WASAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
+        when(syncopeClient.getService(WASAML2SPKeystoreService.class)).thenReturn(saml2SPKeystoreService);
 
         when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
         return restClient;
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGeneratorTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGeneratorTest.java
index 11d01ae..2acf6fb 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGeneratorTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2ClientMetadataGeneratorTest.java
@@ -23,7 +23,6 @@ import org.apache.commons.io.IOUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
@@ -45,6 +44,8 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
+
 public class SyncopeWASAML2ClientMetadataGeneratorTest extends BaseSyncopeWASAML2ClientTest {
     private static WARestClient getWaRestClient(final Response response) throws IOException {
         WARestClient restClient = mock(WARestClient.class);
@@ -53,12 +54,12 @@ public class SyncopeWASAML2ClientMetadataGeneratorTest extends BaseSyncopeWASAML
             .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(), StandardCharsets.UTF_8))
             .build();
 
-        SAML2SPMetadataService saml2SPMetadataService = mock(SAML2SPMetadataService.class);
+        WASAML2SPMetadataService saml2SPMetadataService = mock(WASAML2SPMetadataService.class);
         when(saml2SPMetadataService.getByOwner(anyString())).thenReturn(metadataTO);
         when(saml2SPMetadataService.set(any())).thenReturn(response);
 
         SyncopeClient syncopeClient = mock(SyncopeClient.class);
-        when(syncopeClient.getService(SAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
+        when(syncopeClient.getService(WASAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
         when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
         return restClient;
     }
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolverTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolverTest.java
index b7a630f..9a2b27b 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolverTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/SyncopeWASAML2MetadataResolverTest.java
@@ -22,7 +22,6 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 import org.apache.commons.io.IOUtils;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.SAML2SPMetadataTO;
-import org.apache.syncope.common.rest.api.service.wa.SAML2SPMetadataService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.pac4j.saml.client.SAML2Client;
@@ -40,6 +39,8 @@ import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPMetadataService;
+
 public class SyncopeWASAML2MetadataResolverTest extends BaseSyncopeWASAML2ClientTest {
     @Test
     public void fetchMetadata() throws Exception {
@@ -53,12 +54,12 @@ public class SyncopeWASAML2MetadataResolverTest extends BaseSyncopeWASAML2Client
             .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(), StandardCharsets.UTF_8))
             .build();
 
-        SAML2SPMetadataService saml2SPMetadataService = mock(SAML2SPMetadataService.class);
+        WASAML2SPMetadataService saml2SPMetadataService = mock(WASAML2SPMetadataService.class);
         when(saml2SPMetadataService.getByOwner(anyString())).thenReturn(metadataTO);
         when(saml2SPMetadataService.set(any())).thenReturn(Response.created(new URI("http://localhost:9080/syncop-wa")).build());
 
         SyncopeClient syncopeClient = mock(SyncopeClient.class);
-        when(syncopeClient.getService(SAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
+        when(syncopeClient.getService(WASAML2SPMetadataService.class)).thenReturn(saml2SPMetadataService);
         when(restClient.getSyncopeClient()).thenReturn(syncopeClient);
 
         SyncopeWASAML2MetadataResolver resolver = new SyncopeWASAML2MetadataResolver(restClient, client);
diff --git a/wa/starter/src/test/resources/dev/application-dev.properties b/wa/starter/src/test/resources/debug/application-debug.properties
similarity index 100%
rename from wa/starter/src/test/resources/dev/application-dev.properties
rename to wa/starter/src/test/resources/debug/application-debug.properties
diff --git a/wa/starter/src/test/resources/dev/keymaster.properties b/wa/starter/src/test/resources/debug/keymaster.properties
similarity index 100%
rename from wa/starter/src/test/resources/dev/keymaster.properties
rename to wa/starter/src/test/resources/debug/keymaster.properties
diff --git a/wa/starter/src/test/resources/dev/log4j2.xml b/wa/starter/src/test/resources/debug/log4j2.xml
similarity index 100%
rename from wa/starter/src/test/resources/dev/log4j2.xml
rename to wa/starter/src/test/resources/debug/log4j2.xml
diff --git a/wa/starter/src/test/resources/dev/wa.properties b/wa/starter/src/test/resources/debug/wa.properties
similarity index 96%
rename from wa/starter/src/test/resources/dev/wa.properties
rename to wa/starter/src/test/resources/debug/wa.properties
index dac755a..c44903d 100644
--- a/wa/starter/src/test/resources/dev/wa.properties
+++ b/wa/starter/src/test/resources/debug/wa.properties
@@ -22,7 +22,6 @@ useGZIPCompression=true
 # Conf directories
 conf.directory=${conf.directory}
 cas.standalone.configurationDirectory=${conf.directory}
-cas.authn.oidc.jwks.jwks-file=file:${conf.directory}/oidc.keystore
 
 cas.server.name=http://localhost:8080
 cas.server.prefix=${cas.server.name}/syncope-wa
@@ -30,6 +29,7 @@ cas.server.scope=syncope.org
 cas.authn.syncope.url=http://localhost:9080/syncope/rest/
 
 cas.tgc.secure=false
+cas.logout.follow-service-redirects=true
 
 cas.authn.saml-idp.entity-id=https://syncope.apache.org/saml