Repository: pac4j/undertow-pac4j
Pull request #212: Update pac4j to 6.1.1
Author: login: sake92
Created: 2025-04-01T15:22:06Z | Merged: 2025-04-10T13:19:54Z

Not an expert here, and I will probably need some guidance (there a few TODOs I left).  
I've mostly looked into https://github.com/pac4j/javalin-pac4j and JEE implementations since they seem similar to undertow.

I will try to add some tests too, adapt from javalin-pac4j


Diff:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7499249..bd66c3e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,7 +1,7 @@
 name: Java CI
 
 env:
-  JDK_CURRENT: 11
+  JDK_CURRENT: 17
   DISTRIBUTION: zulu
 
 on:
diff --git a/pom.xml b/pom.xml
index 53f6956..bb4664c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
     <artifactId>undertow-pac4j</artifactId>
     <packaging>jar</packaging>
     <name>pac4j implementation for Undertow</name>
-    <version>5.0.2-SNAPSHOT</version>
+    <version>6.0.0-SNAPSHOT</version>
     <description>Security library for Undertow based on pac4j</description>
     <url>https://github.com/pac4j/undertow-pac4j</url>
 
@@ -45,9 +45,9 @@
     </scm>
 
     <properties>
-        <pac4j.version>5.7.7</pac4j.version>
+        <pac4j.version>6.1.1</pac4j.version>
         <undertow.version>2.3.18.Final</undertow.version>
-        <java.version>11</java.version>
+        <java.version>17</java.version>
     </properties>
 
     <dependencies>
@@ -118,7 +118,7 @@
                 </configuration>
                 <executions>
                     <execution>
-                        <id>run-sportbugs</id>
+                        <id>run-spotbugs</id>
                         <phase>compile</phase>
                         <goals>
                             <goal>check</goal>
diff --git a/src/main/java/org/pac4j/framework/adapter/FrameworkAdapterImpl.java b/src/main/java/org/pac4j/framework/adapter/FrameworkAdapterImpl.java
new file mode 100644
index 0000000..6a3324a
--- /dev/null
+++ b/src/main/java/org/pac4j/framework/adapter/FrameworkAdapterImpl.java
@@ -0,0 +1,28 @@
+package org.pac4j.framework.adapter;
+
+import org.pac4j.core.adapter.DefaultFrameworkAdapter;
+import org.pac4j.core.config.Config;
+import org.pac4j.undertow.context.UndertowContextFactory;
+import org.pac4j.undertow.context.UndertowSessionStoreFactory;
+import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+
+/**
+ * This class is found on classpath by pac4j
+ * @author Sakib Hadziavdic
+ * @since 6.0.0
+ */
+public class FrameworkAdapterImpl extends DefaultFrameworkAdapter {
+
+    @Override
+    public void applyDefaultSettingsIfUndefined(final Config config) {
+        super.applyDefaultSettingsIfUndefined(config);
+        config.setWebContextFactoryIfUndefined(UndertowContextFactory.INSTANCE);
+        config.setSessionStoreFactoryIfUndefined(UndertowSessionStoreFactory.INSTANCE);
+        config.setHttpActionAdapterIfUndefined(UndertowHttpActionAdapter.INSTANCE);
+    }
+
+    @Override
+    public String toString() {
+        return "Undertow";
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/pac4j/undertow/account/Pac4jAccount.java b/src/main/java/org/pac4j/undertow/account/Pac4jAccount.java
index 2906900..5ec94fc 100644
--- a/src/main/java/org/pac4j/undertow/account/Pac4jAccount.java
+++ b/src/main/java/org/pac4j/undertow/account/Pac4jAccount.java
@@ -19,18 +19,15 @@
 public class Pac4jAccount implements Account {
 
     private final List<UserProfile> profiles;
-
-    private Set<String> roles;
-    private Principal principal;
+    private final Set<String> roles;
+    private final Principal principal;
 
     public Pac4jAccount(final LinkedHashMap<String, UserProfile> profiles) {
         this.roles = new HashSet<>();
         this.profiles = ProfileHelper.flatIntoAProfileList(profiles);
         for (final UserProfile profile : this.profiles) {
             final Set<String> roles = profile.getRoles();
-            for (final String role : roles) {
-                this.roles.add(role);
-            }
+            this.roles.addAll(roles);
         }
         final UserProfile profile = ProfileHelper.flatIntoOneProfile(this.profiles).get();
         this.principal = () -> profile.getId();
diff --git a/src/main/java/org/pac4j/undertow/context/UndertowContextFactory.java b/src/main/java/org/pac4j/undertow/context/UndertowContextFactory.java
index 0932b96..678a02c 100644
--- a/src/main/java/org/pac4j/undertow/context/UndertowContextFactory.java
+++ b/src/main/java/org/pac4j/undertow/context/UndertowContextFactory.java
@@ -1,8 +1,9 @@
 package org.pac4j.undertow.context;
 
-import io.undertow.server.HttpServerExchange;
+import org.pac4j.core.context.FrameworkParameters;
 import org.pac4j.core.context.WebContext;
 import org.pac4j.core.context.WebContextFactory;
+import org.pac4j.core.exception.TechnicalException;
 
 /**
  * Specific web context factory.
@@ -15,7 +16,10 @@ public class UndertowContextFactory implements WebContextFactory {
     public static final UndertowContextFactory INSTANCE = new UndertowContextFactory();
 
     @Override
-    public WebContext newContext(final Object... parameters) {
-        return new UndertowWebContext((HttpServerExchange) parameters[0]);
+    public WebContext newContext(FrameworkParameters parameters) {
+        if (parameters instanceof UndertowParameters undertowParameters) {
+            return new UndertowWebContext(undertowParameters.exchange());
+        }
+        throw new TechnicalException("Bad parameters type");
     }
 }
diff --git a/src/main/java/org/pac4j/undertow/context/UndertowParameters.java b/src/main/java/org/pac4j/undertow/context/UndertowParameters.java
new file mode 100644
index 0000000..a79b686
--- /dev/null
+++ b/src/main/java/org/pac4j/undertow/context/UndertowParameters.java
@@ -0,0 +1,13 @@
+package org.pac4j.undertow.context;
+
+import io.undertow.server.HttpServerExchange;
+import org.pac4j.core.context.FrameworkParameters;
+
+/**
+ * Parameters for Undertow.
+ *
+ * @author Sakib Hadziavdic
+ * @since 6.0.0
+ */
+public record UndertowParameters(HttpServerExchange exchange) implements FrameworkParameters {
+}
diff --git a/src/main/java/org/pac4j/undertow/context/UndertowSessionStore.java b/src/main/java/org/pac4j/undertow/context/UndertowSessionStore.java
index 97c4532..9cf3eff 100644
--- a/src/main/java/org/pac4j/undertow/context/UndertowSessionStore.java
+++ b/src/main/java/org/pac4j/undertow/context/UndertowSessionStore.java
@@ -1,27 +1,29 @@
 package org.pac4j.undertow.context;
 
+import java.util.Optional;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.server.session.*;
 import org.pac4j.core.context.WebContext;
+import org.pac4j.core.context.session.PrefixedSessionStore;
 import org.pac4j.core.context.session.SessionStore;
 
-import java.util.Optional;
-
 /**
  * Specific session store for Undertow relying on the {@link SessionManager} and {@link SessionConfig}.
  *
  * @author Jerome Leleu
  * @since 1.1.0
  */
-public class UndertowSessionStore implements SessionStore {
+public class UndertowSessionStore extends PrefixedSessionStore {
 
-    private SessionManager sessionManager;
-    private SessionConfig sessionConfig;
+    private final HttpServerExchange exchange;
+    private final SessionManager sessionManager;
+    private final SessionConfig sessionConfig;
     private Session session;
 
     private String sessionCookieName = "JSESSIONID";
 
     public UndertowSessionStore(final HttpServerExchange exchange) {
+        this.exchange = exchange;
         this.sessionManager = exchange.getAttachment(SessionManager.ATTACHMENT_KEY);
         this.sessionConfig = exchange.getAttachment(SessionConfig.ATTACHMENT_KEY);
     }
@@ -49,27 +51,20 @@ private Optional<Session> getSession(final WebContext webContext, final boolean
 
     @Override
     public Optional<String> getSessionId(final WebContext context, final boolean createSession) {
-        final Optional<Session> session = getSession(context, createSession);
-        if (session.isPresent()) {
-            return Optional.of(session.get().getId());
-        } else {
-            return Optional.empty();
-        }
+        final var session = getSession(context, createSession);
+        return session.map(Session::getId);
     }
 
 
     @Override
     public Optional<Object> get(final WebContext context, final String key) {
-        final Optional<Session> session = getSession(context, false);
-        if (session.isEmpty()) {
-            return Optional.empty();
-        }
-        return Optional.ofNullable(session.get().getAttribute(key));
+        final var session = getSession(context, false);
+        return session.map(value -> value.getAttribute(key));
     }
 
     @Override
     public void set(final WebContext context, final String key, final Object value) {
-        final Optional<Session> session = getSession(context, true);
+        final var session = getSession(context, true);
         session.get().setAttribute(key, value);
     }
 
@@ -84,9 +79,7 @@ public SessionConfig getSessionConfig() {
     @Override
     public boolean destroySession(final WebContext context) {
         final Optional<Session> session = getSession(context, false);
-        if (session.isPresent()) {
-            session.get().invalidate(((UndertowWebContext) context).getExchange());
-        }
+        session.ifPresent(value -> value.invalidate(((UndertowWebContext) context).getExchange()));
         return true;
     }
 
@@ -98,7 +91,10 @@ public Optional<Object> getTrackableSession(final WebContext context) {
     @Override
     public Optional<SessionStore> buildFromTrackableSession(final WebContext context, final Object trackableSession) {
         if (trackableSession != null) {
-            return Optional.of(new UndertowSessionStore(((UndertowWebContext) context).getExchange(), (Session) trackableSession));
+            var undertowSession = (Session) trackableSession;
+            var sessionStore = new UndertowSessionStore(exchange, undertowSession);
+            sessionStore.setPrefix(this.getPrefix());
+            return Optional.of(sessionStore);
         } else {
             return Optional.empty();
         }
diff --git a/src/main/java/org/pac4j/undertow/context/UndertowSessionStoreFactory.java b/src/main/java/org/pac4j/undertow/context/UndertowSessionStoreFactory.java
new file mode 100644
index 0000000..717f0ae
--- /dev/null
+++ b/src/main/java/org/pac4j/undertow/context/UndertowSessionStoreFactory.java
@@ -0,0 +1,31 @@
+package org.pac4j.undertow.context;
+
+import org.pac4j.core.context.FrameworkParameters;
+import org.pac4j.core.context.session.SessionStore;
+import org.pac4j.core.context.session.SessionStoreFactory;
+import org.pac4j.core.exception.TechnicalException;
+
+/**
+ * Build an Undertow session store from parameters.
+ *
+ * @author Sakib Hadziavdic
+ * @since 6.0.0
+ */
+public class UndertowSessionStoreFactory implements SessionStoreFactory {
+
+    /** Constant <code>INSTANCE</code> */
+    public static final SessionStoreFactory INSTANCE = new UndertowSessionStoreFactory();
+    
+    /**
+     * {@inheritDoc}
+     *
+     * Create the session store.
+     */
+    @Override
+    public SessionStore newSessionStore(final FrameworkParameters parameters) {
+        if (parameters instanceof UndertowParameters undertowParameters) {
+            return new UndertowSessionStore(undertowParameters.exchange());
+        }
+        throw new TechnicalException("Bad parameters type");
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/pac4j/undertow/context/UndertowWebContext.java b/src/main/java/org/pac4j/undertow/context/UndertowWebContext.java
index da0d493..20ff4b7 100644
--- a/src/main/java/org/pac4j/undertow/context/UndertowWebContext.java
+++ b/src/main/java/org/pac4j/undertow/context/UndertowWebContext.java
@@ -8,7 +8,6 @@
 import io.undertow.util.HttpString;
 
 import java.util.*;
-import java.util.Map.Entry;
 import java.util.stream.Collectors;
 
 import org.pac4j.core.context.Cookie;
@@ -37,11 +36,11 @@ public HttpServerExchange getExchange() {
 
     @Override
     public Optional<String> getRequestParameter(final String name) {
-        Deque<String> param = exchange.getQueryParameters().get(name);
+        var param = getExchange().getQueryParameters().get(name);
         if (param != null) {
             return Optional.ofNullable(param.peek());
         } else {
-            FormData data = exchange.getAttachment(FormDataParser.FORM_DATA);
+            FormData data = getExchange().getAttachment(FormDataParser.FORM_DATA);
             if (data != null && data.get(name) != null) {
                 return Optional.ofNullable(data.get(name).peek().getValue());
             }
@@ -51,12 +50,12 @@ public Optional<String> getRequestParameter(final String name) {
 
     @Override
     public Map<String, String[]> getRequestParameters() {
-        Map<String, Deque<String>> params = exchange.getQueryParameters();
-        Map<String, String[]> map = new HashMap<>();
-        for (Entry<String, Deque<String>> entry : params.entrySet()) {
+        var params = getExchange().getQueryParameters();
+        var map = new HashMap<String, String[]>();
+        for (var entry : params.entrySet()) {
             map.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
         }
-        FormData data = exchange.getAttachment(FormDataParser.FORM_DATA);
+        FormData data = getExchange().getAttachment(FormDataParser.FORM_DATA);
         if (data != null) {
             for (String key : data) {
                 map.put(key, data.get(key).stream().map(f -> f.getValue()).collect(Collectors.toList()).toArray(new String[data.get(key).size()]));
@@ -67,7 +66,7 @@ public Map<String, String[]> getRequestParameters() {
 
     @Override
     public Optional<String> getRequestHeader(final String name) {
-        return Optional.ofNullable(exchange.getRequestHeaders().get(name, 0));
+        return Optional.ofNullable(getExchange().getRequestHeaders().get(name, 0));
     }
 
     @Override
@@ -77,41 +76,41 @@ public String getRequestMethod() {
 
     @Override
     public Optional<String> getResponseHeader(final String name) {
-        return Optional.ofNullable(exchange.getResponseHeaders().getFirst(name));
+        return Optional.ofNullable(getExchange().getResponseHeaders().getFirst(name));
     }
 
     @Override
     public void setResponseHeader(final String name, final String value) {
-        exchange.getResponseHeaders().put(HttpString.tryFromString(name), value);
+        getExchange().getResponseHeaders().put(HttpString.tryFromString(name), value);
     }
 
     @Override
     public String getServerName() {
-        return exchange.getHostName();
+        return getExchange().getHostName();
     }
 
     @Override
     public int getServerPort() {
-        return exchange.getHostPort();
+        return getExchange().getHostPort();
     }
 
     @Override
     public String getScheme() {
-        return exchange.getRequestScheme();
+        return getExchange().getRequestScheme();
     }
 
     @Override
     public String getFullRequestURL() {
-        String full = exchange.getRequestURL();
-        if (CommonHelper.isNotBlank(exchange.getQueryString())) {
-            full = full + "?" + exchange.getQueryString();
+        String full = getExchange().getRequestURL();
+        if (CommonHelper.isNotBlank(getExchange().getQueryString())) {
+            full = full + "?" + getExchange().getQueryString();
         }
         return full;
     }
 
     @Override
     public String getRemoteAddr() {
-        return exchange.getSourceAddress().getAddress().getHostAddress();
+        return getExchange().getSourceAddress().getAddress().getHostAddress();
     }
 
     @Override
@@ -123,27 +122,27 @@ public void addResponseCookie(final Cookie cookie) {
         newCookie.setMaxAge(cookie.getMaxAge() < 0 ? null : cookie.getMaxAge());
         newCookie.setSecure(cookie.isSecure());
         newCookie.setHttpOnly(cookie.isHttpOnly());
-        exchange.setResponseCookie(newCookie);
+        getExchange().setResponseCookie(newCookie);
     }
 
     @Override
     public void setRequestAttribute(final String name, final Object value) {
-        RequestAttributesMap.getOrInitialize(exchange).put(name, value);
+        RequestAttributesMap.getOrInitialize(getExchange()).put(name, value);
     }
 
     @Override
     public String getPath() {
-        return exchange.getRequestPath();
+        return getExchange().getRequestPath();
     }
 
     @Override
     public void setResponseContentType(final String content) {
-        exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, content);
+        getExchange().getResponseHeaders().add(Headers.CONTENT_TYPE, content);
     }
 
     @Override
     public Collection<Cookie> getRequestCookies() {
-        final Collection<io.undertow.server.handlers.Cookie> uCookies = exchange.getRequestCookies().values();
+        final Collection<io.undertow.server.handlers.Cookie> uCookies = getExchange().getRequestCookies().values();
         final List<Cookie> cookies = new ArrayList<>(uCookies.size());
         for (final io.undertow.server.handlers.Cookie uCookie : uCookies) {
             final Cookie cookie = new Cookie(uCookie.getName(), uCookie.getValue());
@@ -160,11 +159,11 @@ public Collection<Cookie> getRequestCookies() {
 
     @Override
     public Optional<Object> getRequestAttribute(final String name) {
-        return Optional.ofNullable(RequestAttributesMap.getOrInitialize(exchange).get(name));
+        return Optional.ofNullable(RequestAttributesMap.getOrInitialize(getExchange()).get(name));
     }
 
     @Override
     public boolean isSecure() {
-        return exchange.isSecure();
+        return getExchange().isSecure();
     }
 }
diff --git a/src/main/java/org/pac4j/undertow/handler/CallbackHandler.java b/src/main/java/org/pac4j/undertow/handler/CallbackHandler.java
index bc95f77..a010a64 100644
--- a/src/main/java/org/pac4j/undertow/handler/CallbackHandler.java
+++ b/src/main/java/org/pac4j/undertow/handler/CallbackHandler.java
@@ -2,21 +2,14 @@
 
 import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
-
 import io.undertow.server.handlers.BlockingHandler;
 import io.undertow.server.handlers.form.EagerFormParsingHandler;
 import io.undertow.server.handlers.form.FormEncodedDataDefinition;
 import io.undertow.server.handlers.form.FormParserFactory;
+import org.pac4j.core.adapter.FrameworkAdapter;
 import org.pac4j.core.config.Config;
-import org.pac4j.core.context.WebContext;
-import org.pac4j.core.context.session.SessionStore;
 import org.pac4j.core.engine.CallbackLogic;
-import org.pac4j.core.engine.DefaultCallbackLogic;
-import org.pac4j.core.http.adapter.HttpActionAdapter;
-import org.pac4j.core.util.FindBest;
-import org.pac4j.undertow.context.UndertowContextFactory;
-import org.pac4j.undertow.context.UndertowSessionStore;
-import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+import org.pac4j.undertow.context.UndertowParameters;
 
 /**
  * <p>This filter finishes the login process for an indirect client.</p>
@@ -63,12 +56,14 @@ public static HttpHandler build(final Config config, final String defaultUrl, fi
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) {
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final CallbackLogic bestLogic = FindBest.callbackLogic(callbackLogic, config, DefaultCallbackLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, config, bestAdapter, this.defaultUrl, this.renewSession, this.defaultClient);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        config.getCallbackLogic().perform(
+                this.config,
+                this.defaultUrl,
+                this.renewSession,
+                config.getClients().getClients().get(0).getName(),
+                new UndertowParameters(exchange)
+        );
     }
 
     protected CallbackLogic getCallbackLogic() {
diff --git a/src/main/java/org/pac4j/undertow/handler/LogoutHandler.java b/src/main/java/org/pac4j/undertow/handler/LogoutHandler.java
index 9fa347e..62f7073 100644
--- a/src/main/java/org/pac4j/undertow/handler/LogoutHandler.java
+++ b/src/main/java/org/pac4j/undertow/handler/LogoutHandler.java
@@ -2,17 +2,10 @@
 
 import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
-
+import org.pac4j.core.adapter.FrameworkAdapter;
 import org.pac4j.core.config.Config;
-import org.pac4j.core.context.WebContext;
-import org.pac4j.core.context.session.SessionStore;
-import org.pac4j.core.engine.DefaultLogoutLogic;
 import org.pac4j.core.engine.LogoutLogic;
-import org.pac4j.core.http.adapter.HttpActionAdapter;
-import org.pac4j.core.util.FindBest;
-import org.pac4j.undertow.context.UndertowContextFactory;
-import org.pac4j.undertow.context.UndertowSessionStore;
-import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+import org.pac4j.undertow.context.UndertowParameters;
 
 /**
  * <p>This filter handles the (application + identity provider) logout process.</p>
@@ -24,7 +17,7 @@ public class LogoutHandler implements HttpHandler {
     
     private LogoutLogic logoutLogic;
 
-    private Config config;
+    private final Config config;
 
     private String defaultUrl;
 
@@ -52,14 +45,16 @@ public LogoutHandler(final Config config, final String defaultUrl, final String
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final LogoutLogic bestLogic = FindBest.logoutLogic(logoutLogic, config, DefaultLogoutLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, config, bestAdapter, defaultUrl, logoutUrlPattern,
-                localLogout, destroySession, centralLogout);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        config.getLogoutLogic().perform(
+                this.config,
+                this.defaultUrl,
+                this.logoutUrlPattern,
+                this.localLogout,
+                this.destroySession,
+                this.centralLogout,
+                new UndertowParameters(exchange)
+        );
     }
 
     public LogoutLogic getLogoutLogic() {
diff --git a/src/main/java/org/pac4j/undertow/handler/SecurityHandler.java b/src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
index ba198bb..701afd8 100644
--- a/src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
+++ b/src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
@@ -3,16 +3,10 @@
 import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.server.handlers.BlockingHandler;
+import org.pac4j.core.adapter.FrameworkAdapter;
 import org.pac4j.core.config.Config;
-import org.pac4j.core.context.WebContext;
-import org.pac4j.core.context.session.SessionStore;
-import org.pac4j.core.engine.DefaultSecurityLogic;
 import org.pac4j.core.engine.SecurityLogic;
-import org.pac4j.core.http.adapter.HttpActionAdapter;
-import org.pac4j.core.util.FindBest;
-import org.pac4j.undertow.context.UndertowContextFactory;
-import org.pac4j.undertow.context.UndertowSessionStore;
-import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+import org.pac4j.undertow.context.UndertowParameters;
 import org.pac4j.undertow.profile.UndertowProfileManager;
 
 /**
@@ -23,15 +17,11 @@
  */
 public class SecurityHandler implements HttpHandler {
 
-    static {
-        Config.defaultProfileManagerFactory("UndertowProfileManager", (ctx, store) -> new UndertowProfileManager(ctx, store));
-    }
-
     private SecurityLogic securityLogic;
 
-    private HttpHandler toWrap;
+    private final HttpHandler toWrap;
 
-    private Config config;
+    private final Config config;
 
     private String clients;
 
@@ -45,6 +35,7 @@ protected SecurityHandler(final HttpHandler toWrap, final Config config, final S
         this.clients = clients;
         this.authorizers = authorizers;
         this.matchers = matchers;
+        config.setProfileManagerFactory(UndertowProfileManager::new);
     }
 
     public static HttpHandler build(final HttpHandler toWrap, Config config) {
@@ -73,18 +64,18 @@ public static HttpHandler build(final HttpHandler toWrap, Config config, final S
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final SecurityLogic bestLogic = FindBest.securityLogic(securityLogic, config, DefaultSecurityLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, this.config, (ctx, store, profiles, parameters) -> {
-
-            toWrap.handleRequest(exchange);
-            return null;
-
-        }, bestAdapter, this.clients, this.authorizers, this.matchers);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        config.getSecurityLogic().perform(
+                this.config,
+                (ctx, store, profiles) -> {
+                    this.toWrap.handleRequest(exchange);
+                    return null;
+                },
+                this.clients,
+                this.authorizers,
+                this.matchers,
+                new UndertowParameters(exchange)
+        );
     }
 
     protected SecurityLogic getSecurityLogic() {
diff --git a/src/main/java/org/pac4j/undertow/http/UndertowHttpActionAdapter.java b/src/main/java/org/pac4j/undertow/http/UndertowHttpActionAdapter.java
index 4d0ab99..39d7e0f 100644
--- a/src/main/java/org/pac4j/undertow/http/UndertowHttpActionAdapter.java
+++ b/src/main/java/org/pac4j/undertow/http/UndertowHttpActionAdapter.java
@@ -27,11 +27,9 @@ public Object adapt(final HttpAction action, final WebContext context) {
             final HttpServerExchange exchange = ((UndertowWebContext) context).getExchange();
             exchange.setStatusCode(code);
 
-            if (action instanceof WithLocationAction) {
-                final WithLocationAction withLocationAction = (WithLocationAction) action;
+            if (action instanceof WithLocationAction withLocationAction) {
                 context.setResponseHeader(HttpConstants.LOCATION_HEADER, withLocationAction.getLocation());
-            } else if (action instanceof WithContentAction) {
-                final WithContentAction withContentAction = (WithContentAction) action;
+            } else if (action instanceof WithContentAction withContentAction) {
                 final String content = withContentAction.getContent();
                 exchange.getResponseSender().send(content);
             }
diff --git a/src/main/java/org/pac4j/undertow/util/UndertowHelper.java b/src/main/java/org/pac4j/undertow/util/UndertowHelper.java
index 6c6cc0b..98db7a4 100644
--- a/src/main/java/org/pac4j/undertow/util/UndertowHelper.java
+++ b/src/main/java/org/pac4j/undertow/util/UndertowHelper.java
@@ -25,7 +25,7 @@ public class UndertowHelper {
      * @param profiles the linked hashmap of profiles
      */
     public static void populateContext(final UndertowWebContext context, final LinkedHashMap<String, UserProfile> profiles) {
-        if (profiles != null && profiles.size() > 0) {
+        if (profiles != null && !profiles.isEmpty()) {
             final HttpServerExchange exchange = context.getExchange();
             SecurityContext securityContext = exchange.getSecurityContext();
             if (securityContext == null) {


Reviews:
user: login: leleuj
body: Please find the requested changes
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-07T13:34:48Z
user: login: sake92
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:08:35Z
user: login: sake92
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:09:34Z

Review comments:
diff_hunk: @@ -0,0 +1,24 @@
+package org.pac4j.framework.adapter;
+
+import org.pac4j.core.adapter.DefaultFrameworkAdapter;
+import org.pac4j.core.config.Config;
+import org.pac4j.undertow.context.UndertowContextFactory;
+import org.pac4j.undertow.context.UndertowSessionStoreFactory;
+import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+
+// found on classpath by pac4j
+public class FrameworkAdapterImpl extends DefaultFrameworkAdapter {
path: src/main/java/org/pac4j/framework/adapter/FrameworkAdapterImpl.java
user: login: leleuj
body: Please add javadocs with `@since` and `@author` for any new class.
created_at: 2025-04-02T05:32:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,7 @@
+package org.pac4j.undertow.context;
+
+import io.undertow.server.HttpServerExchange;
+import org.pac4j.core.context.FrameworkParameters;
+
+public record UndertowParameters(HttpServerExchange exchange) implements FrameworkParameters {
path: src/main/java/org/pac4j/undertow/context/UndertowParameters.java
user: login: leleuj
body: Javadocs
created_at: 2025-04-02T05:32:43Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,31 @@
+package org.pac4j.undertow.context;
+
+import org.pac4j.core.context.FrameworkParameters;
+import org.pac4j.core.context.session.SessionStore;
+import org.pac4j.core.context.session.SessionStoreFactory;
+import org.pac4j.core.exception.TechnicalException;
+
+/**
path: src/main/java/org/pac4j/undertow/context/UndertowSessionStoreFactory.java
user: login: leleuj
body: Bad javadoc, replace
created_at: 2025-04-02T05:32:56Z
author_association: MEMBER
diff_hunk: @@ -73,18 +65,24 @@ public static HttpHandler build(final HttpHandler toWrap, Config config, final S
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final SecurityLogic bestLogic = FindBest.securityLogic(securityLogic, config, DefaultSecurityLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, this.config, (ctx, store, profiles, parameters) -> {
-
-            toWrap.handleRequest(exchange);
-            return null;
-
-        }, bestAdapter, this.clients, this.authorizers, this.matchers);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        // adapted from https://github.com/pac4j/javalin-pac4j/blob/6.0.x/src/main/java/org/pac4j/javalin/SecurityHandler.java#L47-L60
+        var result = config.getSecurityLogic().perform(
+                this.config,
+                (ctx, store, profiles) -> AUTH_GRANTED,
+                this.clients,
+                this.authorizers,
+                this.matchers,
+                new UndertowParameters(exchange)
+        );
+        // TODO else reject with 401 or?
+        if (result == AUTH_GRANTED) {
+            this.toWrap.handleRequest(exchange);
+        }
+        /*if (result != AUTH_GRANTED) {
path: src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
user: login: leleuj
body: Please remove this comment
created_at: 2025-04-02T05:54:53Z
author_association: MEMBER
diff_hunk: @@ -73,18 +65,24 @@ public static HttpHandler build(final HttpHandler toWrap, Config config, final S
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final SecurityLogic bestLogic = FindBest.securityLogic(securityLogic, config, DefaultSecurityLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, this.config, (ctx, store, profiles, parameters) -> {
-
-            toWrap.handleRequest(exchange);
-            return null;
-
-        }, bestAdapter, this.clients, this.authorizers, this.matchers);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        // adapted from https://github.com/pac4j/javalin-pac4j/blob/6.0.x/src/main/java/org/pac4j/javalin/SecurityHandler.java#L47-L60
path: src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
user: login: leleuj
body: Remove this comment as well
created_at: 2025-04-02T05:56:34Z
author_association: MEMBER
diff_hunk: @@ -73,18 +65,24 @@ public static HttpHandler build(final HttpHandler toWrap, Config config, final S
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final SecurityLogic bestLogic = FindBest.securityLogic(securityLogic, config, DefaultSecurityLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, this.config, (ctx, store, profiles, parameters) -> {
-
-            toWrap.handleRequest(exchange);
-            return null;
-
-        }, bestAdapter, this.clients, this.authorizers, this.matchers);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        // adapted from https://github.com/pac4j/javalin-pac4j/blob/6.0.x/src/main/java/org/pac4j/javalin/SecurityHandler.java#L47-L60
+        var result = config.getSecurityLogic().perform(
+                this.config,
+                (ctx, store, profiles) -> AUTH_GRANTED,
+                this.clients,
+                this.authorizers,
+                this.matchers,
+                new UndertowParameters(exchange)
+        );
+        // TODO else reject with 401 or?
path: src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
user: login: leleuj
body: And this one too. If you look at the code of the `DefaultSecurityLogic`, you see that a 401 is returned if the user is not authenticated...
created_at: 2025-04-02T05:57:22Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,24 @@
+package org.pac4j.framework.adapter;
+
+import org.pac4j.core.adapter.DefaultFrameworkAdapter;
+import org.pac4j.core.config.Config;
+import org.pac4j.undertow.context.UndertowContextFactory;
+import org.pac4j.undertow.context.UndertowSessionStoreFactory;
+import org.pac4j.undertow.http.UndertowHttpActionAdapter;
+
+// found on classpath by pac4j
+public class FrameworkAdapterImpl extends DefaultFrameworkAdapter {
path: src/main/java/org/pac4j/framework/adapter/FrameworkAdapterImpl.java
user: login: sake92
body: Added.
created_at: 2025-04-10T11:08:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -73,18 +65,24 @@ public static HttpHandler build(final HttpHandler toWrap, Config config, final S
 
     @Override
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
-
-        final SessionStore bestSessionStore = FindBest.sessionStore(null, config, new UndertowSessionStore(exchange));
-        final HttpActionAdapter bestAdapter = FindBest.httpActionAdapter(null, config, UndertowHttpActionAdapter.INSTANCE);
-        final SecurityLogic bestLogic = FindBest.securityLogic(securityLogic, config, DefaultSecurityLogic.INSTANCE);
-
-        final WebContext context = FindBest.webContextFactory(null, config, UndertowContextFactory.INSTANCE).newContext(exchange);
-        bestLogic.perform(context, bestSessionStore, this.config, (ctx, store, profiles, parameters) -> {
-
-            toWrap.handleRequest(exchange);
-            return null;
-
-        }, bestAdapter, this.clients, this.authorizers, this.matchers);
+        FrameworkAdapter.INSTANCE.applyDefaultSettingsIfUndefined(config);
+        // adapted from https://github.com/pac4j/javalin-pac4j/blob/6.0.x/src/main/java/org/pac4j/javalin/SecurityHandler.java#L47-L60
+        var result = config.getSecurityLogic().perform(
+                this.config,
+                (ctx, store, profiles) -> AUTH_GRANTED,
+                this.clients,
+                this.authorizers,
+                this.matchers,
+                new UndertowParameters(exchange)
+        );
+        // TODO else reject with 401 or?
path: src/main/java/org/pac4j/undertow/handler/SecurityHandler.java
user: login: sake92
body: Ok, I didnt really understand how it works.  
So that callback is triggered on successful auth, if I understood correctly..  
created_at: 2025-04-10T11:09:34Z
author_association: CONTRIBUTOR

PR comments:
user: login: leleuj
created_at: 2025-04-02T05:59:09Z
body: Please fix the `ci.yml` file to release 17 for the build to start.

Overall, LGTM. A few comments to address. Can you update at best the undertow-pac4j-demo as well? Thanks
author_association: MEMBER
user: login: sake92
created_at: 2025-04-04T17:25:27Z
body: Updated the CI now.  
Which comments I need to address?
I will update the demo after we get a new release, no problem.
author_association: CONTRIBUTOR
user: login: sake92
created_at: 2025-04-10T11:10:41Z
body: @leleuj I've addressed your comments, please have a look again.  
I've tested this locally with a FormClient, works fine.

I'll try to add some real tests in future PRs.
author_association: CONTRIBUTOR
user: login: leleuj
created_at: 2025-04-10T13:20:10Z
body: I just merged your PR. Thanks for the contribution.
author_association: MEMBER