Am 2019-12-02 um 18:51 schrieb ma...@apache.org:
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
      new e9430e1  https://bz.apache.org/bugzilla/show_bug.cgi?id=63937 
allowCorsPreflight
e9430e1 is described below

commit e9430e1db97d9ffc31d4d4431af92f2511d1b950
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Dec 2 14:01:13 2019 +0000

     https://bz.apache.org/bugzilla/show_bug.cgi?id=63937 allowCorsPreflight
Add a new attribute to the standard Authenticator implementations,
     allowCorsPreflight, that allows the Authenticators to be configured to
     allow CORS preflight requests to bypass authentication as required by
     the CORS specification.
---
  .../catalina/authenticator/AuthenticatorBase.java  |  88 ++++++++++
  java/org/apache/catalina/filters/CorsFilter.java   |  34 +---
  java/org/apache/tomcat/util/http/RequestUtil.java  |  43 +++++
  .../TestAuthenticatorBaseCorsPreflight.java        | 177 +++++++++++++++++++++
  .../apache/catalina/filters/TestCorsFilter.java    |  12 +-
  webapps/docs/changelog.xml                         |   8 +
  webapps/docs/config/valve.xml                      |  93 +++++++++--
  7 files changed, 413 insertions(+), 42 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java 
b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
index 76e712b..308b019 100644
--- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java
+++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
@@ -33,6 +33,7 @@ import javax.security.auth.message.config.AuthConfigProvider;
  import javax.security.auth.message.config.RegistrationListener;
  import javax.security.auth.message.config.ServerAuthConfig;
  import javax.security.auth.message.config.ServerAuthContext;
+import javax.servlet.DispatcherType;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.Cookie;
@@ -53,6 +54,7 @@ import 
org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl;
  import org.apache.catalina.authenticator.jaspic.MessageInfoImpl;
  import org.apache.catalina.connector.Request;
  import org.apache.catalina.connector.Response;
+import org.apache.catalina.filters.CorsFilter;
  import org.apache.catalina.filters.RemoteIpFilter;
  import org.apache.catalina.realm.GenericPrincipal;
  import org.apache.catalina.util.SessionIdGeneratorBase;
@@ -63,9 +65,12 @@ import org.apache.coyote.ActionCode;
  import org.apache.juli.logging.Log;
  import org.apache.juli.logging.LogFactory;
  import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.descriptor.web.FilterDef;
+import org.apache.tomcat.util.descriptor.web.FilterMap;
  import org.apache.tomcat.util.descriptor.web.LoginConfig;
  import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
  import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.RequestUtil;
  import org.apache.tomcat.util.res.StringManager;
/**
@@ -237,12 +242,22 @@ public abstract class AuthenticatorBase extends ValveBase
       */
      protected SingleSignOn sso = null;
+ private AllowCorsPreflight allowCorsPreflight = AllowCorsPreflight.NEVER;
+
      private volatile String jaspicAppContextID = null;
      private volatile Optional<AuthConfigProvider> jaspicProvider = null;
// ------------------------------------------------------------- Properties + public String getAllowCorsPreflight() {
+        return allowCorsPreflight.name().toLowerCase();
+    }
+
+    public void setAllowCorsPreflight(String allowCorsPreflight) {
+        this.allowCorsPreflight = 
AllowCorsPreflight.valueOf(allowCorsPreflight.trim().toUpperCase());
+    }
+

toLowerCase() and toUpperCase() should be locale-agnostic. I bet FILTER will fail with tr_TR.

      public boolean getAlwaysUseSession() {
          return alwaysUseSession;
      }
@@ -593,6 +608,14 @@ public abstract class AuthenticatorBase extends ValveBase
JaspicState jaspicState = null; + if ((authRequired || constraints != null) && allowCorsPreflightBypass(request)) {
+            if (log.isDebugEnabled()) {
+                log.debug(" CORS Preflight request bypassing authentication");
                             ^^
                             Is that space intended?
+            }
+            getNext().invoke(request, response);
+            return;
+        }
+
          if (authRequired) {
              if (log.isDebugEnabled()) {
                  log.debug(" Calling authenticate()");
@@ -648,6 +671,64 @@ public abstract class AuthenticatorBase extends ValveBase
      }
+ protected boolean allowCorsPreflightBypass(Request request) {
+        boolean allowBypass = false;
+
+        if (allowCorsPreflight != AllowCorsPreflight.NEVER) {
+            // First check to see if this is a CORS Preflight request
+            // This is a subset of the tests in CorsFilter.checkRequestType
+            if ("OPTIONS".equals(request.getMethod())) {
+                String originHeader = 
request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN);
+                if (originHeader != null &&
+                        !originHeader.isEmpty() &&
+                        RequestUtil.isValidOrigin(originHeader) &&
+                        !RequestUtil.isSameOrigin(request, originHeader)) {
+                    String accessControlRequestMethodHeader =
+                            
request.getHeader(CorsFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD);
+                    if (accessControlRequestMethodHeader != null &&
+                            !accessControlRequestMethodHeader.isEmpty()) {
+                        // This appears to be a CORS Preflight request
+                        if (allowCorsPreflight == AllowCorsPreflight.ALWAYS) {
+                            allowBypass = true;
+                        } else if (allowCorsPreflight == 
AllowCorsPreflight.FILTER) {
+                            if (DispatcherType.REQUEST == 
request.getDispatcherType()) {
+                                // Look at Filter configuration for the Context
+                                // Can't cache this unless we add a listener to
+                                // the Context to clear the cache on reload
+                                for (FilterDef filterDef : 
request.getContext().findFilterDefs()) {
+                                    if 
(CorsFilter.class.getName().equals(filterDef.getFilterClass())) {
+                                        for (FilterMap filterMap : 
context.findFilterMaps()) {
+                                            if 
(filterMap.getFilterName().equals(filterDef.getFilterName())) {
+                                                if ((filterMap.getDispatcherMapping() 
& FilterMap.REQUEST) > 0) {
+                                                    for (String urlPattern : 
filterMap.getURLPatterns()) {
+                                                        if 
("/*".equals(urlPattern)) {
So basically, if I have applied the CorsFilter to "/api/* it will evaluate to false?! This is why I brought up BZ 63938.
You see no other way to make it an exact match a not blanket?

+                                                            allowBypass = true;
+                                                            // No need to 
check other patterns
+                                                            break;
+                                                        }
+                                                    }
+                                                }
+                                                // Found mappings for CORS 
filter.
+                                                // No need to look further
+                                                break;
+                                            }
+                                        }
+                                        // Found the CORS filter. No need to 
look further.
+                                        break;
+                                    }
+                                }
+                            }
+                        } else {
+                            // Unexpected enum type
+                        }
+                    }
+                }
+            }
+        }
+        return allowBypass;
+    }
+
+
      @Override
      public boolean authenticate(Request request, HttpServletResponse 
httpResponse)
              throws IOException {
@@ -1301,4 +1382,11 @@ public abstract class AuthenticatorBase extends ValveBase
          public MessageInfo messageInfo = null;
          public ServerAuthContext serverAuthContext = null;
      }
+
+
+    protected enum AllowCorsPreflight {
+        NEVER,
+        FILTER,
+        ALWAYS
+    }
  }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 359f9a4..c7eb551 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -61,6 +61,14 @@
          changes introduced in 9.0.28. Connections to URLs obtained for JAR
          resources could not be cast to <code>JarURLConnection</code>. (markt)
        </fix>
+      <add>
+        <bug>63937</bug>: Add a new attribute to the standard
+        <code>Authenticator</code> implementations,
+        <code>allowCorsPreflight</code>, that allows the
+        <code>Authenticator</code>s to be configured to allow CORS preflight
+        requests to bypass authentication as required by the CORS 
specification.
+        (markt)
+      </add>
        <fix>
          <bug>63939</bug>: Correct the same origin check in the CORS filter. An
          origin with an explicit default port is now considered to be the same 
as
diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml
index 72f0584..ca32e37 100644
--- a/webapps/docs/config/valve.xml
+++ b/webapps/docs/config/valve.xml
@@ -1201,6 +1201,21 @@
<attributes> + <attribute name="allowCorsPreflight" required="false">
+        <p>Are requests that appear to be CORS preflight requests allowed to
+        bypass the authenticator as required by the CORS specification. The
+        allowed values are <code>never</code>, <code>filter</code> and
+        <code>always</code>. <code>never</code> means that a request will never
+        bypass authentication even if it appears to be a CORS preflight 
request.
+        <code>filter</code> means that a request will bypass authentication if
+        it appears to be a CORS preflight request and the web application the
+        request maps to has the <a href="filter.html#CORS_Filter">CORS

I have the feeling that some word is either wrong or missing here: ... and the web application the request maps ...

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

Reply via email to