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 2025/05/09 13:01:12 UTC

(syncope) 02/02: [SYNCOPE-1877] Removing SAML2SPEntity and related (#1072)

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

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

commit 25fe08c0668b5804904ffececfef34caac5a04b6
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Fri May 9 14:58:28 2025 +0200

    [SYNCOPE-1877] Removing SAML2SPEntity and related (#1072)
    
    Signed-off-by: dependabot[bot] <su...@github.com>
    Co-authored-by: dependabot[bot] <49...@users.noreply.github.com>
---
 .../syncope/client/console/AMConsoleContext.java   |   7 -
 .../client/console/commons/AMConstants.java        |   2 -
 .../apache/syncope/client/console/pages/WA.java    |  11 +-
 .../syncope/client/console/panels/SAML2.java       |  81 --------
 .../panels/SAML2SPEntityDirectoryPanel.java        | 213 ---------------------
 .../console/rest/SAML2SPEntityRestClient.java      |  45 -----
 .../console/wizards/AuthModuleWizardBuilder.java   |  44 ++++-
 .../console/wizards/SAML2EntityWizardBuilder.java  |  65 -------
 .../wizards/SAML2IdPEntityWizardBuilder.java       |  32 +++-
 .../wizards/SAML2SPEntityWizardBuilder.java        | 111 -----------
 .../syncope/client/console/panels/SAML2.html       |  23 ---
 .../panels/SAML2SPEntityDirectoryPanel.properties  |  20 --
 .../SAML2SPEntityDirectoryPanel_fr_CA.properties   |  20 --
 .../SAML2SPEntityDirectoryPanel_it.properties      |  20 --
 .../SAML2SPEntityDirectoryPanel_ja.properties      |  20 --
 .../SAML2SPEntityDirectoryPanel_pt_BR.properties   |  20 --
 .../SAML2SPEntityDirectoryPanel_ru.properties      |  20 --
 ...uthModuleWizardBuilder$AuthModuleConfSAML.html} |   6 +-
 ...l => SAML2IdPEntityWizardBuilder$Metadata.html} |   0
 ...ml => SAML2IdPEntityWizardBuilder$TextPem.html} |   0
 .../common-ui/src/main/resources/MIMETypes.json    |   4 +
 .../wicket/markup/html/form/BinaryFieldPanel.java  |   6 +-
 .../common/lib/auth/SAML2IdPAuthModuleConf.java    |  72 ++++---
 .../syncope/common/lib/to/SAML2SPEntityTO.java     |  93 ---------
 .../syncope/common/lib/types/AMEntitlement.java    |   8 -
 .../syncope/common/lib/types/TriStateBoolean.java  |   9 +-
 .../rest/api/service/SAML2SPEntityService.java     |  92 ---------
 .../rest/api/service/wa/WASAML2SPService.java      |  58 ++++++
 .../apache/syncope/core/logic/AMLogicContext.java  |  11 --
 .../apache/syncope/core/logic/AuthModuleLogic.java |  62 ++++++
 .../syncope/core/logic/SAML2SPEntityLogic.java     | 103 ----------
 .../syncope/core/rest/cxf/AMRESTCXFContext.java    |  17 +-
 .../rest/cxf/service/SAML2SPEntityServiceImpl.java |  53 -----
 .../rest/cxf/service/wa/WASAML2SPServiceImpl.java  |  61 ++++++
 .../syncope/core/logic/ReconciliationLogic.java    |   5 +-
 .../apache/syncope/core/logic/ResourceLogic.java   |   1 -
 .../persistence/api/entity/am/SAML2SPEntity.java   |  32 ----
 .../src/main/resources/schema.xml                  |   8 +-
 .../core/persistence/jpa/PersistenceContext.java   |   8 -
 .../jpa/dao/repo/SAML2SPEntityRepo.java            |  28 ---
 .../jpa/entity/AbstractEntityFactory.java          |   4 -
 .../jpa/entity/am/JPASAML2SPEntity.java            |  64 -------
 .../persistence/jpa/inner/SAML2SPEntityTest.java   | 160 ----------------
 .../src/test/resources/domains/MasterContent.xml   |   2 +-
 .../core/persistence/neo4j/PersistenceContext.java |   8 -
 .../neo4j/dao/repo/SAML2SPEntityRepo.java          |  28 ---
 .../neo4j/entity/Neo4jEntityFactory.java           |   4 -
 .../neo4j/entity/am/Neo4jSAML2SPEntity.java        |  56 ------
 .../persistence/neo4j/inner/SAML2SPEntityTest.java | 158 ---------------
 .../src/test/resources/domains/MasterContent.xml   |   2 +-
 .../api/data/SAML2SPEntityDataBinder.java          |  31 ---
 .../provisioning/java/ProvisioningContext.java     |   8 -
 .../java/data/ResourceDataBinderImpl.java          |   2 -
 .../java/data/SAML2SPEntityDataBinderImpl.java     |  65 -------
 .../pushpull/DefaultUserPushResultHandler.java     |   1 -
 .../java/pushpull/OutboundMatcher.java             |   6 -
 .../org/apache/syncope/fit/AbstractITCase.java     |   4 -
 .../apache/syncope/fit/core/AuthModuleITCase.java  |  13 +-
 .../syncope/fit/core/SAML2SPEntityITCase.java      |  89 ---------
 .../mapping/AuthModulePropertySourceMapper.java    |   8 +-
 .../pac4j/saml/WASAML2ClientKeystoreGenerator.java |  32 ++--
 .../pac4j/saml/WASAML2ClientMetadataGenerator.java |  20 +-
 .../pac4j/saml/WASAML2MetadataResolver.java        |  10 +-
 .../wa/starter/SyncopeCoreTestingServer.java       |   2 +-
 .../starter/pac4j/saml/BaseWASAML2ClientTest.java  |  32 ++++
 .../pac4j/saml/WASAML2ClientCustomizerTest.java    |  26 +--
 .../saml/WASAML2ClientKeystoreGeneratorTest.java   |  31 +--
 .../saml/WASAML2ClientMetadataGeneratorTest.java   |  30 +--
 .../pac4j/saml/WASAML2MetadataResolverTest.java    |  26 +--
 69 files changed, 400 insertions(+), 2013 deletions(-)

diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java b/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java
index 46b94e1603..8d8b53f3bc 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java
@@ -33,7 +33,6 @@ import org.apache.syncope.client.console.rest.ClientAppRestClient;
 import org.apache.syncope.client.console.rest.OIDCJWKSRestClient;
 import org.apache.syncope.client.console.rest.PolicyRestClient;
 import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient;
-import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient;
 import org.apache.syncope.client.console.rest.SRARouteRestClient;
 import org.apache.syncope.client.console.rest.SRAStatisticsRestClient;
 import org.apache.syncope.client.console.rest.WAConfigRestClient;
@@ -100,12 +99,6 @@ public class AMConsoleContext {
         return new SAML2IdPEntityRestClient();
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityRestClient saml2SPEntityRestClient() {
-        return new SAML2SPEntityRestClient();
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SRARouteRestClient sraRouteRestClient() {
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
index 3f6af5ab8d..fcd7b3fc58 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java
@@ -36,8 +36,6 @@ public final class AMConstants {
 
     public static final String PREF_SAML2_IDP_ENTITY_PAGINATOR_ROWS = "saml2idpentity.properties.paginator.rows";
 
-    public static final String PREF_SAML2_SP_ENTITY_PAGINATOR_ROWS = "saml2spentity.properties.paginator.rows";
-
     public static final String PREF_AUTHPROFILE_PAGINATOR_ROWS = "authprofile.paginator.rows";
 
     public static final String PREF_AUTHPROFILE_IMPERSONATED_PAGINATOR_ROWS = "authprofile.impersonated.paginator.rows";
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
index 54b8ea45dd..88dd368310 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
@@ -39,12 +39,13 @@ import org.apache.syncope.client.console.panels.AMSessionPanel;
 import org.apache.syncope.client.console.panels.AttrRepoDirectoryPanel;
 import org.apache.syncope.client.console.panels.AuthModuleDirectoryPanel;
 import org.apache.syncope.client.console.panels.OIDC;
-import org.apache.syncope.client.console.panels.SAML2;
+import org.apache.syncope.client.console.panels.SAML2IdPEntityDirectoryPanel;
 import org.apache.syncope.client.console.panels.WAConfigDirectoryPanel;
 import org.apache.syncope.client.console.panels.WAPushModalPanel;
 import org.apache.syncope.client.console.rest.AttrRepoRestClient;
 import org.apache.syncope.client.console.rest.AuthModuleRestClient;
 import org.apache.syncope.client.console.rest.AuthProfileRestClient;
+import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient;
 import org.apache.syncope.client.console.rest.WAConfigRestClient;
 import org.apache.syncope.client.console.rest.WASessionRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
@@ -82,6 +83,9 @@ public class WA extends BasePage {
     @SpringBean
     protected AttrRepoRestClient attrRepoRestClient;
 
+    @SpringBean
+    protected SAML2IdPEntityRestClient saml2IdPEntityRestClient;
+
     @SpringBean
     protected ServiceOps serviceOps;
 
@@ -127,7 +131,7 @@ public class WA extends BasePage {
 
         if (!instances.isEmpty()) {
             String actuatorEndpoint = StringUtils.appendIfMissing(
-                instances.getFirst().getAddress(), "/") + "actuator/env";
+                    instances.getFirst().getAddress(), "/") + "actuator/env";
             try {
                 Response response = WebClientBuilder.build(actuatorEndpoint,
                         SyncopeWebApplication.get().getAnonymousUser(),
@@ -204,7 +208,8 @@ public class WA extends BasePage {
 
             @Override
             public Panel getPanel(final String panelId) {
-                return new SAML2(panelId, waPrefix, getPageReference());
+                return new SAML2IdPEntityDirectoryPanel(
+                        panelId, saml2IdPEntityRestClient, waPrefix, getPageReference());
             }
         });
 
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java
deleted file mode 100644
index 04fa7d2c50..0000000000
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.panels;
-
-import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient;
-import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient;
-import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.types.AMEntitlement;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
-import org.apache.wicket.extensions.markup.html.tabs.ITab;
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.spring.injection.annot.SpringBean;
-
-public class SAML2 extends Panel {
-
-    private static final long serialVersionUID = 7093557205333650002L;
-
-    @SpringBean
-    protected SAML2IdPEntityRestClient saml2IdPEntityRestClient;
-
-    @SpringBean
-    protected SAML2SPEntityRestClient saml2SPEntityRestClient;
-
-    public SAML2(final String id, final String waPrefix, final PageReference pageRef) {
-        super(id);
-
-        add(new AjaxBootstrapTabbedPanel<>("saml2", buildTabList(waPrefix, pageRef)));
-    }
-
-    protected List<ITab> buildTabList(final String waPrefix, final PageReference pageRef) {
-        List<ITab> tabs = new ArrayList<>();
-
-        if (SyncopeConsoleSession.get().owns(AMEntitlement.SAML2_IDP_ENTITY_LIST, SyncopeConstants.ROOT_REALM)) {
-            tabs.add(new AbstractTab(Model.of("Identity Provider")) {
-
-                private static final long serialVersionUID = 5211692813425391144L;
-
-                @Override
-                public Panel getPanel(final String panelId) {
-                    return new SAML2IdPEntityDirectoryPanel(panelId, saml2IdPEntityRestClient, waPrefix, pageRef);
-                }
-            });
-        }
-
-        if (SyncopeConsoleSession.get().owns(AMEntitlement.SAML2_SP_ENTITY_LIST, SyncopeConstants.ROOT_REALM)) {
-            tabs.add(new AbstractTab(Model.of("Service Provider")) {
-
-                private static final long serialVersionUID = 5211692813425391144L;
-
-                @Override
-                public Panel getPanel(final String panelId) {
-                    return new SAML2SPEntityDirectoryPanel(panelId, saml2SPEntityRestClient, waPrefix, pageRef);
-                }
-            });
-        }
-
-        return tabs;
-    }
-}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java
deleted file mode 100644
index 10f9940912..0000000000
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.panels;
-
-import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.commons.AMConstants;
-import org.apache.syncope.client.console.commons.DirectoryDataProvider;
-import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
-import org.apache.syncope.client.console.panels.SAML2SPEntityDirectoryPanel.SAML2SPEntityProvider;
-import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
-import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
-import org.apache.syncope.client.console.wizards.SAML2SPEntityWizardBuilder;
-import org.apache.syncope.client.ui.commons.Constants;
-import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
-import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.lib.types.AMEntitlement;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.event.Broadcast;
-import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
-import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.link.ExternalLink;
-import org.apache.wicket.markup.repeater.Item;
-import org.apache.wicket.model.CompoundPropertyModel;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.model.StringResourceModel;
-
-public class SAML2SPEntityDirectoryPanel extends DirectoryPanel<
-        SAML2SPEntityTO, SAML2SPEntityTO, SAML2SPEntityProvider, SAML2SPEntityRestClient> {
-
-    private static final long serialVersionUID = -3890622383545171017L;
-
-    private final String waPrefix;
-
-    public SAML2SPEntityDirectoryPanel(
-            final String id,
-            final SAML2SPEntityRestClient restClient,
-            final String waPrefix,
-            final PageReference pageRef) {
-
-        super(id, restClient, pageRef);
-        this.waPrefix = waPrefix;
-
-        disableCheckBoxes();
-
-        modal.size(Modal.Size.Large);
-        modal.addSubmitButton();
-
-        modal.setWindowClosedCallback(target -> {
-            updateResultTable(target);
-            modal.show(false);
-        });
-
-        addNewItemPanelBuilder(new SAML2SPEntityWizardBuilder(new SAML2SPEntityTO(), restClient, pageRef), true);
-
-        MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.SAML2_SP_ENTITY_SET);
-
-        initResultTable();
-    }
-
-    @Override
-    protected List<IColumn<SAML2SPEntityTO, String>> getColumns() {
-        List<IColumn<SAML2SPEntityTO, String>> columns = new ArrayList<>();
-
-        columns.add(new PropertyColumn<>(
-                new StringResourceModel(Constants.KEY_FIELD_NAME, this),
-                Constants.KEY_FIELD_NAME, Constants.KEY_FIELD_NAME));
-
-        columns.add(new AbstractColumn<>(Model.of("URL")) {
-
-            private static final long serialVersionUID = -7226955670801277153L;
-
-            @Override
-            public void populateItem(
-                    final Item<ICellPopulator<SAML2SPEntityTO>> cellItem,
-                    final String componentId,
-                    final IModel<SAML2SPEntityTO> rowModel) {
-
-                String metadataURL = waPrefix + "/sp/" + rowModel.getObject().getKey() + "/metadata";
-                cellItem.add(new ExternalLink(
-                        componentId,
-                        Model.of(metadataURL),
-                        Model.of(metadataURL)) {
-
-                    private static final long serialVersionUID = -1919646533527005367L;
-
-                    @Override
-                    protected void onComponentTag(final ComponentTag tag) {
-                        super.onComponentTag(tag);
-
-                        tag.setName("a");
-                        if (metadataURL.startsWith("http")) {
-                            tag.put("href", getDefaultModelObject().toString());
-                            tag.put("target", "_blank");
-                        }
-                    }
-                });
-            }
-        });
-
-        return columns;
-    }
-
-    @Override
-    protected ActionsPanel<SAML2SPEntityTO> getActions(final IModel<SAML2SPEntityTO> model) {
-        ActionsPanel<SAML2SPEntityTO> panel = super.getActions(model);
-
-        panel.add(new ActionLink<>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final SAML2SPEntityTO ignore) {
-                send(SAML2SPEntityDirectoryPanel.this, Broadcast.EXACT,
-                        new AjaxWizard.EditItemActionEvent<>(
-                                restClient.get(model.getObject().getKey()), target));
-            }
-        }, ActionLink.ActionType.EDIT, AMEntitlement.SAML2_SP_ENTITY_SET);
-
-        panel.add(new ActionLink<>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final SAML2SPEntityTO ignore) {
-                try {
-                    restClient.delete(model.getObject().getKey());
-
-                    SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
-                    target.add(container);
-                } catch (Exception e) {
-                    LOG.error("While deleting {}", model.getObject().getKey(), e);
-                    SyncopeConsoleSession.get().onException(e);
-                }
-                ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
-            }
-        }, ActionLink.ActionType.DELETE, AMEntitlement.AUTH_MODULE_DELETE, true);
-
-        return panel;
-    }
-
-    @Override
-    protected Collection<ActionLink.ActionType> getBatches() {
-        return List.of();
-    }
-
-    @Override
-    protected SAML2SPEntityProvider dataProvider() {
-        return new SAML2SPEntityProvider(rows);
-    }
-
-    @Override
-    protected String paginatorRowsKey() {
-        return AMConstants.PREF_SAML2_SP_ENTITY_PAGINATOR_ROWS;
-    }
-
-    protected final class SAML2SPEntityProvider extends DirectoryDataProvider<SAML2SPEntityTO> {
-
-        private static final long serialVersionUID = 5282134321828253058L;
-
-        private final SortableDataProviderComparator<SAML2SPEntityTO> comparator;
-
-        public SAML2SPEntityProvider(final int paginatorRows) {
-            super(paginatorRows);
-            comparator = new SortableDataProviderComparator<>(this);
-        }
-
-        @Override
-        public Iterator<? extends SAML2SPEntityTO> iterator(final long first, final long count) {
-            List<SAML2SPEntityTO> sps = restClient.list();
-            sps.sort(comparator);
-            return sps.subList((int) first, (int) first + (int) count).iterator();
-        }
-
-        @Override
-        public long size() {
-            return restClient.list().size();
-        }
-
-        @Override
-        public IModel<SAML2SPEntityTO> model(final SAML2SPEntityTO metadata) {
-            return new CompoundPropertyModel<>(metadata);
-        }
-    }
-}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java
deleted file mode 100644
index 42873a25a3..0000000000
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.rest;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-
-public class SAML2SPEntityRestClient extends BaseRestClient {
-
-    private static final long serialVersionUID = -1392090291817187902L;
-
-    public List<SAML2SPEntityTO> list() {
-        return new ArrayList<>(getService(SAML2SPEntityService.class).list());
-    }
-
-    public SAML2SPEntityTO get(final String key) {
-        return getService(SAML2SPEntityService.class).get(key);
-    }
-
-    public void set(final SAML2SPEntityTO entityTO) {
-        getService(SAML2SPEntityService.class).set(entityTO);
-    }
-
-    public void delete(final String key) {
-        getService(SAML2SPEntityService.class).delete(key);
-    }
-}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java
index a0b7317bf4..2dac0c7875 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java
@@ -25,6 +25,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.SyncopeWebApplication;
 import org.apache.syncope.client.console.panels.BeanPanel;
 import org.apache.syncope.client.console.rest.AuthModuleRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
 import org.apache.syncope.client.console.wizards.mapping.AuthModuleMappingPanel;
 import org.apache.syncope.client.ui.commons.Constants;
 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
@@ -36,6 +38,7 @@ import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
 import org.apache.syncope.common.lib.AbstractLDAPConf;
 import org.apache.syncope.common.lib.auth.AuthModuleConf;
 import org.apache.syncope.common.lib.auth.LDAPDependantAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
 import org.apache.syncope.common.lib.types.AuthModuleState;
 import org.apache.wicket.PageReference;
@@ -92,6 +95,7 @@ public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder<AuthModuleTO>
         wizardModel.add(new Profile(modelObject, authModuleConfs, authModuleConfClass));
         wizardModel.add(new Configuration(modelObject));
         wizardModel.add(new AuthModuleConfLDAP(modelObject, authModuleConfClass));
+        wizardModel.add(new AuthModuleConfSAML(modelObject, authModuleConfClass));
         wizardModel.add(new Mapping(modelObject));
         return wizardModel;
     }
@@ -170,8 +174,44 @@ public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder<AuthModuleTO>
         private static final long serialVersionUID = -785981096328637758L;
 
         Configuration(final AuthModuleTO authModule) {
-            add(new BeanPanel<>("bean", new PropertyModel<>(authModule, "conf"), pageRef, "ldap").
-                    setRenderBodyOnly(true));
+            add(new BeanPanel<>("bean", new PropertyModel<>(authModule, "conf"), pageRef,
+                    "ldap", "keystore", "serviceProviderMetadata").setRenderBodyOnly(true));
+        }
+    }
+
+    protected class AuthModuleConfSAML extends WizardStep implements WizardModel.ICondition {
+
+        private static final long serialVersionUID = 8139350816753061469L;
+
+        private final Model<Class<? extends AuthModuleConf>> authModuleConfClass;
+
+        AuthModuleConfSAML(
+                final AuthModuleTO authModule,
+                final Model<Class<? extends AuthModuleConf>> authModuleConfClass) {
+
+            this.authModuleConfClass = authModuleConfClass;
+
+            add(new BinaryFieldPanel(
+                    "keystore",
+                    "",
+                    new PropertyModel<>(authModule, "conf.keystore"),
+                    "application/x-java-keystore",
+                    authModule.getKey()) {
+
+                private static final long serialVersionUID = -3268213909514986831L;
+
+                @Override
+                protected PageReference getPageReference() {
+                    return pageRef;
+                }
+            });
+            add(new XMLEditorPanel(null,
+                    new PropertyModel<>(authModule, "conf.serviceProviderMetadata"), false, pageRef));
+        }
+
+        @Override
+        public boolean evaluate() {
+            return SAML2IdPAuthModuleConf.class.isAssignableFrom(authModuleConfClass.getObject());
         }
     }
 
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder.java
deleted file mode 100644
index 0e7393a5ab..0000000000
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.wizards;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
-import org.apache.syncope.common.lib.to.SAML2EntityTO;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.extensions.wizard.WizardStep;
-import org.apache.wicket.model.PropertyModel;
-
-abstract class SAML2EntityWizardBuilder<T extends SAML2EntityTO> extends BaseAjaxWizardBuilder<T> {
-
-    private static final long serialVersionUID = 1L;
-
-    protected SAML2EntityWizardBuilder(final T defaultItem, final PageReference pageRef) {
-        super(defaultItem, pageRef);
-    }
-
-    protected class Metadata extends WizardStep {
-
-        private static final long serialVersionUID = -3043839139187792810L;
-
-        Metadata(final T entity, final PageReference pageRef) {
-            add(new XMLEditorPanel(null, new PropertyModel<>(entity, "metadata"), false, pageRef));
-        }
-
-        @Override
-        public String getTitle() {
-            return "Metadata";
-        }
-    }
-
-    protected abstract class Pem extends WizardStep {
-
-        private static final long serialVersionUID = -3043839139187792810L;
-
-        protected final String property;
-
-        Pem(final String property) {
-            this.property = property;
-        }
-
-        @Override
-        public String getTitle() {
-            return StringUtils.capitalize(property);
-        }
-    }
-}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java
index 9d88b52989..2e3c7ced70 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java
@@ -21,14 +21,17 @@ package org.apache.syncope.client.console.wizards;
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.TextEditorPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
 import org.apache.syncope.common.lib.to.SAML2IdPEntityTO;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
 import org.apache.wicket.model.PropertyModel;
 
-public class SAML2IdPEntityWizardBuilder extends SAML2EntityWizardBuilder<SAML2IdPEntityTO> {
+public class SAML2IdPEntityWizardBuilder extends BaseAjaxWizardBuilder<SAML2IdPEntityTO> {
 
     private static final long serialVersionUID = -8013493490328546125L;
 
@@ -100,14 +103,35 @@ public class SAML2IdPEntityWizardBuilder extends SAML2EntityWizardBuilder<SAML2I
         return wizardModel;
     }
 
-    protected class TextPem extends Pem {
+    protected class Metadata extends WizardStep {
 
-        private static final long serialVersionUID = 1L;
+        private static final long serialVersionUID = -3043839139187792810L;
+
+        Metadata(final SAML2IdPEntityTO entity, final PageReference pageRef) {
+            add(new XMLEditorPanel(null, new PropertyModel<>(entity, "metadata"), false, pageRef));
+        }
+
+        @Override
+        public String getTitle() {
+            return "Metadata";
+        }
+    }
+
+    protected class TextPem extends WizardStep {
+
+        private static final long serialVersionUID = -3713108738476604821L;
+
+        protected final String property;
 
         public TextPem(final SAML2IdPEntityTO entity, final String property, final PageReference pageRef) {
-            super(property);
+            this.property = property;
 
             add(new TextEditorPanel(null, new PropertyModel<>(entity, property), false, pageRef));
         }
+
+        @Override
+        public String getTitle() {
+            return StringUtils.capitalize(property);
+        }
     }
 }
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java
deleted file mode 100644
index d326218945..0000000000
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.wizards;
-
-import jakarta.ws.rs.core.MediaType;
-import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
-import org.apache.syncope.client.ui.commons.Constants;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.extensions.wizard.WizardModel;
-import org.apache.wicket.extensions.wizard.WizardStep;
-import org.apache.wicket.model.PropertyModel;
-
-public class SAML2SPEntityWizardBuilder extends SAML2EntityWizardBuilder<SAML2SPEntityTO> {
-
-    private static final long serialVersionUID = 2400472385439304277L;
-
-    protected final SAML2SPEntityRestClient saml2SPEntityRestClient;
-
-    public SAML2SPEntityWizardBuilder(
-            final SAML2SPEntityTO defaultItem,
-            final SAML2SPEntityRestClient saml2SPEntityRestClient,
-            final PageReference pageRef) {
-
-        super(defaultItem, pageRef);
-        this.saml2SPEntityRestClient = saml2SPEntityRestClient;
-    }
-
-    @Override
-    protected Serializable onApplyInternal(final SAML2SPEntityTO modelObject) {
-        if (modelObject.getMetadata() != null) {
-            modelObject.setMetadata(Base64.getEncoder().encodeToString(
-                    modelObject.getMetadata().getBytes(StandardCharsets.UTF_8)));
-        }
-        saml2SPEntityRestClient.set(modelObject);
-        return modelObject;
-    }
-
-    @Override
-    protected WizardModel buildModelSteps(final SAML2SPEntityTO modelObject, final WizardModel wizardModel) {
-        if (modelObject.getMetadata() != null) {
-            modelObject.setMetadata(new String(Base64.getDecoder().decode(
-                    modelObject.getMetadata()), StandardCharsets.UTF_8));
-        }
-
-        wizardModel.add(new Profile(modelObject, mode == AjaxWizard.Mode.CREATE));
-        wizardModel.add(new Metadata(modelObject, pageRef));
-        wizardModel.add(new BinaryPem(modelObject, "keystore", pageRef));
-        return wizardModel;
-    }
-
-    protected static class Profile extends WizardStep {
-
-        private static final long serialVersionUID = -3043839139187792810L;
-
-        Profile(final SAML2SPEntityTO entity, final boolean isNew) {
-            AjaxTextFieldPanel key = new AjaxTextFieldPanel(
-                    Constants.KEY_FIELD_NAME, Constants.KEY_FIELD_NAME,
-                    new PropertyModel<>(entity, Constants.KEY_FIELD_NAME));
-            key.addRequiredLabel();
-            key.setEnabled(isNew);
-            add(key);
-        }
-    }
-
-    protected class BinaryPem extends Pem {
-
-        private static final long serialVersionUID = 1L;
-
-        public BinaryPem(final SAML2SPEntityTO entity, final String property, final PageReference pageRef) {
-            super(property);
-
-            add(new BinaryFieldPanel(
-                    "content",
-                    "",
-                    new PropertyModel<>(entity, property),
-                    MediaType.APPLICATION_OCTET_STREAM,
-                    entity.getKey()) {
-
-                private static final long serialVersionUID = -3268213909514986831L;
-
-                @Override
-                protected PageReference getPageReference() {
-                    return pageRef;
-                }
-            });
-        }
-    }
-}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2.html
deleted file mode 100644
index a82819c549..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2.html
+++ /dev/null
@@ -1,23 +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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
-    <div wicket:id="saml2"/>
-  </wicket:panel>
-</html>
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.properties
deleted file mode 100644
index 5289997f8c..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=Edit ${key}
-any.new=New SP Entity
-any.finish=Submit ${key}
-any.cancel=Cancel ${key}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_fr_CA.properties
deleted file mode 100644
index c8a88c81ca..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_fr_CA.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=Modifier ${key}
-any.new=New SP Entity
-any.finish=Soumettre ${key}
-any.cancel=Annuler ${key}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_it.properties
deleted file mode 100644
index 9129629c7a..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_it.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=Modifica ${key}
-any.new=Nuova Entit\u00e0 SP
-any.finish=Invia ${key}
-any.cancel=Annulla ${key}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ja.properties
deleted file mode 100644
index cf51cb13e1..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ja.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=${key} \u3092\u7de8\u96c6
-any.new=New SP Entity
-any.finish=${key} \u3092\u5b9f\u884c
-any.cancel=${key} \u3092\u30ad\u30e3\u30f3\u30bb\u30eb
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_pt_BR.properties
deleted file mode 100644
index 5289997f8c..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_pt_BR.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=Edit ${key}
-any.new=New SP Entity
-any.finish=Submit ${key}
-any.cancel=Cancel ${key}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ru.properties
deleted file mode 100644
index 651eac5cc6..0000000000
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel_ru.properties
+++ /dev/null
@@ -1,20 +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.
-any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c ${key}
-any.new=New SP Entity
-any.finish=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c ${key}
-any.cancel=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c ${key}
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder$Profile.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfSAML.html
similarity index 84%
rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder$Profile.html
rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfSAML.html
index 993f7801bf..ddacc6fb1b 100644
--- a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder$Profile.html
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfSAML.html
@@ -18,6 +18,10 @@ under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
   <wicket:panel>
-    <div class="form-group"><span wicket:id="key">[key]</span></div>
+    <label class="form-label">Keystore</label>
+    <div wicket:id="keystore"/>
+    
+    <label class="form-label">SP Metadata</label>
+    <div wicket:id="content"/>
   </wicket:panel>
 </html>
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder$Metadata.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder$Metadata.html
similarity index 100%
rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder$Metadata.html
rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder$Metadata.html
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder$Pem.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder$TextPem.html
similarity index 100%
rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2EntityWizardBuilder$Pem.html
rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder$TextPem.html
diff --git a/client/idrepo/common-ui/src/main/resources/MIMETypes.json b/client/idrepo/common-ui/src/main/resources/MIMETypes.json
index e7e36820f0..5d7b638765 100644
--- a/client/idrepo/common-ui/src/main/resources/MIMETypes.json
+++ b/client/idrepo/common-ui/src/main/resources/MIMETypes.json
@@ -84,6 +84,10 @@
   {
     "name": "application/java-byte-code"
   },
+  {
+    "name": "application/x-java-keystore",
+    "extension": "jks"
+  },
   {
     "name": "application/javascript"
   },
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
index fdc90afd26..69e38e9d7e 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/BinaryFieldPanel.java
@@ -216,7 +216,11 @@ public class BinaryFieldPanel extends BaseBinaryFieldPanel {
     }
 
     protected Response buildResponse() {
-        return Response.ok(new ByteArrayInputStream(Base64.getMimeDecoder().decode(getModelObject()))).
+        byte[] content = Optional.ofNullable(getModelObject()).
+                map(modelObject -> Base64.getMimeDecoder().decode(modelObject)).
+                orElseGet(() -> new byte[0]);
+
+        return Response.ok(new ByteArrayInputStream(content)).
                 type(StringUtils.isBlank(mimeType) ? MediaType.APPLICATION_OCTET_STREAM : mimeType).
                 header(HttpHeaders.LOCATION, StringUtils.EMPTY).
                 build();
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java
index b78b3a2010..35e4e0c839 100644
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/SAML2IdPAuthModuleConf.java
@@ -23,33 +23,27 @@ import java.util.List;
 import java.util.Map;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
+import org.apache.syncope.common.lib.types.TriStateBoolean;
 
 public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthModuleConf {
 
     private static final long serialVersionUID = -471527731042579422L;
 
     /**
-     * The attribute value that should be used
-     * for the authenticated username, upon a successful authentication
+     * The attribute value that should be used for the authenticated username, upon a successful authentication
      * attempt.
      */
     protected String userIdAttribute;
 
     /**
-     * The destination binding to use
-     * when creating authentication requests.
+     * The destination binding to use when creating authentication requests.
      */
     protected SAML2BindingType destinationBinding = SAML2BindingType.REDIRECT;
 
     /**
-     * The Service Provider metadata path.
+     * Base64-encoded keystore content..
      */
-    protected String serviceProviderMetadataPath;
-
-    /**
-     * The path to the keystore.
-     */
-    protected String keystorePath;
+    protected String keystore;
 
     /**
      * The password to use when generating the SP keystore.
@@ -59,7 +53,12 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
     /**
      * The password to use when generating the private key for the SP keystore.
      */
-    protected String protectedKeyPassword;
+    protected String privateKeyPassword;
+
+    /**
+     * Base64-encoded SP metadata content.
+     */
+    protected String serviceProviderMetadata;
 
     /**
      * The metadata location of the identity provider that is to handle authentications.
@@ -67,11 +66,10 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
     protected String identityProviderMetadataPath;
 
     /**
-     * Flag to indicate whether the allow-create flags
-     * for nameid policies should be set to true, false or ignored/defined.
-     * Accepted values are true, false or undefined.
+     * Flag to indicate whether the allow-create flags for nameid policies should be set to true, false or
+     * ignored/undefined.
      */
-    protected String nameIdPolicyAllowCreate = "undefined";
+    protected TriStateBoolean nameIdPolicyAllowCreate = TriStateBoolean.TRUE;
 
     /**
      * Once you have an authenticated session on the identity provider, usually it won't prompt you again to enter your
@@ -149,8 +147,7 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
     protected int assertionConsumerServiceIndex = -1;
 
     /**
-     * Whether name qualifiers should be produced
-     * in the final saml response.
+     * Whether name qualifiers should be produced in the final saml response.
      */
     protected boolean useNameQualifier = true;
 
@@ -191,8 +188,7 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
 
     /**
      * Provider name set for the saml authentication request.
-     * Sets the human-readable name of the requester for use by
-     * the presenter's user agent or the identity provider.
+     * Sets the human-readable name of the requester for use by the presenter's user agent or the identity provider.
      */
     protected String providerName;
 
@@ -212,36 +208,36 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
         this.destinationBinding = destinationBinding;
     }
 
-    public String getServiceProviderMetadataPath() {
-        return serviceProviderMetadataPath;
+    public String getKeystorePassword() {
+        return keystorePassword;
     }
 
-    public void setServiceProviderMetadataPath(final String serviceProviderMetadataPath) {
-        this.serviceProviderMetadataPath = serviceProviderMetadataPath;
+    public void setKeystorePassword(final String keystorePassword) {
+        this.keystorePassword = keystorePassword;
     }
 
-    public String getKeystorePath() {
-        return keystorePath;
+    public String getPrivateKeyPassword() {
+        return privateKeyPassword;
     }
 
-    public void setKeystorePath(final String keystorePath) {
-        this.keystorePath = keystorePath;
+    public void setPrivateKeyPassword(final String privateKeyPassword) {
+        this.privateKeyPassword = privateKeyPassword;
     }
 
-    public String getKeystorePassword() {
-        return keystorePassword;
+    public String getKeystore() {
+        return keystore;
     }
 
-    public void setKeystorePassword(final String keystorePassword) {
-        this.keystorePassword = keystorePassword;
+    public void setKeystore(final String keystore) {
+        this.keystore = keystore;
     }
 
-    public String getPrivateKeyPassword() {
-        return protectedKeyPassword;
+    public String getServiceProviderMetadata() {
+        return serviceProviderMetadata;
     }
 
-    public void setPrivateKeyPassword(final String protectedKeyPassword) {
-        this.protectedKeyPassword = protectedKeyPassword;
+    public void setServiceProviderMetadata(final String serviceProviderMetadata) {
+        this.serviceProviderMetadata = serviceProviderMetadata;
     }
 
     public String getIdentityProviderMetadataPath() {
@@ -292,11 +288,11 @@ public class SAML2IdPAuthModuleConf extends Pac4jAuthModuleConf implements AuthM
         this.passive = passive;
     }
 
-    public String getNameIdPolicyAllowCreate() {
+    public TriStateBoolean getNameIdPolicyAllowCreate() {
         return nameIdPolicyAllowCreate;
     }
 
-    public void setNameIdPolicyAllowCreate(final String nameIdPolicyAllowCreate) {
+    public void setNameIdPolicyAllowCreate(final TriStateBoolean nameIdPolicyAllowCreate) {
         this.nameIdPolicyAllowCreate = nameIdPolicyAllowCreate;
     }
 
diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/SAML2SPEntityTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/SAML2SPEntityTO.java
deleted file mode 100644
index ee1f1d8190..0000000000
--- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/SAML2SPEntityTO.java
+++ /dev/null
@@ -1,93 +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.to;
-
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-
-public class SAML2SPEntityTO extends SAML2EntityTO {
-
-    private static final long serialVersionUID = 6215073386484048953L;
-
-    public static class Builder extends SAML2EntityTO.Builder<SAML2SPEntityTO, Builder> {
-
-        @Override
-        protected SAML2SPEntityTO newInstance() {
-            return new SAML2SPEntityTO();
-        }
-
-        public Builder keystore(final String keystore) {
-            getInstance().setKeystore(keystore);
-            return this;
-        }
-
-        public Builder metadata(final String metadata) {
-            getInstance().setMetadata(metadata);
-            return this;
-        }
-    }
-
-    private String keystore;
-
-    private String metadata;
-
-    public String getKeystore() {
-        return keystore;
-    }
-
-    public void setKeystore(final String keystore) {
-        this.keystore = keystore;
-    }
-
-    public String getMetadata() {
-        return metadata;
-    }
-
-    public void setMetadata(final String metadata) {
-        this.metadata = metadata;
-    }
-
-    @Override
-    public int hashCode() {
-        return new HashCodeBuilder().
-                appendSuper(super.hashCode()).
-                append(keystore).
-                append(metadata).
-                build();
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        SAML2SPEntityTO other = (SAML2SPEntityTO) obj;
-        return new EqualsBuilder().
-                appendSuper(super.equals(obj)).
-                append(keystore, other.keystore).
-                append(metadata, other.metadata).
-                build();
-    }
-}
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 7b914dff91..ceae04b368 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
@@ -74,14 +74,6 @@ public final class AMEntitlement {
 
     public static final String SAML2_IDP_ENTITY_GET = "SAML2_IDP_ENTITY_GET";
 
-    public static final String SAML2_SP_ENTITY_SET = "SAML2_SP_ENTITY_SET";
-
-    public static final String SAML2_SP_ENTITY_DELETE = "SAML2_SP_ENTITY_DELETE";
-
-    public static final String SAML2_SP_ENTITY_LIST = "SAML2_SP_ENTITY_LIST";
-
-    public static final String SAML2_SP_ENTITY_GET = "SAML2_SP_ENTITY_GET";
-
     public static final String AUTH_PROFILE_DELETE = "AUTH_PROFILE_DELETE";
 
     public static final String AUTH_PROFILE_CREATE = "AUTH_PROFILE_CREATE";
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/SAML2SPEntityDAO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/TriStateBoolean.java
similarity index 81%
rename from core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/SAML2SPEntityDAO.java
rename to common/am/lib/src/main/java/org/apache/syncope/common/lib/types/TriStateBoolean.java
index 567c00b2f6..0639751737 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/SAML2SPEntityDAO.java
+++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/TriStateBoolean.java
@@ -16,9 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.syncope.core.persistence.api.dao;
+package org.apache.syncope.common.lib.types;
 
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
+public enum TriStateBoolean {
+
+    TRUE,
+    FALSE,
+    UNDEFINED;
 
-public interface SAML2SPEntityDAO extends DAO<SAML2SPEntity> {
 }
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPEntityService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPEntityService.java
deleted file mode 100644
index 1aae8f1453..0000000000
--- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SAML2SPEntityService.java
+++ /dev/null
@@ -1,92 +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.rest.api.service;
-
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.enums.ParameterIn;
-import io.swagger.v3.oas.annotations.media.Schema;
-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 jakarta.validation.constraints.NotNull;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.MediaType;
-import java.util.List;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-
-/**
- * REST operations for SAML 2.0 SP entity.
- */
-@Tag(name = "SAML 2.0")
-@SecurityRequirements({
-    @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer") })
-@Path("saml2/sp")
-public interface SAML2SPEntityService extends JAXRSService {
-
-    /**
-     * Returns the SAML 2.0 SP entities.
-     *
-     * @return SAML 2.0 SP entities
-     */
-    @GET
-    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    List<SAML2SPEntityTO> list();
-
-    /**
-     * Returns the SAML 2.0 SP entity matching the given key.
-     *
-     * @param key key of requested SAML 2.0 SP entity
-     * @return SAML 2.0 SP entity with matching key
-     */
-    @GET
-    @Path("{key}")
-    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    SAML2SPEntityTO get(@NotNull @PathParam("key") String key);
-
-    /**
-     * Store the entity to finalize the generation process.
-     *
-     * @param entityTO entity to be created
-     */
-    @Parameter(name = "key", description = "SAML2SPEntityTO's key", in = ParameterIn.PATH, schema =
-            @Schema(type = "string"))
-    @POST
-    @Path("{key}")
-    @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    void set(@NotNull SAML2SPEntityTO entityTO);
-
-    /**
-     * Delets the SAML 2.0 SP entity matching the given key.
-     *
-     * @param key key of requested SAML 2.0 SP entity
-     */
-    @DELETE
-    @Path("{key}")
-    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    void delete(@NotNull @PathParam("key") String key);
-}
diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPService.java
new file mode 100644
index 0000000000..850cdbe189
--- /dev/null
+++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/WASAML2SPService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.rest.api.service.wa;
+
+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 jakarta.validation.constraints.NotNull;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Response;
+import java.io.InputStream;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
+
+/**
+ * REST operations for WA to work with SAML2SP clients.
+ */
+@Tag(name = "WA")
+@SecurityRequirements({
+    @SecurityRequirement(name = "BasicAuthentication"),
+    @SecurityRequirement(name = "Bearer") })
+@Path("wa/saml2sp")
+public interface WASAML2SPService extends JAXRSService {
+
+    @GET
+    @Path("{clientName}/keystore")
+    Response getSAML2SPKeystore(@NotNull @PathParam("clientName") String clientName);
+
+    @PUT
+    @Path("{clientName}/keystore")
+    void setSAML2SPKeystore(@NotNull @PathParam("clientName") String clientName, InputStream keystore);
+
+    @GET
+    @Path("{clientName}/metadata")
+    Response getSAML2SPMetadata(@NotNull @PathParam("clientName") String clientName);
+
+    @PUT
+    @Path("{clientName}/metadata")
+    void setSAML2SPMetadata(@NotNull @PathParam("clientName") String clientName, InputStream metadata);
+}
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AMLogicContext.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AMLogicContext.java
index ce6fb71ab3..bdff58a04e 100644
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AMLogicContext.java
+++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AMLogicContext.java
@@ -35,7 +35,6 @@ import org.apache.syncope.core.persistence.api.dao.OIDCJWKSDAO;
 import org.apache.syncope.core.persistence.api.dao.OIDCRPClientAppDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2IdPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2SPClientAppDAO;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SRARouteDAO;
 import org.apache.syncope.core.persistence.api.dao.WAConfigDAO;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
@@ -46,7 +45,6 @@ import org.apache.syncope.core.provisioning.api.data.AuthProfileDataBinder;
 import org.apache.syncope.core.provisioning.api.data.ClientAppDataBinder;
 import org.apache.syncope.core.provisioning.api.data.OIDCJWKSDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SAML2IdPEntityDataBinder;
-import org.apache.syncope.core.provisioning.api.data.SAML2SPEntityDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SRARouteDataBinder;
 import org.apache.syncope.core.provisioning.api.data.WAConfigDataBinder;
 import org.apache.syncope.core.provisioning.api.data.wa.WAClientAppDataBinder;
@@ -130,15 +128,6 @@ public class AMLogicContext {
         return new SAML2IdPEntityLogic(binder, saml2IdPEntityDAO);
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityLogic saml2SPEntityLogic(
-            final SAML2SPEntityDataBinder binder,
-            final SAML2SPEntityDAO saml2SPEntityDAO) {
-
-        return new SAML2SPEntityLogic(binder, saml2SPEntityDAO);
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SRARouteLogic sraRouteLogic(
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 8c8a17960a..0d547fa85a 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
@@ -18,11 +18,19 @@
  */
 package org.apache.syncope.core.logic;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.Objects;
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.auth.Pac4jAuthModuleConf;
+import org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf;
 import org.apache.syncope.common.lib.to.AuthModuleTO;
 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.core.persistence.api.dao.AuthModuleDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -81,6 +89,60 @@ public class AuthModuleLogic extends AbstractTransactionalLogic<AuthModuleTO> {
         return deleted;
     }
 
+    protected AuthModule readByClientName(final String clientName) {
+        return authModuleDAO.findAll().stream().
+                filter(m -> m.getConf() instanceof Pac4jAuthModuleConf conf
+                && (Objects.equals(clientName, conf.getClientName())
+                || Objects.equals(clientName, m.getKey()))).findFirst().
+                orElseThrow(() -> new NotFoundException("AuthModule with client name " + clientName));
+    }
+
+    @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    @Transactional(readOnly = true)
+    public SAML2IdPAuthModuleConf readSAML2SPConf(final String clientName) {
+        AuthModule authModule = readByClientName(clientName);
+
+        return (SAML2IdPAuthModuleConf) authModule.getConf();
+    }
+
+    @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    public void setSAML2SPKeystore(final String clientName, final InputStream keystore) {
+        AuthModule authModule = readByClientName(clientName);
+        SAML2IdPAuthModuleConf conf = (SAML2IdPAuthModuleConf) authModule.getConf();
+
+        try {
+            conf.setKeystore(new String(keystore.readAllBytes(), StandardCharsets.UTF_8));
+            authModule.setConf(conf);
+
+            authModuleDAO.save(authModule);
+        } catch (IOException e) {
+            LOG.error("While reading the provided keystore", e);
+
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidEntity);
+            sce.getElements().add(e.getMessage());
+            throw sce;
+        }
+    }
+
+    @PreAuthorize("hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
+    public void setSAML2SPMetadata(final String clientName, final InputStream metadata) {
+        AuthModule authModule = readByClientName(clientName);
+        SAML2IdPAuthModuleConf conf = (SAML2IdPAuthModuleConf) authModule.getConf();
+
+        try {
+            conf.setServiceProviderMetadata(new String(metadata.readAllBytes(), StandardCharsets.UTF_8));
+            authModule.setConf(conf);
+
+            authModuleDAO.save(authModule);
+        } catch (IOException e) {
+            LOG.error("While reading the provided metadata", e);
+
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidEntity);
+            sce.getElements().add(e.getMessage());
+            throw sce;
+        }
+    }
+
     @Override
     protected AuthModuleTO resolveReference(final Method method, final Object... args)
             throws UnresolvedReferenceException {
diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPEntityLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPEntityLogic.java
deleted file mode 100644
index 1373489123..0000000000
--- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPEntityLogic.java
+++ /dev/null
@@ -1,103 +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.core.logic;
-
-import java.lang.reflect.Method;
-import java.util.List;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.lib.types.AMEntitlement;
-import org.apache.syncope.common.lib.types.IdRepoEntitlement;
-import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.provisioning.api.data.SAML2SPEntityDataBinder;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.transaction.annotation.Transactional;
-
-public class SAML2SPEntityLogic extends AbstractTransactionalLogic<SAML2SPEntityTO> {
-
-    protected final SAML2SPEntityDataBinder binder;
-
-    protected final SAML2SPEntityDAO saml2SPEntityDAO;
-
-    public SAML2SPEntityLogic(final SAML2SPEntityDataBinder binder, final SAML2SPEntityDAO saml2SPEntityDAO) {
-        this.binder = binder;
-        this.saml2SPEntityDAO = saml2SPEntityDAO;
-    }
-
-    @PreAuthorize("hasRole('" + AMEntitlement.SAML2_SP_ENTITY_LIST + "')")
-    @Transactional(readOnly = true)
-    public List<SAML2SPEntityTO> list() {
-        return saml2SPEntityDAO.findAll().stream().
-                map(binder::getSAML2SPEntityTO).
-                toList();
-    }
-
-    @PreAuthorize("hasRole('" + AMEntitlement.SAML2_SP_ENTITY_GET + "') "
-            + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    @Transactional(readOnly = true)
-    public SAML2SPEntityTO read(final String key) {
-        return saml2SPEntityDAO.findById(key).
-                map(binder::getSAML2SPEntityTO).
-                orElseThrow(() -> new NotFoundException(key + " not found"));
-    }
-
-    @PreAuthorize("hasRole('" + AMEntitlement.SAML2_SP_ENTITY_SET + "') "
-            + "or hasRole('" + IdRepoEntitlement.ANONYMOUS + "')")
-    public SAML2SPEntityTO set(final SAML2SPEntityTO entityTO) {
-        SAML2SPEntity entity = saml2SPEntityDAO.findById(entityTO.getKey()).
-                map(metadata -> binder.update(metadata, entityTO)).
-                orElseGet(() -> binder.create(entityTO));
-        return binder.getSAML2SPEntityTO(saml2SPEntityDAO.save(entity));
-    }
-
-    @PreAuthorize("hasRole('" + AMEntitlement.SAML2_SP_ENTITY_DELETE + "')")
-    public void delete(final String key) {
-        saml2SPEntityDAO.findById(key).ifPresentOrElse(
-                saml2SPEntityDAO::delete,
-                () -> new NotFoundException("SAML SP " + key));
-    }
-
-    @Override
-    protected SAML2SPEntityTO resolveReference(final Method method, final Object... args)
-            throws UnresolvedReferenceException {
-
-        String key = null;
-        if (ArrayUtils.isNotEmpty(args)) {
-            for (int i = 0; key == null && i < args.length; i++) {
-                if (args[i] instanceof String string) {
-                    key = string;
-                } else if (args[i] instanceof SAML2SPEntityTO saml2SPEntityTO) {
-                    key = saml2SPEntityTO.getKey();
-                }
-            }
-        }
-
-        if (key != null) {
-            try {
-                return binder.getSAML2SPEntityTO(saml2SPEntityDAO.findById(key).orElseThrow());
-            } catch (Throwable ignore) {
-                LOG.debug("Unresolved reference", ignore);
-                throw new UnresolvedReferenceException(ignore);
-            }
-        }
-        throw new UnresolvedReferenceException();
-    }
-}
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java
index bcae28de55..3ca003d1d7 100644
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java
@@ -24,7 +24,6 @@ import org.apache.syncope.common.rest.api.service.AuthProfileService;
 import org.apache.syncope.common.rest.api.service.ClientAppService;
 import org.apache.syncope.common.rest.api.service.OIDCJWKSService;
 import org.apache.syncope.common.rest.api.service.SAML2IdPEntityService;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
 import org.apache.syncope.common.rest.api.service.SRARouteService;
 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthAccountService;
 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthTokenService;
@@ -32,6 +31,7 @@ import org.apache.syncope.common.rest.api.service.wa.ImpersonationService;
 import org.apache.syncope.common.rest.api.service.wa.MfaTrustStorageService;
 import org.apache.syncope.common.rest.api.service.wa.WAClientAppService;
 import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
 import org.apache.syncope.common.rest.api.service.wa.WebAuthnRegistrationService;
 import org.apache.syncope.core.logic.AttrRepoLogic;
 import org.apache.syncope.core.logic.AuthModuleLogic;
@@ -39,7 +39,6 @@ import org.apache.syncope.core.logic.AuthProfileLogic;
 import org.apache.syncope.core.logic.ClientAppLogic;
 import org.apache.syncope.core.logic.OIDCJWKSLogic;
 import org.apache.syncope.core.logic.SAML2IdPEntityLogic;
-import org.apache.syncope.core.logic.SAML2SPEntityLogic;
 import org.apache.syncope.core.logic.SRARouteLogic;
 import org.apache.syncope.core.logic.wa.GoogleMfaAuthAccountLogic;
 import org.apache.syncope.core.logic.wa.GoogleMfaAuthTokenLogic;
@@ -54,7 +53,6 @@ import org.apache.syncope.core.rest.cxf.service.AuthProfileServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.ClientAppServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.OIDCJWKSServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.SAML2IdPEntityServiceImpl;
-import org.apache.syncope.core.rest.cxf.service.SAML2SPEntityServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.SRARouteServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.GoogleMfaAuthAccountServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.GoogleMfaAuthTokenServiceImpl;
@@ -62,6 +60,7 @@ import org.apache.syncope.core.rest.cxf.service.wa.ImpersonationServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.MfaTrustStorageServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.WAClientAppServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.WAConfigServiceImpl;
+import org.apache.syncope.core.rest.cxf.service.wa.WASAML2SPServiceImpl;
 import org.apache.syncope.core.rest.cxf.service.wa.WebAuthnRegistrationServiceImpl;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
@@ -128,12 +127,6 @@ public class AMRESTCXFContext {
         return new SAML2IdPEntityServiceImpl(saml2IdPEntityLogic);
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityService saml2SPEntityService(final SAML2SPEntityLogic saml2SPEntityLogic) {
-        return new SAML2SPEntityServiceImpl(saml2SPEntityLogic);
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SRARouteService sraRouteService(final SRARouteLogic sraRouteLogic) {
@@ -152,6 +145,12 @@ public class AMRESTCXFContext {
         return new WAClientAppServiceImpl(waClientAppLogic);
     }
 
+    @ConditionalOnMissingBean
+    @Bean
+    public WASAML2SPService waSAML2SPService(final AuthModuleLogic authModuleLogic) {
+        return new WASAML2SPServiceImpl(authModuleLogic);
+    }
+
     @ConditionalOnMissingBean
     @Bean
     public WAConfigService waConfigService(final WAConfigLogic waConfigLogic) {
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPEntityServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPEntityServiceImpl.java
deleted file mode 100644
index a3d5507a32..0000000000
--- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/SAML2SPEntityServiceImpl.java
+++ /dev/null
@@ -1,53 +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.core.rest.cxf.service;
-
-import java.util.List;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.core.logic.SAML2SPEntityLogic;
-
-public class SAML2SPEntityServiceImpl extends AbstractService implements SAML2SPEntityService {
-
-    protected final SAML2SPEntityLogic logic;
-
-    public SAML2SPEntityServiceImpl(final SAML2SPEntityLogic logic) {
-        this.logic = logic;
-    }
-
-    @Override
-    public List<SAML2SPEntityTO> list() {
-        return logic.list();
-    }
-
-    @Override
-    public SAML2SPEntityTO get(final String key) {
-        return logic.read(key);
-    }
-
-    @Override
-    public void set(final SAML2SPEntityTO entityTO) {
-        logic.set(entityTO);
-    }
-
-    @Override
-    public void delete(final String key) {
-        logic.delete(key);
-    }
-}
diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPServiceImpl.java
new file mode 100644
index 0000000000..7fa509eaca
--- /dev/null
+++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/wa/WASAML2SPServiceImpl.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.rest.cxf.service.wa;
+
+import jakarta.ws.rs.core.Response;
+import java.io.InputStream;
+import java.util.Optional;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
+import org.apache.syncope.core.logic.AuthModuleLogic;
+import org.apache.syncope.core.rest.cxf.service.AbstractService;
+
+public class WASAML2SPServiceImpl extends AbstractService implements WASAML2SPService {
+
+    protected final AuthModuleLogic logic;
+
+    public WASAML2SPServiceImpl(final AuthModuleLogic logic) {
+        this.logic = logic;
+    }
+
+    @Override
+    public Response getSAML2SPKeystore(final String clientName) {
+        return Optional.ofNullable(logic.readSAML2SPConf(clientName).getKeystore()).
+                map(Response::ok).
+                orElseGet(() -> Response.status(Response.Status.NOT_FOUND)).
+                build();
+    }
+
+    @Override
+    public void setSAML2SPKeystore(final String clientName, final InputStream keystore) {
+        logic.setSAML2SPKeystore(clientName, keystore);
+    }
+
+    @Override
+    public Response getSAML2SPMetadata(final String clientName) {
+        return Optional.ofNullable(logic.readSAML2SPConf(clientName).getServiceProviderMetadata()).
+                map(Response::ok).
+                orElseGet(() -> Response.status(Response.Status.NOT_FOUND)).
+                build();
+    }
+
+    @Override
+    public void setSAML2SPMetadata(final String clientName, final InputStream metadata) {
+        logic.setSAML2SPMetadata(clientName, metadata);
+    }
+}
diff --git a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
index 40fd1f311e..91092829b0 100644
--- a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
+++ b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -286,7 +286,6 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
     }
 
     protected SyncDeltaBuilder syncDeltaBuilder(
-            final AnyType anyType,
             final ExternalResource resource,
             final Provision provision,
             final Filter filter,
@@ -328,7 +327,7 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
         Triple<AnyType, ExternalResource, Provision> triple = getProvision(anyTypeKey, resourceKey);
 
         SyncDeltaBuilder syncDeltaBuilder = syncDeltaBuilder(
-                triple.getLeft(), triple.getMiddle(), triple.getRight(), filter, moreAttrsToGet);
+                triple.getMiddle(), triple.getRight(), filter, moreAttrsToGet);
 
         ReconStatus status = new ReconStatus();
         if (syncDeltaBuilder.getObject() != null) {
@@ -414,7 +413,7 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
         Triple<AnyType, ExternalResource, Provision> triple = getProvision(anyTypeKey, resourceKey);
 
         SyncDeltaBuilder syncDeltaBuilder = syncDeltaBuilder(
-                triple.getLeft(), triple.getMiddle(), triple.getRight(), filter, moreAttrsToGet);
+                triple.getMiddle(), triple.getRight(), filter, moreAttrsToGet);
 
         SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
         List<ProvisioningReport> results = new ArrayList<>();
diff --git a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index d4a88b91ff..b653b9b4fa 100644
--- a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -357,7 +357,6 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
                 connectorManager.getConnector(triple.getMiddle()),
                 connObjectKeyItem,
                 connObjectKeyValue,
-                triple.getMiddle(),
                 triple.getRight(),
                 Optional.empty()).
                 map(connectorObject -> ConnObjectUtils.getConnObjectTO(
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/SAML2SPEntity.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/SAML2SPEntity.java
deleted file mode 100644
index 469e68d24b..0000000000
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/SAML2SPEntity.java
+++ /dev/null
@@ -1,32 +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.core.persistence.api.entity.am;
-
-import org.apache.syncope.core.persistence.api.entity.ProvidedKeyEntity;
-
-public interface SAML2SPEntity extends ProvidedKeyEntity {
-
-    byte[] getKeystore();
-
-    void setKeystore(byte[] keystore);
-
-    byte[] getMetadata();
-
-    void setMetadata(byte[] metadata);
-}
diff --git a/core/persistence-jpa-upgrader/src/main/resources/schema.xml b/core/persistence-jpa-upgrader/src/main/resources/schema.xml
index 6c16bbee01..e0de4a63b3 100644
--- a/core/persistence-jpa-upgrader/src/main/resources/schema.xml
+++ b/core/persistence-jpa-upgrader/src/main/resources/schema.xml
@@ -1140,12 +1140,6 @@ under the License.
             <unique name="U_SML2TPP_NAME" column="name"/>
             <unique name="U_SML2TPP_ENTITYID" column="entityId"/>
         </table>
-        <table name="SAML2SPEntity">
-            <pk column="id"/>
-            <column name="id" type="varchar" not-null="true" size="255"/>
-            <column name="keystore" type="blob" size="-1"/>
-            <column name="metadata" type="blob" size="-1"/>
-        </table>
         <table name="SRARoute">
             <pk column="id"/>
             <column name="id" type="varchar" not-null="true" size="36"/>
@@ -1431,4 +1425,4 @@ under the License.
             <column name="waConfigValues" type="clob" size="-1"/>
         </table>
     </schema>
-</schemas>
\ No newline at end of file
+</schemas>
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
index b44799e0de..9eee3cbcd5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
@@ -69,7 +69,6 @@ import org.apache.syncope.core.persistence.api.dao.ReportExecDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2IdPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2SPClientAppDAO;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SRARouteDAO;
 import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
@@ -174,7 +173,6 @@ import org.apache.syncope.core.persistence.jpa.dao.repo.SAML2IdPEntityRepo;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SAML2SPClientAppRepo;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SAML2SPClientAppRepoExt;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SAML2SPClientAppRepoExtImpl;
-import org.apache.syncope.core.persistence.jpa.dao.repo.SAML2SPEntityRepo;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SRARouteRepo;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SecurityQuestionRepo;
 import org.apache.syncope.core.persistence.jpa.dao.repo.SecurityQuestionRepoExt;
@@ -927,12 +925,6 @@ public class PersistenceContext {
         return jpaRepositoryFactory.getRepository(SAML2SPClientAppRepo.class, saml2SPClientAppRepoExt);
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityDAO saml2SPEntityDAO(final JpaRepositoryFactory jpaRepositoryFactory) {
-        return jpaRepositoryFactory.getRepository(SAML2SPEntityRepo.class);
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SecurityQuestionRepoExt securityQuestionRepoExt(
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/SAML2SPEntityRepo.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/SAML2SPEntityRepo.java
deleted file mode 100644
index 94dfe9736f..0000000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/repo/SAML2SPEntityRepo.java
+++ /dev/null
@@ -1,28 +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.core.persistence.jpa.dao.repo;
-
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
-import org.apache.syncope.core.persistence.jpa.entity.am.JPASAML2SPEntity;
-import org.springframework.data.repository.ListCrudRepository;
-
-public interface SAML2SPEntityRepo
-        extends ListCrudRepository<JPASAML2SPEntity, String>, SAML2SPEntityDAO {
-
-}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntityFactory.java
index a91b28266a..c1089baa2b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntityFactory.java
@@ -55,7 +55,6 @@ import org.apache.syncope.core.persistence.api.entity.am.OIDCJWKS;
 import org.apache.syncope.core.persistence.api.entity.am.OIDCRPClientApp;
 import org.apache.syncope.core.persistence.api.entity.am.SAML2IdPEntity;
 import org.apache.syncope.core.persistence.api.entity.am.SAML2SPClientApp;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
 import org.apache.syncope.core.persistence.api.entity.am.WAConfigEntry;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
@@ -102,7 +101,6 @@ import org.apache.syncope.core.persistence.jpa.entity.am.JPAOIDCJWKS;
 import org.apache.syncope.core.persistence.jpa.entity.am.JPAOIDCRPClientApp;
 import org.apache.syncope.core.persistence.jpa.entity.am.JPASAML2IdPEntity;
 import org.apache.syncope.core.persistence.jpa.entity.am.JPASAML2SPClientApp;
-import org.apache.syncope.core.persistence.jpa.entity.am.JPASAML2SPEntity;
 import org.apache.syncope.core.persistence.jpa.entity.am.JPAWAConfigEntry;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
@@ -282,8 +280,6 @@ abstract class AbstractEntityFactory implements EntityFactory {
             result = (E) new JPASAML2SPClientApp();
         } else if (reference.equals(SAML2IdPEntity.class)) {
             result = (E) new JPASAML2IdPEntity();
-        } else if (reference.equals(SAML2SPEntity.class)) {
-            result = (E) new JPASAML2SPEntity();
         } else if (reference.equals(AuthProfile.class)) {
             result = (E) new JPAAuthProfile();
         } else if (reference.equals(OIDCJWKS.class)) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/JPASAML2SPEntity.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/JPASAML2SPEntity.java
deleted file mode 100644
index c0e6f79d1d..0000000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/JPASAML2SPEntity.java
+++ /dev/null
@@ -1,64 +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.core.persistence.jpa.entity.am;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Lob;
-import jakarta.persistence.Table;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractProvidedKeyEntity;
-
-@Entity
-@Table(name = JPASAML2SPEntity.TABLE)
-public class JPASAML2SPEntity extends AbstractProvidedKeyEntity implements SAML2SPEntity {
-
-    public static final String TABLE = "SAML2SPEntity";
-
-    private static final long serialVersionUID = 12342617217394093L;
-
-    @Column(nullable = true)
-    @Lob
-    private byte[] keystore;
-
-    @Column(nullable = true)
-    @Lob
-    private byte[] metadata;
-
-    @Override
-    public byte[] getKeystore() {
-        return keystore;
-    }
-
-    @Override
-    public void setKeystore(final byte[] keystore) {
-        this.keystore = ArrayUtils.clone(keystore);
-    }
-
-    @Override
-    public byte[] getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public void setMetadata(final byte[] metadata) {
-        this.metadata = ArrayUtils.clone(metadata);
-    }
-}
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/SAML2SPEntityTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/SAML2SPEntityTest.java
deleted file mode 100644
index 324e6e0cfc..0000000000
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/SAML2SPEntityTest.java
+++ /dev/null
@@ -1,160 +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.core.persistence.jpa.inner;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.Signature;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.util.Date;
-import java.util.UUID;
-import org.apache.cxf.helpers.IOUtils;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.persistence.jpa.AbstractTest;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificate;
-import org.bouncycastle.asn1.x509.Time;
-import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.transaction.annotation.Transactional;
-
-@Transactional
-public class SAML2SPEntityTest extends AbstractTest {
-
-    private static Certificate createSelfSignedCert(final KeyPair keyPair) throws Exception {
-        X500Name dn = new X500Name("cn=Unknown");
-        V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator();
-
-        certGen.setSerialNumber(new ASN1Integer(BigInteger.valueOf(1)));
-        certGen.setIssuer(dn);
-        certGen.setSubject(dn);
-        certGen.setStartDate(new Time(new Date(System.currentTimeMillis() - 1000L)));
-
-        Date expiration = new Date(System.currentTimeMillis() + 100000);
-        certGen.setEndDate(new Time(expiration));
-
-        AlgorithmIdentifier sigAlgID = new AlgorithmIdentifier(
-                PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE);
-        certGen.setSignature(sigAlgID);
-        certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
-
-        Signature sig = Signature.getInstance("SHA1WithRSA");
-        sig.initSign(keyPair.getPrivate());
-        sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER));
-
-        TBSCertificate tbsCert = certGen.generateTBSCertificate();
-        ASN1EncodableVector v = new ASN1EncodableVector();
-
-        v.add(tbsCert);
-        v.add(sigAlgID);
-        v.add(new DERBitString(sig.sign()));
-
-        Certificate cert = CertificateFactory.getInstance("X.509").
-                generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
-        cert.verify(keyPair.getPublic());
-        return cert;
-    }
-
-    @Autowired
-    private SAML2SPEntityDAO saml2SPEntityDAO;
-
-    private SAML2SPEntity create(final String owner) throws Exception {
-        SAML2SPEntity entity = entityFactory.newEntity(SAML2SPEntity.class);
-        entity.setKey(owner);
-        entity.setMetadata(IOUtils.toString(
-                new ClassPathResource("sp-metadata.xml").getInputStream()).getBytes(StandardCharsets.UTF_8));
-
-        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-        char[] pwdArray = "password".toCharArray();
-        ks.load(null, pwdArray);
-
-        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-        keyPairGenerator.initialize(4096);
-        KeyPair keyPair = keyPairGenerator.generateKeyPair();
-        Certificate certificate = createSelfSignedCert(keyPair);
-        ks.setKeyEntry("main", keyPair.getPrivate(), "password".toCharArray(), new Certificate[] { certificate });
-
-        try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
-            ks.store(fos, pwdArray);
-            fos.flush();
-            entity.setKeystore(fos.toByteArray());
-        }
-        assertNotNull(entity.getKeystore());
-
-        entity = saml2SPEntityDAO.save(entity);
-        assertNotNull(saml2SPEntityDAO.findById(entity.getKey()));
-        return entity;
-    }
-
-    @Test
-    public void find() throws Exception {
-        create("Syncope");
-
-        assertTrue(saml2SPEntityDAO.findById("Syncope").isPresent());
-
-        assertTrue(saml2SPEntityDAO.findById(UUID.randomUUID().toString()).isEmpty());
-    }
-
-    @Test
-    public void save() throws Exception {
-        SAML2SPEntity created = create("SyncopeCreate");
-
-        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-        char[] pwdArray = "password".toCharArray();
-        ks.load(new ByteArrayInputStream(created.getKeystore()), pwdArray);
-        assertTrue(ks.size() > 0);
-    }
-
-    @Test
-    public void update() throws Exception {
-        SAML2SPEntity entity = create("SyncopeUpdate");
-        assertNotNull(entity);
-        entity.setKey("OtherSyncope");
-
-        entity = saml2SPEntityDAO.save(entity);
-        assertNotNull(entity);
-
-        entityManager.flush();
-
-        SAML2SPEntity found = saml2SPEntityDAO.findById(entity.getKey()).orElseThrow();
-        assertEquals("OtherSyncope", found.getKey());
-    }
-}
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 9009ca3c27..9e02cede0c 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -78,7 +78,7 @@ under the License.
               description="Duo Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.DuoMfaAuthModuleConf","integrationKey":"DIOXVRZD2UMZ8XXMNFQ5","secretKey":"Q2IU2i8BFNd6VYflZT8Evl6lF7oPlj3PM15BmRU7", "apiHost":"theapi.duosecurity.com"}'/>
   <AuthModule id="DefaultOIDCAuthModule" authModuleState="ACTIVE"
               description="OIDC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","discoveryUri":"https://localhost:9443/syncope-wa/oidc/.well-known/openid-configuration", "clientId":"client-id", "clientSecret": "client-secret" }'/>
-  <AuthModule id="DefaultSAML2IdPAuthModule" authModuleState="ACTIVE"
+  <AuthModule id="DefaultSAML2IdPAuthModule" authModuleState="ACTIVE" authModuleOrder="0"
               description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"https://localhost:9443/syncope-wa/idp/metadata", "serviceProviderEntityId":"syncope:apache:org"}'/>
   <AuthModule id="DefaultJaasAuthModule" authModuleState="ACTIVE"
               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"}'/>
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
index 8546109452..9544c68fcd 100644
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
+++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/PersistenceContext.java
@@ -71,7 +71,6 @@ import org.apache.syncope.core.persistence.api.dao.ReportExecDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2IdPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2SPClientAppDAO;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
 import org.apache.syncope.core.persistence.api.dao.SRARouteDAO;
 import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
@@ -183,7 +182,6 @@ import org.apache.syncope.core.persistence.neo4j.dao.repo.SAML2IdPEntityRepo;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SAML2SPClientAppRepo;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SAML2SPClientAppRepoExt;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SAML2SPClientAppRepoExtImpl;
-import org.apache.syncope.core.persistence.neo4j.dao.repo.SAML2SPEntityRepo;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SRARouteRepo;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SecurityQuestionRepo;
 import org.apache.syncope.core.persistence.neo4j.dao.repo.SecurityQuestionRepoExt;
@@ -1335,12 +1333,6 @@ public class PersistenceContext {
         return neo4jRepositoryFactory.getRepository(SAML2SPClientAppRepo.class, saml2SPClientAppRepoExt);
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityDAO saml2SPEntityDAO(final SyncopeNeo4jRepositoryFactory neo4jRepositoryFactory) {
-        return neo4jRepositoryFactory.getRepository(SAML2SPEntityRepo.class);
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SecurityQuestionRepoExt securityQuestionRepoExt(
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/SAML2SPEntityRepo.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/SAML2SPEntityRepo.java
deleted file mode 100644
index b76b7daa3d..0000000000
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/dao/repo/SAML2SPEntityRepo.java
+++ /dev/null
@@ -1,28 +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.core.persistence.neo4j.dao.repo;
-
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
-import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jSAML2SPEntity;
-import org.springframework.data.repository.ListCrudRepository;
-
-public interface SAML2SPEntityRepo
-        extends ListCrudRepository<Neo4jSAML2SPEntity, String>, SAML2SPEntityDAO {
-
-}
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jEntityFactory.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jEntityFactory.java
index 5a79855f47..b8f71ea913 100644
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jEntityFactory.java
+++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jEntityFactory.java
@@ -56,7 +56,6 @@ import org.apache.syncope.core.persistence.api.entity.am.OIDCJWKS;
 import org.apache.syncope.core.persistence.api.entity.am.OIDCRPClientApp;
 import org.apache.syncope.core.persistence.api.entity.am.SAML2IdPEntity;
 import org.apache.syncope.core.persistence.api.entity.am.SAML2SPClientApp;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
 import org.apache.syncope.core.persistence.api.entity.am.WAConfigEntry;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
@@ -103,7 +102,6 @@ import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jOIDCJWKS;
 import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jOIDCRPClientApp;
 import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jSAML2IdPEntity;
 import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jSAML2SPClientApp;
-import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jSAML2SPEntity;
 import org.apache.syncope.core.persistence.neo4j.entity.am.Neo4jWAConfigEntry;
 import org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jADynGroupMembership;
 import org.apache.syncope.core.persistence.neo4j.entity.anyobject.Neo4jAMembership;
@@ -283,8 +281,6 @@ public class Neo4jEntityFactory implements EntityFactory {
             result = (E) new Neo4jSAML2SPClientApp();
         } else if (reference.equals(SAML2IdPEntity.class)) {
             result = (E) new Neo4jSAML2IdPEntity();
-        } else if (reference.equals(SAML2SPEntity.class)) {
-            result = (E) new Neo4jSAML2SPEntity();
         } else if (reference.equals(AuthProfile.class)) {
             result = (E) new Neo4jAuthProfile();
         } else if (reference.equals(OIDCJWKS.class)) {
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/am/Neo4jSAML2SPEntity.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/am/Neo4jSAML2SPEntity.java
deleted file mode 100644
index ba40300265..0000000000
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/am/Neo4jSAML2SPEntity.java
+++ /dev/null
@@ -1,56 +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.core.persistence.neo4j.entity.am;
-
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.persistence.neo4j.entity.AbstractProvidedKeyNode;
-import org.springframework.data.neo4j.core.schema.Node;
-
-@Node(Neo4jSAML2SPEntity.NODE)
-public class Neo4jSAML2SPEntity extends AbstractProvidedKeyNode implements SAML2SPEntity {
-
-    public static final String NODE = "SAML2SPEntity";
-
-    private static final long serialVersionUID = 12342617217394093L;
-
-    private byte[] keystore;
-
-    private byte[] metadata;
-
-    @Override
-    public byte[] getKeystore() {
-        return keystore;
-    }
-
-    @Override
-    public void setKeystore(final byte[] keystore) {
-        this.keystore = ArrayUtils.clone(keystore);
-    }
-
-    @Override
-    public byte[] getMetadata() {
-        return metadata;
-    }
-
-    @Override
-    public void setMetadata(final byte[] metadata) {
-        this.metadata = ArrayUtils.clone(metadata);
-    }
-}
diff --git a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/SAML2SPEntityTest.java b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/SAML2SPEntityTest.java
deleted file mode 100644
index 27232e6464..0000000000
--- a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/SAML2SPEntityTest.java
+++ /dev/null
@@ -1,158 +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.core.persistence.neo4j.inner;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.Signature;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.util.Date;
-import java.util.UUID;
-import org.apache.cxf.helpers.IOUtils;
-import org.apache.syncope.core.persistence.api.dao.SAML2SPEntityDAO;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.persistence.neo4j.AbstractTest;
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.DERBitString;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.asn1.x509.TBSCertificate;
-import org.bouncycastle.asn1.x509.Time;
-import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.transaction.annotation.Transactional;
-
-@Transactional
-public class SAML2SPEntityTest extends AbstractTest {
-
-    private static Certificate createSelfSignedCert(final KeyPair keyPair) throws Exception {
-        X500Name dn = new X500Name("cn=Unknown");
-        V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator();
-
-        certGen.setSerialNumber(new ASN1Integer(BigInteger.valueOf(1)));
-        certGen.setIssuer(dn);
-        certGen.setSubject(dn);
-        certGen.setStartDate(new Time(new Date(System.currentTimeMillis() - 1000L)));
-
-        Date expiration = new Date(System.currentTimeMillis() + 100000);
-        certGen.setEndDate(new Time(expiration));
-
-        AlgorithmIdentifier sigAlgID = new AlgorithmIdentifier(
-                PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE);
-        certGen.setSignature(sigAlgID);
-        certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
-
-        Signature sig = Signature.getInstance("SHA1WithRSA");
-        sig.initSign(keyPair.getPrivate());
-        sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER));
-
-        TBSCertificate tbsCert = certGen.generateTBSCertificate();
-        ASN1EncodableVector v = new ASN1EncodableVector();
-
-        v.add(tbsCert);
-        v.add(sigAlgID);
-        v.add(new DERBitString(sig.sign()));
-
-        Certificate cert = CertificateFactory.getInstance("X.509").
-                generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
-        cert.verify(keyPair.getPublic());
-        return cert;
-    }
-
-    @Autowired
-    private SAML2SPEntityDAO saml2SPEntityDAO;
-
-    private SAML2SPEntity create(final String owner) throws Exception {
-        SAML2SPEntity entity = entityFactory.newEntity(SAML2SPEntity.class);
-        entity.setKey(owner);
-        entity.setMetadata(IOUtils.toString(
-                new ClassPathResource("sp-metadata.xml").getInputStream()).getBytes(StandardCharsets.UTF_8));
-
-        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-        char[] pwdArray = "password".toCharArray();
-        ks.load(null, pwdArray);
-
-        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-        keyPairGenerator.initialize(4096);
-        KeyPair keyPair = keyPairGenerator.generateKeyPair();
-        Certificate certificate = createSelfSignedCert(keyPair);
-        ks.setKeyEntry("main", keyPair.getPrivate(), "password".toCharArray(), new Certificate[] { certificate });
-
-        try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
-            ks.store(fos, pwdArray);
-            fos.flush();
-            entity.setKeystore(fos.toByteArray());
-        }
-        assertNotNull(entity.getKeystore());
-
-        entity = saml2SPEntityDAO.save(entity);
-        assertNotNull(saml2SPEntityDAO.findById(entity.getKey()));
-        return entity;
-    }
-
-    @Test
-    public void find() throws Exception {
-        create("Syncope");
-
-        assertTrue(saml2SPEntityDAO.findById("Syncope").isPresent());
-
-        assertTrue(saml2SPEntityDAO.findById(UUID.randomUUID().toString()).isEmpty());
-    }
-
-    @Test
-    public void save() throws Exception {
-        SAML2SPEntity created = create("SyncopeCreate");
-
-        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-        char[] pwdArray = "password".toCharArray();
-        ks.load(new ByteArrayInputStream(created.getKeystore()), pwdArray);
-        assertTrue(ks.size() > 0);
-    }
-
-    @Test
-    public void update() throws Exception {
-        SAML2SPEntity entity = create("SyncopeUpdate");
-        assertNotNull(entity);
-        entity.setKey("OtherSyncope");
-
-        entity = saml2SPEntityDAO.save(entity);
-        assertNotNull(entity);
-
-        SAML2SPEntity found = saml2SPEntityDAO.findById(entity.getKey()).orElseThrow();
-        assertEquals("OtherSyncope", found.getKey());
-    }
-}
diff --git a/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml b/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
index 0d8c78b01a..c271719ecf 100644
--- a/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-neo4j/src/test/resources/domains/MasterContent.xml
@@ -78,7 +78,7 @@ under the License.
               description="Duo Mfa auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.DuoMfaAuthModuleConf","integrationKey":"DIOXVRZD2UMZ8XXMNFQ5","secretKey":"Q2IU2i8BFNd6VYflZT8Evl6lF7oPlj3PM15BmRU7", "apiHost":"theapi.duosecurity.com"}'/>
   <AuthModule id="DefaultOIDCAuthModule" authModuleState="ACTIVE"
               description="OIDC auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OIDCAuthModuleConf","discoveryUri":"https://localhost:9443/syncope-wa/oidc/.well-known/openid-configuration", "clientId":"client-id", "clientSecret": "client-secret" }'/>
-  <AuthModule id="DefaultSAML2IdPAuthModule" authModuleState="ACTIVE"
+  <AuthModule id="DefaultSAML2IdPAuthModule" authModuleState="ACTIVE" authModuleOrder="0"
               description="SAML2 IdP auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.SAML2IdPAuthModuleConf","keystorePassword":"p@$$word","privateKeyPassword":"p@$$word","identityProviderMetadataPath":"https://localhost:9443/syncope-wa/idp/metadata", "serviceProviderEntityId":"syncope:apache:org"}'/>
   <AuthModule id="DefaultJaasAuthModule" authModuleState="ACTIVE"
               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"}'/>
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/SAML2SPEntityDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/SAML2SPEntityDataBinder.java
deleted file mode 100644
index f21ae3586d..0000000000
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/SAML2SPEntityDataBinder.java
+++ /dev/null
@@ -1,31 +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.core.provisioning.api.data;
-
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-
-public interface SAML2SPEntityDataBinder {
-
-    SAML2SPEntity create(SAML2SPEntityTO entityTO);
-
-    SAML2SPEntity update(SAML2SPEntity entity, SAML2SPEntityTO entityTO);
-
-    SAML2SPEntityTO getSAML2SPEntityTO(SAML2SPEntity entity);
-}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
index 580783622c..47b0a67cd8 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
@@ -96,7 +96,6 @@ import org.apache.syncope.core.provisioning.api.data.ReportDataBinder;
 import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder;
 import org.apache.syncope.core.provisioning.api.data.RoleDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SAML2IdPEntityDataBinder;
-import org.apache.syncope.core.provisioning.api.data.SAML2SPEntityDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SRARouteDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SchemaDataBinder;
 import org.apache.syncope.core.provisioning.api.data.SecurityQuestionDataBinder;
@@ -134,7 +133,6 @@ import org.apache.syncope.core.provisioning.java.data.ReportDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.ResourceDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.RoleDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.SAML2IdPEntityDataBinderImpl;
-import org.apache.syncope.core.provisioning.java.data.SAML2SPEntityDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.SRARouteDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.SchemaDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.SecurityQuestionDataBinderImpl;
@@ -1010,12 +1008,6 @@ public class ProvisioningContext {
         return new SAML2IdPEntityDataBinderImpl(entityFactory);
     }
 
-    @ConditionalOnMissingBean
-    @Bean
-    public SAML2SPEntityDataBinder saml2SPEntityDataBinder(final EntityFactory entityFactory) {
-        return new SAML2SPEntityDataBinderImpl(entityFactory);
-    }
-
     @ConditionalOnMissingBean
     @Bean
     public SRARouteDataBinder sraRouteDataBinder() {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 3f2dc2c94d..a83fb9fcdc 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -206,7 +206,6 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                     });
 
                     populateMapping(
-                            resource,
                             provisionTO.getMapping(),
                             mapping,
                             anyType.getKind(),
@@ -363,7 +362,6 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
     }
 
     protected void populateMapping(
-            final ExternalResource resource,
             final Mapping mappingTO,
             final Mapping mapping,
             final AnyTypeKind anyTypeKind,
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2SPEntityDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2SPEntityDataBinderImpl.java
deleted file mode 100644
index 2ea41ee719..0000000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2SPEntityDataBinderImpl.java
+++ /dev/null
@@ -1,65 +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.core.provisioning.java.data;
-
-import java.util.Base64;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.am.SAML2SPEntity;
-import org.apache.syncope.core.provisioning.api.data.SAML2SPEntityDataBinder;
-
-public class SAML2SPEntityDataBinderImpl implements SAML2SPEntityDataBinder {
-
-    protected final EntityFactory entityFactory;
-
-    public SAML2SPEntityDataBinderImpl(final EntityFactory entityFactory) {
-        this.entityFactory = entityFactory;
-    }
-
-    @Override
-    public SAML2SPEntity create(final SAML2SPEntityTO entityTO) {
-        SAML2SPEntity entity = entityFactory.newEntity(SAML2SPEntity.class);
-        entity.setKey(entityTO.getKey());
-        return update(entity, entityTO);
-    }
-
-    @Override
-    public SAML2SPEntity update(final SAML2SPEntity entity, final SAML2SPEntityTO entityTO) {
-        entity.setKeystore(entityTO.getKeystore() == null
-                ? null
-                : Base64.getDecoder().decode(entityTO.getKeystore()));
-        entity.setMetadata(entityTO.getMetadata() == null
-                ? null
-                : Base64.getDecoder().decode(entityTO.getMetadata()));
-        return entity;
-    }
-
-    @Override
-    public SAML2SPEntityTO getSAML2SPEntityTO(final SAML2SPEntity entity) {
-        SAML2SPEntityTO entityTO = new SAML2SPEntityTO();
-        entityTO.setKey(entity.getKey());
-        if (entity.getKeystore() != null) {
-            entityTO.setKeystore(Base64.getEncoder().encodeToString(entity.getKeystore()));
-        }
-        if (entity.getMetadata() != null) {
-            entityTO.setMetadata(Base64.getEncoder().encodeToString(entity.getMetadata()));
-        }
-        return entityTO;
-    }
-}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
index 24421002ba..10d0e9d44b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
@@ -226,7 +226,6 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
                 profile.getConnector(),
                 connObjectKeyItem,
                 account.getConnObjectKeyValue(),
-                profile.getTask().getResource(),
                 provision,
                 Optional.empty()));
         LOG.debug("Match found for linked account {} as {}: {}", account, provision.getObjectClass(), connObj);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
index 038df153f0..c0020ea25e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
@@ -134,7 +134,6 @@ public class OutboundMatcher {
                 result.addAll(matchByCorrelationRule(
                         connector,
                         rule.get().getFilter(any, taskInfo.getResource(), provision),
-                        taskInfo.getResource(),
                         provision,
                         Optional.of(moreAttrsToGet.toArray(String[]::new))));
             } else {
@@ -142,7 +141,6 @@ public class OutboundMatcher {
                         connector,
                         connObjectKeyItem,
                         connObjectKeyValue,
-                        taskInfo.getResource(),
                         provision,
                         Optional.of(moreAttrsToGet.toArray(String[]::new)))).ifPresent(result::add);
             }
@@ -192,7 +190,6 @@ public class OutboundMatcher {
                 result.addAll(matchByCorrelationRule(
                         connector,
                         rule.get().getFilter(any, resource, provision),
-                        resource,
                         provision,
                         effectiveMATG));
             } else {
@@ -204,7 +201,6 @@ public class OutboundMatcher {
                             connector,
                             connObjectKeyItem.get(),
                             connObjectKeyValue.get(),
-                            resource,
                             provision,
                             effectiveMATG).
                             ifPresent(result::add);
@@ -220,7 +216,6 @@ public class OutboundMatcher {
     protected List<ConnectorObject> matchByCorrelationRule(
             final Connector connector,
             final Filter filter,
-            final ExternalResource resource,
             final Provision provision,
             final Optional<String[]> moreAttrsToGet) {
 
@@ -255,7 +250,6 @@ public class OutboundMatcher {
             final Connector connector,
             final Item connObjectKeyItem,
             final String connObjectKeyValue,
-            final ExternalResource resource,
             final Provision provision,
             final Optional<String[]> moreAttrsToGet) {
 
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 230656a3fd..5813a6d0dc 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
@@ -154,7 +154,6 @@ import org.apache.syncope.common.rest.api.service.RoleService;
 import org.apache.syncope.common.rest.api.service.SAML2IdPEntityService;
 import org.apache.syncope.common.rest.api.service.SAML2SP4UIIdPService;
 import org.apache.syncope.common.rest.api.service.SAML2SP4UIService;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
 import org.apache.syncope.common.rest.api.service.SCIMConfService;
 import org.apache.syncope.common.rest.api.service.SRARouteService;
 import org.apache.syncope.common.rest.api.service.SchemaService;
@@ -378,8 +377,6 @@ public abstract class AbstractITCase {
 
     protected static AuthProfileService AUTH_PROFILE_SERVICE;
 
-    protected static SAML2SPEntityService SAML2SP_ENTITY_SERVICE;
-
     protected static SAML2IdPEntityService SAML2IDP_ENTITY_SERVICE;
 
     protected static OIDCJWKSService OIDC_JWKS_SERVICE;
@@ -577,7 +574,6 @@ public abstract class AbstractITCase {
         CLIENT_APP_SERVICE = ADMIN_CLIENT.getService(ClientAppService.class);
         AUTH_MODULE_SERVICE = ADMIN_CLIENT.getService(AuthModuleService.class);
         ATTR_REPO_SERVICE = ADMIN_CLIENT.getService(AttrRepoService.class);
-        SAML2SP_ENTITY_SERVICE = ADMIN_CLIENT.getService(SAML2SPEntityService.class);
         SAML2IDP_ENTITY_SERVICE = ADMIN_CLIENT.getService(SAML2IdPEntityService.class);
         AUTH_PROFILE_SERVICE = ADMIN_CLIENT.getService(AuthProfileService.class);
         OIDC_JWKS_SERVICE = ADMIN_CLIENT.getService(OIDCJWKSService.class);
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 49f115008d..2b79628be5 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
@@ -26,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import jakarta.ws.rs.core.Response;
 import java.io.IOException;
+import java.util.Base64;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
@@ -414,9 +415,11 @@ public class AuthModuleITCase extends AbstractITCase {
         newsaml2IdpAuthModuleTO = createAuthModule(newsaml2IdpAuthModuleTO);
         assertNotNull(newsaml2IdpAuthModuleTO);
 
-        AuthModuleConf conf = saml2IdpAuthModuleTO.getConf();
+        SAML2IdPAuthModuleConf conf = (SAML2IdPAuthModuleConf) saml2IdpAuthModuleTO.getConf();
         assertNotNull(conf);
-        SAML2IdPAuthModuleConf.class.cast(conf).setServiceProviderEntityId("newEntityId");
+        conf.setClientName("clientName");
+        conf.setServiceProviderEntityId("newEntityId");
+        conf.setServiceProviderMetadata(Base64.getEncoder().encodeToString("testMetadata".getBytes()));
         newsaml2IdpAuthModuleTO.setConf(conf);
 
         // update new auth module
@@ -424,8 +427,10 @@ public class AuthModuleITCase extends AbstractITCase {
         newsaml2IdpAuthModuleTO = AUTH_MODULE_SERVICE.read(newsaml2IdpAuthModuleTO.getKey());
         assertNotNull(newsaml2IdpAuthModuleTO);
 
-        conf = newsaml2IdpAuthModuleTO.getConf();
-        assertEquals("newEntityId", SAML2IdPAuthModuleConf.class.cast(conf).getServiceProviderEntityId());
+        conf = (SAML2IdPAuthModuleConf) newsaml2IdpAuthModuleTO.getConf();
+        assertEquals("clientName", conf.getClientName());
+        assertEquals("newEntityId", conf.getServiceProviderEntityId());
+        assertEquals("testMetadata", new String(Base64.getDecoder().decode(conf.getServiceProviderMetadata())));
     }
 
     @Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPEntityITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPEntityITCase.java
deleted file mode 100644
index 26fd91ba8c..0000000000
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2SPEntityITCase.java
+++ /dev/null
@@ -1,89 +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 static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.fit.AbstractITCase;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-public class SAML2SPEntityITCase extends AbstractITCase {
-
-    private static final String OWNER = "owner";
-
-    private static SAML2SPEntityService WA_SAML2SP_ENTITY_SERVICE;
-
-    @BeforeAll
-    public static void setup() {
-        assumeTrue(CLIENT_FACTORY.getContentType() == SyncopeClientFactoryBean.ContentType.JSON);
-
-        WA_SAML2SP_ENTITY_SERVICE = ANONYMOUS_CLIENT.getService(SAML2SPEntityService.class);
-    }
-
-    private static SAML2SPEntityTO set() {
-        SAML2SPEntityTO entityTO = new SAML2SPEntityTO.Builder().
-                key(OWNER).
-                metadata(Base64.getEncoder().encodeToString("testMetadata".getBytes(StandardCharsets.UTF_8))).
-                build();
-        WA_SAML2SP_ENTITY_SERVICE.set(entityTO);
-
-        return entityTO;
-    }
-
-    @Test
-    public void get() {
-        SAML2SPEntityTO entityTO;
-        try {
-            entityTO = WA_SAML2SP_ENTITY_SERVICE.get(OWNER);
-        } catch (SyncopeClientException e) {
-            entityTO = set();
-        }
-        assertNotNull(entityTO);
-
-        assertEquals(OWNER, entityTO.getKey());
-    }
-
-    @Test
-    public void getAndSet() {
-        SAML2SPEntityTO entityTO;
-        try {
-            entityTO = WA_SAML2SP_ENTITY_SERVICE.get(OWNER);
-        } catch (SyncopeClientException e) {
-            entityTO = set();
-        }
-        assertNotNull(entityTO);
-
-        entityTO.setMetadata(Base64.getEncoder().encodeToString("new metadata".getBytes(StandardCharsets.UTF_8)));
-        WA_SAML2SP_ENTITY_SERVICE.set(entityTO);
-
-        entityTO = WA_SAML2SP_ENTITY_SERVICE.get(entityTO.getKey());
-        assertEquals(
-                "new metadata",
-                new String(Base64.getDecoder().decode(entityTO.getMetadata()), StandardCharsets.UTF_8));
-    }
-}
diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
index a659e47d54..0add168ac6 100644
--- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
+++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/mapping/AuthModulePropertySourceMapper.java
@@ -288,8 +288,6 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
         props.setBlockedSignatureSigningAlgorithms(conf.getBlockedSignatureSigningAlgorithms());
         props.setDestinationBinding(conf.getDestinationBinding().getUri());
         props.getMetadata().setIdentityProviderMetadataPath(conf.getIdentityProviderMetadataPath());
-        props.getMetadata().getServiceProvider().getFileSystem().setLocation(conf.getServiceProviderMetadataPath());
-        props.setKeystorePath(conf.getKeystorePath());
         props.setWantsAssertionsSigned(conf.isWantsAssertionsSigned());
         props.setWantsResponsesSigned(conf.isResponsesSigned());
         props.setKeystorePassword(conf.getKeystorePassword());
@@ -302,9 +300,9 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme
         props.setSignatureCanonicalizationAlgorithm(conf.getSignatureCanonicalizationAlgorithm());
         props.setSignatureReferenceDigestMethods(conf.getSignatureReferenceDigestMethods());
         props.setPrincipalIdAttribute(conf.getUserIdAttribute());
-        props.setNameIdPolicyAllowCreate(StringUtils.isBlank(conf.getNameIdPolicyAllowCreate())
-                ? TriStateBoolean.UNDEFINED
-                : TriStateBoolean.valueOf(conf.getNameIdPolicyAllowCreate().toUpperCase()));
+        props.setNameIdPolicyAllowCreate(Optional.ofNullable(conf.getNameIdPolicyAllowCreate()).
+                map(v -> TriStateBoolean.valueOf(v.name())).
+                orElse(TriStateBoolean.UNDEFINED));
 
         return prefix("cas.authn.pac4j.saml[].", WAConfUtils.asMap(props));
     }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGenerator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGenerator.java
index a02327dab0..ec328b6a21 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGenerator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGenerator.java
@@ -18,15 +18,17 @@
  */
 package org.apache.syncope.wa.starter.pac4j.saml;
 
+import jakarta.ws.rs.core.Response;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyStore;
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
 import java.util.Base64;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.pac4j.saml.client.SAML2Client;
 import org.pac4j.saml.metadata.keystore.BaseSAML2KeystoreGenerator;
@@ -50,8 +52,9 @@ public class WASAML2ClientKeystoreGenerator extends BaseSAML2KeystoreGenerator {
     @Override
     public boolean shouldGenerate() {
         try {
-            SAML2SPEntityTO spEntity = waRestClient.getService(SAML2SPEntityService.class).get(saml2Client.getName());
-            return spEntity.getKeystore() == null;
+            Response response = waRestClient.getService(WASAML2SPService.class).
+                    getSAML2SPKeystore(saml2Client.getName());
+            return response.getStatus() == Response.Status.NOT_FOUND.getStatusCode() || !response.hasEntity();
         } catch (Exception e) {
             LOG.error("While attempting to read if keystore is available for SP Entity {}", saml2Client.getName(), e);
             return true;
@@ -71,27 +74,18 @@ public class WASAML2ClientKeystoreGenerator extends BaseSAML2KeystoreGenerator {
             LOG.debug("Encoded keystore {}", encodedKeystore);
         }
 
-        SAML2SPEntityTO entityTO;
-        try {
-            entityTO = waRestClient.getService(SAML2SPEntityService.class).get(saml2Client.getName());
-            entityTO.setKeystore(encodedKeystore);
-        } catch (Exception e) {
-            LOG.debug("SP Entity {} keystore not found, creating new", saml2Client.getName(), e);
-
-            entityTO = new SAML2SPEntityTO.Builder().key(saml2Client.getName()).keystore(encodedKeystore).build();
-        }
-
-        LOG.debug("Storing SP Entity {}", entityTO);
-        waRestClient.getService(SAML2SPEntityService.class).set(entityTO);
+        waRestClient.getService(WASAML2SPService.class).setSAML2SPKeystore(
+                saml2Client.getName(), IOUtils.toInputStream(encodedKeystore, StandardCharsets.UTF_8));
     }
 
     @Override
     public InputStream retrieve() throws Exception {
         try {
-            SAML2SPEntityTO spEntity = waRestClient.getService(SAML2SPEntityService.class).get(saml2Client.getName());
+            String encodedKeystore = waRestClient.getService(WASAML2SPService.class).
+                    getSAML2SPKeystore(saml2Client.getName()).readEntity(String.class);
 
-            LOG.debug("Retrieved keystore {}", spEntity.getKeystore());
-            return new ByteArrayInputStream(Base64.getDecoder().decode(spEntity.getKeystore()));
+            LOG.debug("Retrieved keystore {}", encodedKeystore);
+            return new ByteArrayInputStream(Base64.getDecoder().decode(encodedKeystore));
         } catch (Exception e) {
             String message = "Unable to fetch SAML2 SP keystore for " + saml2Client.getName();
             LOG.error(message, e);
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGenerator.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGenerator.java
index 89b1e3f605..9f90207dca 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGenerator.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGenerator.java
@@ -20,8 +20,8 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.opensaml.saml.metadata.resolver.MetadataResolver;
 import org.opensaml.saml.metadata.resolver.impl.AbstractMetadataResolver;
@@ -57,23 +57,15 @@ public class WASAML2ClientMetadataGenerator extends BaseSAML2MetadataGenerator {
     public MetadataResolver buildMetadataResolver() throws Exception {
         String encodedMetadata = Base64.getEncoder().encodeToString(
                 getMetadata(buildEntityDescriptor()).getBytes(StandardCharsets.UTF_8));
+        LOG.debug("Encoded SP metadata {}", encodedMetadata);
 
-        SAML2SPEntityTO entityTO;
         try {
-            entityTO = waRestClient.getService(SAML2SPEntityService.class).get(saml2Client.getName());
-            entityTO.setMetadata(encodedMetadata);
+            waRestClient.getService(WASAML2SPService.class).setSAML2SPMetadata(
+                    saml2Client.getName(), IOUtils.toInputStream(encodedMetadata, StandardCharsets.UTF_8));
         } catch (Exception e) {
-            LOG.debug("SP Entity {} not found, creating new", saml2Client.getName(), e);
-
-            entityTO = new SAML2SPEntityTO.Builder().
-                    key(saml2Client.getName()).
-                    metadata(encodedMetadata).
-                    build();
+            LOG.error("While storing SP {} metadata", saml2Client.getName(), e);
         }
 
-        LOG.debug("Storing SP Entity {}", entityTO);
-        waRestClient.getService(SAML2SPEntityService.class).set(entityTO);
-
         return super.buildMetadataResolver();
     }
 }
diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolver.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolver.java
index 4bbddf064e..1788e31baf 100644
--- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolver.java
+++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolver.java
@@ -20,8 +20,7 @@ package org.apache.syncope.wa.starter.pac4j.saml;
 
 import java.util.Base64;
 import net.shibboleth.shared.resolver.ResolverException;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
 import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver;
 import org.pac4j.saml.client.SAML2Client;
@@ -49,8 +48,11 @@ public class WASAML2MetadataResolver extends AbstractReloadingMetadataResolver {
     @Override
     protected byte[] fetchMetadata() throws ResolverException {
         try {
-            SAML2SPEntityTO metadataTO = waRestClient.getService(SAML2SPEntityService.class).get(saml2Client.getName());
-            return Base64.getDecoder().decode(metadataTO.getMetadata());
+            String encodedMetadata = waRestClient.getService(WASAML2SPService.class).
+                    getSAML2SPMetadata(saml2Client.getName()).readEntity(String.class);
+
+            LOG.debug("Retrieved keystore {}", encodedMetadata);
+            return Base64.getDecoder().decode(encodedMetadata);
         } catch (Exception e) {
             String message = "Unable to fetch SP metadata for " + saml2Client.getName();
             LOG.error(message, e);
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeCoreTestingServer.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeCoreTestingServer.java
index 96a20e9dee..929d15f920 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeCoreTestingServer.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/SyncopeCoreTestingServer.java
@@ -72,7 +72,7 @@ public class SyncopeCoreTestingServer implements ApplicationListener<ContextRefr
         @Override
         public AuthModuleTO read(final String key) {
             return AUTH_MODULES.stream().filter(m -> Objects.equals(key, m.getKey())).
-                    findFirst().orElseThrow(() -> new NotFoundException("Auth Module with key " + key));
+                    findFirst().orElseThrow(() -> new NotFoundException("AuthModule with key " + key));
         }
 
         @Override
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/BaseWASAML2ClientTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/BaseWASAML2ClientTest.java
index 8630fde937..8ed84ab130 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/BaseWASAML2ClientTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/BaseWASAML2ClientTest.java
@@ -18,10 +18,20 @@
  */
 package org.apache.syncope.wa.starter.pac4j.saml;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import jakarta.ws.rs.core.Response;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
@@ -30,6 +40,9 @@ import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.util.Base64;
 import java.util.Date;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.rest.api.service.wa.WASAML2SPService;
+import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1Encoding;
 import org.bouncycastle.asn1.ASN1Integer;
@@ -99,6 +112,7 @@ public abstract class BaseWASAML2ClientTest {
         cfg.setServiceProviderMetadataResource(new FileSystemResource(File.createTempFile("sp-metadata", ".xml")));
 
         SAML2Client client = new SAML2Client(cfg);
+        client.setName("CAS");
         client.setCallbackUrl("https://syncope.apache.org");
         return client;
     }
@@ -123,4 +137,22 @@ public abstract class BaseWASAML2ClientTest {
             return Base64.getEncoder().encodeToString(fos.toByteArray());
         }
     }
+
+    protected static String getSPMetadata() throws IOException {
+        return Base64.getEncoder().encodeToString(
+                IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(), StandardCharsets.UTF_8).
+                        getBytes(StandardCharsets.UTF_8));
+    }
+
+    protected static WARestClient getWARestClient() throws Exception {
+        WASAML2SPService service = mock(WASAML2SPService.class);
+        when(service.getSAML2SPKeystore(anyString())).thenReturn(Response.ok(getKeystoreAsString()).build());
+        when(service.getSAML2SPMetadata(anyString())).thenReturn(Response.ok(getSPMetadata()).build());
+        doNothing().when(service).setSAML2SPKeystore(anyString(), any(InputStream.class));
+        doNothing().when(service).setSAML2SPMetadata(anyString(), any(InputStream.class));
+
+        WARestClient waRestClient = mock(WARestClient.class);
+        when(waRestClient.getService(WASAML2SPService.class)).thenReturn(service);
+        return waRestClient;
+    }
 }
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientCustomizerTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientCustomizerTest.java
index 94b4db1552..406452871e 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientCustomizerTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientCustomizerTest.java
@@ -19,39 +19,15 @@
 package org.apache.syncope.wa.starter.pac4j.saml;
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
-import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.pac4j.saml.client.SAML2Client;
-import org.springframework.core.io.ClassPathResource;
 
 public class WASAML2ClientCustomizerTest extends BaseWASAML2ClientTest {
 
     @Test
     public void customize() throws Exception {
-        SAML2SPEntityTO entityTO = new SAML2SPEntityTO.Builder()
-                .key("CAS")
-                .keystore(getKeystoreAsString())
-                .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(),
-                        StandardCharsets.UTF_8))
-                .build();
-        SAML2SPEntityService service = mock(SAML2SPEntityService.class);
-        when(service.get(anyString())).thenReturn(entityTO);
-        doNothing().when(service).set(any(SAML2SPEntityTO.class));
-
-        WARestClient waRestClient = mock(WARestClient.class);
-        when(waRestClient.getService(SAML2SPEntityService.class)).thenReturn(service);
-
-        WASAML2ClientCustomizer customizer = new WASAML2ClientCustomizer(waRestClient);
+        WASAML2ClientCustomizer customizer = new WASAML2ClientCustomizer(getWARestClient());
         SAML2Client client = getSAML2Client();
         customizer.customize(client);
         client.init();
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGeneratorTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGeneratorTest.java
index 43457616b8..99e5686e0b 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGeneratorTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientKeystoreGeneratorTest.java
@@ -19,44 +19,15 @@
 package org.apache.syncope.wa.starter.pac4j.saml;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
-import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
-import org.pac4j.saml.client.SAML2Client;
 import org.pac4j.saml.metadata.keystore.SAML2KeystoreGenerator;
-import org.springframework.core.io.ClassPathResource;
 
 public class WASAML2ClientKeystoreGeneratorTest extends BaseWASAML2ClientTest {
 
-    private static WARestClient getWaRestClient() throws Exception {
-        SAML2SPEntityTO keystoreTO = new SAML2SPEntityTO.Builder()
-                .key("CAS")
-                .keystore(getKeystoreAsString())
-                .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(),
-                        StandardCharsets.UTF_8))
-                .build();
-        SAML2SPEntityService service = mock(SAML2SPEntityService.class);
-        when(service.get(anyString())).thenReturn(keystoreTO);
-        doNothing().when(service).set(any(SAML2SPEntityTO.class));
-
-        WARestClient waRestClient = mock(WARestClient.class);
-        when(waRestClient.getService(SAML2SPEntityService.class)).thenReturn(service);
-        return waRestClient;
-    }
-
     @Test
     public void generate() throws Exception {
-        SAML2Client client = getSAML2Client();
-        SAML2KeystoreGenerator generator = new WASAML2ClientKeystoreGenerator(getWaRestClient(), client);
+        SAML2KeystoreGenerator generator = new WASAML2ClientKeystoreGenerator(getWARestClient(), getSAML2Client());
         assertDoesNotThrow(generator::generate);
     }
 }
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGeneratorTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGeneratorTest.java
index 5683c09707..d5449e96a8 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGeneratorTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2ClientMetadataGeneratorTest.java
@@ -19,50 +19,22 @@
 package org.apache.syncope.wa.starter.pac4j.saml;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
 import org.pac4j.saml.client.SAML2Client;
 import org.pac4j.saml.metadata.SAML2MetadataGenerator;
-import org.springframework.core.io.ClassPathResource;
 
 public class WASAML2ClientMetadataGeneratorTest extends BaseWASAML2ClientTest {
 
-    private static WARestClient getWaRestClient() throws IOException {
-        SAML2SPEntityTO metadataTO = new SAML2SPEntityTO.Builder()
-                .key("Syncope")
-                .metadata(IOUtils.toString(new ClassPathResource("sp-metadata.xml").getInputStream(),
-                        StandardCharsets.UTF_8))
-                .build();
-
-        SAML2SPEntityService saml2SPMetadataService = mock(SAML2SPEntityService.class);
-        when(saml2SPMetadataService.get(anyString())).thenReturn(metadataTO);
-        doNothing().when(saml2SPMetadataService).set(any(SAML2SPEntityTO.class));
-
-        WARestClient waRestClient = mock(WARestClient.class);
-        when(waRestClient.getService(SAML2SPEntityService.class)).thenReturn(saml2SPMetadataService);
-        return waRestClient;
-    }
-
     @Test
     public void storeMetadata() throws Exception {
         SAML2Client client = getSAML2Client();
         String keystoreFile = File.createTempFile("keystore", "jks").getCanonicalPath();
         client.getConfiguration().setKeystoreResourceFilepath(keystoreFile);
 
-        SAML2MetadataGenerator generator = new WASAML2ClientMetadataGenerator(getWaRestClient(), client);
+        SAML2MetadataGenerator generator = new WASAML2ClientMetadataGenerator(getWARestClient(), client);
         EntityDescriptor entityDescriptor = generator.buildEntityDescriptor();
         String metadata = generator.getMetadata(entityDescriptor);
         assertNotNull(generator.storeMetadata(metadata, false));
diff --git a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolverTest.java b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolverTest.java
index c30758ecea..60d4e652bc 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolverTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/pac4j/saml/WASAML2MetadataResolverTest.java
@@ -19,21 +19,10 @@
 package org.apache.syncope.wa.starter.pac4j.saml;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.io.File;
-import java.util.Base64;
-import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.to.SAML2SPEntityTO;
-import org.apache.syncope.common.rest.api.service.SAML2SPEntityService;
-import org.apache.syncope.wa.bootstrap.WARestClient;
 import org.junit.jupiter.api.Test;
 import org.pac4j.saml.client.SAML2Client;
-import org.springframework.core.io.ClassPathResource;
 
 public class WASAML2MetadataResolverTest extends BaseWASAML2ClientTest {
 
@@ -43,20 +32,7 @@ public class WASAML2MetadataResolverTest extends BaseWASAML2ClientTest {
         String keystoreFile = File.createTempFile("keystore", "jks").getCanonicalPath();
         client.getConfiguration().setKeystoreResourceFilepath(keystoreFile);
 
-        SAML2SPEntityTO metadataTO = new SAML2SPEntityTO.Builder()
-                .key("Syncope")
-                .metadata(Base64.getEncoder().encodeToString(
-                        IOUtils.toByteArray(new ClassPathResource("sp-metadata.xml").getInputStream())))
-                .build();
-
-        SAML2SPEntityService saml2SPMetadataService = mock(SAML2SPEntityService.class);
-        when(saml2SPMetadataService.get(anyString())).thenReturn(metadataTO);
-        doNothing().when(saml2SPMetadataService).set(any(SAML2SPEntityTO.class));
-
-        WARestClient waRestClient = mock(WARestClient.class);
-        when(waRestClient.getService(SAML2SPEntityService.class)).thenReturn(saml2SPMetadataService);
-
-        WASAML2MetadataResolver resolver = new WASAML2MetadataResolver(waRestClient, client);
+        WASAML2MetadataResolver resolver = new WASAML2MetadataResolver(getWARestClient(), client);
         assertNotNull(resolver.fetchMetadata());
     }
 }