You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/09/30 08:50:32 UTC

(tomcat) branch 9.0.x updated (fee51e710c -> 99f7d442ac)

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

rmaucher pushed a change to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


    from fee51e710c Explicitly state virtual host and SNI matching are separate
     new f22f92c7a9 Stop SSO session listeners accumulating on sessions by re-keying the SSO entry on session ID change without registering an additional listener
     new f155614b3c Guard SpnegoAuthenticator against missing JAAS/Kerberos config files, handle the unchecked SecurityException they would cause and log GSS ticket failures with the correct message
     new 75a18cba77 Load statically configured ServerAuthModule classes via the thread context (web application) class loader first, matching the pattern used for AuthConfigProvider classes, so modules packaged in WEB-INF/lib are found
     new c2a0f093e5 Document that a failure to create a persistent JASPIC provider registration is deliberately fatal rather than silently skipped, since skipping an authentication provider would fail open
     new 1ce6c6159d Update the JASPIC client Subject only when password validation succeeded (or was not requested), failing closed rather than adding a principal derived from untrusted caller-supplied data when validation failed
     new 99f7d442ac Store the JASPIC isMandatory MessageInfo property as a Boolean as the specification requires rather than a String, and throw IllegalArgumentException rather than NullPointerException when null is passed to the MessageInfoImpl request/response message setters

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../catalina/authenticator/SingleSignOn.java       |  9 +++++---
 .../catalina/authenticator/SingleSignOnEntry.java  | 14 ++++++++++++
 .../authenticator/SpnegoAuthenticator.java         | 26 +++++++++++++++++-----
 .../jaspic/AuthConfigFactoryImpl.java              |  7 ++++++
 .../authenticator/jaspic/CallbackHandlerImpl.java  | 14 ++++++++++--
 .../authenticator/jaspic/MessageInfoImpl.java      | 10 ++++-----
 .../jaspic/SimpleServerAuthConfig.java             | 11 ++++++++-
 7 files changed, 74 insertions(+), 17 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 01/06: Stop SSO session listeners accumulating on sessions by re-keying the SSO entry on session ID change without registering an additional listener

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit f22f92c7a9a3472d8a7581ae98482fd44b9aace9
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:11:25 2026 +0200

    Stop SSO session listeners accumulating on sessions by re-keying the SSO entry on session ID change without registering an additional listener
---
 java/org/apache/catalina/authenticator/SingleSignOn.java   |  9 ++++++---
 .../apache/catalina/authenticator/SingleSignOnEntry.java   | 14 ++++++++++++++
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java
index fa683c154d..7dd0b6b14b 100644
--- a/java/org/apache/catalina/authenticator/SingleSignOn.java
+++ b/java/org/apache/catalina/authenticator/SingleSignOn.java
@@ -683,10 +683,13 @@ public class SingleSignOn extends ValveBase {
         }
 
         /*
-         * Associate the new sessionId with this SingleSignOnEntry. A SessionListener will be registered for the new
-         * sessionID. If not, then we would not notice any subsequent Session.SESSION_DESTROYED_EVENT for the session.
+         * Associate the new sessionId with this SingleSignOnEntry. No additional SessionListener is registered. The
+         * SessionListener is registered against the Session object, not the session ID, so the listener that
+         * triggered this method remains registered and will notice any subsequent
+         * Session.SESSION_CHANGED_ID_EVENT or Session.SESSION_DESTROYED_EVENT for the session. Registering a new
+         * listener on every ID change would leave the previous listener(s) orphaned on the session.
          */
-        entry.addSession(this, ssoId, session);
+        entry.reassociateSession(session);
 
         /*
          * Remove the obsolete sessionId from the SingleSignOnEntry. The sessionId part of the SingleSignOnSessionKey is
diff --git a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
index 09d6a6a3c1..490508452c 100644
--- a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
+++ b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
@@ -105,6 +105,20 @@ public class SingleSignOnEntry implements Serializable {
         }
     }
 
+
+    /**
+     * Re-associates a <code>Session</code> with this SSO after its ID has changed, without registering an additional
+     * session listener. The listener is associated with the <code>Session</code> object rather than with the session
+     * ID, so the listener registered when the session was first associated with this SSO continues to receive events
+     * for the session. Registering another listener on each ID change would cause unbounded listener accumulation.
+     *
+     * @param session The <code>Session</code> being re-associated with this SSO.
+     */
+    public void reassociateSession(Session session) {
+        SingleSignOnSessionKey key = new SingleSignOnSessionKey(session);
+        sessionKeys.putIfAbsent(key, key);
+    }
+
     /**
      * Removes the given <code>Session</code> from the list of those associated with this SSO.
      *


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 04/06: Document that a failure to create a persistent JASPIC provider registration is deliberately fatal rather than silently skipped, since skipping an authentication provider would fail open

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c2a0f093e5fbdfb8c68796cc3262ba2887914df3
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:22:41 2026 +0200

    Document that a failure to create a persistent JASPIC provider registration is deliberately fatal rather than silently skipped, since skipping an authentication provider would fail open
---
 .../catalina/authenticator/jaspic/AuthConfigFactoryImpl.java       | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java b/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
index d82e55e808..aff2e72874 100644
--- a/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
+++ b/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
@@ -388,6 +388,13 @@ public class AuthConfigFactoryImpl extends AuthConfigFactory {
                 }
                 Providers providers = PersistentProviderRegistrations.loadProviders(CONFIG_FILE);
                 for (Provider provider : providers.getProviders()) {
+                    /*
+                     * If a configured provider cannot be created, the resulting exception is allowed to propagate to
+                     * the caller. This is deliberate: JASPIC is an authentication mechanism so, for security, a
+                     * registration that cannot be honoured must be fatal rather than silently skipped, since silently
+                     * skipping it could allow requests to be processed without the expected authentication provider.
+                     * The admin must fix or remove the offending entry in jaspic-providers.xml.
+                     */
                     doRegisterConfigProvider(provider.getClassName(), provider.getProperties(), provider.getLayer(),
                             provider.getAppContext(), provider.getDescription(), wrappersToNotify);
                 }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 06/06: Store the JASPIC isMandatory MessageInfo property as a Boolean as the specification requires rather than a String, and throw IllegalArgumentException rather than NullPointerException when null is passed to the MessageInfoImpl request/response message setters

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 99f7d442acadf907d36d4905f190df664219b4d8
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:26:09 2026 +0200

    Store the JASPIC isMandatory MessageInfo property as a Boolean as the specification requires rather than a String, and throw IllegalArgumentException rather than NullPointerException when null is passed to the MessageInfoImpl request/response message setters
---
 .../apache/catalina/authenticator/jaspic/MessageInfoImpl.java  | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java b/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java
index 8c49352842..5fda2d9d15 100644
--- a/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java
+++ b/java/org/apache/catalina/authenticator/jaspic/MessageInfoImpl.java
@@ -59,7 +59,7 @@ public class MessageInfoImpl implements MessageInfo {
     public MessageInfoImpl(HttpServletRequest request, HttpServletResponse response, boolean authMandatory) {
         this.request = request;
         this.response = response;
-        map.put(IS_MANDATORY, Boolean.toString(authMandatory));
+        map.put(IS_MANDATORY, Boolean.valueOf(authMandatory));
     }
 
     @Override
@@ -82,8 +82,8 @@ public class MessageInfoImpl implements MessageInfo {
     @Override
     public void setRequestMessage(Object request) {
         if (!(request instanceof HttpServletRequest)) {
-            throw new IllegalArgumentException(
-                    sm.getString("authenticator.jaspic.badRequestType", request.getClass().getName()));
+            String typeName = request == null ? "null" : request.getClass().getName();
+            throw new IllegalArgumentException(sm.getString("authenticator.jaspic.badRequestType", typeName));
         }
         this.request = (HttpServletRequest) request;
     }
@@ -91,8 +91,8 @@ public class MessageInfoImpl implements MessageInfo {
     @Override
     public void setResponseMessage(Object response) {
         if (!(response instanceof HttpServletResponse)) {
-            throw new IllegalArgumentException(
-                    sm.getString("authenticator.jaspic.badResponseType", response.getClass().getName()));
+            String typeName = response == null ? "null" : response.getClass().getName();
+            throw new IllegalArgumentException(sm.getString("authenticator.jaspic.badResponseType", typeName));
         }
         this.response = (HttpServletResponse) response;
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 03/06: Load statically configured ServerAuthModule classes via the thread context (web application) class loader first, matching the pattern used for AuthConfigProvider classes, so modules packaged in WEB-INF/lib are found

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 75a18cba77ef84457a09dc9265b61af624b813d1
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:20:47 2026 +0200

    Load statically configured ServerAuthModule classes via the thread
    context (web application) class loader first, matching the pattern used
    for AuthConfigProvider classes, so modules packaged in WEB-INF/lib are
    found
---
 .../catalina/authenticator/jaspic/SimpleServerAuthConfig.java | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthConfig.java b/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthConfig.java
index c6fd8f4a1d..28d165e5fa 100644
--- a/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthConfig.java
+++ b/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthConfig.java
@@ -141,7 +141,16 @@ public class SimpleServerAuthConfig implements ServerAuthConfig {
                     String moduleClassName = mergedProperties.get(key);
                     while (moduleClassName != null) {
                         try {
-                            Class<?> clazz = Class.forName(moduleClassName);
+                            Class<?> clazz = null;
+                            try {
+                                clazz = Class.forName((String) moduleClassName, true,
+                                        Thread.currentThread().getContextClassLoader());
+                            } catch (ClassNotFoundException ignore) {
+                                // Ignore so the re-try below can proceed
+                            }
+                            if (clazz == null) {
+                                clazz = Class.forName((String) moduleClassName);
+                            }
                             ServerAuthModule module = (ServerAuthModule) clazz.getConstructor().newInstance();
                             module.initialize(null, null, handler, mergedProperties);
                             modules.add(module);


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 02/06: Guard SpnegoAuthenticator against missing JAAS/Kerberos config files, handle the unchecked SecurityException they would cause and log GSS ticket failures with the correct message

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit f155614b3c9dbad7b8b131a41c917437fe5f1100
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:14:02 2026 +0200

    Guard SpnegoAuthenticator against missing JAAS/Kerberos config files, handle the unchecked SecurityException they would cause and log GSS ticket failures with the correct message
---
 .../authenticator/SpnegoAuthenticator.java         | 26 +++++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
index bb36b921ff..5ac5822ff1 100644
--- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
@@ -166,17 +166,25 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
         // Kerberos configuration file location
         String krb5Conf = System.getProperty(Constants.KRB5_CONF_PROPERTY);
         if (krb5Conf == null) {
-            // System property not set, use the Tomcat default
+            // System property not set, use the Tomcat default if the file exists. If it does not, leave the JVM
+            // defaults in place. Pointing the property at a file that does not exist breaks Kerberos/JAAS for the
+            // whole JVM.
             File krb5ConfFile = new File(container.getCatalinaBase(), Constants.DEFAULT_KRB5_CONF);
-            System.setProperty(Constants.KRB5_CONF_PROPERTY, krb5ConfFile.getAbsolutePath());
+            if (krb5ConfFile.isFile()) {
+                System.setProperty(Constants.KRB5_CONF_PROPERTY, krb5ConfFile.getAbsolutePath());
+            }
         }
 
         // JAAS configuration file location
         String jaasConf = System.getProperty(Constants.JAAS_CONF_PROPERTY);
         if (jaasConf == null) {
-            // System property not set, use the Tomcat default
+            // System property not set, use the Tomcat default if the file exists. If it does not, leave the JVM
+            // defaults in place. Pointing the property at a file that does not exist causes the LoginContext
+            // constructor to throw an unchecked SecurityException for the whole JVM.
             File jaasConfFile = new File(container.getCatalinaBase(), Constants.DEFAULT_JAAS_CONF);
-            System.setProperty(Constants.JAAS_CONF_PROPERTY, jaasConfFile.getAbsolutePath());
+            if (jaasConfFile.isFile()) {
+                System.setProperty(Constants.JAAS_CONF_PROPERTY, jaasConfFile.getAbsolutePath());
+            }
         }
     }
 
@@ -255,7 +263,10 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
             try {
                 lc = new LoginContext(getLoginConfigName());
                 lc.login();
-            } catch (LoginException e) {
+            } catch (LoginException | SecurityException e) {
+                // SecurityException may be thrown (wrapping an IOException) by the LoginContext constructor if the
+                // JAAS configuration file referenced by the java.security.auth.login.config system property does not
+                // exist.
                 log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e);
                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                 return false;
@@ -304,10 +315,13 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
             response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
             return false;
         } catch (CompletionException e) {
+            // Subject.callAs() wraps any exception thrown by the action in a CompletionException, so GSS failures
+            // (e.g. an invalid or expired client ticket) arrive here rather than in the GSSException catch block
+            // above.
             Throwable cause = e.getCause();
             if (cause instanceof GSSException) {
                 if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("spnegoAuthenticator.serviceLoginFail"), e);
+                    log.debug(sm.getString("spnegoAuthenticator.ticketValidateFail"), e);
                 }
             } else {
                 log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e);


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 05/06: Update the JASPIC client Subject only when password validation succeeded (or was not requested), failing closed rather than adding a principal derived from untrusted caller-supplied data when validation failed

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1ce6c6159d80bc127ba2ada6bfc97094690c398e
Author: opencode <re...@apache.org>
AuthorDate: Wed Sep 30 10:24:46 2026 +0200

    Update the JASPIC client Subject only when password validation succeeded
    (or was not requested), failing closed rather than adding a principal
    derived from untrusted caller-supplied data when validation failed
---
 .../catalina/authenticator/jaspic/CallbackHandlerImpl.java | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java b/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
index fb638e1ea6..b5ea0f476f 100644
--- a/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
+++ b/java/org/apache/catalina/authenticator/jaspic/CallbackHandlerImpl.java
@@ -63,6 +63,7 @@ public class CallbackHandlerImpl implements CallbackHandler, Contained {
         Principal principal = null;
         Subject subject = null;
         String[] groups = null;
+        boolean passwordValidationFailed = false;
 
         if (callbacks != null) {
             /*
@@ -84,14 +85,19 @@ public class CallbackHandlerImpl implements CallbackHandler, Contained {
                 } else if (callback instanceof PasswordValidationCallback) {
                     if (container == null) {
                         log.warn(sm.getString("callbackHandlerImpl.containerMissing", callback.getClass().getName()));
+                        passwordValidationFailed = true;
                     } else if (container.getRealm() == null) {
                         log.warn(sm.getString("callbackHandlerImpl.realmMissing", callback.getClass().getName(),
                                 container.getName()));
+                        passwordValidationFailed = true;
                     } else {
                         PasswordValidationCallback pvc = (PasswordValidationCallback) callback;
                         principal =
                                 container.getRealm().authenticate(pvc.getUsername(), String.valueOf(pvc.getPassword()));
                         pvc.setResult(principal != null);
+                        if (principal == null) {
+                            passwordValidationFailed = true;
+                        }
                         subject = pvc.getSubject();
                     }
                 } else {
@@ -99,8 +105,12 @@ public class CallbackHandlerImpl implements CallbackHandler, Contained {
                 }
             }
 
-            // If subject is null, there is nothing to do
-            if (subject != null) {
+            /*
+             * If subject is null, there is nothing to do. If password validation was requested and failed, do not
+             * update the subject. The Jakarta Authentication specification requires the runtime to update the subject
+             * only if authentication succeeds and, for security, the handler must fail closed.
+             */
+            if (subject != null && !passwordValidationFailed) {
 
                 // Need a name to create a Principal
                 if (name == null && principal != null) {


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org