This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit d1211048a9b4a0cf9e968f1f7a3f8fd09c7c2d94 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Jun 27 23:05:52 2019 +0100 Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63531 Refactor authenticators so that the session last accessed time is not updated if the cache attribute is set to false and FORM authentication is not being used. --- .../catalina/authenticator/AuthenticatorBase.java | 87 ++++++++-------------- .../catalina/authenticator/FormAuthenticator.java | 36 ++++++++- webapps/docs/changelog.xml | 6 ++ 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java index eb9d35e..e67cd20 100644 --- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java +++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java @@ -431,55 +431,13 @@ public abstract class AuthenticatorBase extends ValveBase } } - // Special handling for form-based logins to deal with the case - // where the login form (and therefore the "j_security_check" URI - // to which it submits) might be outside the secured area - String contextPath = this.context.getPath(); - String requestURI = request.getDecodedRequestURI(); - if (requestURI.startsWith(contextPath) && - requestURI.endsWith(Constants.FORM_ACTION)) { - if (!authenticate(request, response, config)) { - if (log.isDebugEnabled()) - log.debug(" Failed authenticate() test ??" + requestURI ); - return; - } - } - - // Special handling for form-based logins to deal with the case where - // a resource is protected for some HTTP methods but not protected for - // GET which is used after authentication when redirecting to the - // protected resource. - // TODO: This is similar to the FormAuthenticator.matchRequest() logic - // Is there a way to remove the duplication? - Session session = request.getSessionInternal(false); - if (session != null) { - SavedRequest savedRequest = - (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); - if (savedRequest != null) { - String decodedRequestURI = request.getDecodedRequestURI(); - if (decodedRequestURI != null && - decodedRequestURI.equals( - savedRequest.getDecodedRequestURI())) { - if (!authenticate(request, response)) { - if (log.isDebugEnabled()) { - log.debug(" Failed authenticate() test"); - } - /* - * ASSERT: Authenticator already set the appropriate - * HTTP status code, so we do not have to do anything - * special - */ - return; - } - } - } - } + boolean authRequired = isContinuationRequired(request); Realm realm = this.context.getRealm(); // Is this request URI subject to a security constraint? SecurityConstraint[] constraints = realm.findSecurityConstraints(request, this.context); - if (constraints == null && !context.getPreemptiveAuthentication()) { + if (constraints == null && !context.getPreemptiveAuthentication() && !authRequired) { if (log.isDebugEnabled()) { log.debug(" Not subject to any constraint"); } @@ -520,23 +478,25 @@ public abstract class AuthenticatorBase extends ValveBase // Since authenticate modifies the response on failure, // we have to check for allow-from-all first. - boolean authRequired; - if (constraints == null) { - authRequired = false; - } else { - authRequired = true; - for(int i = 0; i < constraints.length && authRequired; i++) { - if(!constraints[i].getAuthConstraint()) { - authRequired = false; - } else if(!constraints[i].getAllRoles()) { - String [] roles = constraints[i].findAuthRoles(); - if(roles == null || roles.length == 0) { - authRequired = false; + boolean hasAuthConstraint = false; + if (constraints != null) { + hasAuthConstraint = true; + for (int i = 0; i < constraints.length && hasAuthConstraint; i++) { + if (!constraints[i].getAuthConstraint()) { + hasAuthConstraint = false; + } else if (!constraints[i].getAllRoles()) { + String[] roles = constraints[i].findAuthRoles(); + if (roles == null || roles.length == 0) { + hasAuthConstraint = false; } } } } + if (!authRequired && hasAuthConstraint) { + authRequired = true; + } + if (!authRequired && context.getPreemptiveAuthentication()) { authRequired = request.getCoyoteRequest().getMimeHeaders().getValue("authorization") != null; @@ -593,6 +553,21 @@ public abstract class AuthenticatorBase extends ValveBase // ------------------------------------------------------ Protected Methods /** + * Does this authenticator require that {@link #authenticate(Request, + * HttpServletResponse)} is called to continue an authentication process + * that started in a previous request? + * + * @param request The request currently being processed + * + * @return {@code true} if authenticate() must be called, otherwise + * {@code false} + */ + protected boolean isContinuationRequired(Request request) { + return false; + } + + + /** * 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. diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java index 809556e..5b55664 100644 --- a/java/org/apache/catalina/authenticator/FormAuthenticator.java +++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java @@ -352,13 +352,43 @@ public class FormAuthenticator } + // ------------------------------------------------------ Protected Methods + @Override - protected String getAuthMethod() { - return HttpServletRequest.FORM_AUTH; + protected boolean isContinuationRequired(Request request) { + // Special handling for form-based logins to deal with the case + // where the login form (and therefore the "j_security_check" URI + // to which it submits) might be outside the secured area + String contextPath = this.context.getPath(); + String decodedRequestURI = request.getDecodedRequestURI(); + if (decodedRequestURI.startsWith(contextPath) && + decodedRequestURI.endsWith(Constants.FORM_ACTION)) { + return true; + } + + // Special handling for form-based logins to deal with the case where + // a resource is protected for some HTTP methods but not protected for + // GET which is used after authentication when redirecting to the + // protected resource. + // TODO: This is similar to the FormAuthenticator.matchRequest() logic + // Is there a way to remove the duplication? + Session session = request.getSessionInternal(false); + if (session != null) { + SavedRequest savedRequest = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); + if (savedRequest != null && + decodedRequestURI.equals(savedRequest.getDecodedRequestURI())) { + return true; + } + } + + return false; } - // ------------------------------------------------------ Protected Methods + @Override + protected String getAuthMethod() { + return HttpServletRequest.FORM_AUTH; + } /** diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 64db49f..11afd1e 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -117,6 +117,12 @@ <code>RequestDispatcher</code>. The requested target path is logged as a warning since this is an application error. (markt) </add> + <fix> + <bug>63531</bug>: Refactor authenticators so that the session last + accessed time is not updated if the cache attribute is set to + <code>false</code> and <code>FORM</code> authentication is not being + used. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org