This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new d40cf27 Refactored check for preemptive authentication d40cf27 is described below commit d40cf2715094172a489591fb73176ef98e791229 Author: Robert Rodewald <r.rodew...@airitsystems.de> AuthorDate: Tue Aug 10 19:11:24 2021 +0200 Refactored check for preemptive authentication - new protected method isPreemptiveAuthPossible() in AuthenticatorBase which is overridden in some authenticators - moved getRequestCertificates() from AuthenticatorBase to SSLAuthenticator - Added more specific check for value of header "authorization" # Conflicts: # webapps/docs/changelog.xml # Conflicts: # java/org/apache/catalina/authenticator/AuthenticatorBase.java --- .../catalina/authenticator/AuthenticatorBase.java | 56 +++++++--------------- .../catalina/authenticator/BasicAuthenticator.java | 8 ++++ .../authenticator/DigestAuthenticator.java | 8 ++++ .../catalina/authenticator/SSLAuthenticator.java | 39 +++++++++++++++ .../authenticator/SpnegoAuthenticator.java | 7 +++ webapps/docs/changelog.xml | 6 +++ 6 files changed, 85 insertions(+), 39 deletions(-) diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java index c46b0ba..ad67a4a 100644 --- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java +++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java @@ -18,7 +18,6 @@ package org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; -import java.security.cert.X509Certificate; import java.util.Locale; import java.util.Map; import java.util.Optional; @@ -61,7 +60,6 @@ import org.apache.catalina.util.SessionIdGeneratorBase; import org.apache.catalina.util.StandardSessionIdGenerator; import org.apache.catalina.valves.RemoteIpValve; import org.apache.catalina.valves.ValveBase; -import org.apache.coyote.ActionCode; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; @@ -596,15 +594,9 @@ public abstract class AuthenticatorBase extends ValveBase authRequired = true; } - if (!authRequired && context.getPreemptiveAuthentication()) { - authRequired = - request.getCoyoteRequest().getMimeHeaders().getValue("authorization") != null; - } - if (!authRequired && context.getPreemptiveAuthentication() && - HttpServletRequest.CLIENT_CERT_AUTH.equals(getAuthMethod())) { - X509Certificate[] certs = getRequestCertificates(request); - authRequired = certs != null && certs.length > 0; + isPreemptiveAuthPossible(request)) { + authRequired = true; } JaspicState jaspicState = null; @@ -862,35 +854,6 @@ public abstract class AuthenticatorBase extends ValveBase /** - * Look for the X509 certificate chain in the Request under the key - * <code>javax.servlet.request.X509Certificate</code>. If not found, trigger - * extracting the certificate chain from the Coyote request. - * - * @param request - * Request to be processed - * - * @return The X509 certificate chain if found, <code>null</code> otherwise. - */ - protected X509Certificate[] getRequestCertificates(final Request request) - throws IllegalStateException { - - X509Certificate certs[] = - (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); - - if ((certs == null) || (certs.length < 1)) { - try { - request.getCoyoteRequest().action(ActionCode.REQ_SSL_CERTIFICATE, null); - certs = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); - } catch (IllegalStateException ise) { - // Request body was too large for save buffer - // Return null which will trigger an auth failure - } - } - - return certs; - } - - /** * Associate the specified single sign on identifier with the specified * Session. * @@ -1386,6 +1349,7 @@ public abstract class AuthenticatorBase extends ValveBase super.startInternal(); } + /** * Stop this component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. @@ -1403,6 +1367,20 @@ public abstract class AuthenticatorBase extends ValveBase } + /** + * Can the authenticator perform preemptive authentication for the given + * request? + * + * @param request + * + * @return {@code true} if preemptive authentication is possible, otherwise + * {@code false} + */ + protected boolean isPreemptiveAuthPossible(Request request) { + return false; + } + + private AuthConfigProvider getJaspicProvider() { Optional<AuthConfigProvider> provider = jaspicProvider; if (provider == null) { diff --git a/java/org/apache/catalina/authenticator/BasicAuthenticator.java b/java/org/apache/catalina/authenticator/BasicAuthenticator.java index 12c60ee..452dc10 100644 --- a/java/org/apache/catalina/authenticator/BasicAuthenticator.java +++ b/java/org/apache/catalina/authenticator/BasicAuthenticator.java @@ -127,12 +127,20 @@ public class BasicAuthenticator extends AuthenticatorBase { } + @Override protected String getAuthMethod() { return HttpServletRequest.BASIC_AUTH; } + @Override + protected boolean isPreemptiveAuthPossible(Request request) { + MessageBytes authorizationHeader = request.getCoyoteRequest().getMimeHeaders().getValue("authorization"); + return authorizationHeader != null && authorizationHeader.startsWithIgnoreCase("basic ", 0); + } + + /** * Parser for an HTTP Authorization header for BASIC authentication * as per RFC 2617 section 2, and the Base64 encoded credentials as diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java b/java/org/apache/catalina/authenticator/DigestAuthenticator.java index 3fa2679..9684fcc 100644 --- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java +++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java @@ -31,6 +31,7 @@ import org.apache.catalina.Realm; import org.apache.catalina.connector.Request; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.parser.Authorization; import org.apache.tomcat.util.security.ConcurrentMessageDigest; import org.apache.tomcat.util.security.MD5Encoder; @@ -367,6 +368,13 @@ public class DigestAuthenticator extends AuthenticatorBase { } + @Override + protected boolean isPreemptiveAuthPossible(Request request) { + MessageBytes authorizationHeader = request.getCoyoteRequest().getMimeHeaders().getValue("authorization"); + return authorizationHeader != null && authorizationHeader.startsWithIgnoreCase("digest ", 0); + } + + // ------------------------------------------------------- Lifecycle Methods @Override diff --git a/java/org/apache/catalina/authenticator/SSLAuthenticator.java b/java/org/apache/catalina/authenticator/SSLAuthenticator.java index 10a03cf..ee771c4 100644 --- a/java/org/apache/catalina/authenticator/SSLAuthenticator.java +++ b/java/org/apache/catalina/authenticator/SSLAuthenticator.java @@ -23,7 +23,9 @@ import java.security.cert.X509Certificate; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; +import org.apache.coyote.ActionCode; /** * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication @@ -100,4 +102,41 @@ public class SSLAuthenticator extends AuthenticatorBase { protected String getAuthMethod() { return HttpServletRequest.CLIENT_CERT_AUTH; } + + + @Override + protected boolean isPreemptiveAuthPossible(Request request) { + X509Certificate[] certs = getRequestCertificates(request); + return certs != null && certs.length > 0; + } + + + /** + * Look for the X509 certificate chain in the Request under the key + * <code>jakarta.servlet.request.X509Certificate</code>. If not found, trigger + * extracting the certificate chain from the Coyote request. + * + * @param request + * Request to be processed + * + * @return The X509 certificate chain if found, <code>null</code> otherwise. + */ + protected X509Certificate[] getRequestCertificates(final Request request) + throws IllegalStateException { + + X509Certificate certs[] = + (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); + + if ((certs == null) || (certs.length < 1)) { + try { + request.getCoyoteRequest().action(ActionCode.REQ_SSL_CERTIFICATE, null); + certs = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); + } catch (IllegalStateException ise) { + // Request body was too large for save buffer + // Return null which will trigger an auth failure + } + } + + return certs; + } } diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java index 4edaa12..e208916 100644 --- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java +++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java @@ -299,6 +299,13 @@ public class SpnegoAuthenticator extends AuthenticatorBase { } + @Override + protected boolean isPreemptiveAuthPossible(Request request) { + MessageBytes authorizationHeader = request.getCoyoteRequest().getMimeHeaders().getValue("authorization"); + return authorizationHeader != null && authorizationHeader.startsWithIgnoreCase("negotiate ", 0); + } + + /** * This class gets a gss credential via a privileged action. */ diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index b6f0f82..cd64663 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -127,6 +127,12 @@ <code>false</code>. Fixed via pull request <pr>438</pr> provided by Robert Rodewald. (markt) </fix> + <scode> + Refactor the authenticators to delegate the check for preemptive + authentication to the individual authenticators where an authentication + scheme specific check can be performed. Based on pull request + <pr>444</pr> by Robert Rodewald. (markt) + </scode> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org