You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/11/30 11:54:07 UTC
[tomcat] 02/02: Fix
https://bz.apache.org/bugzilla/show_bug.cgi?id=63939 same origin
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
commit afe40851efbdddc44862a7b314a07d86ca04f06d
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Nov 29 23:19:00 2019 +0000
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63939 same origin
Refactor isSameOrigin test into utility class (for re-use in
AuthenticatorBase) and fix two bugs:
- comparison should be case-sensitive
- origin may or may not include default port
---
java/org/apache/catalina/filters/CorsFilter.java | 33 +-----
java/org/apache/tomcat/util/http/RequestUtil.java | 51 ++++++++++
.../util/http/TestRequestUtilSameOrigin.java | 113 +++++++++++++++++++++
3 files changed, 166 insertions(+), 31 deletions(-)
diff --git a/java/org/apache/catalina/filters/CorsFilter.java b/java/org/apache/catalina/filters/CorsFilter.java
index ad5a1f4..4213fb4 100644
--- a/java/org/apache/catalina/filters/CorsFilter.java
+++ b/java/org/apache/catalina/filters/CorsFilter.java
@@ -39,6 +39,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.http.ResponseUtil;
import org.apache.tomcat.util.res.StringManager;
@@ -591,7 +592,7 @@ public class CorsFilter extends GenericFilter {
requestType = CORSRequestType.INVALID_CORS;
} else if (!isValidOrigin(originHeader)) {
requestType = CORSRequestType.INVALID_CORS;
- } else if (isLocalOrigin(request, originHeader)) {
+ } else if (RequestUtil.isSameOrigin(request, originHeader)) {
return CORSRequestType.NOT_CORS;
} else {
String method = request.getMethod();
@@ -634,36 +635,6 @@ public class CorsFilter extends GenericFilter {
}
- private boolean isLocalOrigin(HttpServletRequest request, String origin) {
-
- // Build scheme://host:port from request
- StringBuilder target = new StringBuilder();
- String scheme = request.getScheme();
- if (scheme == null) {
- return false;
- } else {
- scheme = scheme.toLowerCase(Locale.ENGLISH);
- }
- target.append(scheme);
- target.append("://");
-
- String host = request.getServerName();
- if (host == null) {
- return false;
- }
- target.append(host);
-
- int port = request.getServerPort();
- if ("http".equals(scheme) && port != 80 ||
- "https".equals(scheme) && port != 443) {
- target.append(':');
- target.append(port);
- }
-
- return origin.equalsIgnoreCase(target.toString());
- }
-
-
/**
* Return the lower case, trimmed value of the media type from the content
* type.
diff --git a/java/org/apache/tomcat/util/http/RequestUtil.java b/java/org/apache/tomcat/util/http/RequestUtil.java
index 28922c4..cfa9c57 100644
--- a/java/org/apache/tomcat/util/http/RequestUtil.java
+++ b/java/org/apache/tomcat/util/http/RequestUtil.java
@@ -16,6 +16,10 @@
*/
package org.apache.tomcat.util.http;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
public class RequestUtil {
private RequestUtil() {
@@ -113,4 +117,51 @@ public class RequestUtil {
// Return the normalized path that we have completed
return normalized;
}
+
+
+ public static boolean isSameOrigin(HttpServletRequest request, String origin) {
+ // Build scheme://host:port from request
+ StringBuilder target = new StringBuilder();
+ String scheme = request.getScheme();
+ if (scheme == null) {
+ return false;
+ } else {
+ scheme = scheme.toLowerCase(Locale.ENGLISH);
+ }
+ target.append(scheme);
+ target.append("://");
+
+ String host = request.getServerName();
+ if (host == null) {
+ return false;
+ }
+ target.append(host);
+
+ int port = request.getServerPort();
+ // Origin may or may not include the (default) port.
+ // At this point target doesn't include a port.
+ if (target.length() == origin.length()) {
+ // origin and target can only be equal if both are using default
+ // ports. Therefore only append the port to the target if a
+ // non-default port is used.
+ if (("http".equals(scheme) || "ws".equals(scheme)) && port != 80 ||
+ ("https".equals(scheme) || "wss".equals(scheme)) && port != 443) {
+ target.append(':');
+ target.append(port);
+ }
+ } else {
+ // origin and target can only be equal if:
+ // a) origin includes an explicit default port
+ // b) origin is using a non-default port
+ // Either way, add the port to the target so it can be compared
+ target.append(':');
+ target.append(port);
+ }
+
+
+ // Both scheme and host are case-insensitive but the CORS spec states
+ // this check should be case-sensitive
+ return origin.equals(target.toString());
+ }
+
}
diff --git a/test/org/apache/tomcat/util/http/TestRequestUtilSameOrigin.java b/test/org/apache/tomcat/util/http/TestRequestUtilSameOrigin.java
new file mode 100644
index 0000000..5b4c0d0
--- /dev/null
+++ b/test/org/apache/tomcat/util/http/TestRequestUtilSameOrigin.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import org.apache.catalina.connector.Request;
+
+@RunWith(Parameterized.class)
+public class TestRequestUtilSameOrigin {
+
+ @Parameterized.Parameters(name = "{index}: request[{0}], origin[{1}]")
+ public static Collection<Object[]> parameters() {
+ List<Object[]> parameterSets = new ArrayList<>();
+
+ TesterRequest request1 = new TesterRequest("http", "example.com", 80);
+ TesterRequest request2 = new TesterRequest("ws", "example.com", 80);
+ TesterRequest request3 = new TesterRequest("http", "example.com", 443);
+ TesterRequest request4 = new TesterRequest("http", "example.com", 8080);
+
+ parameterSets.add(new Object[] { request1, "http://example.com", Boolean.TRUE });
+ parameterSets.add(new Object[] { request1, "http://example.com:80", Boolean.TRUE });
+ parameterSets.add(new Object[] { request1, "http://example.com:8080", Boolean.FALSE});
+
+ parameterSets.add(new Object[] { request2, "ws://example.com", Boolean.TRUE });
+ parameterSets.add(new Object[] { request2, "ws://example.com:80", Boolean.TRUE });
+ parameterSets.add(new Object[] { request2, "ws://example.com:8080", Boolean.FALSE});
+
+ parameterSets.add(new Object[] { request3, "http://example.com", Boolean.FALSE });
+ parameterSets.add(new Object[] { request3, "http://example.com:80", Boolean.FALSE });
+ parameterSets.add(new Object[] { request3, "http://example.com:443", Boolean.TRUE});
+
+ parameterSets.add(new Object[] { request4, "http://example.com", Boolean.FALSE });
+ parameterSets.add(new Object[] { request4, "http://example.com:80", Boolean.FALSE });
+ parameterSets.add(new Object[] { request4, "http://example.com:8080", Boolean.TRUE});
+
+ return parameterSets;
+ }
+
+
+ @Parameter(0)
+ public HttpServletRequest request;
+ @Parameter(1)
+ public String origin;
+ @Parameter(2)
+ public Boolean same;
+
+
+ @Test
+ public void testSameOrigin() {
+ Assert.assertEquals(same, Boolean.valueOf(RequestUtil.isSameOrigin(request, origin)));
+ }
+
+
+ private static class TesterRequest extends HttpServletRequestWrapper {
+
+ private final String scheme;
+ private final String host;
+ private final int port;
+
+ public TesterRequest(String scheme, String host, int port) {
+ super(new Request(null));
+ this.scheme = scheme;
+ this.host = host;
+ this.port = port;
+ }
+
+ @Override
+ public String getScheme() {
+ return scheme;
+ }
+
+ @Override
+ public String getServerName() {
+ return host;
+ }
+
+ @Override
+ public int getServerPort() {
+ return port;
+ }
+
+ @Override
+ public String toString() {
+ return scheme + "://" + host + ":" + port;
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org