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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0398acc977 Switch to Spring Boot 3.4 / CAS 7.2 / CXF 4.1 (#969)
0398acc977 is described below

commit 0398acc977feb4b0e0b022966513310a8f909769
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Tue Jan 28 17:33:45 2025 +0100

    Switch to Spring Boot 3.4 / CAS 7.2 / CXF 4.1 (#969)
---
 .../support/SyncopeNeo4jRepositoryFactory.java     |   8 +-
 .../apache/syncope/core/logic/SAML2SP4UILogic.java |   2 +-
 .../org/apache/syncope/fit/AbstractITCase.java     |  39 +--
 ...{OIDCSRAITCase.java => AbstractOIDCITCase.java} |  45 +---
 .../apache/syncope/fit/sra/AbstractSRAITCase.java  |   2 +-
 .../apache/syncope/fit/sra/OAUTH2SRAITCase.java    |   2 +-
 .../org/apache/syncope/fit/sra/OIDCSRAITCase.java  | 275 +--------------------
 .../apache/syncope/fit/ui/SAML2SP4UIITCase.java    |   4 -
 pom.xml                                            |  66 +----
 .../sra/security/pac4j/RedirectionActionUtils.java |  59 -----
 .../pac4j/ServerWebExchangeHttpActionAdapter.java  |  70 ++++++
 .../saml2/SAML2RequestServerLogoutHandler.java     |   6 +-
 .../SAML2WebSsoAuthenticationRequestWebFilter.java |   4 +-
 sra/src/main/resources/sra.properties              |   2 +-
 .../asciidoc/getting-started/introduction.adoc     |   2 +-
 .../reference-guide/architecture/core.adoc         |   2 +-
 .../concepts/attributerepositories.adoc            |  14 +-
 .../concepts/authenticationmodules.adoc            |  36 +--
 .../concepts/clientapplications.adoc               |   6 +-
 .../reference-guide/concepts/entitlements.adoc     |   2 +-
 .../reference-guide/concepts/policies.adoc         |   8 +-
 .../asciidoc/reference-guide/concepts/reports.adoc |   2 +-
 .../asciidoc/reference-guide/concepts/routes.adoc  |   4 +-
 .../asciidoc/reference-guide/concepts/tasks.adoc   |   8 +-
 .../reference-guide/concepts/typemanagement.adoc   |   2 +-
 .../configuration/configurationparameters.adoc     |   2 +-
 .../reference-guide/configuration/dbms.adoc        |   8 +-
 .../reference-guide/configuration/deployment.adoc  |   8 +-
 .../asciidoc/reference-guide/usage/actuator.adoc   |  14 +-
 src/main/asciidoc/reference-guide/usage/core.adoc  |   2 +-
 .../reference-guide/usage/customization.adoc       |   8 +-
 wa/starter/pom.xml                                 |  11 +-
 .../syncope/wa/starter/config/WAContext.java       |  12 +-
 .../saml/idp/WASamlIdPCasEventListener.java        |  31 ---
 .../thymeleaf/templates/fragments/footer.html      |  20 +-
 wa/starter/src/main/resources/wa.properties        |  27 +-
 .../apache/syncope/wa/starter/AbstractTest.java    |  27 +-
 37 files changed, 260 insertions(+), 580 deletions(-)

diff --git 
a/core/persistence-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/SyncopeNeo4jRepositoryFactory.java
 
b/core/persistence-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/SyncopeNeo4jRepositoryFactory.java
index bea0c09b89..109c1ed527 100644
--- 
a/core/persistence-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/SyncopeNeo4jRepositoryFactory.java
+++ 
b/core/persistence-neo4j/src/main/java/org/springframework/data/neo4j/repository/support/SyncopeNeo4jRepositoryFactory.java
@@ -28,7 +28,8 @@ import 
org.springframework.data.repository.core.RepositoryMetadata;
 import org.springframework.data.repository.core.support.RepositoryComposition;
 import 
org.springframework.data.repository.core.support.RepositoryFactorySupport;
 import org.springframework.data.repository.query.QueryLookupStrategy;
-import 
org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
+import org.springframework.data.repository.query.ValueExpressionDelegate;
+import org.springframework.lang.Nullable;
 
 public class SyncopeNeo4jRepositoryFactory extends RepositoryFactorySupport {
 
@@ -63,10 +64,9 @@ public class SyncopeNeo4jRepositoryFactory extends 
RepositoryFactorySupport {
 
     @Override
     protected Optional<QueryLookupStrategy> getQueryLookupStrategy(
-            final QueryLookupStrategy.Key key,
-            final QueryMethodEvaluationContextProvider 
evaluationContextProvider) {
+            final @Nullable QueryLookupStrategy.Key key, final 
ValueExpressionDelegate valueExpressionDelegate) {
 
-        return delegate.getQueryLookupStrategy(key, evaluationContextProvider);
+        return delegate.getQueryLookupStrategy(key, valueExpressionDelegate);
     }
 
     @Override
diff --git 
a/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/SAML2SP4UILogic.java
 
b/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/SAML2SP4UILogic.java
index 12d8415d05..ca96a99001 100644
--- 
a/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/SAML2SP4UILogic.java
+++ 
b/ext/saml2sp4ui/logic/src/main/java/org/apache/syncope/core/logic/SAML2SP4UILogic.java
@@ -367,7 +367,7 @@ public class SAML2SP4UILogic extends 
AbstractSAML2SP4UILogic {
             keyValue = nameID.getValue();
         }
 
-        loginResp.setNotOnOrAfter(new 
Date(authCreds.getConditions().getNotOnOrAfter().toInstant().toEpochMilli()));
+        loginResp.setNotOnOrAfter(new 
Date(authCreds.getConditions().getNotOnOrAfter().toEpochMilli()));
 
         loginResp.setSessionIndex(authCreds.getSessionIndex());
 
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 016026baf3..a3038f2ec1 100644
--- a/fit/wa-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -49,7 +49,6 @@ import 
org.apache.syncope.common.rest.api.service.SAML2SP4UIIdPService;
 import org.apache.syncope.common.rest.api.service.SRARouteService;
 import org.apache.syncope.common.rest.api.service.UserService;
 import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
-import org.apache.syncope.fit.sra.AbstractSRAITCase;
 import org.apereo.cas.oidc.OidcConstants;
 import org.jsoup.Connection;
 import org.jsoup.Jsoup;
@@ -60,7 +59,7 @@ import org.slf4j.LoggerFactory;
 
 public abstract class AbstractITCase {
 
-    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractSRAITCase.class);
+    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractITCase.class);
 
     protected static final String ADMIN_UNAME = "admin";
 
@@ -159,45 +158,53 @@ public abstract class AbstractITCase {
     protected static Triple<String, String, String> parseSAMLRequestForm(final 
String body) {
         FormElement form = (FormElement) 
Jsoup.parse(body).body().getElementsByTag("form").first();
         assertNotNull(form);
+        LOG.debug("SAML Request Form: {}", form.outerHtml());
 
         String action = form.attr("action");
         assertNotNull(action);
+        LOG.debug("SAML Request Form action: {}", action);
 
-        Optional<String> relayState = form.formData().stream().
+        String relayState = form.formData().stream().
                 filter(keyval -> "RelayState".equals(keyval.key())).
                 map(Connection.KeyVal::value).
-                findFirst();
-        assertTrue(relayState.isPresent());
+                findFirst().
+                orElseThrow(() -> new IllegalArgumentException("No RelayState 
found"));
+        LOG.debug("SAML Request Form RelayState: {}", relayState);
 
-        Optional<String> samlRequest = form.formData().stream().
+        String samlRequest = form.formData().stream().
                 filter(keyval -> "SAMLRequest".equals(keyval.key())).
                 map(Connection.KeyVal::value).
-                findFirst();
-        assertTrue(samlRequest.isPresent());
+                findFirst().
+                orElseThrow(() -> new IllegalArgumentException("No SAMLRequest 
found"));
+        LOG.debug("SAML Request Form SAMLRequest: {}", samlRequest);
 
-        return Triple.of(action, relayState.get(), samlRequest.get());
+        return Triple.of(action, relayState, samlRequest);
     }
 
     protected static Triple<String, String, String> 
parseSAMLResponseForm(final String body) {
         FormElement form = (FormElement) 
Jsoup.parse(body).body().getElementsByTag("form").first();
         assertNotNull(form);
+        LOG.debug("SAML Response Form: {}", form.outerHtml());
 
         String action = form.attr("action");
         assertNotNull(action);
+        LOG.debug("SAML Response Form action: {}", action);
 
-        Optional<String> relayState = form.formData().stream().
+        String relayState = form.formData().stream().
                 filter(keyval -> "RelayState".equals(keyval.key())).
                 map(Connection.KeyVal::value).
-                findFirst();
-        assertTrue(relayState.isPresent());
+                findFirst().
+                orElseThrow(() -> new IllegalArgumentException("No RelayState 
found"));
+        LOG.debug("SAML Response Form RelayState: {}", relayState);
 
-        Optional<String> samlResponse = form.formData().stream().
+        String samlResponse = form.formData().stream().
                 filter(keyval -> "SAMLResponse".equals(keyval.key())).
                 map(Connection.KeyVal::value).
-                findFirst();
-        assertTrue(samlResponse.isPresent());
+                findFirst().
+                orElseThrow(() -> new IllegalArgumentException("No 
SAMLResponse found"));
+        LOG.debug("SAML Response Form SAMLResponse: {}", samlResponse);
 
-        return Triple.of(action, relayState.get(), samlResponse.get());
+        return Triple.of(action, relayState, samlResponse);
     }
 
     protected static String extractWAExecution(final String body) {
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractOIDCITCase.java
similarity index 89%
copy from 
fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
copy to 
fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractOIDCITCase.java
index 0ef72a1366..2f5ae3042c 100644
--- 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
+++ 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractOIDCITCase.java
@@ -27,7 +27,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -38,15 +37,11 @@ import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import java.io.IOException;
-import java.io.InputStream;
-import java.lang.invoke.MethodHandles;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.http.Consts;
 import org.apache.http.HttpStatus;
@@ -71,10 +66,9 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
 import org.apereo.cas.oidc.OidcConstants;
 import org.jsoup.Jsoup;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
-public class OIDCSRAITCase extends AbstractSRAITCase {
+abstract class AbstractOIDCITCase extends AbstractSRAITCase {
 
     protected static String SRA_REGISTRATION_ID;
 
@@ -86,13 +80,6 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
 
     protected static String TOKEN_URI;
 
-    @BeforeAll
-    public static void startSRA() throws IOException, InterruptedException, 
TimeoutException {
-        
assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
-
-        doStartSRA("oidc");
-    }
-
     protected static void oidcClientAppSetup(
             final String appName,
             final String sraRegistrationId,
@@ -159,30 +146,8 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
         WA_CONFIG_SERVICE.pushToWA(WAConfigService.PushSubject.clientApps, 
List.of());
     }
 
-    @BeforeAll
-    public static void clientAppSetup() {
-        
assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
-
-        Properties props = new Properties();
-        try (InputStream propStream = 
OIDCSRAITCase.class.getResourceAsStream("/sra-oidc.properties")) {
-            props.load(propStream);
-        } catch (Exception e) {
-            fail("Could not load /sra-oidc.properties", e);
-        }
-        SRA_REGISTRATION_ID = "OIDC";
-        CLIENT_APP_ID = 1L;
-        CLIENT_ID = props.getProperty("sra.oidc.client-id");
-        assertNotNull(CLIENT_ID);
-        CLIENT_SECRET = props.getProperty("sra.oidc.client-secret");
-        assertNotNull(CLIENT_SECRET);
-        TOKEN_URI = WA_ADDRESS + "/oidc/accessToken";
-
-        oidcClientAppSetup(
-                OIDCSRAITCase.class.getName(), SRA_REGISTRATION_ID, 
CLIENT_APP_ID, CLIENT_ID, CLIENT_SECRET);
-    }
-
     @Test
-    public void web() throws IOException {
+    void web() throws IOException {
         CloseableHttpClient httpclient = HttpClients.createDefault();
         HttpClientContext context = HttpClientContext.create();
         context.setCookieStore(new BasicCookieStore());
@@ -279,12 +244,10 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
         groups.stream().anyMatch(g -> ((Map<String, String>) 
g).equals(Map.of("groupName", "citizen")));
     }
 
-    protected boolean checkIdToken() {
-        return true;
-    }
+    protected abstract boolean checkIdToken();
 
     @Test
-    public void rest() throws IOException, ParseException {
+    void rest() throws IOException, ParseException {
         // 0. access public route
         WebClient client = WebClient.create(SRA_ADDRESS + "/public/post").
                 
accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractSRAITCase.java
 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractSRAITCase.java
index ce9e7ab5ac..2e979013c9 100644
--- 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractSRAITCase.java
+++ 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/AbstractSRAITCase.java
@@ -65,7 +65,7 @@ import org.apache.syncope.fit.AbstractITCase;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 
-public abstract class AbstractSRAITCase extends AbstractITCase {
+abstract class AbstractSRAITCase extends AbstractITCase {
 
     protected static final JsonMapper MAPPER = 
JsonMapper.builder().findAndAddModules().build();
 
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
index 4f6cec2040..1d89ac56d5 100644
--- 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
+++ 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OAUTH2SRAITCase.java
@@ -32,7 +32,7 @@ import org.apache.http.HttpStatus;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.junit.jupiter.api.BeforeAll;
 
-public class OAUTH2SRAITCase extends OIDCSRAITCase {
+class OAUTH2SRAITCase extends AbstractOIDCITCase {
 
     @BeforeAll
     public static void startSRA() throws IOException, InterruptedException, 
TimeoutException {
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
index 0ef72a1366..16bf410049 100644
--- 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
+++ 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
@@ -18,73 +18,18 @@
  */
 package org.apache.syncope.fit.sra;
 
-import static org.awaitility.Awaitility.await;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.oneOf;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.nimbusds.jwt.SignedJWT;
-import jakarta.ws.rs.core.Form;
-import jakarta.ws.rs.core.HttpHeaders;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.invoke.MethodHandles;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.http.Consts;
-import org.apache.http.HttpStatus;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.protocol.HttpClientContext;
-import org.apache.http.impl.client.BasicCookieStore;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.util.EntityUtils;
-import org.apache.syncope.common.lib.OIDCScopeConstants;
-import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.to.OIDCRPClientAppTO;
-import org.apache.syncope.common.lib.types.ClientAppType;
-import org.apache.syncope.common.lib.types.OIDCGrantType;
-import org.apache.syncope.common.lib.types.OIDCSubjectType;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
-import org.apereo.cas.oidc.OidcConstants;
-import org.jsoup.Jsoup;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
 
-public class OIDCSRAITCase extends AbstractSRAITCase {
-
-    protected static String SRA_REGISTRATION_ID;
-
-    protected static Long CLIENT_APP_ID;
-
-    protected static String CLIENT_ID;
-
-    protected static String CLIENT_SECRET;
-
-    protected static String TOKEN_URI;
+class OIDCSRAITCase extends AbstractOIDCITCase {
 
     @BeforeAll
     public static void startSRA() throws IOException, InterruptedException, 
TimeoutException {
@@ -93,72 +38,6 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
         doStartSRA("oidc");
     }
 
-    protected static void oidcClientAppSetup(
-            final String appName,
-            final String sraRegistrationId,
-            final Long clientAppId,
-            final String clientId,
-            final String clientSecret) {
-
-        OIDCRPClientAppTO clientApp = 
CLIENT_APP_SERVICE.list(ClientAppType.OIDCRP).stream().
-                filter(app -> appName.equals(app.getName())).
-                map(OIDCRPClientAppTO.class::cast).
-                findFirst().
-                orElseGet(() -> {
-                    OIDCRPClientAppTO app = new OIDCRPClientAppTO();
-                    app.setName(appName);
-                    app.setRealm(SyncopeConstants.ROOT_REALM);
-                    app.setClientAppId(clientAppId);
-                    app.setClientId(clientId);
-                    app.setClientSecret(clientSecret);
-                    app.setBypassApprovalPrompt(false);
-
-                    Response response = 
CLIENT_APP_SERVICE.create(ClientAppType.OIDCRP, app);
-                    if (response.getStatusInfo().getStatusCode() != 
Response.Status.CREATED.getStatusCode()) {
-                        fail("Could not create OIDC Client App");
-                    }
-
-                    return CLIENT_APP_SERVICE.read(
-                            ClientAppType.OIDCRP, 
response.getHeaderString(RESTHeaders.RESOURCE_KEY));
-                });
-
-        clientApp.setJwtAccessToken(true);
-        clientApp.setClientId(clientId);
-        clientApp.setClientSecret(clientSecret);
-        clientApp.setSubjectType(OIDCSubjectType.PUBLIC);
-        clientApp.getRedirectUris().clear();
-        clientApp.getRedirectUris().add(SRA_ADDRESS + "/login/oauth2/code/" + 
sraRegistrationId);
-        clientApp.setSignIdToken(true);
-        clientApp.setLogoutUri(SRA_ADDRESS + "/logout");
-        clientApp.setAuthPolicy(getAuthPolicy().getKey());
-        clientApp.setAttrReleasePolicy(getAttrReleasePolicy().getKey());
-        clientApp.getScopes().add(OIDCScopeConstants.OPEN_ID);
-        clientApp.getScopes().add(OIDCScopeConstants.PROFILE);
-        clientApp.getScopes().add(OIDCScopeConstants.EMAIL);
-        clientApp.getSupportedGrantTypes().add(OIDCGrantType.password);
-        
clientApp.getSupportedGrantTypes().add(OIDCGrantType.authorization_code);
-
-        CLIENT_APP_SERVICE.update(ClientAppType.OIDCRP, clientApp);
-
-        await().atMost(60, TimeUnit.SECONDS).pollInterval(20, 
TimeUnit.SECONDS).until(() -> {
-            try {
-                String metadata = WebClient.create(
-                        WA_ADDRESS + "/oidc/" + 
OidcConstants.WELL_KNOWN_OPENID_CONFIGURATION_URL).
-                        get().readEntity(String.class);
-                if (!metadata.contains("groups")) {
-                    
WA_CONFIG_SERVICE.pushToWA(WAConfigService.PushSubject.conf, List.of());
-                    throw new IllegalStateException();
-                }
-
-                return true;
-            } catch (Exception e) {
-                // ignore
-            }
-            return false;
-        });
-        WA_CONFIG_SERVICE.pushToWA(WAConfigService.PushSubject.clientApps, 
List.of());
-    }
-
     @BeforeAll
     public static void clientAppSetup() {
         
assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
@@ -181,158 +60,8 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
                 OIDCSRAITCase.class.getName(), SRA_REGISTRATION_ID, 
CLIENT_APP_ID, CLIENT_ID, CLIENT_SECRET);
     }
 
-    @Test
-    public void web() throws IOException {
-        CloseableHttpClient httpclient = HttpClients.createDefault();
-        HttpClientContext context = HttpClientContext.create();
-        context.setCookieStore(new BasicCookieStore());
-
-        // 1. public
-        HttpGet get = new HttpGet(SRA_ADDRESS + "/public/get?" + QUERY_STRING);
-        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
-        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-        CloseableHttpResponse response = httpclient.execute(get, context);
-
-        ObjectNode headers = checkGetResponse(response, 
get.getURI().toASCIIString().replace("/public", ""));
-        assertFalse(headers.has(HttpHeaders.COOKIE));
-
-        // 2. protected
-        get = new HttpGet(SRA_ADDRESS + "/protected/get?" + QUERY_STRING);
-        String originalRequestURI = get.getURI().toASCIIString();
-        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
-        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-        response = httpclient.execute(get, context);
-        assertEquals(HttpStatus.SC_OK, 
response.getStatusLine().getStatusCode());
-
-        // 2a. redirected to WA login screen
-        String responseBody = EntityUtils.toString(response.getEntity());
-        response = authenticateToWA("bellini", "password", responseBody, 
httpclient, context);
-
-        // 2b. WA attribute consent screen
-        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
-            responseBody = EntityUtils.toString(response.getEntity());
-            String execution = extractWAExecution(responseBody);
-
-            List<NameValuePair> form = new ArrayList<>();
-            form.add(new BasicNameValuePair("_eventId", "confirm"));
-            form.add(new BasicNameValuePair("execution", execution));
-            form.add(new BasicNameValuePair("option", "1"));
-            form.add(new BasicNameValuePair("reminder", "30"));
-            form.add(new BasicNameValuePair("reminderTimeUnit", "days"));
-
-            HttpPost post = new HttpPost(WA_ADDRESS + "/login");
-            post.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
-            post.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-            post.setEntity(new UrlEncodedFormEntity(form, Consts.UTF_8));
-            response = httpclient.execute(post, context);
-        }
-        assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, 
response.getStatusLine().getStatusCode());
-
-        // 2c. WA scope consent screen
-        get = new 
HttpGet(response.getLastHeader(HttpHeaders.LOCATION).getValue());
-        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
-        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-        response = httpclient.execute(get, context);
-        assertEquals(HttpStatus.SC_OK, 
response.getStatusLine().getStatusCode());
-
-        responseBody = EntityUtils.toString(response.getEntity());
-
-        String allow = Jsoup.parse(responseBody).body().
-                getElementsByTag("a").select("a[name=allow]").first().
-                attr("href");
-        assertNotNull(allow);
-
-        // 2d. finally get requested content
-        get = new HttpGet(allow);
-        get.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
-        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-        response = httpclient.execute(get, context);
-
-        headers = checkGetResponse(response, 
originalRequestURI.replace("/protected", ""));
-        
assertTrue(headers.get(HttpHeaders.COOKIE).asText().contains("SESSION"));
-
-        // 3. logout
-        get = new HttpGet(SRA_ADDRESS + "/protected/logout");
-        get.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
-        response = httpclient.execute(get, context);
-        checkLogout(response);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void checkJWT(final String token, final boolean idToken) throws 
ParseException {
-        assertNotNull(token);
-        SignedJWT jwt = SignedJWT.parse(token);
-        assertNotNull(jwt);
-        JWTClaimsSet idTokenClaimsSet = jwt.getJWTClaimsSet();
-        assertEquals("verdi", idTokenClaimsSet.getSubject());
-        if (idToken) {
-            assertEquals("verdi", 
idTokenClaimsSet.getStringClaim("preferred_username"));
-        }
-        assertEquals("[email protected]", 
idTokenClaimsSet.getStringClaim("email"));
-        assertEquals("Verdi", idTokenClaimsSet.getStringClaim("family_name"));
-        assertEquals("Giuseppe", 
idTokenClaimsSet.getStringClaim("given_name"));
-        assertEquals("Giuseppe Verdi", 
idTokenClaimsSet.getStringClaim("name"));
-        List<Object> groups = idTokenClaimsSet.getListClaim("groups");
-        assertEquals(3, groups.size());
-        groups.stream().anyMatch(g -> ((Map<String, String>) 
g).equals(Map.of("groupName", "root")));
-        groups.stream().anyMatch(g -> ((Map<String, String>) 
g).equals(Map.of("groupName", "child")));
-        groups.stream().anyMatch(g -> ((Map<String, String>) 
g).equals(Map.of("groupName", "citizen")));
-    }
-
+    @Override
     protected boolean checkIdToken() {
         return true;
     }
-
-    @Test
-    public void rest() throws IOException, ParseException {
-        // 0. access public route
-        WebClient client = WebClient.create(SRA_ADDRESS + "/public/post").
-                
accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
-        Response response = client.post(null);
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-        // 1. obtain id and access tokens
-        Form form = new Form().
-                param("grant_type", "password").
-                param("client_id", CLIENT_ID).
-                param("client_secret", CLIENT_SECRET).
-                param("username", "verdi").
-                param("password", "password").
-                param("scope", "openid profile email syncope");
-        response = WebClient.create(TOKEN_URI).post(form);
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        
assertTrue(response.getHeaderString(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.APPLICATION_JSON));
-
-        JsonNode json = MAPPER.readTree(response.readEntity(String.class));
-
-        if (checkIdToken()) {
-            // 1a. take and verify id_token
-            String idToken = json.get("id_token").asText();
-            assertNotNull(idToken);
-            checkJWT(idToken, true);
-        }
-
-        // 1b. take and verify access_token
-        String accessToken = json.get("access_token").asText();
-        checkJWT(accessToken, false);
-
-        // 2. access protected route
-        client = WebClient.create(SRA_ADDRESS + "/protected/post").
-                authorization("Bearer " + accessToken).
-                
accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
-        response = client.post(null);
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-
-        json = MAPPER.readTree(response.readEntity(String.class));
-
-        ObjectNode headers = (ObjectNode) json.get("headers");
-        assertEquals(MediaType.APPLICATION_JSON, 
headers.get(HttpHeaders.ACCEPT).asText());
-        assertEquals(MediaType.APPLICATION_JSON, 
headers.get(HttpHeaders.CONTENT_TYPE).asText());
-        assertThat(headers.get("X-Forwarded-Host").asText(), 
is(oneOf("localhost:8080", "127.0.0.1:8080")));
-
-        String withHost = 
client.getBaseURI().toASCIIString().replace("/protected", "");
-        String withIP = withHost.replace("localhost", "127.0.0.1");
-        assertThat(json.get("url").asText(), is(oneOf(withHost, withIP)));
-    }
 }
diff --git 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/SAML2SP4UIITCase.java
 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/SAML2SP4UIITCase.java
index 929824c8c4..9a869059b1 100644
--- 
a/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/SAML2SP4UIITCase.java
+++ 
b/fit/wa-reference/src/test/java/org/apache/syncope/fit/ui/SAML2SP4UIITCase.java
@@ -242,10 +242,6 @@ public class SAML2SP4UIITCase extends AbstractUIITCase {
 
         // 2c. WA attribute consent screen
         if (isOk) {
-            // check attribute repository
-            assertTrue(responseBody.contains("identifier"));
-            assertTrue(responseBody.contains("[value1]"));
-
             String execution = extractWAExecution(responseBody);
 
             List<NameValuePair> form = new ArrayList<>();
diff --git a/pom.xml b/pom.xml
index f34696ee67..c5b6cf8fb8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -392,7 +392,7 @@ under the License.
   </contributors>
 
   <properties>
-    
<project.build.outputTimestamp>2024-12-27T11:02:14Z</project.build.outputTimestamp>
+    
<project.build.outputTimestamp>2025-01-27T11:24:15Z</project.build.outputTimestamp>
     <syncope.version>${project.version}</syncope.version>
 
     <connid.version>1.6.0.0-SNAPSHOT</connid.version>
@@ -410,12 +410,12 @@ under the License.
     <connid.cmd.version>0.5</connid.cmd.version>
     <connid.kafka.version>1.0.0</connid.kafka.version>
 
-    <cxf.version>4.0.6</cxf.version>
+    <cxf.version>4.1.0</cxf.version>
     <bouncycastle.version>1.80</bouncycastle.version>
     <nimbus-jose-jwt.version>10.0.1</nimbus-jose-jwt.version>
 
-    <spring-boot.version>3.3.8</spring-boot.version>
-    <spring-cloud-gateway.version>4.1.6</spring-cloud-gateway.version>
+    <spring-boot.version>3.4.2</spring-boot.version>
+    <spring-cloud-gateway.version>4.2.0</spring-cloud-gateway.version>
 
     <openjpa.version>4.0.1</openjpa.version>
 
@@ -436,9 +436,9 @@ under the License.
     <commons-jexl.version>3.4.0</commons-jexl.version>
     <commons-text.version>1.13.0</commons-text.version>
 
-    <pac4j.version>6.0.6</pac4j.version>
+    <pac4j.version>6.1.0</pac4j.version>
 
-    <cas.version>7.1.4</cas.version>
+    <cas.version>7.2.0-RC4</cas.version>
     <cas-client.version>4.0.4</cas-client.version>
 
     <swagger-core.version>2.2.28</swagger-core.version>
@@ -498,7 +498,7 @@ under the License.
     <cargo.rmi.port>9805</cargo.rmi.port>
     <cargo.deployable.ping.timeout>60000</cargo.deployable.ping.timeout>
 
-    <tomcat.version>10.1.33</tomcat.version>
+    <tomcat.version>10.1.34</tomcat.version>
     <wildfly.version>35.0.0.Final</wildfly.version>
     <payara.version>6.2025.1</payara.version>
     <jakarta.faces.version>4.1.2</jakarta.faces.version>
@@ -1360,7 +1360,7 @@ under the License.
       <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-contract-wiremock</artifactId>
-        <version>4.1.5</version>
+        <version>${spring-cloud-gateway.version}</version>
         <scope>test</scope>
       </dependency>
     </dependencies>
@@ -2052,11 +2052,11 @@ under the License.
             
<link>https://commons.apache.org/proper/commons-lang/javadocs/api-release/</link>
             
<link>https://commons.apache.org/proper/commons-jexl/apidocs/</link>
             <link>https://tika.apache.org/3.0.0/api/</link>
-            <link>https://docs.spring.io/spring-boot/3.3/api/java/</link>
-            
<link>https://docs.spring.io/spring-framework/docs/6.1.x/javadoc-api/</link>
-            
<link>https://docs.spring.io/spring-security/site/docs/6.3.6/api/</link>
+            <link>https://docs.spring.io/spring-boot/3.4/api/java/</link>
+            
<link>https://docs.spring.io/spring-framework/docs/6.2.x/javadoc-api/</link>
+            
<link>https://docs.spring.io/spring-security/site/docs/6.4.x/api/</link>
             <link>https://www.flowable.com/open-source/docs/javadocs/</link>
-            <link>https://docs.swagger.io/swagger-core/v2.2.27/apidocs/</link>
+            <link>https://docs.swagger.io/swagger-core/v2.2.28/apidocs/</link>
           </links>
           <additionalOptions>
             <additionalOption>--legal-notices</additionalOption>
@@ -2345,48 +2345,6 @@ under the License.
         </plugins>
       </build>
     </profile>
-
-    <profile>
-      <id>jdk24</id>
-
-      <activation>
-        <jdk>[24,)</jdk>
-      </activation>
-
-      <properties>
-        <mockito.version>5.15.2</mockito.version>
-        <byte-buddy.version>1.16.1</byte-buddy.version>
-      </properties>
-
-      <dependencyManagement>
-        <dependencies>
-          <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-junit-jupiter</artifactId>
-            <version>${mockito.version}</version>
-            <scope>test</scope>
-          </dependency>
-          <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <version>${mockito.version}</version>
-            <scope>test</scope>
-          </dependency>
-          <dependency>
-            <groupId>net.bytebuddy</groupId>
-            <artifactId>byte-buddy</artifactId>
-            <version>${byte-buddy.version}</version>
-            <scope>test</scope>
-          </dependency>
-          <dependency>
-            <groupId>net.bytebuddy</groupId>
-            <artifactId>byte-buddy-agent</artifactId>
-            <version>${byte-buddy.version}</version>
-            <scope>test</scope>
-          </dependency>
-        </dependencies>
-      </dependencyManagement>
-    </profile>
   </profiles>
 
   <modules>
diff --git 
a/sra/src/main/java/org/apache/syncope/sra/security/pac4j/RedirectionActionUtils.java
 
b/sra/src/main/java/org/apache/syncope/sra/security/pac4j/RedirectionActionUtils.java
deleted file mode 100644
index 63cbc6a68a..0000000000
--- 
a/sra/src/main/java/org/apache/syncope/sra/security/pac4j/RedirectionActionUtils.java
+++ /dev/null
@@ -1,59 +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.sra.security.pac4j;
-
-import java.net.URI;
-import java.util.Optional;
-import org.pac4j.core.exception.http.RedirectionAction;
-import org.pac4j.core.exception.http.WithContentAction;
-import org.pac4j.core.exception.http.WithLocationAction;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import reactor.core.publisher.Mono;
-
-public final class RedirectionActionUtils {
-
-    public static Mono<Void> handle(
-            final RedirectionAction action,
-            final ServerWebExchangeContext swec) {
-
-        if (action instanceof WithLocationAction withLocationAction) {
-            swec.getNative().getResponse().setStatusCode(HttpStatus.FOUND);
-            
swec.getNative().getResponse().getHeaders().setLocation(URI.create(withLocationAction.getLocation()));
-            return swec.getNative().getResponse().setComplete();
-        }
-
-        if (action instanceof WithContentAction withContentAction) {
-            String content = 
Optional.ofNullable(withContentAction.getContent()).
-                    orElseThrow(() -> new IllegalArgumentException("No content 
set for POST AuthnRequest"));
-
-            return Mono.defer(() -> {
-                
swec.getNative().getResponse().getHeaders().setContentType(MediaType.TEXT_HTML);
-                return swec.getNative().getResponse().
-                        
writeWith(Mono.just(swec.getNative().getResponse().bufferFactory().wrap(content.getBytes())));
-            });
-        }
-
-        throw new IllegalArgumentException("Unsupported Action: " + 
action.getClass().getName());
-    }
-
-    private RedirectionActionUtils() {
-        // private constructor for static utility class
-    }
-}
diff --git 
a/sra/src/main/java/org/apache/syncope/sra/security/pac4j/ServerWebExchangeHttpActionAdapter.java
 
b/sra/src/main/java/org/apache/syncope/sra/security/pac4j/ServerWebExchangeHttpActionAdapter.java
new file mode 100644
index 0000000000..0e03134b57
--- /dev/null
+++ 
b/sra/src/main/java/org/apache/syncope/sra/security/pac4j/ServerWebExchangeHttpActionAdapter.java
@@ -0,0 +1,70 @@
+/*
+ * 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.sra.security.pac4j;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import org.pac4j.core.context.WebContext;
+import org.pac4j.core.exception.TechnicalException;
+import org.pac4j.core.exception.http.HttpAction;
+import org.pac4j.core.exception.http.WithContentAction;
+import org.pac4j.core.exception.http.WithLocationAction;
+import org.pac4j.core.http.adapter.HttpActionAdapter;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import reactor.core.publisher.Mono;
+
+public class ServerWebExchangeHttpActionAdapter implements HttpActionAdapter {
+
+    public static final ServerWebExchangeHttpActionAdapter INSTANCE = new 
ServerWebExchangeHttpActionAdapter();
+
+    @Override
+    public Mono<Void> adapt(final HttpAction action, final WebContext context) 
{
+        if (action == null) {
+            throw new TechnicalException("No action provided");
+        }
+
+        ServerHttpResponse response = ((ServerWebExchangeContext) 
context).getNative().getResponse();
+
+        switch (action) {
+            case WithLocationAction withLocationAction -> {
+                response.setStatusCode(HttpStatus.FOUND);
+                
response.getHeaders().setLocation(URI.create(withLocationAction.getLocation()));
+                return response.setComplete();
+            }
+
+            case WithContentAction withContentAction -> {
+                String content = 
Optional.ofNullable(withContentAction.getContent()).
+                        orElseThrow(() -> new TechnicalException("No content 
set for POST AuthnRequest"));
+
+                return Mono.defer(() -> {
+                    response.getHeaders().setContentType(MediaType.TEXT_HTML);
+                    return response.writeWith(Mono.just(
+                            
response.bufferFactory().wrap(content.getBytes(StandardCharsets.UTF_8))));
+                });
+            }
+
+            default -> {
+                throw new TechnicalException("Unsupported Action: " + 
action.getClass().getName());
+            }
+        }
+    }
+}
diff --git 
a/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2RequestServerLogoutHandler.java
 
b/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2RequestServerLogoutHandler.java
index 57f5fcee80..2ada82e1a9 100644
--- 
a/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2RequestServerLogoutHandler.java
+++ 
b/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2RequestServerLogoutHandler.java
@@ -20,8 +20,8 @@ package org.apache.syncope.sra.security.saml2;
 
 import org.apache.syncope.sra.SessionConfig;
 import org.apache.syncope.sra.security.pac4j.NoOpSessionStore;
-import org.apache.syncope.sra.security.pac4j.RedirectionActionUtils;
 import org.apache.syncope.sra.security.pac4j.ServerWebExchangeContext;
+import 
org.apache.syncope.sra.security.pac4j.ServerWebExchangeHttpActionAdapter;
 import org.pac4j.core.context.CallContext;
 import org.pac4j.saml.client.SAML2Client;
 import org.pac4j.saml.credentials.SAML2AuthenticationCredentials;
@@ -50,7 +50,7 @@ public class SAML2RequestServerLogoutHandler implements 
ServerLogoutHandler {
     public Mono<Void> logout(final WebFilterExchange exchange, final 
Authentication authentication) {
         return exchange.getExchange().getSession().
                 flatMap(session -> {
-                    SAML2AuthenticationCredentials credentials = 
+                    SAML2AuthenticationCredentials credentials =
                             (SAML2AuthenticationCredentials) 
authentication.getPrincipal();
 
                     LOG.debug("Creating SAML2 SP Logout Request for IDP[{}] 
and Profile[{}]",
@@ -61,7 +61,7 @@ public class SAML2RequestServerLogoutHandler implements 
ServerLogoutHandler {
                     
cacheManager.getCache(SessionConfig.DEFAULT_CACHE).evictIfPresent(session.getId());
                     return 
session.invalidate().then(saml2Client.getLogoutAction(
                             new CallContext(swec, NoOpSessionStore.INSTANCE), 
credentials.getUserProfile(), null).
-                            map(action -> 
RedirectionActionUtils.handle(action, swec)).
+                            map(action -> 
ServerWebExchangeHttpActionAdapter.INSTANCE.adapt(action, swec)).
                             orElseThrow(() -> new IllegalStateException("No 
action generated")));
                 }).onErrorResume(Mono::error);
     }
diff --git 
a/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2WebSsoAuthenticationRequestWebFilter.java
 
b/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2WebSsoAuthenticationRequestWebFilter.java
index 30c5159723..3fd3e7c50b 100644
--- 
a/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2WebSsoAuthenticationRequestWebFilter.java
+++ 
b/sra/src/main/java/org/apache/syncope/sra/security/saml2/SAML2WebSsoAuthenticationRequestWebFilter.java
@@ -20,8 +20,8 @@ package org.apache.syncope.sra.security.saml2;
 
 import java.net.URI;
 import org.apache.syncope.sra.security.pac4j.NoOpSessionStore;
-import org.apache.syncope.sra.security.pac4j.RedirectionActionUtils;
 import org.apache.syncope.sra.security.pac4j.ServerWebExchangeContext;
+import 
org.apache.syncope.sra.security.pac4j.ServerWebExchangeHttpActionAdapter;
 import org.apache.syncope.sra.session.SessionUtils;
 import org.pac4j.core.context.CallContext;
 import org.pac4j.saml.client.SAML2Client;
@@ -67,7 +67,7 @@ public class SAML2WebSsoAuthenticationRequestWebFilter 
implements WebFilter {
 
                     return saml2Client.getRedirectionAction(
                             new CallContext(swec, NoOpSessionStore.INSTANCE)).
-                            map(action -> 
RedirectionActionUtils.handle(action, swec)).
+                            map(action -> 
ServerWebExchangeHttpActionAdapter.INSTANCE.adapt(action, swec)).
                             orElseThrow(() -> new IllegalStateException("No 
action generated"));
                 }).onErrorResume(Mono::error);
     }
diff --git a/sra/src/main/resources/sra.properties 
b/sra/src/main/resources/sra.properties
index eb3ae97a2a..a4973bb1c3 100644
--- a/sra/src/main/resources/sra.properties
+++ b/sra/src/main/resources/sra.properties
@@ -20,7 +20,7 @@ spring.main.banner-mode=log
 
 server.port=8080
 
-management.endpoint.gateway.enabled=true
+management.endpoint.gateway.access=UNRESTRICTED
 
management.endpoints.web.exposure.include=info,health,loggers,metrics,gateway,sraSessions
 management.endpoint.health.show-details=ALWAYS
 management.endpoint.env.show-values=WHEN_AUTHORIZED
diff --git a/src/main/asciidoc/getting-started/introduction.adoc 
b/src/main/asciidoc/getting-started/introduction.adoc
index 2317c9c329..e74249d295 100644
--- a/src/main/asciidoc/getting-started/introduction.adoc
+++ b/src/main/asciidoc/getting-started/introduction.adoc
@@ -146,7 +146,7 @@ http://www.bpmn.org/[BPMN 2.0^] implementations - or define 
new, custom ones.
  * *_Persistence_* manages all data (users, groups, attributes, resources, 
...) at a high level 
 using a standard https://en.wikipedia.org/wiki/Jakarta_Persistence[Jakarta 
Persistence 3.1] approach. The data is persisted to an underlying 
 database, referred to as *_Internal Storage_*. Consistency is ensured via the 
comprehensive
-https://docs.spring.io/spring-framework/reference/6.1/data-access/transaction.html[transaction
 management^] 
+https://docs.spring.io/spring-framework/reference/6.2/data-access/transaction.html[transaction
 management^] 
 provided by the Spring Framework. +
 Globally, this offers the ability to easily scale up to a million entities and 
at the same time allows great portability with no code 
 changes: PostgreSQL, MySQL, MariaDB and Oracle are fully supported deployment 
options.
diff --git a/src/main/asciidoc/reference-guide/architecture/core.adoc 
b/src/main/asciidoc/reference-guide/architecture/core.adoc
index 3d04e5bb05..712c6fee1d 100644
--- a/src/main/asciidoc/reference-guide/architecture/core.adoc
+++ b/src/main/asciidoc/reference-guide/architecture/core.adoc
@@ -83,7 +83,7 @@ All data (users, groups, attributes, resources, ...) is 
internally managed at a
 https://en.wikipedia.org/wiki/Jakarta_Persistence[Jakarta Persistence 3.1] 
approach based on https://openjpa.apache.org[Apache OpenJPA^].
 The data is persisted into an underlying 
 database, referred to as *_Internal Storage_*. Consistency is ensured via the 
comprehensive
-https://docs.spring.io/spring-framework/reference/6.1/data-access/transaction.html[transaction
 management^] 
+https://docs.spring.io/spring-framework/reference/6.2/data-access/transaction.html[transaction
 management^] 
 provided by the Spring Framework.
 
 Globally, this offers the ability to easily scale up to a million entities and 
at the same time allows great portability
diff --git 
a/src/main/asciidoc/reference-guide/concepts/attributerepositories.adoc 
b/src/main/asciidoc/reference-guide/concepts/attributerepositories.adoc
index 0aad019ae1..02021734d3 100644
--- a/src/main/asciidoc/reference-guide/concepts/attributerepositories.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/attributerepositories.adoc
@@ -23,12 +23,12 @@ certain <<policies-attribute-release,Attribute Release 
Policy>>.
 
 Some attribute repositories are provided:
 
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-JDBC.html[Database^]
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-LDAP.html[LDAP^]
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-Stub.html[Stub^]
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-Syncope.html[Syncope^]
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-AzureAD.html[Azure
 Active Directory^]
-* 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution-Okta.html[Okta^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-JDBC.html[Database^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-LDAP.html[LDAP^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-Stub.html[Stub^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-Syncope.html[Syncope^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-AzureAD.html[Azure
 Active Directory^]
+* 
https://apereo.github.io/cas/development/integration/Attribute-Resolution-Okta.html[Okta^]
 
 [TIP]
 ====
@@ -51,4 +51,4 @@ class.
 
 [NOTE]
 Attribute Repositories are dynamically translated into 
-https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution.html[CAS 
Attribute Resolution^] configuration.
+https://apereo.github.io/cas/development/integration/Attribute-Resolution.html[CAS
 Attribute Resolution^] configuration.
diff --git 
a/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc 
b/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
index 1930eb16f6..89c691e217 100644
--- a/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/authenticationmodules.adoc
@@ -24,24 +24,24 @@ technology or repository, in the context of a certain 
<<policies-authentication,
 Several authentication modules are provided:
 
 * Principal Authentication:
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/Database-Authentication.html[Database^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/JAAS-Authentication.html[JAAS^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/LDAP-Authentication.html[LDAP^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/SPNEGO-Authentication.html[SPNEGO^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/Syncope-Authentication.html[Syncope^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/Azure-ActiveDirectory-Authentication.html[Azure
 Active Directory^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/Okta-Authentication.html[Okta^]
-    ** 
https://apereo.github.io/cas/7.1.x/authentication/X509-Authentication.html[X509^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-Generic-OpenID-Connect.html[OpenID
 Connect^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-OAuth20.html[OAuth2^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-SAML.htmll[SAML^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-Apple.html[Apple
 Signin^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-Azure-AD.html[Azure
 Active Directory (OIDC)^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-Google-OpenID-Connect.html[Google
 OpenID^]
-    ** 
https://apereo.github.io/cas/7.1.x/integration/Delegate-Authentication-Keycloak.html[Keycloak^]
+    ** 
https://apereo.github.io/cas/development/authentication/Database-Authentication.html[Database^]
+    ** 
https://apereo.github.io/cas/development/authentication/JAAS-Authentication.html[JAAS^]
+    ** 
https://apereo.github.io/cas/development/authentication/LDAP-Authentication.html[LDAP^]
+    ** 
https://apereo.github.io/cas/development/authentication/SPNEGO-Authentication.html[SPNEGO^]
+    ** 
https://apereo.github.io/cas/development/authentication/Syncope-Authentication.html[Syncope^]
+    ** 
https://apereo.github.io/cas/development/authentication/Azure-ActiveDirectory-Authentication.html[Azure
 Active Directory^]
+    ** 
https://apereo.github.io/cas/development/authentication/Okta-Authentication.html[Okta^]
+    ** 
https://apereo.github.io/cas/development/authentication/X509-Authentication.html[X509^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-Generic-OpenID-Connect.html[OpenID
 Connect^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-OAuth20.html[OAuth2^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-SAML.htmll[SAML^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-Apple.html[Apple
 Signin^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-Azure-AD.html[Azure
 Active Directory (OIDC)^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-Google-OpenID-Connect.html[Google
 OpenID^]
+    ** 
https://apereo.github.io/cas/development/integration/Delegate-Authentication-Keycloak.html[Keycloak^]
 * MFA:
-    ** 
https://apereo.github.io/cas/7.1.x/mfa/DuoSecurity-Authentication.html[Duo 
Security^]
-    ** 
https://apereo.github.io/cas/7.1.x/mfa/GoogleAuthenticator-Authentication.html[Google
 Authenticator^]
+    ** 
https://apereo.github.io/cas/development/mfa/DuoSecurity-Authentication.html[Duo
 Security^]
+    ** 
https://apereo.github.io/cas/development/mfa/GoogleAuthenticator-Authentication.html[Google
 Authenticator^]
 
 [TIP]
 ====
@@ -64,4 +64,4 @@ class.
 
 [NOTE]
 Authentication Modules are dynamically translated into
-https://apereo.github.io/cas/7.1.x/authentication/Configuring-Authentication-Components.html#authentication-handlers[CAS
 Authentication Handlers^].
+https://apereo.github.io/cas/development/authentication/Configuring-Authentication-Components.html#authentication-handlers[CAS
 Authentication Handlers^].
diff --git a/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc 
b/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc
index 744b1a81f2..8c12ae2a86 100644
--- a/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc
@@ -34,17 +34,17 @@ When defining a client application, the following 
parameters shall be specified:
 . name - regular expression to match requests
 . description - optional textual description
 . username attribute provider, mapping to
-https://apereo.github.io/cas/7.1.x/integration/Attribute-Release-PrincipalId-Attribute.html[CAS
 Attribute-based Principal Id^]
+https://apereo.github.io/cas/development/integration/Attribute-Release-PrincipalId-Attribute.html[CAS
 Attribute-based Principal Id^]
 . <<policies-authentication,authentication policy>>
 . <<policies-access,access policy>>
 . <<policies-attribute-release,attribute release policy>>
 . <<policies-ticket-expiration,ticket expiration policy>>
 . additional properties
 . logout type, mapping to
-https://apereo.github.io/cas/7.1.x/installation/Logout-Single-Signout.html#slo-requests[the
 equivalent CAS setting^]
+https://apereo.github.io/cas/development/installation/Logout-Single-Signout.html#slo-requests[the
 equivalent CAS setting^]
 
 More parameters are required to be specified depending on the actual client 
application type.
 
 [NOTE]
 Client Applications are dynamically translated into
-https://apereo.github.io/cas/7.1.x/services/Service-Management.html[CAS 
Services^].
+https://apereo.github.io/cas/development/services/Service-Management.html[CAS 
Services^].
diff --git a/src/main/asciidoc/reference-guide/concepts/entitlements.adoc 
b/src/main/asciidoc/reference-guide/concepts/entitlements.adoc
index 8ac00aa43c..c52e00dee2 100644
--- a/src/main/asciidoc/reference-guide/concepts/entitlements.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/entitlements.adoc
@@ -30,7 +30,7 @@ ifeval::["{snapshotOrRelease}" == "snapshot"]
 
https://github.com/apache/syncope/blob/master/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/RealmLogic.java[RealmLogic^]
 endif::[]
 , the
-https://docs.spring.io/spring-security/reference/6.3/servlet/authorization/method-security.html#authorization-expressions[`hasRole`
 expression^]
+https://docs.spring.io/spring-security/reference/6.4/servlet/authorization/method-security.html#authorization-expressions[`hasRole`
 expression^]
 is used together with one of the standard entitlements to restrict access only 
to Users owning the `REALM_SEARCH`
 entitlement.
 
diff --git a/src/main/asciidoc/reference-guide/concepts/policies.adoc 
b/src/main/asciidoc/reference-guide/concepts/policies.adoc
index 488015930a..576f5ef7ec 100644
--- a/src/main/asciidoc/reference-guide/concepts/policies.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/policies.adoc
@@ -320,7 +320,7 @@ endif::[]
 
 [NOTE]
 Access Policy instances are dynamically translated into
-https://apereo.github.io/cas/7.1.x/services/Configuring-Service-Access-Strategy.html#configure-service-access-strategy[CAS
 Service Access Strategy^].
+https://apereo.github.io/cas/development/services/Configuring-Service-Access-Strategy.html#configure-service-access-strategy[CAS
 Service Access Strategy^].
 
 [[policies-attribute-release]]
 ==== Attribute Release
@@ -332,7 +332,7 @@ values.
 
 [NOTE]
 Attribute Release Policy instances are dynamically translated into
-https://apereo.github.io/cas/7.1.x/integration/Attribute-Release-Policies.html#attribute-release-policies[CAS
 Attribute Release Policy^].
+https://apereo.github.io/cas/development/integration/Attribute-Release-Policies.html#attribute-release-policies[CAS
 Attribute Release Policy^].
 
 [[policies-authentication]]
 ==== Authentication
@@ -359,7 +359,7 @@ be considered successful.
 
 [NOTE]
 Authentication Policy instances are dynamically translated into
-https://apereo.github.io/cas/7.1.x/authentication/Configuring-Authentication-Policy.html#authentication-policy[CAS
 Authentication Policy^].
+https://apereo.github.io/cas/development/authentication/Configuring-Authentication-Policy.html#authentication-policy[CAS
 Authentication Policy^].
 
 [[policies-propagation]]
 ==== Propagation
@@ -478,4 +478,4 @@ Ticket Expiration policies control the duration of various 
types of WA sessions.
 
 [NOTE]
 Ticket Expiration Policy instances are dynamically translated into
-https://apereo.github.io/cas/7.1.x/ticketing/Configuring-Ticket-Expiration-Policy.html[their
 CAS equivalent^].
+https://apereo.github.io/cas/development/ticketing/Configuring-Ticket-Expiration-Policy.html[their
 CAS equivalent^].
diff --git a/src/main/asciidoc/reference-guide/concepts/reports.adoc 
b/src/main/asciidoc/reference-guide/concepts/reports.adoc
index 726c45b22a..428933142b 100644
--- a/src/main/asciidoc/reference-guide/concepts/reports.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/reports.adoc
@@ -34,4 +34,4 @@ endif::[]
 providing the custom logic to extract information from Syncope and generate 
output according to the configured mime type
 * scheduling information:
 ** when to start
-** 
https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
+** 
https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
diff --git a/src/main/asciidoc/reference-guide/concepts/routes.adoc 
b/src/main/asciidoc/reference-guide/concepts/routes.adoc
index ff62175562..761e5b100c 100644
--- a/src/main/asciidoc/reference-guide/concepts/routes.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/routes.adoc
@@ -50,7 +50,7 @@ The received response, after being post-processed by matching 
route's _filters_,
 ==== Predicates
 
 Inside Route definition, each predicate will be referring to some Spring Cloud 
Gateway's 
-https://docs.spring.io/spring-cloud-gateway/docs/4.1.x/reference/html/#gateway-request-predicates-factories[Predicate
 factory^]:
+https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/request-predicates-factories.html[Predicate
 factory^]:
 
    * `AFTER` matches requests that happen after the specified datetime;
    * `BEFORE` matches requests that happen before the specified datetime;
@@ -74,7 +74,7 @@ endif::[]
 ==== Filters
 
 Inside Route definition, each filter will be referring to some Spring Cloud 
Gateway's 
-https://docs.spring.io/spring-cloud-gateway/docs/4.1.x/reference/html/#gatewayfilter-factories[Filter
 factory^]:
+https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories.html[Filter
 factory^]:
 
    * `ADD_REQUEST_HEADER` adds a header to the downstream request's headers;
    * `ADD_REQUEST_PARAMETER` adds a parameter too the downstream request's 
query string;
diff --git a/src/main/asciidoc/reference-guide/concepts/tasks.adoc 
b/src/main/asciidoc/reference-guide/concepts/tasks.adoc
index bab4b1c087..fe9c3fc9f5 100644
--- a/src/main/asciidoc/reference-guide/concepts/tasks.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/tasks.adoc
@@ -101,7 +101,7 @@ When defining a pull task, the following information must 
be provided:
 * <<pull-templates,entity templates>>
 * scheduling information:
 ** when to start
-** 
https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
+** 
https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
 
 [NOTE]
 ====
@@ -189,7 +189,7 @@ When defining a push task, the following information must 
be provided:
 * optional <<pushactions,push action(s)>>
 * scheduling information:
 ** when to start
-** 
https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
+** 
https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
 
 [NOTE]
 ====
@@ -258,7 +258,7 @@ When defining a macro task, the following information must 
be provided:
 list, update or execute the given macro task
 * scheduling information:
 ** when to start
-** 
https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
+** 
https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
 
 ===== MacroActions
 
@@ -289,7 +289,7 @@ endif::[]
 providing the custom logic to execute
 * scheduling information:
 ** when to start
-** 
https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
+** 
https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron
 expression^]
 
 [TIP]
 ====
diff --git a/src/main/asciidoc/reference-guide/concepts/typemanagement.adoc 
b/src/main/asciidoc/reference-guide/concepts/typemanagement.adoc
index daf6de4689..a0699b8bcf 100644
--- a/src/main/asciidoc/reference-guide/concepts/typemanagement.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/typemanagement.adoc
@@ -48,7 +48,7 @@ 
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/text/DateForma
 ** `Dropdown` - allows to specify an <<implementations,implementation>> which 
will dynamically return the value(s) that
 can be selected
 ** `Encrypted`
-*** secret key (stored or referenced as 
https://docs.spring.io/spring-framework/reference/6.1/core/beans/environment.html#beans-using-propertysource[Spring
 property^])
+*** secret key (stored or referenced as 
https://docs.spring.io/spring-framework/reference/6.2/core/beans/environment.html#beans-using-propertysource[Spring
 property^])
 *** cipher algorithm
 *** whether transparent encryption is to be enabled, e.g. attribute values are 
stored as encrypted but available as
 cleartext on-demand (requires AES ciphering)
diff --git 
a/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc 
b/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
index cc8bab7ec9..bba639466b 100644
--- 
a/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
+++ 
b/src/main/asciidoc/reference-guide/configuration/configurationparameters.adoc
@@ -34,7 +34,7 @@ at runtime, expecially with high-availability.
 * `jwt.lifetime.minutes` - validity of 
https://en.wikipedia.org/wiki/JSON_Web_Token[JSON Web Token^] values used for
 <<rest-authentication-and-authorization,authentication>> (in minutes);
 * `notificationjob.cronExpression` -
-https://docs.spring.io/spring-framework/reference/6.1/integration/scheduling.html#scheduling-cron-expression[cron^]
 expression describing how
+https://docs.spring.io/spring-framework/reference/6.2/integration/scheduling.html#scheduling-cron-expression[cron^]
 expression describing how
 frequently the pending <<tasks-notification,notification tasks>> are 
processed: empty means disabled;
 [NOTE]
 Restarting the deployment is required when changing value for this parameter.
diff --git a/src/main/asciidoc/reference-guide/configuration/dbms.adoc 
b/src/main/asciidoc/reference-guide/configuration/dbms.adoc
index 9a7cfb5bd5..bf3dd003e4 100644
--- a/src/main/asciidoc/reference-guide/configuration/dbms.adoc
+++ b/src/main/asciidoc/reference-guide/configuration/dbms.adoc
@@ -40,7 +40,7 @@ persistence.domain[0].poolMinIdle=5
 as `core/src/main/resources/core-postgresql.properties`.
 
 Do not forget to include `postgresql` as
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
 for the Core application.
 
 [WARNING]
@@ -73,7 +73,7 @@ persistence.domain[0].poolMinIdle=5
 as `core/src/main/resources/core-mysql.properties`.
 
 Do not forget to include `mysql` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
 for the Core application.
 
 [CAUTION]
@@ -110,7 +110,7 @@ persistence.domain[0].poolMinIdle=5
 as `core/src/main/resources/core-mariadb.properties`.
 
 Do not forget to include `mariadb` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
 for the Core application.
 
 [CAUTION]
@@ -159,7 +159,7 @@ persistence.domain[0].poolMinIdle=5
 as `core/src/main/resources/core-oracle.properties`.
 
 Do not forget to include `oracle` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
 for the Core application.
 
 [WARNING]
diff --git a/src/main/asciidoc/reference-guide/configuration/deployment.adoc 
b/src/main/asciidoc/reference-guide/configuration/deployment.adoc
index 48276c09db..2d85e88497 100644
--- a/src/main/asciidoc/reference-guide/configuration/deployment.adoc
+++ b/src/main/asciidoc/reference-guide/configuration/deployment.adoc
@@ -24,7 +24,7 @@ Jakarta EE containers.
 
 [WARNING]
 The only exception is <<secure-remote-access>> that, being based on Spring 
Cloud Gateway - which in turn is built on 
-https://docs.spring.io/spring-framework/reference/6.1/web-reactive.html[Spring 
WebFlux^] and
+https://docs.spring.io/spring-framework/reference/6.2/web-reactive.html[Spring 
WebFlux^] and
 https://projectreactor.io/docs[Project Reactor^], is only available as 
standalone application.
 
 [CAUTION]
@@ -51,7 +51,7 @@ applications as standalone fat JAR or WAR files.
 
 [TIP]
 Spring Boot applications can also be
-https://docs.spring.io/spring-boot/3.3/how-to/deployment/installing.html[installed
 as system services^].
+https://docs.spring.io/spring-boot/3.4/how-to/deployment/installing.html[installed
 as system services^].
 
 .Run Core application as standalone under GNU / Linux
 ====
@@ -71,7 +71,7 @@ $ java -Dsyncope.conf.dir=/opt/syncope/conf \
   -jar /opt/syncope/lib/syncope.war
 ----
 Further options can be passed to last command, according to Spring Boot
-https://docs.spring.io/spring-boot/3.3/appendix/application-properties/index.html[documentation^];
+https://docs.spring.io/spring-boot/3.4/appendix/application-properties/index.html[documentation^];
 for example:
 
 * `--spring.config.additional-location=/path` +
@@ -283,7 +283,7 @@ 
javadocPaths=/WEB-INF/lib/syncope-common-idrepo-rest-api-${syncope.version}-java
 as `core/src/main/resources/core-wildfy.properties`.
 
 Do not forget to include `widlfly` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html[Spring 
Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html[Spring 
Boot profile^]
 for the Core application.
 
 [WARNING]
diff --git a/src/main/asciidoc/reference-guide/usage/actuator.adoc 
b/src/main/asciidoc/reference-guide/usage/actuator.adoc
index 672f845903..566113fad7 100644
--- a/src/main/asciidoc/reference-guide/usage/actuator.adoc
+++ b/src/main/asciidoc/reference-guide/usage/actuator.adoc
@@ -23,7 +23,7 @@ Spring Boot's actuator endpoints let you monitor and interact 
with Syncope compo
 Each individual endpoint can be enabled / disabled and exposed over HTTP 
(pre-defined, under the `/actuator` subcontext)
 or JMX.
 
-Besides a number of 
https://docs.spring.io/spring-boot/3.3/reference/actuator/endpoints.html[built-in
 endpoints^],
+Besides a number of 
https://docs.spring.io/spring-boot/3.4/reference/actuator/endpoints.html[built-in
 endpoints^],
 more are made available for each component, as reported below.
 
 [NOTE]
@@ -55,15 +55,15 @@ a| Allows to work with 
https://openjpa.apache.org/builds/4.0.1/apache-openjpa/do
 |===
 
 | `ssoSessions`
-| 
https://apereo.github.io/cas/7.1.x/authentication/Configuring-SSO.html#actuator-endpoints[More
 details^]
+| 
https://apereo.github.io/cas/development/authentication/Configuring-SSO.html#actuator-endpoints[More
 details^]
 | `registeredServices`
-| 
https://apereo.github.io/cas/7.1.x/services/Service-Management.html#actuator-endpoints[More
 details^]
+| 
https://apereo.github.io/cas/development/services/Service-Management.html#actuator-endpoints[More
 details^]
 | `authenticationHandlers`
-| 
https://apereo.github.io/cas/7.1.x/authentication/Configuring-Authentication-Components.html#actuator-endpoints[More
 details^]
+| 
https://apereo.github.io/cas/development/authentication/Configuring-Authentication-Components.html#actuator-endpoints[More
 details^]
 | `authenticationPolicies`
-| 
https://apereo.github.io/cas/7.1.x/authentication/Configuring-Authentication-Policy.html#actuator-endpoints[More
 details^]
+| 
https://apereo.github.io/cas/development/authentication/Configuring-Authentication-Policy.html#actuator-endpoints[More
 details^]
 | `resolveAttributes`
-| 
https://apereo.github.io/cas/7.1.x/integration/Attribute-Resolution.html#actuator-endpoints[More
 details^]
+| 
https://apereo.github.io/cas/development/integration/Attribute-Resolution.html#actuator-endpoints[More
 details^]
 
 |===
 
@@ -80,6 +80,6 @@ a|
 * `DELETE {id}` - removes the session with given `id`
 
 | `gateway`
-| 
https://docs.spring.io/spring-cloud-gateway/docs/4.1.x/reference/html/#actuator-api[More
 details^]
+| 
https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/actuator-api.html[More
 details^]
 
 |===
diff --git a/src/main/asciidoc/reference-guide/usage/core.adoc 
b/src/main/asciidoc/reference-guide/usage/core.adoc
index c15a8af491..c89aab24fe 100644
--- a/src/main/asciidoc/reference-guide/usage/core.adoc
+++ b/src/main/asciidoc/reference-guide/usage/core.adoc
@@ -98,7 +98,7 @@ The set of RESTful services provided by Apache Syncope can be 
divided as:
 . endpoints disclosing information about the given Syncope deployment 
(available <<schema,schema>>, configured
 <<extensions,extensions>>, Groups, ...), requiring some sort of shared 
authentication defined by the
 `anonymousKey` value  in the `security.properties` file - for more 
information, read about Spring Security's
-https://docs.spring.io/spring-security/reference/6.3/servlet/authentication/anonymous.html#page-title[Anonymous
 Authentication^];
+https://docs.spring.io/spring-security/reference/6.4/servlet/authentication/anonymous.html#page-title[Anonymous
 Authentication^];
 . endpoints for self-service (self-update, password change, ...), requiring 
user authentication and no entitlements;
 . endpoints for administrative operations, requiring user authentication with 
authorization granted by the related
 <<entitlements,entitlements>>, handed over to users via <<roles,roles>>.
diff --git a/src/main/asciidoc/reference-guide/usage/customization.adoc 
b/src/main/asciidoc/reference-guide/usage/customization.adoc
index 4a11d2e3b9..611f5a7c77 100644
--- a/src/main/asciidoc/reference-guide/usage/customization.adoc
+++ b/src/main/asciidoc/reference-guide/usage/customization.adoc
@@ -155,7 +155,7 @@ endif::[]
 ===== Extending configuration
 Apache Syncope <<architecture,components>> are built on 
https://spring.io/projects/spring-boot[Spring Boot^],
 hence designing and extending Syncope configuration very much comes down to
-https://docs.spring.io/spring-boot/3.3/index.html[their guide^], some aspects 
of which are briefly
+https://docs.spring.io/spring-boot/3.4/index.html[their guide^], some aspects 
of which are briefly
 highlighted here.
 
 To design your own configuration class, take inspiration from the following 
sample:
@@ -236,7 +236,7 @@ $ mkdir /opt/syncope/conf
 [TIP]
 ====
 The `conf` directory must be configured for deployment, following Spring Boot's
-https://docs.spring.io/spring-boot/3.3/reference/features/external-config.html[Externalized
 Configuration^]
+https://docs.spring.io/spring-boot/3.4/reference/features/external-config.html[Externalized
 Configuration^]
 settings; with above reference:
 
 * <<standalone>>: `--spring.config.additional-location=/opt/syncope/conf/`
@@ -383,7 +383,7 @@ elasticsearch.numberOfReplicas=1
 as `core/src/main/resources/core-elasticsearch.properties`.
 
 Do not forget to include `elasticsearch` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html[Spring 
Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html[Spring 
Boot profile^]
 for the Core application.
 
 If needed, customize the `@Bean` declarations from
@@ -436,7 +436,7 @@ opensearch.numberOfReplicas=1
 as `core/src/main/resources/core-opensearch.properties`.
 
 Do not forget to include `opensearch` as 
-https://docs.spring.io/spring-boot/3.3/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+https://docs.spring.io/spring-boot/3.4/reference/features/profiles.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
 for the Core application.
 
 If needed, customize the `@Bean` declarations from
diff --git a/wa/starter/pom.xml b/wa/starter/pom.xml
index 781e85443a..62ab33d62f 100644
--- a/wa/starter/pom.xml
+++ b/wa/starter/pom.xml
@@ -532,20 +532,21 @@ under the License.
       <id>debug</id>
 
       <properties>
+        <maven.build.cache.skipCache>true</maven.build.cache.skipCache>
         <maven.test.skip>true</maven.test.skip>
       </properties>
 
       <dependencies>
+        <dependency>
+          <groupId>org.springframework.boot</groupId>
+          <artifactId>spring-boot-starter-tomcat</artifactId>
+        </dependency>
+
         <dependency>
           <groupId>org.apache.syncope.common.keymaster.self</groupId>
           <artifactId>syncope-common-keymaster-client-self</artifactId>
           <version>${project.version}</version>
         </dependency>
-
-        <dependency>
-          <groupId>com.h2database</groupId>
-          <artifactId>h2</artifactId>
-        </dependency>        
       </dependencies>
 
       <build>
diff --git 
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java 
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
index 18fdb485ae..885f9944af 100644
--- 
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
+++ 
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/config/WAContext.java
@@ -59,7 +59,6 @@ import 
org.apache.syncope.wa.starter.mapping.TimeBasedAccessMapper;
 import 
org.apache.syncope.wa.starter.mfa.WAMultifactorAuthenticationTrustStorage;
 import org.apache.syncope.wa.starter.oidc.WAOIDCJWKSGeneratorService;
 import org.apache.syncope.wa.starter.pac4j.saml.WASAML2ClientCustomizer;
-import org.apache.syncope.wa.starter.saml.idp.WASamlIdPCasEventListener;
 import 
org.apache.syncope.wa.starter.saml.idp.metadata.WASamlIdPMetadataGenerator;
 import 
org.apache.syncope.wa.starter.saml.idp.metadata.WASamlIdPMetadataLocator;
 import org.apache.syncope.wa.starter.services.WAServiceRegistry;
@@ -80,7 +79,6 @@ import org.apereo.cas.support.events.CasEventRepository;
 import org.apereo.cas.support.events.CasEventRepositoryFilter;
 import 
org.apereo.cas.support.pac4j.authentication.clients.DelegatedClientFactoryCustomizer;
 import 
org.apereo.cas.support.pac4j.authentication.handler.support.DelegatedClientAuthenticationHandler;
-import org.apereo.cas.support.saml.idp.SamlIdPCasEventListener;
 import 
org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGenerator;
 import 
org.apereo.cas.support.saml.idp.metadata.generator.SamlIdPMetadataGeneratorConfigurationContext;
 import org.apereo.cas.support.saml.idp.metadata.locator.SamlIdPMetadataLocator;
@@ -89,6 +87,7 @@ import 
org.apereo.cas.trusted.authentication.api.MultifactorAuthenticationTrustR
 import 
org.apereo.cas.trusted.authentication.api.MultifactorAuthenticationTrustStorage;
 import org.apereo.cas.util.LdapUtils;
 import org.apereo.cas.util.crypto.CipherExecutor;
+import org.apereo.cas.util.spring.CasApplicationReadyListener;
 import org.apereo.cas.webauthn.storage.WebAuthnCredentialRepository;
 import org.ldaptive.ConnectionFactory;
 import org.pac4j.core.client.Client;
@@ -101,7 +100,6 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.ScopedProxyMode;
 import org.springframework.security.core.userdetails.User;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -232,10 +230,10 @@ public class WAContext {
     }
 
     @Bean
-    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
-    @Lazy(false)
-    public SamlIdPCasEventListener samlIdPCasEventListener() {
-        return new WASamlIdPCasEventListener();
+    public CasApplicationReadyListener samlIdPCasEventListener() {
+        // skip generating IdP metadata at this stage, as the default 
samlIdPCasEventListener bean is doing
+        return event -> {
+        };
     }
 
     @Bean
diff --git 
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/WASamlIdPCasEventListener.java
 
b/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/WASamlIdPCasEventListener.java
deleted file mode 100644
index da1bcaf72c..0000000000
--- 
a/wa/starter/src/main/java/org/apache/syncope/wa/starter/saml/idp/WASamlIdPCasEventListener.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.wa.starter.saml.idp;
-
-import org.apereo.cas.support.saml.idp.SamlIdPCasEventListener;
-import org.springframework.boot.context.event.ApplicationReadyEvent;
-
-public class WASamlIdPCasEventListener implements SamlIdPCasEventListener {
-
-    @Override
-    public void handleApplicationReadyEvent(final ApplicationReadyEvent event) 
{
-        // skip generating IdP metadata at this stage, as
-        // org.apereo.cas.support.saml.idp.DefaultSamlIdPCasEventListener is 
doing
-    }
-}
diff --git 
a/wa/starter/src/main/resources/thymeleaf/templates/fragments/footer.html 
b/wa/starter/src/main/resources/thymeleaf/templates/fragments/footer.html
index d991bf5eba..8ba1fd7b45 100644
--- a/wa/starter/src/main/resources/thymeleaf/templates/fragments/footer.html
+++ b/wa/starter/src/main/resources/thymeleaf/templates/fragments/footer.html
@@ -16,15 +16,21 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<footer class="py-4 d-flex flex-column justify-content-center cas-footer 
text-center">
+<footer th:if="${'true' == 
#strings.defaultString(#themes.code('cas.footer.show'), 'true')}"
+        class="py-3 d-flex justify-content-center align-items-center 
cas-footer">
   <div class="pb-1 pt-1">
-    Copyright © 2010-${year}
-    <a href="http://www.apache.org/"; target="_blank" rel="noopener 
noreferrer">The Apache Software Foundation</a>.</strong>
-    All rights reserved.
+    <span id="copyright" class="me-2 d-inline-block">Copyright © 2010-${year}
+      <a href="http://www.apache.org/"; target="_blank" rel="noopener 
noreferrer">The Apache Software Foundation</a>.</strong>
+      All rights reserved.
+    </span>
   </div>
   <div class="pb-1 pt-1">
-    <span id="copyright" th:utext="#{copyright}" class="mr-2 
d-inline-block">Copyright Date Apereo, Inc</span>
-    <span class="mr-2 d-inline-block">Powered by <a 
href="https://github.com/apereo/cas";>Apereo CAS</a></span>
-    <code class="version" 
th:text="${T(org.apereo.cas.util.CasVersion).getVersion() + ' ' + 
T(org.apereo.cas.util.CasVersion).getDateTime()}"></code>
+    <span id="copyright" th:utext="#{copyright}" class="me-2 
d-inline-block">Copyright Date Apereo, Inc</span>
+    <span id="poweredBy" class="px-3 d-inline-block">
+      <span th:utext="#{poweredBy}">Powered by </span><a 
href="https://github.com/apereo/cas";>Apereo CAS</a>
+    </span>
+    <code class="version"
+          th:if="${'true' == 
#strings.defaultString(#themes.code('cas.footer.show-version'), 'true')}"
+          th:text="${T(org.apereo.cas.util.CasVersion).getVersion() + ' ' + 
T(org.apereo.cas.util.CasVersion).getDateTime()}"></code>
   </div>
 </footer>
diff --git a/wa/starter/src/main/resources/wa.properties 
b/wa/starter/src/main/resources/wa.properties
index 1291ccc994..8c2951a789 100644
--- a/wa/starter/src/main/resources/wa.properties
+++ b/wa/starter/src/main/resources/wa.properties
@@ -36,7 +36,7 @@ server.servlet.session.tracking-modes=COOKIE
 
spring.web.resources.static-locations=classpath:/thymeleaf/static,classpath:/syncope/static,classpath:/static
 
 cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
-management.endpoints.enabled-by-default=true
+management.endpoints.access.default=UNRESTRICTED
 
management.endpoints.web.exposure.include=info,health,env,loggers,ssoSessions,registeredServices,refresh,authenticationHandlers,authenticationPolicies,resolveAttributes
 management.endpoint.health.show-details=ALWAYS
 management.endpoint.env.show-values=WHEN_AUTHORIZED
@@ -112,3 +112,28 @@ spring.mvc.pathmatch.matching-strategy=ant-path-matcher
 # Disable CGLib Proxies
 spring.aop.auto=true
 spring.aop.proxy-target-class=false
+
+##
+# Metrics Configuration
+management.cloudwatch.metrics.export.enabled=false
+management.atlas.metrics.export.enabled=false
+management.datadog.metrics.export.enabled=false
+management.ganglia.metrics.export.enabled=false
+management.graphite.metrics.export.enabled=false
+management.influx.metrics.export.enabled=false
+management.jmx.metrics.export.enabled=false
+management.newrelic.metrics.export.enabled=false
+management.prometheus.metrics.export.enabled=false
+management.signalfx.metrics.export.enabled=false
+management.statsd.metrics.export.enabled=false
+management.wavefront.metrics.export.enabled=false
+management.elastic.metrics.export.enabled=false
+
+management.defaults.metrics.export.enabled=true
+
+management.metrics.enable.logback=false
+management.metrics.enable.process.files=true
+management.metrics.enable.system.cpu=true
+management.metrics.enable.process.cpu=true
+management.metrics.enable.process.uptime=true
+management.metrics.enable.process.start.time=true
diff --git 
a/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java 
b/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
index f06aa39938..587079e08a 100644
--- a/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
+++ b/wa/starter/src/test/java/org/apache/syncope/wa/starter/AbstractTest.java
@@ -20,6 +20,7 @@ package org.apache.syncope.wa.starter;
 
 import static org.awaitility.Awaitility.await;
 
+import com.okta.sdk.client.Client;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -40,7 +41,10 @@ import org.apereo.cas.authentication.principal.Service;
 import org.apereo.cas.authentication.principal.attribute.PersonAttributeDao;
 import 
org.apereo.cas.authentication.principal.attribute.PersonAttributeDaoFilter;
 import org.apereo.cas.authentication.principal.attribute.PersonAttributes;
+import 
org.apereo.cas.persondir.PersonDirectoryAttributeRepositoryPlanConfigurer;
 import org.apereo.cas.services.RegisteredService;
+import org.apereo.cas.util.spring.beans.BeanContainer;
+import org.apereo.cas.util.spring.beans.BeanSupplier;
 import org.junit.jupiter.api.BeforeEach;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -205,11 +209,6 @@ public abstract class AbstractTest {
                 public AttributeDefinitionStore store(final Resource resource) 
{
                     return this;
                 }
-
-                @Override
-                public AttributeDefinitionStore importStore(final 
AttributeDefinitionStore definitionStore) {
-                    return this;
-                }
             };
         }
 
@@ -224,6 +223,24 @@ public abstract class AbstractTest {
         public PersonAttributeDao aggregatingAttributeRepository() {
             return new DummyIPersonAttributeDao();
         }
+
+        @Bean(name = "oktaPersonDirectoryClient")
+        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
+        public Client oktaPersonDirectoryClient() {
+            return null;
+        }
+
+        @Bean(name = "oktaPersonAttributeDaos")
+        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
+        public BeanContainer<PersonAttributeDao> oktaPersonAttributeDaos() {
+            return BeanContainer.empty();
+        }
+
+        @Bean(name = "oktaAttributeRepositoryPlanConfigurer")
+        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
+        public PersonDirectoryAttributeRepositoryPlanConfigurer 
oktaAttributeRepositoryPlanConfigurer() {
+            return 
BeanSupplier.of(PersonDirectoryAttributeRepositoryPlanConfigurer.class).otherwiseProxy().get();
+        }
     }
 
     @LocalServerPort


Reply via email to