From 3574e5692da6da9b0eb9fbee66ef197ffbf1d1cd Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Fri, 14 Oct 2016 22:10:15 -0700 Subject: [PATCH] HADOOP-13707. Skip authorization for anonymous user to access Hadoop web interface in non-secure environment. (Yuanbo Liu via eyang) --- .../org/apache/hadoop/conf/ConfServlet.java | 8 ++++- .../hadoop/http/AdminAuthorizedServlet.java | 11 +++++-- .../org/apache/hadoop/http/HttpServer2.java | 31 +++++++++++++++++-- .../org/apache/hadoop/jmx/JMXJsonServlet.java | 8 ++++- .../java/org/apache/hadoop/log/LogLevel.java | 10 ++++-- .../apache/hadoop/http/TestHttpServer.java | 17 +++++++++- 6 files changed, 73 insertions(+), 12 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/ConfServlet.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/ConfServlet.java index c7f11b38dbd..d4b34e948a0 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/ConfServlet.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/ConfServlet.java @@ -20,6 +20,7 @@ package org.apache.hadoop.conf; import java.io.IOException; import java.io.Writer; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -56,7 +57,12 @@ public class ConfServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (!HttpServer2.isInstrumentationAccessAllowed(getServletContext(), + // If user is a static user and auth Type is null, that means + // there is a non-security environment and no need authorization, + // otherwise, do the authorization. + final ServletContext servletContext = getServletContext(); + if (!HttpServer2.isStaticUserAndNoneAuthType(servletContext, request) && + !HttpServer2.isInstrumentationAccessAllowed(servletContext, request, response)) { return; } diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/AdminAuthorizedServlet.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/AdminAuthorizedServlet.java index ef562b41e6e..e591ab4faf6 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/AdminAuthorizedServlet.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/AdminAuthorizedServlet.java @@ -19,6 +19,7 @@ package org.apache.hadoop.http; import java.io.IOException; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -35,9 +36,13 @@ public class AdminAuthorizedServlet extends DefaultServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - // Do the authorization - if (HttpServer2.hasAdministratorAccess(getServletContext(), request, + throws ServletException, IOException { + // If user is a static user and auth Type is null, that means + // there is a non-security environment and no need authorization, + // otherwise, do the authorization. + final ServletContext servletContext = getServletContext(); + if (HttpServer2.isStaticUserAndNoneAuthType(servletContext, request) || + HttpServer2.hasAdministratorAccess(servletContext, request, response)) { // Authorization is done. Just call super. super.doGet(request, response); diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java index 4b1e6ab022c..d498d7f9aaa 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java @@ -94,6 +94,8 @@ import org.mortbay.util.MultiException; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.sun.jersey.spi.container.servlet.ServletContainer; +import static org.apache.hadoop.fs.CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER; +import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER; /** * Create a Jetty embedded server to answer http requests. The primary goal is @@ -1080,6 +1082,24 @@ public final class HttpServer2 implements FilterContainer { return sb.toString(); } + /** + * check whether user is static and unauthenticated, if the + * answer is TRUE, that means http sever is in non-security + * environment. + * @param servletContext the servlet context. + * @param request the servlet request. + * @return TRUE/FALSE based on the logic described above. + */ + public static boolean isStaticUserAndNoneAuthType( + ServletContext servletContext, HttpServletRequest request) { + Configuration conf = + (Configuration) servletContext.getAttribute(CONF_CONTEXT_ATTRIBUTE); + final String authType = request.getAuthType(); + final String staticUser = conf.get(HADOOP_HTTP_STATIC_USER, + DEFAULT_HADOOP_HTTP_STATIC_USER); + return authType == null && staticUser.equals(request.getRemoteUser()); + } + /** * Checks the user has privileges to access to instrumentation servlets. *

@@ -1177,9 +1197,14 @@ public final class HttpServer2 implements FilterContainer { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - if (!HttpServer2.isInstrumentationAccessAllowed(getServletContext(), - request, response)) { + throws ServletException, IOException { + // If user is a static user and auth Type is null, that means + // there is a non-security environment and no need authorization, + // otherwise, do the authorization. + final ServletContext servletContext = getServletContext(); + if (!HttpServer2.isStaticUserAndNoneAuthType(servletContext, request) && + !HttpServer2.isInstrumentationAccessAllowed(servletContext, + request, response)) { return; } response.setContentType("text/plain; charset=UTF-8"); diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/jmx/JMXJsonServlet.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/jmx/JMXJsonServlet.java index f59b64c616b..6546c05c002 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/jmx/JMXJsonServlet.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/jmx/JMXJsonServlet.java @@ -38,6 +38,7 @@ import javax.management.RuntimeMBeanException; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeType; import javax.management.openmbean.TabularData; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -166,7 +167,12 @@ public class JMXJsonServlet extends HttpServlet { String jsonpcb = null; PrintWriter writer = null; try { - if (!isInstrumentationAccessAllowed(request, response)) { + // If user is a static user and auth Type is null, that means + // there is a non-security environment and no need authorization, + // otherwise, do the authorization. + final ServletContext servletContext = getServletContext(); + if (!HttpServer2.isStaticUserAndNoneAuthType(servletContext, request) && + !isInstrumentationAccessAllowed(request, response)) { return; } diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/log/LogLevel.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/log/LogLevel.java index 11326ca01bc..bc03a6aa08c 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/log/LogLevel.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/log/LogLevel.java @@ -93,9 +93,13 @@ public class LogLevel { public void doGet(HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { - // Do the authorization - if (!HttpServer2.hasAdministratorAccess(getServletContext(), request, - response)) { + // If user is a static user and auth Type is null, that means + // there is a non-security environment and no need authorization, + // otherwise, do the authorization. + final ServletContext servletContext = getServletContext(); + if (!HttpServer2.isStaticUserAndNoneAuthType(servletContext, request) && + !HttpServer2.hasAdministratorAccess(servletContext, + request, response)) { return; } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java index d85935bd815..e71ceea38d3 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServer.java @@ -66,6 +66,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import static org.apache.hadoop.fs.CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER; +import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER; + public class TestHttpServer extends HttpServerFunctionalTest { static final Log LOG = LogFactory.getLog(TestHttpServer.class); private static HttpServer2 server; @@ -453,7 +456,7 @@ public class TestHttpServer extends HttpServerFunctionalTest { String serverURL = "http://" + NetUtils.getHostPortString(myServer.getConnectorAddress(0)) + "/"; for (String servlet : new String[] { "conf", "logs", "stacks", - "logLevel", "metrics" }) { + "logLevel", "metrics", "jmx" }) { for (String user : new String[] { "userA", "userB", "userC", "userD" }) { assertEquals(HttpURLConnection.HTTP_OK, getHttpStatusCode(serverURL + servlet, user)); @@ -461,6 +464,18 @@ public class TestHttpServer extends HttpServerFunctionalTest { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, getHttpStatusCode( serverURL + servlet, "userE")); } + + // hadoop.security.authorization is set as true while + // hadoop.http.authentication.type's value is `simple`(default value) + // in this case, static user has administrator access + final String staticUser = conf.get(HADOOP_HTTP_STATIC_USER, + DEFAULT_HADOOP_HTTP_STATIC_USER); + for (String servlet : new String[] {"conf", "logs", "stacks", + "logLevel", "jmx"}) { + assertEquals(HttpURLConnection.HTTP_OK, getHttpStatusCode( + serverURL + servlet, staticUser)); + } + myServer.stop(); }