YARN-10833. Set the X-FRAME-OPTIONS header for the default contexts. (#3203)

* YARN-10833. Set the X-FRAME-OPTIONS header for the default contexts.

* fixup: YARN-10833. Set the X-FRAME-OPTIONS header for the default contexts.

Co-authored-by: Benjamin Teke <bteke@cloudera.com>
This commit is contained in:
Benjamin Teke 2021-07-24 05:44:21 +02:00 committed by GitHub
parent 63dfd84947
commit 05b6a1a06a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 112 deletions

View File

@ -41,7 +41,6 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.security.http.RestCsrfPreventionFilter;
import org.apache.hadoop.security.http.XFrameOptionsFilter;
import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
@ -325,6 +324,19 @@ public void setup() {
YarnConfiguration.YARN_ADMIN_ACL,
YarnConfiguration.DEFAULT_YARN_ADMIN_ACL)))
.setPathSpec(pathList.toArray(new String[0]));
// Set the X-FRAME-OPTIONS header, use the HttpServer2 default if
// the header value is not specified
Map<String, String> xfsParameters =
getConfigParameters(xfsConfigPrefix);
if (xfsParameters != null) {
String xFrameOptions = xfsParameters.get("xframe-options");
if (xFrameOptions != null) {
builder.configureXFrame(hasXFSEnabled())
.setXFrameOption(xFrameOptions);
}
}
// Get port ranges from config.
IntegerRanges ranges = null;
if (portRangeConfigKey != null) {
@ -395,15 +407,6 @@ public void setup() {
new String[] {"/*"});
}
params = getConfigParameters(xfsConfigPrefix);
if (hasXFSEnabled()) {
String xfsClassName = XFrameOptionsFilter.class.getName();
HttpServer2.defineFilter(server.getWebAppContext(), xfsClassName,
xfsClassName, params,
new String[] {"/*"});
}
HttpServer2.defineFilter(server.getWebAppContext(), "guice",
GuiceFilter.class.getName(), null, new String[] { "/*" });
@ -489,14 +492,6 @@ private void addFiltersForNewContext(WebAppContext ui2Context) {
HttpServer2.defineFilter(ui2Context, restCsrfClassName,
restCsrfClassName, params, new String[]{"/*"});
}
params = getConfigParameters(xfsConfigPrefix);
if (hasXFSEnabled()) {
String xfsClassName = XFrameOptionsFilter.class.getName();
HttpServer2.defineFilter(ui2Context, xfsClassName, xfsClassName, params,
new String[]{"/*"});
}
}
private String inferHostClass() {

View File

@ -18,126 +18,97 @@
package org.apache.hadoop.yarn.webapp;
import com.google.inject.Guice;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import com.sun.jersey.test.framework.WebAppDescriptor;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.http.XFrameOptionsFilter;
import org.apache.hadoop.http.HttpServer2;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.JAXBContextResolver;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebServices;
import org.junit.Before;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Used TestRMWebServices as an example of web invocations of RM and added
* test for XFS Filter.
*/
public class TestRMWithXFSFilter extends JerseyTestBase {
public class TestRMWithXFSFilter {
private static MockRM rm;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
}
public TestRMWithXFSFilter() {
super(new WebAppDescriptor.Builder(
"org.apache.hadoop.yarn.server.resourcemanager.webapp")
.contextListenerClass(GuiceServletConfig.class)
.filterClass(com.google.inject.servlet.GuiceFilter.class)
.contextPath("jersey-guice-filter").servletPath("/").build());
private void createMockRm(final Boolean xfsEnabled,
final String xfsHeaderValue) {
Configuration conf = new Configuration();
conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class,
ResourceScheduler.class);
conf.setBoolean("mockrm.webapp.enabled", true);
if (xfsEnabled != null) {
conf.setBoolean(YarnConfiguration.YARN_XFS_ENABLED, xfsEnabled);
}
if (xfsHeaderValue != null) {
conf.setStrings(YarnConfiguration.RM_XFS_OPTIONS, xfsHeaderValue);
}
rm = new MockRM(conf);
rm.start();
}
@Test
public void testDefaultBehavior() throws Exception {
createInjector();
public void testXFrameOptionsDefaultBehaviour() throws Exception {
createMockRm(null, null);
WebResource r = resource();
ClientResponse response = r.path("ws").path("v1").path("cluster")
.path("info").accept("application/xml")
.get(ClientResponse.class);
assertEquals("Should have received DENY x-frame options header",
"DENY",
response.getHeaders().get(XFrameOptionsFilter.X_FRAME_OPTIONS).get(0));
}
protected void createInjector(String headerValue) {
createInjector(headerValue, false);
}
protected void createInjector() {
createInjector(null, false);
}
protected void createInjector(final String headerValue,
final boolean explicitlyDisabled) {
GuiceServletConfig.setInjector(Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(JAXBContextResolver.class);
bind(RMWebServices.class);
bind(GenericExceptionHandler.class);
Configuration conf = new Configuration();
conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class,
ResourceScheduler.class);
rm = new MockRM(conf);
bind(ResourceManager.class).toInstance(rm);
serve("/*").with(GuiceContainer.class);
XFrameOptionsFilter xfsFilter = new XFrameOptionsFilter();
Map<String, String> initParams = new HashMap<>();
if (headerValue != null) {
initParams.put(XFrameOptionsFilter.CUSTOM_HEADER_PARAM, headerValue);
}
if (explicitlyDisabled) {
initParams.put(
"xframe-options-enabled", "false");
}
filter("/*").through(xfsFilter, initParams);
}
}));
URL url = new URL("http://localhost:8088/ws/v1/cluster/info");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
Assert.assertTrue(xfoHeader.endsWith(HttpServer2.XFrameOption
.SAMEORIGIN.toString()));
}
@Test
public void testSameOrigin() throws Exception {
createInjector("SAMEORIGIN");
public void testXFrameOptionsExplicitlyEnabled() throws Exception {
createMockRm(true, HttpServer2.XFrameOption
.SAMEORIGIN.toString());
WebResource r = resource();
ClientResponse response = r.path("ws").path("v1").path("cluster")
.path("info").accept("application/xml")
.get(ClientResponse.class);
assertEquals("Should have received SAMEORIGIN x-frame options header",
"SAMEORIGIN",
response.getHeaders().get(XFrameOptionsFilter.X_FRAME_OPTIONS).get(0));
URL url = new URL("http://localhost:8088/ws/v1/cluster/info");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
Assert.assertTrue(xfoHeader.endsWith(HttpServer2.XFrameOption
.SAMEORIGIN.toString()));
}
@Test
public void testExplicitlyDisabled() throws Exception {
createInjector(null, true);
public void testXFrameOptionsEnabledDefaultApps() throws Exception {
createMockRm(true, HttpServer2.XFrameOption
.SAMEORIGIN.toString());
WebResource r = resource();
ClientResponse response = r.path("ws").path("v1").path("cluster")
.path("info").accept("application/xml")
.get(ClientResponse.class);
assertFalse("Should have not received x-frame options header",
response.getHeaders().get(XFrameOptionsFilter.X_FRAME_OPTIONS) == null);
URL url = new URL("http://localhost:8088/logs");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
Assert.assertTrue(xfoHeader.endsWith(HttpServer2.XFrameOption
.SAMEORIGIN.toString()));
}
@Test
public void testXFrameOptionsDisabled() throws Exception {
createMockRm(false, null);
URL url = new URL("http://localhost:8088/ws/v1/cluster/info");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
String xfoHeader = conn.getHeaderField("X-FRAME-OPTIONS");
Assert.assertNull("Unexpected X-FRAME-OPTION in header", xfoHeader);
}
@Test
public void testXFrameOptionsIllegalOption() {
IllegalArgumentException e = Assert.assertThrows(
IllegalArgumentException.class,
() -> createMockRm(true, "otherValue"));
}
@After
public void tearDown() throws IOException {
rm.close();
}
}