YARN-2277. Added cross-origin support for the timeline server web services. Contributed by Jonathan Eagles.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1617832 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
065d9ec5d9
commit
41aa4badf8
@ -41,6 +41,9 @@ Release 2.6.0 - UNRELEASED
|
|||||||
YARN-1337. Recover containers upon nodemanager restart. (Jason Lowe via
|
YARN-1337. Recover containers upon nodemanager restart. (Jason Lowe via
|
||||||
junping_du)
|
junping_du)
|
||||||
|
|
||||||
|
YARN-2277. Added cross-origin support for the timeline server web services.
|
||||||
|
(Jonathan Eagles via zjshen)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
|
|
||||||
YARN-2242. Improve exception information on AM launch crashes. (Li Lu
|
YARN-2242. Improve exception information on AM launch crashes. (Li Lu
|
||||||
|
@ -0,0 +1,220 @@
|
|||||||
|
/**
|
||||||
|
* 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.hadoop.yarn.server.timeline.webapp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
public class CrossOriginFilter implements Filter {
|
||||||
|
|
||||||
|
private static final Log LOG = LogFactory.getLog(CrossOriginFilter.class);
|
||||||
|
|
||||||
|
// HTTP CORS Request Headers
|
||||||
|
static final String ORIGIN = "Origin";
|
||||||
|
static final String ACCESS_CONTROL_REQUEST_METHOD =
|
||||||
|
"Access-Control-Request-Method";
|
||||||
|
static final String ACCESS_CONTROL_REQUEST_HEADERS =
|
||||||
|
"Access-Control-Request-Headers";
|
||||||
|
|
||||||
|
// HTTP CORS Response Headers
|
||||||
|
static final String ACCESS_CONTROL_ALLOW_ORIGIN =
|
||||||
|
"Access-Control-Allow-Origin";
|
||||||
|
static final String ACCESS_CONTROL_ALLOW_CREDENTIALS =
|
||||||
|
"Access-Control-Allow-Credentials";
|
||||||
|
static final String ACCESS_CONTROL_ALLOW_METHODS =
|
||||||
|
"Access-Control-Allow-Methods";
|
||||||
|
static final String ACCESS_CONTROL_ALLOW_HEADERS =
|
||||||
|
"Access-Control-Allow-Headers";
|
||||||
|
static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
|
||||||
|
|
||||||
|
// Filter configuration
|
||||||
|
public static final String ALLOWED_ORIGINS = "allowed-origins";
|
||||||
|
public static final String ALLOWED_ORIGINS_DEFAULT = "*";
|
||||||
|
public static final String ALLOWED_METHODS = "allowed-methods";
|
||||||
|
public static final String ALLOWED_METHODS_DEFAULT = "GET,POST,HEAD";
|
||||||
|
public static final String ALLOWED_HEADERS = "allowed-headers";
|
||||||
|
public static final String ALLOWED_HEADERS_DEFAULT =
|
||||||
|
"X-Requested-With,Content-Type,Accept,Origin";
|
||||||
|
public static final String MAX_AGE = "max-age";
|
||||||
|
public static final String MAX_AGE_DEFAULT = "1800";
|
||||||
|
|
||||||
|
private List<String> allowedMethods = new ArrayList<String>();
|
||||||
|
private List<String> allowedHeaders = new ArrayList<String>();
|
||||||
|
private List<String> allowedOrigins = new ArrayList<String>();
|
||||||
|
private String maxAge;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
initializeAllowedMethods(filterConfig);
|
||||||
|
initializeAllowedHeaders(filterConfig);
|
||||||
|
initializeAllowedOrigins(filterConfig);
|
||||||
|
initializeMaxAge(filterConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest req, ServletResponse res,
|
||||||
|
FilterChain chain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
doCrossFilter((HttpServletRequest) req, (HttpServletResponse) res);
|
||||||
|
chain.doFilter(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
allowedMethods.clear();
|
||||||
|
allowedHeaders.clear();
|
||||||
|
allowedOrigins.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doCrossFilter(HttpServletRequest req, HttpServletResponse res) {
|
||||||
|
|
||||||
|
String origin = encodeHeader(req.getHeader(ORIGIN));
|
||||||
|
if (!isCrossOrigin(origin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOriginAllowed(origin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String accessControlRequestMethod =
|
||||||
|
req.getHeader(ACCESS_CONTROL_REQUEST_METHOD);
|
||||||
|
if (!isMethodAllowed(accessControlRequestMethod)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String accessControlRequestHeaders =
|
||||||
|
req.getHeader(ACCESS_CONTROL_REQUEST_HEADERS);
|
||||||
|
if (!areHeadersAllowed(accessControlRequestHeaders)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||||
|
res.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.TRUE.toString());
|
||||||
|
res.setHeader(ACCESS_CONTROL_ALLOW_METHODS, getAllowedMethodsHeader());
|
||||||
|
res.setHeader(ACCESS_CONTROL_ALLOW_HEADERS, getAllowedHeadersHeader());
|
||||||
|
res.setHeader(ACCESS_CONTROL_MAX_AGE, maxAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
String getAllowedHeadersHeader() {
|
||||||
|
return StringUtils.join(allowedHeaders, ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
String getAllowedMethodsHeader() {
|
||||||
|
return StringUtils.join(allowedMethods, ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeAllowedMethods(FilterConfig filterConfig) {
|
||||||
|
String allowedMethodsConfig =
|
||||||
|
filterConfig.getInitParameter(ALLOWED_METHODS);
|
||||||
|
if (allowedMethodsConfig == null) {
|
||||||
|
allowedMethodsConfig = ALLOWED_METHODS_DEFAULT;
|
||||||
|
}
|
||||||
|
allowedMethods =
|
||||||
|
Arrays.asList(allowedMethodsConfig.trim().split("\\s*,\\s*"));
|
||||||
|
LOG.info("Allowed Methods: " + getAllowedMethodsHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeAllowedHeaders(FilterConfig filterConfig) {
|
||||||
|
String allowedHeadersConfig =
|
||||||
|
filterConfig.getInitParameter(ALLOWED_HEADERS);
|
||||||
|
if (allowedHeadersConfig == null) {
|
||||||
|
allowedHeadersConfig = ALLOWED_HEADERS_DEFAULT;
|
||||||
|
}
|
||||||
|
allowedHeaders =
|
||||||
|
Arrays.asList(allowedHeadersConfig.trim().split("\\s*,\\s*"));
|
||||||
|
LOG.info("Allowed Headers: " + getAllowedHeadersHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeAllowedOrigins(FilterConfig filterConfig) {
|
||||||
|
String allowedOriginsConfig =
|
||||||
|
filterConfig.getInitParameter(ALLOWED_ORIGINS);
|
||||||
|
if (allowedOriginsConfig == null) {
|
||||||
|
allowedOriginsConfig = ALLOWED_ORIGINS_DEFAULT;
|
||||||
|
}
|
||||||
|
allowedOrigins =
|
||||||
|
Arrays.asList(allowedOriginsConfig.trim().split("\\s*,\\s*"));
|
||||||
|
LOG.info("Allowed Origins: " + StringUtils.join(allowedOrigins, ','));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMaxAge(FilterConfig filterConfig) {
|
||||||
|
maxAge = filterConfig.getInitParameter(MAX_AGE);
|
||||||
|
if (maxAge == null) {
|
||||||
|
maxAge = MAX_AGE_DEFAULT;
|
||||||
|
}
|
||||||
|
LOG.info("Max Age: " + maxAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String encodeHeader(final String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Protect against HTTP response splitting vulnerability
|
||||||
|
// since value is written as part of the response header
|
||||||
|
return URLEncoder.encode(header, "ASCII");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isCrossOrigin(String origin) {
|
||||||
|
return origin != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOriginAllowed(String origin) {
|
||||||
|
return allowedOrigins.contains(origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areHeadersAllowed(String accessControlRequestHeaders) {
|
||||||
|
if (accessControlRequestHeaders == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String headers[] = accessControlRequestHeaders.trim().split("\\s*,\\s*");
|
||||||
|
return allowedHeaders.containsAll(Arrays.asList(headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMethodAllowed(String accessControlRequestMethod) {
|
||||||
|
if (accessControlRequestMethod == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return allowedMethods.contains(accessControlRequestMethod);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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.hadoop.yarn.server.timeline.webapp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.http.FilterContainer;
|
||||||
|
import org.apache.hadoop.http.FilterInitializer;
|
||||||
|
|
||||||
|
public class CrossOriginFilterInitializer extends FilterInitializer {
|
||||||
|
|
||||||
|
public static final String PREFIX =
|
||||||
|
"yarn.timeline-service.http-cross-origin.";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initFilter(FilterContainer container, Configuration conf) {
|
||||||
|
|
||||||
|
container.addGlobalFilter("Cross Origin Filter",
|
||||||
|
CrossOriginFilter.class.getName(), getFilterParameters(conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, String> getFilterParameters(Configuration conf) {
|
||||||
|
return conf.getValByRegex(PREFIX);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,214 @@
|
|||||||
|
/**
|
||||||
|
* 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.hadoop.yarn.server.timeline.webapp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
|
||||||
|
public class TestCrossOriginFilter {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSameOrigin() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Setup the configuration settings of the server
|
||||||
|
Map<String, String> conf = new HashMap<String, String>();
|
||||||
|
conf.put(CrossOriginFilter.ALLOWED_ORIGINS, "");
|
||||||
|
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||||
|
|
||||||
|
// Origin is not specified for same origin requests
|
||||||
|
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn(null);
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||||
|
FilterChain mockChain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
CrossOriginFilter filter = new CrossOriginFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
verifyZeroInteractions(mockRes);
|
||||||
|
verify(mockChain).doFilter(mockReq, mockRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowedOrigin() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Setup the configuration settings of the server
|
||||||
|
Map<String, String> conf = new HashMap<String, String>();
|
||||||
|
conf.put(CrossOriginFilter.ALLOWED_ORIGINS, "example.com");
|
||||||
|
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||||
|
|
||||||
|
// Origin is not specified for same origin requests
|
||||||
|
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.org");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||||
|
FilterChain mockChain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
CrossOriginFilter filter = new CrossOriginFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
verifyZeroInteractions(mockRes);
|
||||||
|
verify(mockChain).doFilter(mockReq, mockRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowedMethod() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Setup the configuration settings of the server
|
||||||
|
Map<String, String> conf = new HashMap<String, String>();
|
||||||
|
conf.put(CrossOriginFilter.ALLOWED_ORIGINS, "example.com");
|
||||||
|
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||||
|
|
||||||
|
// Origin is not specified for same origin requests
|
||||||
|
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||||
|
.thenReturn("DISALLOWED_METHOD");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||||
|
FilterChain mockChain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
CrossOriginFilter filter = new CrossOriginFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
verifyZeroInteractions(mockRes);
|
||||||
|
verify(mockChain).doFilter(mockReq, mockRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowedHeader() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Setup the configuration settings of the server
|
||||||
|
Map<String, String> conf = new HashMap<String, String>();
|
||||||
|
conf.put(CrossOriginFilter.ALLOWED_ORIGINS, "example.com");
|
||||||
|
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||||
|
|
||||||
|
// Origin is not specified for same origin requests
|
||||||
|
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||||
|
.thenReturn("GET");
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||||
|
.thenReturn("Disallowed-Header");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||||
|
FilterChain mockChain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
CrossOriginFilter filter = new CrossOriginFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
verifyZeroInteractions(mockRes);
|
||||||
|
verify(mockChain).doFilter(mockReq, mockRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrossOriginFilter() throws ServletException, IOException {
|
||||||
|
|
||||||
|
// Setup the configuration settings of the server
|
||||||
|
Map<String, String> conf = new HashMap<String, String>();
|
||||||
|
conf.put(CrossOriginFilter.ALLOWED_ORIGINS, "example.com");
|
||||||
|
FilterConfig filterConfig = new FilterConfigTest(conf);
|
||||||
|
|
||||||
|
// Origin is not specified for same origin requests
|
||||||
|
HttpServletRequest mockReq = mock(HttpServletRequest.class);
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ORIGIN)).thenReturn("example.com");
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD))
|
||||||
|
.thenReturn("GET");
|
||||||
|
when(mockReq.getHeader(CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS))
|
||||||
|
.thenReturn("X-Requested-With");
|
||||||
|
|
||||||
|
// Objects to verify interactions based on request
|
||||||
|
HttpServletResponse mockRes = mock(HttpServletResponse.class);
|
||||||
|
FilterChain mockChain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
// Object under test
|
||||||
|
CrossOriginFilter filter = new CrossOriginFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
filter.doFilter(mockReq, mockRes, mockChain);
|
||||||
|
|
||||||
|
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||||
|
"example.com");
|
||||||
|
verify(mockRes).setHeader(
|
||||||
|
CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS,
|
||||||
|
Boolean.TRUE.toString());
|
||||||
|
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS,
|
||||||
|
filter.getAllowedMethodsHeader());
|
||||||
|
verify(mockRes).setHeader(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS,
|
||||||
|
filter.getAllowedHeadersHeader());
|
||||||
|
verify(mockChain).doFilter(mockReq, mockRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FilterConfigTest implements FilterConfig {
|
||||||
|
|
||||||
|
final Map<String, String> map;
|
||||||
|
|
||||||
|
FilterConfigTest(Map<String, String> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFilterName() {
|
||||||
|
return "test-filter";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInitParameter(String key) {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getInitParameterNames() {
|
||||||
|
return Collections.enumeration(map.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletContext getServletContext() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* 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.hadoop.yarn.server.timeline.webapp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TestCrossOriginFilterInitializer {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFilterParameters() {
|
||||||
|
|
||||||
|
// Initialize configuration object
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set(CrossOriginFilterInitializer.PREFIX + "rootparam", "rootvalue");
|
||||||
|
conf.set(CrossOriginFilterInitializer.PREFIX + "nested.param",
|
||||||
|
"nestedvalue");
|
||||||
|
conf.set("outofscopeparam", "outofscopevalue");
|
||||||
|
|
||||||
|
// call function under test
|
||||||
|
Map<String, String> filterParameters =
|
||||||
|
CrossOriginFilterInitializer.getFilterParameters(conf);
|
||||||
|
|
||||||
|
// retrieve values
|
||||||
|
String rootvalue =
|
||||||
|
filterParameters.get(CrossOriginFilterInitializer.PREFIX + "rootparam");
|
||||||
|
String nestedvalue =
|
||||||
|
filterParameters.get(CrossOriginFilterInitializer.PREFIX
|
||||||
|
+ "nested.param");
|
||||||
|
String outofscopeparam = filterParameters.get("outofscopeparam");
|
||||||
|
|
||||||
|
// verify expected values are in place
|
||||||
|
Assert.assertEquals("Could not find filter parameter", "rootvalue",
|
||||||
|
rootvalue);
|
||||||
|
Assert.assertEquals("Could not find filter parameter", "nestedvalue",
|
||||||
|
nestedvalue);
|
||||||
|
Assert.assertNull("Found unexpected value in filter parameters",
|
||||||
|
outofscopeparam);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user