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