KNOX-3217: Upgrade pac4j to 6.3.0 for JDK17 (#1110)

* KNOX-3217: Upgrade pac4j for JDK17. Upgraded pac4j to 5.7.8 and javaee-pac4j to 7.1.0.
(Instead of the jee-pac4j artifact, javaee-pac4j needs to be used - then jakartaee-pac4j if we migrate to Jakarta).
Update opensaml to 4.2.0 and cryptacular to 1.2.5 (from pac4j-saml:5.7.8). Pin net.shibboleth.utilities:java-support to 8.3.1.
Fix KnoxSessionStore getSessionId and Pac4jIdentityAdapter removeProfiles call.
Corrected Pac4jProviderTest.
Pac4jSetCookieResponseWrapper.addCookie() is probably not needed anymore, pac4jcsrf is set in Set-Cookie header and is secure by default (goes through KnoxSessionStore).

* KNOX-3217: fix missing net.shibboleth.utilities:java-support:8.3.1 from Shibboleth maven repo. Updated shib-release maven repo URL.

* KNOX-3217: Update javaee-pac4j to 8.1.0, pac4j to 6.3.0 and opensaml to 5.1.6. Update cryptacular to 1.2.7 and xmlsec to 4.0.4.
org.pac4j.oidc.client.AzureAdClient was removed for AzureAd2Client; AzureAdOidcConfiguration to AzureAd2OidcConfiguration.
Pinned managed dependency versions for org.apache.httpcomponents.client5:httpclient5:5.4.3 and org.apache.httpcomponents.core5:5.3.6 should work:
org.pac4j:pac4j-saml:jar:6.3.0 would bring in org.apache.httpcomponents.client5:httpclient5:jar:5.3.1,
plus a dependency convergence error with org.apache.httpcomponents.core5:httpcore5:jar:5.2.5 and 5.2.4.

* KNOX-3217: Also remove pac4jCsrfTokenExpirationDate and pac4jPreviousCsrfToken in logout.jsp (added in pac4j 5.0).

* KNOX-3217: hibernate-core exclusion is not needed for opensaml-storage-impl.

* KNOX-3217: remove managed dependency com.nimbusds:lang-tag:1.5 (will be 1.7, no dependency convergence issues). org.pac4j.pac4j-oidc:6.3.0 needs com.nimbusds:lang-tag:1.7.

* KNOX-3217: Update nimbus-jose-jwt to 10.5 - dependency convergence - org.nimbus-jose-jwt:10.5 is needed for org.pac4j:pac4j-oidc:6.3.0. org.apereo.cas.client:cas-client-core:4.0.4 would need nimbus-jose-jwt:9.37.3 and org.apache.hadoop:hadoop-auth:3.4.1 would need nimbus-jose-jwt:9.37.2.

* KNOX-3217: review findings
diff --git a/gateway-applications/src/main/resources/applications/knoxauth/app/logout.jsp b/gateway-applications/src/main/resources/applications/knoxauth/app/logout.jsp
index debeb6e..5d85d20 100644
--- a/gateway-applications/src/main/resources/applications/knoxauth/app/logout.jsp
+++ b/gateway-applications/src/main/resources/applications/knoxauth/app/logout.jsp
@@ -126,6 +126,8 @@
 
             // remove pac4j cookies
             response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jCsrfToken", p4j_domainName, pac4jPath));
+            response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jCsrfTokenExpirationDate", p4j_domainName, pac4jPath));
+            response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jPreviousCsrfToken", p4j_domainName, pac4jPath));
             response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jRequestedUrl", p4j_domainName, pac4jPath));
             response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jUserProfiles", p4j_domainName, pac4jPath));
             response.addHeader("Set-Cookie", removeCookie("pac4j.session.pac4jUserProfiles", p4j_domainName, pac4jPath+"/websso"));
diff --git a/gateway-provider-security-pac4j/pom.xml b/gateway-provider-security-pac4j/pom.xml
index 5e27fa3..ee7e55c 100644
--- a/gateway-provider-security-pac4j/pom.xml
+++ b/gateway-provider-security-pac4j/pom.xml
@@ -28,6 +28,19 @@
     <name>gateway-provider-security-pac4j</name>
     <description>An extension of the gateway integrating pac4j as an authentication provider.</description>
 
+    <repositories>
+        <repository>
+            <id>shib-release</id>
+            <url>https://build.shibboleth.net/maven/releases</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
+
     <dependencies>
         <dependency>
             <groupId>org.apache.knox</groupId>
@@ -101,6 +114,10 @@
         </dependency>
         <dependency>
             <groupId>org.pac4j</groupId>
+            <artifactId>pac4j-javaee</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.pac4j</groupId>
             <artifactId>pac4j-oauth</artifactId>
         </dependency>
         <dependency>
@@ -109,7 +126,7 @@
         </dependency>
         <dependency>
             <groupId>org.pac4j</groupId>
-            <artifactId>pac4j-saml-opensamlv3</artifactId>
+            <artifactId>pac4j-saml</artifactId>
             <exclusions>
                 <exclusion>
                     <groupId>ch.qos.logback</groupId>
@@ -135,13 +152,7 @@
         </dependency>
         <dependency>
             <groupId>org.pac4j</groupId>
-            <artifactId>jee-pac4j</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.pac4j</groupId>
-                    <artifactId>pac4j-core</artifactId>
-                </exclusion>
-            </exclusions>
+            <artifactId>javaee-pac4j</artifactId>
         </dependency>
         <dependency>
             <groupId>net.shibboleth.utilities</groupId>
diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecorator.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecorator.java
index 5021536..6338ce1 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecorator.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecorator.java
@@ -22,17 +22,17 @@
 
 import org.pac4j.core.client.Client;
 import org.pac4j.core.http.callback.PathParameterCallbackUrlResolver;
-import org.pac4j.oidc.client.AzureAdClient;
+import org.pac4j.oidc.client.AzureAd2Client;
 
 public class AzureADClientConfigurationDecorator implements ClientConfigurationDecorator {
-  private static final String AZURE_AD_CLIENT_CLASS_NAME = AzureAdClient.class.getSimpleName();
+  private static final String AZURE_AD_CLIENT_CLASS_NAME = AzureAd2Client.class.getSimpleName();
 
   @Override
   public void decorateClients(List<Client> clients, Map<String, String> properties) {
     for (Client client : clients) {
       if (AZURE_AD_CLIENT_CLASS_NAME.equalsIgnoreCase(client.getName())) {
         // special handling for Azure AD, use path separators instead of query params
-        ((AzureAdClient) client).setCallbackUrlResolver(new PathParameterCallbackUrlResolver());
+        ((AzureAd2Client) client).setCallbackUrlResolver(new PathParameterCallbackUrlResolver());
       }
     }
   }
diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/SAML2ClientConfigurationDecorator.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/SAML2ClientConfigurationDecorator.java
index b5a283d..1ce44da 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/SAML2ClientConfigurationDecorator.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/config/SAML2ClientConfigurationDecorator.java
@@ -83,7 +83,7 @@
   private void setKeyStoreType(Map<String, String> properties, final SAML2Client saml2Client) {
     final String keyStoreType = properties.get(KEYSTORE_TYPE);
     if (StringUtils.isNotBlank(keyStoreType)) {
-      saml2Client.getConfiguration().setKeystoreType(keyStoreType);
+      saml2Client.getConfiguration().setKeyStoreType(keyStoreType);
       log.pac4jSamlKeystoreType(keyStoreType);
     }
   }
diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
index 08b2a0e..5172773 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
@@ -40,14 +40,15 @@
 import org.pac4j.config.client.PropertiesConstants;
 import org.pac4j.core.client.Client;
 import org.pac4j.core.config.Config;
-import org.pac4j.core.context.session.JEESessionStore;
+import org.pac4j.core.context.FrameworkParameters;
 import org.pac4j.core.context.session.SessionStore;
 import org.pac4j.core.util.CommonHelper;
 import org.pac4j.http.client.indirect.IndirectBasicAuthClient;
 import org.pac4j.http.credentials.authenticator.test.SimpleTestUsernamePasswordAuthenticator;
+import org.pac4j.jee.context.session.JEESessionStore;
 import org.pac4j.jee.filter.CallbackFilter;
 import org.pac4j.jee.filter.SecurityFilter;
-import org.pac4j.oidc.client.AzureAdClient;
+import org.pac4j.oidc.client.AzureAd2Client;
 import org.pac4j.saml.client.SAML2Client;
 
 import javax.servlet.Filter;
@@ -186,7 +187,7 @@
        add the callback parameter to know it's a callback,
        Azure AD does not honor query param so we add callback param as path element.
     */
-    if (AzureAdClient.class.getSimpleName().equals(clientNameParameter) || (
+    if (AzureAd2Client.class.getSimpleName().equals(clientNameParameter) || (
         !StringUtils.isBlank(oidcType) && PAC4J_OICD_TYPE_AZURE
             .equals(oidcType))) {
       pac4jCallbackUrl = pac4jCallbackUrl + URL_PATH_SEPARATOR + PAC4J_CALLBACK_PARAMETER;
@@ -252,12 +253,12 @@
 
     if(!StringUtils.isBlank(sessionStoreVar) && JEESessionStore.class.getName().contains(sessionStoreVar) ) {
       /* NOTE: this is a final variable, and will be used by all requests in Knox */
-      sessionStore = JEESessionStore.INSTANCE;
+      sessionStore = new JEESessionStore();
     } else {
       sessionStore = new KnoxSessionStore(cryptoService, clusterName, domainSuffix, sessionStoreConfigs);
     }
 
-    config.setSessionStore(sessionStore);
+    config.setSessionStoreFactory((FrameworkParameters parameters) -> sessionStore);
 
     SessionInvalidators.KNOX_SSO_INVALIDATOR.registerSessionInvalidator(this);
 
diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jIdentityAdapter.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jIdentityAdapter.java
index ecc0ec4..7c59c6b 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jIdentityAdapter.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jIdentityAdapter.java
@@ -30,9 +30,13 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.pac4j.core.config.Config;
-import org.pac4j.core.context.JEEContext;
-import org.pac4j.core.profile.CommonProfile;
+import org.pac4j.core.context.FrameworkParameters;
+import org.pac4j.core.context.session.SessionStore;
 import org.pac4j.core.profile.ProfileManager;
+import org.pac4j.core.profile.UserProfile;
+import org.pac4j.core.util.Pac4jConstants;
+import org.pac4j.jee.context.JEEContext;
+import org.pac4j.jee.context.JEEFrameworkParameters;
 
 import javax.security.auth.Subject;
 import javax.servlet.Filter;
@@ -46,6 +50,7 @@
 import java.io.IOException;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.LinkedHashMap;
 import java.util.Optional;
 
 /**
@@ -84,13 +89,17 @@
 
     final HttpServletRequest request = (HttpServletRequest) servletRequest;
     final HttpServletResponse response = (HttpServletResponse) servletResponse;
-    final JEEContext context = new JEEContext(request, response, ((Config)request.getAttribute(PAC4J_CONFIG)).getSessionStore());
-    final ProfileManager<CommonProfile> manager = new ProfileManager<>(context);
-    final Optional<CommonProfile> optional = manager.get(true);
+    final JEEContext context = new JEEContext(request, response);
+    Config pac4jConfig = ((Config)request.getAttribute(PAC4J_CONFIG));
+    FrameworkParameters frameworkParameters = new JEEFrameworkParameters(request, response);
+    SessionStore sessionStore = pac4jConfig.getSessionStoreFactory().newSessionStore(frameworkParameters);
+    final ProfileManager manager = new ProfileManager(context, sessionStore);
+    final Optional<UserProfile> optional = manager.getProfile();
     if (optional.isPresent()) {
-      CommonProfile profile = optional.get();
+      UserProfile profile = optional.get();
       logger.debug("User authenticated as: {}", profile);
-      manager.remove(true);
+      sessionStore.set(context, Pac4jConstants.USER_PROFILES, new LinkedHashMap<String, UserProfile>());
+      context.setRequestAttribute(Pac4jConstants.USER_PROFILES, new LinkedHashMap<String, UserProfile>());
       String id = null;
       if (idAttribute != null) {
         Object attribute = profile.getAttribute(idAttribute);
diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
index 0ac14ac..4522026 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStore.java
@@ -27,20 +27,19 @@
 import org.apache.knox.gateway.util.Urls;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.pac4j.core.context.ContextHelper;
+import org.pac4j.core.context.WebContextHelper;
 import org.pac4j.core.context.Cookie;
-import org.pac4j.core.context.JEEContext;
 import org.pac4j.core.context.WebContext;
 import org.pac4j.core.context.session.SessionStore;
 import org.pac4j.core.exception.TechnicalException;
 import org.pac4j.core.profile.CommonProfile;
-import org.pac4j.core.util.JavaSerializationHelper;
+import org.pac4j.core.util.serializer.JavaSerializer;
 import org.pac4j.core.util.Pac4jConstants;
+import org.pac4j.jee.context.JEEContext;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.Serializable;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -66,7 +65,7 @@
  *
  * @since 0.8.0
  */
-public class KnoxSessionStore<C extends WebContext> implements SessionStore<C> {
+public class KnoxSessionStore implements SessionStore {
 
     private static final Logger logger = LogManager.getLogger(KnoxSessionStore.class);
 
@@ -74,7 +73,7 @@
 
     public static final String PAC4J_SESSION_PREFIX = "pac4j.session.";
 
-    private final JavaSerializationHelper javaSerializationHelper;
+    private final JavaSerializer javaSerializer;
 
     private final CryptoService cryptoService;
 
@@ -85,14 +84,14 @@
     final Map<String, String> sessionStoreConfigs;
 
     public KnoxSessionStore(final CryptoService cryptoService, final String clusterName, final String domainSuffix) {
-        this(cryptoService, clusterName, domainSuffix, new HashMap());
+        this(cryptoService, clusterName, domainSuffix, new HashMap<>());
     }
 
     public KnoxSessionStore(final CryptoService cryptoService,
         final String clusterName,
         final String domainSuffix,
         final Map<String, String> sessionStoreConfigs) {
-        javaSerializationHelper = new JavaSerializationHelper();
+        this.javaSerializer = new JavaSerializer();
         this.cryptoService = cryptoService;
         this.clusterName = clusterName;
         this.domainSuffix = domainSuffix;
@@ -101,11 +100,11 @@
 
 
     @Override
-    public String getOrCreateSessionId(WebContext context) {
-        return null;
+    public Optional<String> getSessionId(WebContext context, boolean createSession) {
+        return Optional.empty();
     }
 
-    private Serializable uncompressDecryptBase64(final String v) {
+    private Object uncompressDecryptBase64(final String v) {
         if (v != null && !v.isEmpty()) {
             byte[] bytes = Base64.decodeBase64(v);
             EncryptionResult result = EncryptionResult.fromByteArray(bytes);
@@ -116,7 +115,7 @@
                 result.salt);
             if (clear != null) {
                 try {
-                    return javaSerializationHelper.deserializeFromBytes(unCompress(clear));
+                    return javaSerializer.deserializeFromBytes(unCompress(clear));
                 } catch (IOException e) {
                     throw new TechnicalException(e);
                 }
@@ -127,7 +126,7 @@
 
     @Override
     public Optional<Object> get(WebContext context, String key) {
-        final Cookie cookie = ContextHelper.getCookie(context, PAC4J_SESSION_PREFIX + key);
+        final Cookie cookie = WebContextHelper.getCookie(context, PAC4J_SESSION_PREFIX + key);
         Object value = null;
         if (cookie != null) {
             value = uncompressDecryptBase64(cookie.getValue());
@@ -141,13 +140,13 @@
             || (o instanceof Map<?,?> && ((Map<?,?>)o).isEmpty())) {
             return null;
         } else {
-            byte[] bytes = javaSerializationHelper.serializeToBytes((Serializable) o);
+            byte[] bytes = javaSerializer.serializeToBytes(o);
 
             /* compress the data  */
             try {
                 bytes = compress(bytes);
 
-                if(bytes.length > 3000) {
+                if (bytes.length > 3000) {
                     logger.warn("Cookie too big, it might not be properly set");
                 }
 
@@ -186,7 +185,7 @@
             throw new TechnicalException(e);
         }
         setCookieHeader.setSecure(true);
-        if(ContextHelper.isHttpsOrSecure(context)) {
+        if (WebContextHelper.isHttpsOrSecure(context)) {
             setCookieHeader.setHttpOnly(true);
         }
 
@@ -293,7 +292,7 @@
     }
 
     @Override
-    public Optional<SessionStore<C>> buildFromTrackableSession(WebContext arg0, Object arg1) {
+    public Optional<SessionStore> buildFromTrackableSession(WebContext arg0, Object arg1) {
         return Optional.empty();
     }
 
@@ -303,7 +302,7 @@
     }
 
     @Override
-    public Optional getTrackableSession(WebContext arg0) {
+    public Optional<Object> getTrackableSession(WebContext arg0) {
         return Optional.empty();
     }
 
diff --git a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
index c4bc8d8..b466ef1 100644
--- a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
+++ b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
@@ -38,7 +38,6 @@
 import javax.servlet.ServletContext;
 import javax.servlet.http.Cookie;
 import java.util.Enumeration;
-import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
 
@@ -112,19 +111,21 @@
         assertEquals(302, response.getStatus());
         assertEquals(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, response.getHeaders().get("Location").get(0));
 
-        List<Cookie> cookies = response.getCookies();
-        assertEquals(1, cookies.size());
-        Optional<String> requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-            .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL))
-                .findFirst();
+        Optional<String> pac4jCsrfToken = findFirstCookieByName(response, Pac4jConstants.CSRF_TOKEN);
+        assertTrue(pac4jCsrfToken.isPresent());
+        assertTrue(pac4jCsrfToken.get().contains("Secure;"));
+
+        assertTrue(findFirstCookieByName(response, Cookies.PREVIOUS_CSRF_TOKEN).isPresent());
+        assertTrue(findFirstCookieByName(response, Cookies.CSRF_TOKEN_EXPIRATION_DATE).isPresent());
+
+        Optional<String> requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.CSRF_TOKEN)).count());
+        assertEquals(1, countCookiesByName(response, Cookies.CSRF_TOKEN));
 
         // step 2: send credentials to the callback url (callback from the identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, "true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, CLIENT_CLASS);
@@ -137,18 +138,16 @@
         assertEquals(302, response.getStatus());
         assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
 
-        Optional<String> userProfilesSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES))
-                .findFirst();
-        requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL + "=null;"))
-                .findFirst();
+        Optional<String> userProfilesSetCookie = findFirstCookieByName(response, Cookies.USER_PROFILES);
         assertTrue(userProfilesSetCookie.isPresent());
+
+        requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
+        assertTrue(cookieValueIsNull(requestedUrlSetCookie.get()));
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), this.setCookieParser(userProfilesSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get()), setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -157,8 +156,7 @@
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES + "=null;")).count());
+        assertEquals(1, countCookiesWithNullValueByName(response, Cookies.USER_PROFILES));
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
@@ -215,19 +213,18 @@
         assertEquals(302, response.getStatus());
         assertEquals(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, response.getHeaders().get("Location").get(0));
 
-        List<Cookie> cookies = response.getCookies();
-        assertEquals(1, cookies.size());
-        Optional<String> requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL))
-                .findFirst();
+        Optional<String> pac4jCsrfToken = findFirstCookieByName(response, Pac4jConstants.CSRF_TOKEN);
+        assertTrue(pac4jCsrfToken.isPresent());
+        assertTrue(pac4jCsrfToken.get().contains("Secure;"));
+
+        Optional<String> requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.CSRF_TOKEN)).count());
+        assertEquals(1, countCookiesByName(response, Cookies.CSRF_TOKEN));
 
         // step 2: send credentials to the callback url (callback from the identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, "true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, CLIENT_CLASS);
@@ -240,18 +237,16 @@
         assertEquals(302, response.getStatus());
         assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
 
-        Optional<String> userProfilesSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES))
-                .findFirst();
-        requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL + "=null;"))
-                .findFirst();
+        Optional<String> userProfilesSetCookie = findFirstCookieByName(response, Cookies.USER_PROFILES);
         assertTrue(userProfilesSetCookie.isPresent());
+
+        requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
+        assertTrue(cookieValueIsNull(requestedUrlSetCookie.get()));
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), this.setCookieParser(userProfilesSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get()), setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -260,8 +255,7 @@
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES + "=null;")).count());
+        assertEquals(1, countCookiesWithNullValueByName(response, Cookies.USER_PROFILES));
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
@@ -318,19 +312,18 @@
         assertEquals(302, response.getStatus());
         assertEquals(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS, response.getHeaders().get("Location").get(0));
 
-        List<Cookie> cookies = response.getCookies();
-        assertEquals(1, cookies.size());
-        Optional<String> requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL))
-                .findFirst();
+        Optional<String> pac4jCsrfToken = findFirstCookieByName(response, Pac4jConstants.CSRF_TOKEN);
+        assertTrue(pac4jCsrfToken.isPresent());
+        assertTrue(pac4jCsrfToken.get().contains("Secure;"));
+
+        Optional<String> requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.CSRF_TOKEN)).count());
+        assertEquals(1, countCookiesByName(response, Cookies.CSRF_TOKEN));
 
         // step 2: send credentials to the callback url (callback from the identity provider)
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get())});
         request.setRequestURL(PAC4J_CALLBACK_URL + "?" + Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER + "=true&" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER + "=" + CLIENT_CLASS);
         request.addParameter(Pac4jDispatcherFilter.PAC4J_CALLBACK_PARAMETER, "true");
         request.addParameter(Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, CLIENT_CLASS);
@@ -343,18 +336,16 @@
         assertEquals(302, response.getStatus());
         assertEquals(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL, response.getHeaders().get("Location").get(0));
 
-        Optional<String> userProfilesSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES))
-                .findFirst();
-        requestedUrlSetCookie = response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL + "=null;"))
-                .findFirst();
+        Optional<String> userProfilesSetCookie = findFirstCookieByName(response, Cookies.USER_PROFILES);
         assertTrue(userProfilesSetCookie.isPresent());
+
+        requestedUrlSetCookie = findFirstCookieByName(response, Cookies.REQUESTED_URL);
         assertTrue(requestedUrlSetCookie.isPresent());
+        assertTrue(cookieValueIsNull(requestedUrlSetCookie.get()));
 
         // step 3: turn pac4j identity into KnoxSSO identity
         request = new MockHttpServletRequest();
-        request.setCookies(new Cookie[]{this.setCookieParser(requestedUrlSetCookie.get()), this.setCookieParser(userProfilesSetCookie.get())});
+        request.setCookies(new Cookie[]{setCookieParser(requestedUrlSetCookie.get()), setCookieParser(userProfilesSetCookie.get())});
         request.setRequestURL(KNOXSSO_SERVICE_URL + "?" + ORIGINAL_URL + "=" + HADOOP_SERVICE_URL);
         request.setServerName(LOCALHOST);
         response = new MockHttpServletResponse();
@@ -363,8 +354,7 @@
         assertEquals(0, response.getStatus());
         adapter.doFilter(request, response, filterChain);
 
-        assertEquals(1, response.getHeaders().get("Set-Cookie").stream()
-                .filter(c -> c.startsWith(KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES + "=null;")).count());
+        assertEquals(1, countCookiesWithNullValueByName(response, Cookies.USER_PROFILES));
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
@@ -401,16 +391,16 @@
         EasyMock.verify(aliasService);
     }
 
-    private Cookie setCookieParser(String setCookie) {
+    private static Cookie setCookieParser(String setCookie) {
         String[] cookieParts = setCookie.split(";");
         String[] nameValuePairs = cookieParts[0].trim().split("=", 2);
 
         return new Cookie(nameValuePairs[0].trim(), nameValuePairs[1].trim());
     }
 
-    private class FilterConfigStub implements FilterConfig {
-        private ServletContext context;
-        private Properties properties = new Properties();
+    private static class FilterConfigStub implements FilterConfig {
+        private final ServletContext context;
+        private final Properties properties = new Properties();
 
         FilterConfigStub(ServletContext context) {
             this.context = context;
@@ -441,4 +431,35 @@
             return (Enumeration<String>) properties.propertyNames();
         }
     }
+
+    private static Optional<String> findFirstCookieByName(MockHttpServletResponse response, String name) {
+        return response.getHeaders().get("Set-Cookie").stream()
+        .filter(c -> c.startsWith(name+"="))
+        .findFirst();
+    }
+
+    private static long countCookiesByName(MockHttpServletResponse response, String name) {
+        return response.getHeaders().get("Set-Cookie").stream()
+        .filter(c -> c.startsWith(name+"="))
+        .count();
+    }
+
+    private static long countCookiesWithNullValueByName(MockHttpServletResponse response, String name) {
+        return response.getHeaders().get("Set-Cookie").stream()
+        .filter(c -> c.startsWith(name+"=null;"))
+        .count();
+    }
+
+    private static boolean cookieValueIsNull(String setCookieHeader) {
+        return setCookieParser(setCookieHeader).getValue().equals("null");
+    }
+
+    private static class Cookies {
+        static final String REQUESTED_URL = KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.REQUESTED_URL;
+        static final String CSRF_TOKEN_EXPIRATION_DATE = KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.CSRF_TOKEN_EXPIRATION_DATE;
+        static final String PREVIOUS_CSRF_TOKEN = KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.PREVIOUS_CSRF_TOKEN;
+        static final String CSRF_TOKEN = KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.CSRF_TOKEN;
+        static final String USER_PROFILES = KnoxSessionStore.PAC4J_SESSION_PREFIX + Pac4jConstants.USER_PROFILES;
+    }
+
 }
diff --git a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecoratorTest.java b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecoratorTest.java
index 0605025..ac1b984 100644
--- a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecoratorTest.java
+++ b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/config/AzureADClientConfigurationDecoratorTest.java
@@ -23,15 +23,15 @@
 
 import org.junit.Test;
 import org.pac4j.core.http.callback.PathParameterCallbackUrlResolver;
-import org.pac4j.oidc.client.AzureAdClient;
-import org.pac4j.oidc.config.AzureAdOidcConfiguration;
+import org.pac4j.oidc.client.AzureAd2Client;
+import org.pac4j.oidc.config.AzureAd2OidcConfiguration;
 
 public class AzureADClientConfigurationDecoratorTest {
 
   @Test
   public void testAzureADClientConfigurationDecoration() throws Exception {
-    final AzureAdOidcConfiguration azureAdConfig = new AzureAdOidcConfiguration();
-    final AzureAdClient client = new AzureAdClient(azureAdConfig);
+    final AzureAd2OidcConfiguration azureAdConfig = new AzureAd2OidcConfiguration();
+    final AzureAd2Client client = new AzureAd2Client(azureAdConfig);
     final AzureADClientConfigurationDecorator azureConfigDecorator = new AzureADClientConfigurationDecorator();
     azureConfigDecorator.decorateClients(Collections.singletonList(client), null);
     assertTrue(client.getCallbackUrlResolver() instanceof PathParameterCallbackUrlResolver);
diff --git a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
index 32cb5e4..a56f682 100644
--- a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
+++ b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/session/KnoxSessionStoreTest.java
@@ -24,9 +24,9 @@
 import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
-import org.pac4j.core.context.JEEContext;
 import org.pac4j.core.profile.CommonProfile;
 import org.pac4j.core.util.Pac4jConstants;
+import org.pac4j.jee.context.JEEContext;
 import org.pac4j.saml.profile.SAML2Profile;
 
 import javax.servlet.http.HttpServletResponse;
diff --git a/pom.xml b/pom.xml
index f7568d6..8551319 100644
--- a/pom.xml
+++ b/pom.xml
@@ -191,7 +191,7 @@
         <commons-net.version>3.9.0</commons-net.version>
         <commons-text.version>1.10.0</commons-text.version>
         <cors-filter.version>2.9.1</cors-filter.version>
-        <cryptacular.version>1.2.4</cryptacular.version>
+        <cryptacular.version>1.2.7</cryptacular.version>
         <curator.version>5.4.0</curator.version>
         <dependency-check-maven.version>6.0.3</dependency-check-maven.version>
         <derby.db.version>10.14.2.0</derby.db.version> <!-- 10.15.1.3 requires Java 9 -->
@@ -233,10 +233,10 @@
         <javax.websocket-api.version>1.1</javax.websocket-api.version>
         <jaxws-ri.version>2.3.3</jaxws-ri.version>
         <jakarta.xml.bind.version>2.3.2</jakarta.xml.bind.version>
-        <java-support.version>7.5.1</java-support.version>
+        <java-support.version>8.3.1</java-support.version>
         <javassist.version>3.27.0-GA</javassist.version>
         <jboss-logging.version>3.4.1.Final</jboss-logging.version>
-        <jee-pac4j.version>5.0.0</jee-pac4j.version>
+        <jee-pac4j.version>8.0.1</jee-pac4j.version>
         <jericho-html.version>3.4</jericho-html.version>
         <jersey.version>2.47</jersey.version>
         <jetty.version>9.4.57.v20241219</jetty.version>
@@ -248,7 +248,6 @@
         <jakarta.annotation-api.version>1.3.4</jakarta.annotation-api.version>
         <junit.version>4.13.2</junit.version>
         <kotlin-stdlib.version>1.9.10</kotlin-stdlib.version>
-        <lang-tag.version>1.5</lang-tag.version>
         <libpam4j.version>1.11</libpam4j.version>
         <log4j2.version>2.20.0</log4j2.version>
         <maven-checkstyle-plugin.version>3.1.1</maven-checkstyle-plugin.version>
@@ -259,11 +258,11 @@
         <metrics.version>4.1.16</metrics.version>
         <mina.version>2.2.4</mina.version>
         <netty.version>4.1.127.Final</netty.version>
-        <nimbus-jose-jwt.version>10.0.2</nimbus-jose-jwt.version>
+        <nimbus-jose-jwt.version>10.5</nimbus-jose-jwt.version>
         <nodejs.version>v22.20.0</nodejs.version>
         <okhttp.version>4.12.0</okhttp.version>
-        <opensaml.version>3.4.5</opensaml.version>
-        <pac4j.version>4.5.6</pac4j.version>
+        <opensaml.version>5.1.6</opensaml.version>
+        <pac4j.version>6.3.0</pac4j.version>
         <postgresql.version>42.4.4</postgresql.version>
         <mysql.version>8.0.28</mysql.version>
         <mariadb.connector.version>3.3.0</mariadb.connector.version>
@@ -292,7 +291,7 @@
         <txw2.version>2.4.0-b180830.0438</txw2.version>
         <velocity.version>2.4.1</velocity.version>
         <woodstox-core.version>6.4.0</woodstox-core.version>
-        <xmlsec.version>2.2.6</xmlsec.version>
+        <xmlsec.version>4.0.4</xmlsec.version>
         <xmltool.version>3.3</xmltool.version>
         <xml-jaxb.version>2.3.1</xml-jaxb.version>
         <xml-matchers.version>0.10</xml-matchers.version>
@@ -385,7 +384,7 @@
                 </repository>
                 <repository>
                     <id>shib-release</id>
-                    <url>https://build.shibboleth.net/nexus/content/groups/public</url>
+                    <url>https://build.shibboleth.net/maven/releases</url>
                     <snapshots>
                         <enabled>false</enabled>
                     </snapshots>
@@ -1481,11 +1480,6 @@
                 <artifactId>nimbus-jose-jwt</artifactId>
                 <version>${nimbus-jose-jwt.version}</version>
             </dependency>
-            <dependency>
-                <groupId>com.nimbusds</groupId>
-                <artifactId>lang-tag</artifactId>
-                <version>${lang-tag.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>net.minidev</groupId>
@@ -2506,6 +2500,11 @@
             </dependency>
             <dependency>
                 <groupId>org.pac4j</groupId>
+                <artifactId>pac4j-javaee</artifactId>
+                <version>${pac4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.pac4j</groupId>
                 <artifactId>pac4j-http</artifactId>
                 <version>${pac4j.version}</version>
             </dependency>
@@ -2521,7 +2520,7 @@
             </dependency>
             <dependency>
                 <groupId>org.pac4j</groupId>
-                <artifactId>pac4j-saml-opensamlv3</artifactId>
+                <artifactId>pac4j-saml</artifactId>
                 <version>${pac4j.version}</version>
                 <exclusions>
                     <exclusion>
@@ -2559,12 +2558,12 @@
 
             <dependency>
                 <groupId>org.pac4j</groupId>
-                <artifactId>jee-pac4j</artifactId>
+                <artifactId>javaee-pac4j</artifactId>
                 <version>${jee-pac4j.version}</version>
                 <exclusions>
                     <exclusion>
                         <groupId>org.pac4j</groupId>
-                        <artifactId>pac4j-core</artifactId>
+                        <artifactId>pac4j-javaee</artifactId>
                     </exclusion>
                 </exclusions>
             </dependency>
@@ -2605,16 +2604,6 @@
                 <groupId>org.opensaml</groupId>
                 <artifactId>opensaml-storage-impl</artifactId>
                 <version>${opensaml.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>org.hibernate</groupId>
-                        <artifactId>hibernate-entitymanager</artifactId>
-                    </exclusion>
-                    <exclusion>
-                        <groupId>org.hibernate.javax.persistence</groupId>
-                        <artifactId>hibernate-jpa-2.1-api</artifactId>
-                    </exclusion>
-                </exclusions>
             </dependency>
             <dependency>
                 <groupId>org.javassist</groupId>