This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 7f59ce77f4ae1c8d4912af7d60b9c31db1290821 Author: Mark Thomas <[email protected]> AuthorDate: Fri Jan 9 16:39:56 2026 +0000 Add ssoReauthenticationMode attribute to built-in Authenticators --- .../catalina/authenticator/AuthenticatorBase.java | 85 ++++++++++++---- .../authenticator/DigestAuthenticator.java | 2 - .../catalina/authenticator/SSLAuthenticator.java | 2 - .../catalina/authenticator/SingleSignOn.java | 9 ++ .../authenticator/SpnegoAuthenticator.java | 2 - webapps/docs/changelog.xml | 5 + webapps/docs/config/valve.xml | 110 +++++++++++++++++++++ 7 files changed, 190 insertions(+), 25 deletions(-) diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java index de9ecc6c26..dd0a905ef0 100644 --- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java +++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java @@ -219,6 +219,8 @@ public abstract class AuthenticatorBase extends ValveBase implements Authenticat */ protected SingleSignOn sso = null; + private SsoReauthenticationMode ssoReauthenticationMode = SsoReauthenticationMode.DEFAULT; + private AllowCorsPreflight allowCorsPreflight = AllowCorsPreflight.NEVER; private volatile String jaspicAppContextID = null; @@ -228,6 +230,15 @@ public abstract class AuthenticatorBase extends ValveBase implements Authenticat // ------------------------------------------------------------- Properties + public String getSsoReauthenticationMode() { + return ssoReauthenticationMode.name().toLowerCase(Locale.ENGLISH); + } + + public void setSsoReauthenticationMode(String ssoReauthenticationMode) { + this.ssoReauthenticationMode = + SsoReauthenticationMode.valueOf(ssoReauthenticationMode.trim().toUpperCase(Locale.ENGLISH)); + } + public String getAllowCorsPreflight() { return allowCorsPreflight.name().toLowerCase(Locale.ENGLISH); } @@ -898,38 +909,66 @@ public abstract class AuthenticatorBase extends ValveBase implements Authenticat * Which cached authentication methods are used depends on the configuration of the SSO Valve and/or the * Authenticator. * - * If the SSO Valve is configured to require re-authentication, any cached Principal will not be used. + * If the SSO Valve is configured to require re-authentication, any cached Principal will not be used unless the + * Authenticator is explicitly configured (via ssoReauthenticationMode) to use it. * * If the SSO Valve is configured to require re-authentication, whether the cached user name and password can be - * used will be determined by the calling Authenticator type. + * used will be determined by the calling Authenticator type unless the Authenticator's ssoReauthenticationMode + * is explicitly configured. */ - // Has the user already been authenticated? - Principal principal = request.getUserPrincipal(); + // Determine which - if any - checks for cached authentication will be made. + boolean checkPrincipal = false; + boolean checkPassword = false; + + // Will be null if SSO is not configured or there is no current SSO session String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (principal != null) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("authenticator.check.found", principal.getName())); - } - // Associate the session with any existing SSO session. Even if - // useSSO is false, this will ensure coordinated session - // invalidation at log out. + + if (sso == null) { + // There is no SSO - check in case some other component has set the Principal + checkPrincipal = true; + } else if (ssoReauthenticationMode == SsoReauthenticationMode.DEFAULT && !sso.getRequireReauthentication() || + ssoReauthenticationMode == SsoReauthenticationMode.PRINCIPAL) { + checkPrincipal = true; + // If checkPrincipal is enabled then checkPassword is enabled if there is an SSO session if (ssoId != null) { - associate(ssoId, request.getSessionInternal(true)); + checkPassword = true; + } + } else if (ssoId != null && (ssoReauthenticationMode == SsoReauthenticationMode.PASSWORD || + sso.getRequireReauthentication() && useSsoCachedUserAndPassword)) { + checkPassword = true; + } + + // Check for a cached Principal. Most likely from SSO but could be another component. + if (checkPrincipal) { + if (ssoId != null && sso.getRequireReauthentication()) { + // There is a valid SSO session but SSO Valve won't have cached the Principal. + sso.populateRequestFromSsoEntry(request, ssoId); + } + + // Has the user already been authenticated? + Principal principal = request.getUserPrincipal(); + if (principal != null) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("authenticator.check.found", principal.getName())); + } + // Associate the session with any existing SSO session. Even if + // useSSO is false, this will ensure coordinated session + // invalidation at log out. + if (ssoId != null) { + associate(ssoId, request.getSessionInternal(true)); + } + return true; } - return true; } - // Is there an SSO session against which we can try to reauthenticate? - if (useSsoCachedUserAndPassword && ssoId != null) { + // Check for a user and password cached by SSO + if (checkPassword) { if (log.isDebugEnabled()) { log.debug(sm.getString("authenticator.check.sso", ssoId)); } /* - * Try to reauthenticate using data cached by SSO. If this fails, either the original SSO logon was of - * DIGEST or SSL (which we can't reauthenticate ourselves because there is no cached username and password), - * or the realm denied the user's reauthentication for some reason. In either case we have to prompt the - * user for a logon + * Try to reauthenticate using data cached by SSO. If this fails we have to prompt the user for credentials. */ if (reauthenticateFromSSO(ssoId, request)) { return true; @@ -1312,4 +1351,12 @@ public abstract class AuthenticatorBase extends ValveBase implements Authenticat FILTER, ALWAYS } + + + protected enum SsoReauthenticationMode { + DEFAULT, + PRINCIPAL, + PASSWORD, + FULL + } } diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java b/java/org/apache/catalina/authenticator/DigestAuthenticator.java index cfb79f0856..d36a8af856 100644 --- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java +++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java @@ -273,8 +273,6 @@ public class DigestAuthenticator extends AuthenticatorBase { * authentication. Reauthenticating with the cached user name and password should be sufficient for DIGEST in * that scenario. However, the original behaviour to reauthenticate has been retained in case of any (very * unlikely) backwards compatibility issues. - * - * TODO: Make the reauthentication behaviour configurable per authenticator. */ if (checkForCachedAuthentication(request, response, false)) { return true; diff --git a/java/org/apache/catalina/authenticator/SSLAuthenticator.java b/java/org/apache/catalina/authenticator/SSLAuthenticator.java index 2883f35410..fb4518f862 100644 --- a/java/org/apache/catalina/authenticator/SSLAuthenticator.java +++ b/java/org/apache/catalina/authenticator/SSLAuthenticator.java @@ -69,8 +69,6 @@ public class SSLAuthenticator extends AuthenticatorBase { * since it will not make any TLS information (client certificate etc) available that a web application may * depend on. Therefore, the reauthentication behaviour for CLIENT-CERT is to perform a normal CLIENT-CERT * authentication. - * - * TODO: Make the reauthentication behaviour configurable per authenticator. */ if (checkForCachedAuthentication(request, response, false)) { return true; diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java index 30f98f7daf..1ae7f90f62 100644 --- a/java/org/apache/catalina/authenticator/SingleSignOn.java +++ b/java/org/apache/catalina/authenticator/SingleSignOn.java @@ -506,6 +506,15 @@ public class SingleSignOn extends ValveBase { } + protected void populateRequestFromSsoEntry(Request request, String ssoId) { + SingleSignOnEntry entry = cache.get(ssoId); + if (entry != null) { + request.setAuthType(entry.getAuthType()); + request.setUserPrincipal(entry.getPrincipal()); + } + } + + /** * Register the specified Principal as being associated with the specified value for the single sign on identifier. * diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java index 018d59b15d..17a376b017 100644 --- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java +++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java @@ -143,8 +143,6 @@ public class SpnegoAuthenticator extends AuthenticatorBase { * Reauthenticating with the cached user name and password may not be sufficient for SPNEGO since it will not * make the delegated credentials available that a web application may depend on. Therefore, the * reauthentication behaviour for SPNEGO is to perform a normal SPNEGO authentication. - * - * TODO: Make the reauthentication behaviour configurable per authenticator. */ if (checkForCachedAuthentication(request, response, false)) { return true; diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index e1ec12b582..8aa824209b 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -211,6 +211,11 @@ recommended versions for Tomcat Native 1.x to 1.3.4. Update the minimum and recommended versions for Tomcat Native 2.x to 2.0.12. (markt) </update> + <add> + Add a new <code>ssoReauthenticationMode</code> to the Tomcat provided + Authenticators that provides a per Authenticator override of the SSO + Valve <code>requireReauthentication</code> attribute. (markt) + </add> </changelog> </subsection> <subsection name="Coyote"> diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml index 7f0ade45c6..07947471f3 100644 --- a/webapps/docs/config/valve.xml +++ b/webapps/docs/config/valve.xml @@ -1427,6 +1427,28 @@ If not specified, the default value is <code>false</code>.</p> </attribute> + <attribute name="ssoReauthenticationMode" required="false"> + <p>Provides a per Authenicator override of the SSO Valve attribute + <code>requireReauthentication</code>. It has the following options:</p> + <dl> + <dt>default</dt> + <dd>Reauthentication behaviour depends on the SSO Valve configuration + and the authentictaor type.</dd> + <dt>principal</dt> + <dd>The authenticator will look first for a cached Principal. If none + is found, the authenticator will look for a cached user name and + password and attempt to use them to reauthenticate. If that fails, + a normal authentication will be performed.</dd> + <dt>password</dt> + <dd>The authenticator will look for a cached user name and password + and attempt to use them to reauthenticate. If that fails, a normal + authentication will be performed.</dd> + <dt>full</dt> + <dd>Only a normal authentication will be performed. The SSO Valve is + effectively ignored.</dd> + </dl> + </attribute> + </attributes> </subsection> @@ -1609,6 +1631,28 @@ If not specified, the default value is <code>false</code>.</p> </attribute> + <attribute name="ssoReauthenticationMode" required="false"> + <p>Provides a per Authenicator override of the SSO Valve attribute + <code>requireReauthentication</code>. It has the following options:</p> + <dl> + <dt>default</dt> + <dd>Reauthentication behaviour depends on the SSO Valve configuration + and the authentictaor type.</dd> + <dt>principal</dt> + <dd>The authenticator will look first for a cached Principal. If none + is found, the authenticator will look for a cached user name and + password and attempt to use them to reauthenticate. If that fails, + a normal authentication will be performed.</dd> + <dt>password</dt> + <dd>The authenticator will look for a cached user name and password + and attempt to use them to reauthenticate. If that fails, a normal + authentication will be performed.</dd> + <dt>full</dt> + <dd>Only a normal authentication will be performed. The SSO Valve is + effectively ignored.</dd> + </dl> + </attribute> + <attribute name="validateUri" required="false"> <p>Should the URI be validated as required by RFC2617? If not specified, the default value of <code>true</code> will be used. This should @@ -1766,6 +1810,28 @@ If not specified, the default value is <code>false</code>.</p> </attribute> + <attribute name="ssoReauthenticationMode" required="false"> + <p>Provides a per Authenicator override of the SSO Valve attribute + <code>requireReauthentication</code>. It has the following options:</p> + <dl> + <dt>default</dt> + <dd>Reauthentication behaviour depends on the SSO Valve configuration + and the authentictaor type.</dd> + <dt>principal</dt> + <dd>The authenticator will look first for a cached Principal. If none + is found, the authenticator will look for a cached user name and + password and attempt to use them to reauthenticate. If that fails, + a normal authentication will be performed.</dd> + <dt>password</dt> + <dd>The authenticator will look for a cached user name and password + and attempt to use them to reauthenticate. If that fails, a normal + authentication will be performed.</dd> + <dt>full</dt> + <dd>Only a normal authentication will be performed. The SSO Valve is + effectively ignored.</dd> + </dl> + </attribute> + </attributes> </subsection> @@ -1882,6 +1948,28 @@ specified, the platform default provider will be used.</p> </attribute> + <attribute name="ssoReauthenticationMode" required="false"> + <p>Provides a per Authenicator override of the SSO Valve attribute + <code>requireReauthentication</code>. It has the following options:</p> + <dl> + <dt>default</dt> + <dd>Reauthentication behaviour depends on the SSO Valve configuration + and the authentictaor type.</dd> + <dt>principal</dt> + <dd>The authenticator will look first for a cached Principal. If none + is found, the authenticator will look for a cached user name and + password and attempt to use them to reauthenticate. If that fails, + a normal authentication will be performed.</dd> + <dt>password</dt> + <dd>The authenticator will look for a cached user name and password + and attempt to use them to reauthenticate. If that fails, a normal + authentication will be performed.</dd> + <dt>full</dt> + <dd>Only a normal authentication will be performed. The SSO Valve is + effectively ignored.</dd> + </dl> + </attribute> + </attributes> </subsection> @@ -2060,6 +2148,28 @@ If not specified, the default value is <code>false</code>.</p> </attribute> + <attribute name="ssoReauthenticationMode" required="false"> + <p>Provides a per Authenicator override of the SSO Valve attribute + <code>requireReauthentication</code>. It has the following options:</p> + <dl> + <dt>default</dt> + <dd>Reauthentication behaviour depends on the SSO Valve configuration + and the authentictaor type.</dd> + <dt>principal</dt> + <dd>The authenticator will look first for a cached Principal. If none + is found, the authenticator will look for a cached user name and + password and attempt to use them to reauthenticate. If that fails, + a normal authentication will be performed.</dd> + <dt>password</dt> + <dd>The authenticator will look for a cached user name and password + and attempt to use them to reauthenticate. If that fails, a normal + authentication will be performed.</dd> + <dt>full</dt> + <dd>Only a normal authentication will be performed. The SSO Valve is + effectively ignored.</dd> + </dl> + </attribute> + <attribute name="storeDelegatedCredential" required="false"> <p>Controls if the user' delegated credential will be stored in the user Principal. If available, the delegated credential will be --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
