Blame SOURCES/tomcat-7.0.76-CVE-2018-8014.patch

9a9096
commit 5877390a9605f56d9bd6859a54ccbfb16374a78b
9a9096
Author: Mark Thomas <markt@apache.org>
9a9096
Date:   Wed May 16 14:56:34 2018 +0000
9a9096
9a9096
    Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=62343
9a9096
    Make CORS filter defaults more secure.
9a9096
    This is the fix for CVE-2018-8014.
9a9096
    
9a9096
    git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk@1831730 13f79535-47bb-0310-9956-ffa450edef68
9a9096
9a9096
diff -up java/org/apache/catalina/filters/CorsFilter.java.orig java/org/apache/catalina/filters/CorsFilter.java
9a9096
--- java/org/apache/catalina/filters/CorsFilter.java.orig	2019-02-28 16:37:12.512591576 -0500
9a9096
+++ java/org/apache/catalina/filters/CorsFilter.java	2019-02-28 16:39:43.449141647 -0500
9a9096
@@ -260,17 +260,14 @@ public class CorsFilter implements Filte
9a9096
9a9096
         // Section 6.1.3
9a9096
         // Add a single Access-Control-Allow-Origin header.
9a9096
-        if (anyOriginAllowed && !supportsCredentials) {
9a9096
-            // If resource doesn't support credentials and if any origin is
9a9096
-            // allowed
9a9096
-            // to make CORS request, return header with '*'.
9a9096
+        if (anyOriginAllowed) {
9a9096
+            // If any origin is allowed, return header with '*'.
9a9096
             response.addHeader(
9a9096
                     CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
9a9096
                     "*");
9a9096
         } else {
9a9096
-            // If the resource supports credentials add a single
9a9096
-            // Access-Control-Allow-Origin header, with the value of the Origin
9a9096
-            // header as value.
9a9096
+            // Add a single Access-Control-Allow-Origin header, with the value
9a9096
+            // of the Origin header as value.
9a9096
             response.addHeader(
9a9096
                     CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
9a9096
                     origin);
9a9096
@@ -799,6 +796,10 @@ public class CorsFilter implements Filte
9a9096
                     .parseBoolean(supportsCredentials);
9a9096
         }
9a9096
 
9a9096
+        if (this.supportsCredentials && this.anyOriginAllowed) {
9a9096
+            throw new ServletException(sm.getString("corsFilter.invalidSupportsCredentials"));
9a9096
+        }
9a9096
+
9a9096
         if (preflightMaxAge != null) {
9a9096
             try {
9a9096
                 if (!preflightMaxAge.isEmpty()) {
9a9096
@@ -1156,7 +1156,7 @@ public class CorsFilter implements Filte
9a9096
     /**
9a9096
      * By default, all origins are allowed to make requests.
9a9096
      */
9a9096
-    public static final String DEFAULT_ALLOWED_ORIGINS = "*";
9a9096
+    public static final String DEFAULT_ALLOWED_ORIGINS = "";
9a9096
9a9096
     /**
9a9096
      * By default, following methods are supported: GET, POST, HEAD and OPTIONS.
9a9096
@@ -1172,7 +1172,7 @@ public class CorsFilter implements Filte
9a9096
     /**
9a9096
      * By default, support credentials is turned on.
9a9096
      */
9a9096
-    public static final String DEFAULT_SUPPORTS_CREDENTIALS = "true";
9a9096
+    public static final String DEFAULT_SUPPORTS_CREDENTIALS = "false";
9a9096
9a9096
     /**
9a9096
      * By default, following headers are supported:
9a9096
diff --git a/java/org/apache/catalina/filters/LocalStrings.properties b/java/org/apache/catalina/filters/LocalStrings.properties
9a9096
index 5c4c792f82..921f101456 100644
9a9096
--- java/org/apache/catalina/filters/LocalStrings.properties
9a9096
+++ java/org/apache/catalina/filters/LocalStrings.properties
9a9096
@@ -14,6 +14,8 @@
9a9096
 # limitations under the License.
9a9096
 
9a9096
 addDefaultCharset.unsupportedCharset=Specified character set [{0}] is not supported
9a9096
+
9a9096
+corsFilter.invalidSupportsCredentials=It is not allowed to configure supportsCredentials=[true] when allowedOrigins=[*]
9a9096
 corsFilter.invalidPreflightMaxAge=Unable to parse preflightMaxAge
9a9096
 corsFilter.nullRequest=HttpServletRequest object is null
9a9096
 corsFilter.nullRequestType=CORSRequestType object is null
9a9096
diff --git a/test/org/apache/catalina/filters/TestCorsFilter.java b/test/org/apache/catalina/filters/TestCorsFilter.java
9a9096
index 06634fbb57..47d520a08e 100644
9a9096
--- test/org/apache/catalina/filters/TestCorsFilter.java
9a9096
+++ test/org/apache/catalina/filters/TestCorsFilter.java
9a9096
@@ -52,8 +52,7 @@ public class TestCorsFilter {
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
9a9096
         Assert.assertTrue(((Boolean) request.getAttribute(
9a9096
                 CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
9a9096
         Assert.assertTrue(request.getAttribute(
9a9096
@@ -85,8 +84,7 @@ public class TestCorsFilter {
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
9a9096
         Assert.assertTrue(((Boolean) request.getAttribute(
9a9096
                 CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
9a9096
         Assert.assertTrue(request.getAttribute(
9a9096
@@ -117,8 +115,7 @@ public class TestCorsFilter {
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
9a9096
         Assert.assertTrue(((Boolean) request.getAttribute(
9a9096
                 CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
9a9096
         Assert.assertTrue(request.getAttribute(
9a9096
@@ -163,41 +160,15 @@ public class TestCorsFilter {
9a9096
     }
9a9096
 
9a9096
     /**
9a9096
-     * Tests the presence of the origin (and not '*') in the response, when
9a9096
-     * supports credentials is enabled alongwith any origin, '*'.
9a9096
+     * Tests the that supports credentials may not be enabled with any origin,
9a9096
+     * '*'.
9a9096
      *
9a9096
-     * @throws IOException
9a9096
      * @throws ServletException
9a9096
      */
9a9096
-    @Test
9a9096
-    public void testDoFilterSimpleAnyOriginAndSupportsCredentials()
9a9096
-            throws IOException, ServletException {
9a9096
-        TesterHttpServletRequest request = new TesterHttpServletRequest();
9a9096
-        request.setHeader(CorsFilter.REQUEST_HEADER_ORIGIN,
9a9096
-                TesterFilterConfigs.HTTPS_WWW_APACHE_ORG);
9a9096
-        request.setMethod("GET");
9a9096
-        TesterHttpServletResponse response = new TesterHttpServletResponse();
9a9096
-
9a9096
+    @Test(expected=ServletException.class)
9a9096
+    public void testDoFilterSimpleAnyOriginAndSupportsCredentials() throws ServletException {
9a9096
         CorsFilter corsFilter = new CorsFilter();
9a9096
-        corsFilter.init(TesterFilterConfigs
9a9096
-                .getFilterConfigAnyOriginAndSupportsCredentials());
9a9096
-        corsFilter.doFilter(request, response, filterChain);
9a9096
-
9a9096
-        Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                TesterFilterConfigs.HTTPS_WWW_APACHE_ORG));
9a9096
-        Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS)
9a9096
-                .equals(
9a9096
-                        "true"));
9a9096
-        Assert.assertTrue(((Boolean) request.getAttribute(
9a9096
-                CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
9a9096
-        Assert.assertTrue(request.getAttribute(
9a9096
-                CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN).equals(
9a9096
-                TesterFilterConfigs.HTTPS_WWW_APACHE_ORG));
9a9096
-        Assert.assertTrue(request.getAttribute(
9a9096
-                CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE).equals(
9a9096
-                CorsFilter.CORSRequestType.SIMPLE.name().toLowerCase(Locale.ENGLISH)));
9a9096
+        corsFilter.init(TesterFilterConfigs.getFilterConfigAnyOriginAndSupportsCredentials());
9a9096
     }
9a9096
 
9a9096
     /**
9a9096
@@ -258,8 +229,7 @@ public class TestCorsFilter {
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
                 CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS)
9a9096
                 .equals(TesterFilterConfigs.EXPOSED_HEADERS));
9a9096
@@ -707,9 +677,8 @@ public class TestCorsFilter {
9a9096
         corsFilter.init(null);
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
-        Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+        Assert.assertNull(response.getHeader(
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN));
9a9096
         Assert.assertTrue(((Boolean) request.getAttribute(
9a9096
                 CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST)).booleanValue());
9a9096
         Assert.assertTrue(request.getAttribute(
9a9096
@@ -1401,7 +1370,7 @@ public class TestCorsFilter {
9a9096
         Assert.assertTrue(corsFilter.getAllowedOrigins().size() == 0);
9a9096
         Assert.assertTrue(corsFilter.isAnyOriginAllowed());
9a9096
         Assert.assertTrue(corsFilter.getExposedHeaders().size() == 0);
9a9096
-        Assert.assertTrue(corsFilter.isSupportsCredentials());
9a9096
+        Assert.assertFalse(corsFilter.isSupportsCredentials());
9a9096
         Assert.assertTrue(corsFilter.getPreflightMaxAge() == 1800);
9a9096
     }
9a9096
 
9a9096
@@ -1437,9 +1406,9 @@ public class TestCorsFilter {
9a9096
         Assert.assertTrue(corsFilter.getAllowedHttpHeaders().size() == 6);
9a9096
         Assert.assertTrue(corsFilter.getAllowedHttpMethods().size() == 4);
9a9096
         Assert.assertTrue(corsFilter.getAllowedOrigins().size() == 0);
9a9096
-        Assert.assertTrue(corsFilter.isAnyOriginAllowed());
9a9096
+        Assert.assertFalse(corsFilter.isAnyOriginAllowed());
9a9096
         Assert.assertTrue(corsFilter.getExposedHeaders().size() == 0);
9a9096
-        Assert.assertTrue(corsFilter.isSupportsCredentials());
9a9096
+        Assert.assertFalse(corsFilter.isSupportsCredentials());
9a9096
         Assert.assertTrue(corsFilter.getPreflightMaxAge() == 1800);
9a9096
     }
9a9096
 
9a9096
@@ -1543,8 +1512,7 @@ public class TestCorsFilter {
9a9096
         corsFilter.doFilter(request, response, filterChain);
9a9096
 
9a9096
         Assert.assertTrue(response.getHeader(
9a9096
-                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals(
9a9096
-                "https://www.apache.org"));
9a9096
+                CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN).equals("*"));
9a9096
         Assert.assertNull(request
9a9096
                 .getAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST));
9a9096
         Assert.assertNull(request
9a9096
diff --git a/test/org/apache/catalina/filters/TesterFilterConfigs.java b/test/org/apache/catalina/filters/TesterFilterConfigs.java
9a9096
index 941d8949d7..cb3d04f813 100644
9a9096
--- test/org/apache/catalina/filters/TesterFilterConfigs.java
9a9096
+++ test/org/apache/catalina/filters/TesterFilterConfigs.java
9a9096
@@ -36,12 +36,13 @@ public class TesterFilterConfigs {
9a9096
     public static final TesterServletContext mockServletContext =
9a9096
             new TesterServletContext();
9a9096
 
9a9096
+    // Default config for the test is to allow any origin
9a9096
     public static FilterConfig getDefaultFilterConfig() {
9a9096
         final String allowedHttpHeaders =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
9a9096
         final String allowedHttpMethods =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
9a9096
-        final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
9a9096
+        final String allowedOrigins = ANY_ORIGIN;
9a9096
         final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
9a9096
         final String supportCredentials =
9a9096
                 CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
9a9096
@@ -59,7 +60,7 @@ public class TesterFilterConfigs {
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
9a9096
         final String allowedHttpMethods =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS + ",PUT";
9a9096
-        final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
9a9096
+        final String allowedOrigins = ANY_ORIGIN;
9a9096
         final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
9a9096
         final String supportCredentials = "true";
9a9096
         final String preflightMaxAge =
9a9096
@@ -77,7 +78,7 @@ public class TesterFilterConfigs {
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
9a9096
         final String allowedHttpMethods =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS + ",PUT";
9a9096
-        final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
9a9096
+        final String allowedOrigins = ANY_ORIGIN;
9a9096
         final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
9a9096
         final String supportCredentials = "false";
9a9096
         final String preflightMaxAge =
9a9096
@@ -131,7 +132,7 @@ public class TesterFilterConfigs {
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
9a9096
         final String allowedHttpMethods =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
9a9096
-        final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
9a9096
+        final String allowedOrigins = ANY_ORIGIN;
9a9096
         final String exposedHeaders = EXPOSED_HEADERS;
9a9096
         final String supportCredentials =
9a9096
                 CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
9a9096
@@ -240,7 +241,7 @@ public class TesterFilterConfigs {
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_HEADERS;
9a9096
         final String allowedHttpMethods =
9a9096
                 CorsFilter.DEFAULT_ALLOWED_HTTP_METHODS;
9a9096
-        final String allowedOrigins = CorsFilter.DEFAULT_ALLOWED_ORIGINS;
9a9096
+        final String allowedOrigins = ANY_ORIGIN;
9a9096
         final String exposedHeaders = CorsFilter.DEFAULT_EXPOSED_HEADERS;
9a9096
         final String supportCredentials =
9a9096
                 CorsFilter.DEFAULT_SUPPORTS_CREDENTIALS;
9a9096
diff -up webapps/docs/changelog.xml.orig webapps/docs/changelog.xml
9a9096
--- webapps/docs/changelog.xml.orig	2019-02-28 16:33:00.254343407 -0500
9a9096
+++ webapps/docs/changelog.xml	2019-02-28 16:33:24.135272232 -0500
9a9096
@@ -78,6 +78,10 @@
9a9096
         NonLoginAuthenticator has to be set for it to work (if no login method
9a9096
         is specified). (remm)
9a9096
       </fix>
9a9096
+      <fix>
9a9096
+        <bug>62343</bug>: Make CORS filter defaults more secure. This is the fix
9a9096
+        for CVE-2018-8014. (markt)
9a9096
+      </fix>
9a9096
     </changelog>
9a9096
   </subsection>
9a9096
 </section>