From add3b30aa1360c93a2b028701c1c3ed317e728db Mon Sep 17 00:00:00 2001 From: Sunil G Date: Tue, 5 Jun 2018 08:18:22 +0530 Subject: [PATCH] YARN-8258 --- .../org/apache/hadoop/yarn/webapp/WebApps.java | 59 +++++++--- .../yarn/server/resourcemanager/TestWebApps.java | 127 +++++++++++++++++++++ 2 files changed, 170 insertions(+), 16 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestWebApps.java diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java index 73644452140..003a93081b7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/WebApps.java @@ -44,6 +44,8 @@ import org.apache.hadoop.security.http.XFrameOptionsFilter; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.webapp.WebAppContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -424,7 +426,7 @@ public WebApp start(WebApp webapp, WebAppContext ui2Context) { WebApp webApp = build(webapp); HttpServer2 httpServer = webApp.httpServer(); if (ui2Context != null) { - addFiltersForNewContext(ui2Context); + addFiltersForUI2Context(ui2Context, httpServer); httpServer.addHandlerAtFront(ui2Context); } try { @@ -437,24 +439,49 @@ public WebApp start(WebApp webapp, WebAppContext ui2Context) { return webApp; } - private void addFiltersForNewContext(WebAppContext ui2Context) { - Map params = getConfigParameters(csrfConfigPrefix); - - if (hasCSRFEnabled(params)) { - LOG.info("CSRF Protection has been enabled for the {} application. " - + "Please ensure that there is an authentication mechanism " - + "enabled (kerberos, custom, etc).", name); - String restCsrfClassName = RestCsrfPreventionFilter.class.getName(); - HttpServer2.defineFilter(ui2Context, restCsrfClassName, - restCsrfClassName, params, new String[]{"/*"}); + private void addFiltersForUI2Context(WebAppContext ui2Context, + HttpServer2 httpServer) { + // Get filters and filtermappings from default context's servlet. + FilterHolder[] filterHolders = httpServer.getWebAppContext() + .getServletHandler().getFilters(); + FilterMapping[] filterMappingsArray = httpServer.getWebAppContext() + .getServletHandler().getFilterMappings(); + + // To define a filter for UI2 context, URL path also needed which is + // available only FilterMapping. Hence convert this to a map for easy + // access. + Map filterMappings = new HashMap<>(); + for (FilterMapping filterMapping : filterMappingsArray) { + filterMappings.put(filterMapping.getFilterName(), filterMapping); } - params = getConfigParameters(xfsConfigPrefix); + // Loop through all filterHolders and add one by one to UI2. + LOG.info("Add filters from default webapp context to UI2 context."); + for (FilterHolder filterHolder : filterHolders) { + // Skip guice filter for UI2. + if ("guice".equals(filterHolder.getName())) { + continue; + } + // Get the path spec from filtermapping for same filter name. + String[] pathSpecs = filterMappings.get(filterHolder.getName()) + .getPathSpecs(); + + // In case of Auth filter, also add "/*" so that all URLs under ui2 + // will be applicable for custom auth handler's like JWT (sso). + if ("authentication".equals(filterHolder.getName())) { + ArrayList paths = new ArrayList<>(); + paths.add("/*"); + HttpServer2.defineFilter(ui2Context, filterHolder.getName(), + filterHolder.getClassName(), filterHolder.getInitParameters(), + paths.toArray(new String[paths.size()])); + } else { + HttpServer2.defineFilter(ui2Context, filterHolder.getName(), + filterHolder.getClassName(), filterHolder.getInitParameters(), + pathSpecs); + } - if (hasXFSEnabled()) { - String xfsClassName = XFrameOptionsFilter.class.getName(); - HttpServer2.defineFilter(ui2Context, xfsClassName, xfsClassName, params, - new String[]{"/*"}); + LOG.info("UI2 context filter Name:" + filterHolder.getName() + + ", className=" + filterHolder.getClassName()); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestWebApps.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestWebApps.java new file mode 100644 index 00000000000..8bf7495d505 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestWebApps.java @@ -0,0 +1,127 @@ +/** + * 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.resourcemanager; + +import java.io.File; + +import static org.junit.Assert.assertTrue; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.CommonConfigurationKeysPublic; +import org.apache.hadoop.http.HttpServer2; +import org.apache.hadoop.minikdc.MiniKdc; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authentication.KerberosTestUtils; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.security.http.RMAuthenticationFilterInitializer; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test TestWebApps. + * + */ +public class TestWebApps { + + private static final File TEST_ROOT_DIR = new File("target", + TestWebApps.class.getName() + "-root"); + private static File httpSpnegoKeytabFile = new File( + KerberosTestUtils.getKeytabFile()); + private static String httpSpnegoPrincipal = KerberosTestUtils + .getServerPrincipal(); + private static boolean miniKDCStarted = false; + private static MiniKdc testMiniKDC; + private static MockRM rm; + + @BeforeClass + public static void setUp() { + try { + testMiniKDC = new MiniKdc(MiniKdc.createConf(), TEST_ROOT_DIR); + setupKDC(); + } catch (Exception e) { + assertTrue("Couldn't create MiniKDC:" + e.getMessage(), false); + } + setupAndStartRM(); + } + + private static void setupAndStartRM() { + Configuration rmconf = new Configuration(); + rmconf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); + rmconf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, + "kerberos"); + rmconf.setBoolean(YarnConfiguration.RM_WEBAPP_DELEGATION_TOKEN_AUTH_FILTER, + true); + rmconf.set("hadoop.http.filter.initializers", + RMAuthenticationFilterInitializer.class.getName()); + rmconf.set(YarnConfiguration.RM_WEBAPP_SPNEGO_USER_NAME_KEY, + httpSpnegoPrincipal); + rmconf.set(YarnConfiguration.RM_KEYTAB, + httpSpnegoKeytabFile.getAbsolutePath()); + rmconf.set(YarnConfiguration.RM_WEBAPP_SPNEGO_KEYTAB_FILE_KEY, + httpSpnegoKeytabFile.getAbsolutePath()); + + rmconf.setBoolean(MockRM.ENABLE_WEBAPP, true); + UserGroupInformation.setConfiguration(rmconf); + rm = new MockRM(rmconf); + rm.start(); + } + + @AfterClass + public static void tearDown() { + if (testMiniKDC != null) { + testMiniKDC.stop(); + } + if (rm != null) { + rm.stop(); + } + } + + private static void setupKDC() throws Exception { + if (!miniKDCStarted) { + testMiniKDC.start(); + getKdc().createPrincipal(httpSpnegoKeytabFile, "HTTP/localhost", + UserGroupInformation.getLoginUser().getShortUserName()); + miniKDCStarted = true; + } + } + + private static MiniKdc getKdc() { + return testMiniKDC; + } + + @Test + public void testWebAppInitializersOrdering() throws Exception { + String[] filterNamesArray = {"NoCacheFilter", "safety", + "RMAuthenticationFilter", "SpnegoFilter", + "org.apache.hadoop.security.http.XFrameOptionsFilter", "guice"}; + + HttpServer2 server = rm.getWebapp().httpServer(); + WebAppContext context = server.getWebAppContext(); + FilterHolder[] filterHolders = context.getServletHandler().getFilters(); + Assert.assertEquals(filterHolders.length, 6); + for (int index = 0; index < filterHolders.length; index++) { + Assert.assertTrue( + filterHolders[index].getName().equals(filterNamesArray[index])); + } + } +} -- 2.14.3 (Apple Git-98)