diff options
author | Jan Bartel | 2014-10-10 04:52:18 +0000 |
---|---|---|
committer | Jan Bartel | 2014-10-10 04:53:13 +0000 |
commit | dd864f97996f8382b8e9f1044f3057fdfe3723f8 (patch) | |
tree | 372723ac70c3637298db19dc40a3fe98e7888f8c | |
parent | 6a0e220b9ccf499048ccb66a945f1bd64d0ca689 (diff) | |
download | org.eclipse.jetty.project-dd864f97996f8382b8e9f1044f3057fdfe3723f8.tar.gz org.eclipse.jetty.project-dd864f97996f8382b8e9f1044f3057fdfe3723f8.tar.xz org.eclipse.jetty.project-dd864f97996f8382b8e9f1044f3057fdfe3723f8.zip |
443529 CrossOriginFilter does not accept wildcard for allowedHeaders
-rw-r--r-- | jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java | 81 | ||||
-rw-r--r-- | jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java | 29 |
2 files changed, 86 insertions, 24 deletions
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java index ff790ade10..3d9f74d7f8 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.servlets; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; @@ -64,7 +65,8 @@ import org.eclipse.jetty.util.log.Logger; * <b>GET,POST,HEAD</b></li> * <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that * are allowed to be specified when accessing the resources. Default value - * is <b>X-Requested-With,Content-Type,Accept,Origin</b></li> + * is <b>X-Requested-With,Content-Type,Accept,Origin</b>. If the value is a single "*", + * this means that any headers will be accepted.</li> * <li><b>preflightMaxAge</b>, the number of seconds that preflight requests * can be cached by the client. Default value is <b>1800</b> seconds, or 30 * minutes</li> @@ -119,8 +121,11 @@ public class CrossOriginFilter implements Filter public static final String CHAIN_PREFLIGHT_PARAM = "chainPreflight"; private static final String ANY_ORIGIN = "*"; private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD"); + private static final List<String> DEFAULT_ALLOWED_METHODS = Arrays.asList("GET", "POST", "HEAD"); + private static final List<String> DEFAULT_ALLOWED_HEADERS = Arrays.asList("X-Requested-With", "Content-Type", "Accept", "Origin"); private boolean anyOriginAllowed; + private boolean anyHeadersAllowed; private List<String> allowedOrigins = new ArrayList<String>(); private List<String> allowedMethods = new ArrayList<String>(); private List<String> allowedHeaders = new ArrayList<String>(); @@ -155,13 +160,17 @@ public class CrossOriginFilter implements Filter String allowedMethodsConfig = config.getInitParameter(ALLOWED_METHODS_PARAM); if (allowedMethodsConfig == null) - allowedMethodsConfig = "GET,POST,HEAD"; - allowedMethods.addAll(Arrays.asList(allowedMethodsConfig.split(","))); + allowedMethods.addAll(DEFAULT_ALLOWED_METHODS); + else + allowedMethods.addAll(Arrays.asList(allowedMethodsConfig.split(","))); String allowedHeadersConfig = config.getInitParameter(ALLOWED_HEADERS_PARAM); if (allowedHeadersConfig == null) - allowedHeadersConfig = "X-Requested-With,Content-Type,Accept,Origin"; - allowedHeaders.addAll(Arrays.asList(allowedHeadersConfig.split(","))); + allowedHeaders.addAll(DEFAULT_ALLOWED_HEADERS); + else if ("*".equals(allowedHeadersConfig)) + anyHeadersAllowed = true; + else + allowedHeaders.addAll(Arrays.asList(allowedHeadersConfig.split(","))); String preflightMaxAgeConfig = config.getInitParameter(PREFLIGHT_MAX_AGE_PARAM); if (preflightMaxAgeConfig == null) @@ -353,9 +362,11 @@ public class CrossOriginFilter implements Filter private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin) { boolean methodAllowed = isMethodAllowed(request); + if (!methodAllowed) return; - boolean headersAllowed = areHeadersAllowed(request); + List<String> headersRequested = getAccessControlRequestHeaders(request); + boolean headersAllowed = areHeadersAllowed(headersRequested); if (!headersAllowed) return; response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin); @@ -367,7 +378,10 @@ public class CrossOriginFilter implements Filter if (preflightMaxAge > 0) response.setHeader(ACCESS_CONTROL_MAX_AGE_HEADER, String.valueOf(preflightMaxAge)); response.setHeader(ACCESS_CONTROL_ALLOW_METHODS_HEADER, commify(allowedMethods)); - response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, commify(allowedHeaders)); + if (anyHeadersAllowed) + response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, commify(headersRequested)); + else + response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, commify(allowedHeaders)); } private boolean isMethodAllowed(HttpServletRequest request) @@ -381,33 +395,52 @@ public class CrossOriginFilter implements Filter return result; } - private boolean areHeadersAllowed(HttpServletRequest request) + List<String> getAccessControlRequestHeaders (HttpServletRequest request) { String accessControlRequestHeaders = request.getHeader(ACCESS_CONTROL_REQUEST_HEADERS_HEADER); LOG.debug("{} is {}", ACCESS_CONTROL_REQUEST_HEADERS_HEADER, accessControlRequestHeaders); + if (accessControlRequestHeaders == null) + return Collections.emptyList(); + + List<String> requestedHeaders = new ArrayList<String>(); + String[] headers = accessControlRequestHeaders.split(","); + for (String header : headers) + { + String h = header.trim(); + if (h.length() > 0) + requestedHeaders.add(h); + } + return requestedHeaders; + } + + + private boolean areHeadersAllowed(List<String> requestedHeaders) + { + if (anyHeadersAllowed) + { + LOG.debug("Any header is allowed"); + return true; + } + boolean result = true; - if (accessControlRequestHeaders != null) + for (String requestedHeader:requestedHeaders) { - String[] headers = accessControlRequestHeaders.split(","); - for (String header : headers) - { - boolean headerAllowed = false; - for (String allowedHeader : allowedHeaders) + boolean headerAllowed = false; + for (String allowedHeader:allowedHeaders) + { + if (requestedHeader.equalsIgnoreCase(allowedHeader.trim())) { - if (header.trim().equalsIgnoreCase(allowedHeader.trim())) - { - headerAllowed = true; - break; - } - } - if (!headerAllowed) - { - result = false; + headerAllowed = true; break; } } + if (!headerAllowed) + { + result = false; + break; + } } - LOG.debug("Headers [{}] are" + (result ? "" : " not") + " among allowed headers {}", accessControlRequestHeaders, allowedHeaders); + LOG.debug("Headers [{}] are" + (result ? "" : " not") + " among allowed headers {}", requestedHeaders, allowedHeaders); return result; } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java index 17916b395e..1d0df1bb9c 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java @@ -299,6 +299,35 @@ public class CrossOriginFilterTest Assert.assertTrue(latch.await(1, TimeUnit.SECONDS)); } + + @Test + public void testPreflightWithWildcardCustomHeaders() throws Exception + { + FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); + filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "*"); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); + + CountDownLatch latch = new CountDownLatch(1); + tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); + + String request = "" + + "OPTIONS / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS_HEADER + ": X-Foo-Bar\r\n" + + CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD_HEADER + ": GET\r\n"+ + "Origin: http://localhost\r\n" + + "\r\n"; + String response = tester.getResponses(request); + Assert.assertTrue(response.contains("HTTP/1.1 200")); + Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER)); + Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS_HEADER)); + Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER)); + Assert.assertTrue(latch.await(1, TimeUnit.SECONDS)); + } + + + @Test public void testPUTRequestWithPreflight() throws Exception { |