Merge -r 1333749:1333750 from trunk to branch. FIXES: HADOOP-8343
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1333752 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9a04fc6caf
commit
d828c4ffeb
|
@ -30,6 +30,9 @@ Release 2.0.0 - UNRELEASED
|
|||
HADOOP-8210. Common side of HDFS-3148: The client should be able
|
||||
to use multiple local interfaces for data transfer. (eli)
|
||||
|
||||
HADOOP-8343. Allow configuration of authorization for JmxJsonServlet and
|
||||
MetricsServlet (tucu)
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
HADOOP-7524. Change RPC to allow multiple protocols including multuple
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package org.apache.hadoop.conf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -57,9 +56,8 @@ public class ConfServlet extends HttpServlet {
|
|||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
// Do the authorization
|
||||
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
|
||||
response)) {
|
||||
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
|
||||
request, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,6 +228,9 @@ public class CommonConfigurationKeysPublic {
|
|||
public static final String HADOOP_SECURITY_AUTHORIZATION =
|
||||
"hadoop.security.authorization";
|
||||
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
|
||||
public static final String HADOOP_SECURITY_INSTRUMENTATION_REQUIRES_ADMIN =
|
||||
"hadoop.security.instrumentation.requires.admin";
|
||||
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
|
||||
public static final String HADOOP_SECURITY_SERVICE_USER_NAME_KEY =
|
||||
"hadoop.security.service.user.name.key";
|
||||
}
|
||||
|
|
|
@ -731,6 +731,37 @@ public class HttpServer implements FilterContainer {
|
|||
: "Inactive HttpServer";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the user has privileges to access to instrumentation servlets.
|
||||
* <p/>
|
||||
* If <code>hadoop.security.instrumentation.requires.admin</code> is set to FALSE
|
||||
* (default value) it always returns TRUE.
|
||||
* <p/>
|
||||
* If <code>hadoop.security.instrumentation.requires.admin</code> is set to TRUE
|
||||
* it will check that if the current user is in the admin ACLS. If the user is
|
||||
* in the admin ACLs it returns TRUE, otherwise it returns FALSE.
|
||||
*
|
||||
* @param servletContext the servlet context.
|
||||
* @param request the servlet request.
|
||||
* @param response the servlet response.
|
||||
* @return TRUE/FALSE based on the logic decribed above.
|
||||
*/
|
||||
public static boolean isInstrumentationAccessAllowed(
|
||||
ServletContext servletContext, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
Configuration conf =
|
||||
(Configuration) servletContext.getAttribute(CONF_CONTEXT_ATTRIBUTE);
|
||||
|
||||
boolean access = true;
|
||||
boolean adminAccess = conf.getBoolean(
|
||||
CommonConfigurationKeys.HADOOP_SECURITY_INSTRUMENTATION_REQUIRES_ADMIN,
|
||||
false);
|
||||
if (adminAccess) {
|
||||
access = hasAdministratorAccess(servletContext, request, response);
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the user sending the HttpServletRequest has the administrator ACLs? If
|
||||
* it isn't the case, response will be modified to send an error to the user.
|
||||
|
@ -746,7 +777,6 @@ public class HttpServer implements FilterContainer {
|
|||
HttpServletResponse response) throws IOException {
|
||||
Configuration conf =
|
||||
(Configuration) servletContext.getAttribute(CONF_CONTEXT_ATTRIBUTE);
|
||||
|
||||
// If there is no authorization, anybody has administrator access.
|
||||
if (!conf.getBoolean(
|
||||
CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, false)) {
|
||||
|
@ -786,12 +816,11 @@ public class HttpServer implements FilterContainer {
|
|||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
// Do the authorization
|
||||
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
|
||||
response)) {
|
||||
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
|
||||
request, response)) {
|
||||
return;
|
||||
}
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
ReflectionUtils.printThreadInfo(out, "");
|
||||
out.close();
|
||||
|
|
|
@ -145,9 +145,8 @@ public class JMXJsonServlet extends HttpServlet {
|
|||
@Override
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
try {
|
||||
// Do the authorization
|
||||
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
|
||||
response)) {
|
||||
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
|
||||
request, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,9 +106,8 @@ public class MetricsServlet extends HttpServlet {
|
|||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
// Do the authorization
|
||||
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
|
||||
response)) {
|
||||
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
|
||||
request, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,15 @@
|
|||
<description>Is service-level authorization enabled?</description>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<name>hadoop.security.instrumentation.requires.admin</name>
|
||||
<value>false</value>
|
||||
<description>
|
||||
Indicates if administrator ACLs are required to access
|
||||
instrumentation servlets (JMX, METRICS, CONF, STACKS).
|
||||
</description>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<name>hadoop.security.authentication</name>
|
||||
<value>simple</value>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.apache.hadoop.http;
|
||||
|
||||
import org.apache.hadoop.security.authorize.AccessControlList;
|
||||
import org.junit.Assert;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
|
||||
|
@ -70,6 +71,12 @@ public class HttpServerFunctionalTest extends Assert {
|
|||
return createServer(TEST, conf);
|
||||
}
|
||||
|
||||
public static HttpServer createTestServer(Configuration conf, AccessControlList adminsAcl)
|
||||
throws IOException {
|
||||
prepareTestWebapp();
|
||||
return createServer(TEST, conf, adminsAcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create but do not start the test webapp server. The test webapp dir is
|
||||
* prepared/checked in advance.
|
||||
|
@ -132,6 +139,11 @@ public class HttpServerFunctionalTest extends Assert {
|
|||
throws IOException {
|
||||
return new HttpServer(webapp, "0.0.0.0", 0, true, conf);
|
||||
}
|
||||
|
||||
public static HttpServer createServer(String webapp, Configuration conf, AccessControlList adminsAcl)
|
||||
throws IOException {
|
||||
return new HttpServer(webapp, "0.0.0.0", 0, true, conf, adminsAcl);
|
||||
}
|
||||
/**
|
||||
* Create an HttpServer instance for the given webapp
|
||||
* @param webapp the webapp to work with
|
||||
|
|
|
@ -60,7 +60,6 @@ import org.apache.hadoop.security.authorize.AccessControlList;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mortbay.util.ajax.JSON;
|
||||
|
||||
|
@ -360,6 +359,8 @@ public class TestHttpServer extends HttpServerFunctionalTest {
|
|||
Configuration conf = new Configuration();
|
||||
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
|
||||
true);
|
||||
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_INSTRUMENTATION_REQUIRES_ADMIN,
|
||||
true);
|
||||
conf.set(HttpServer.FILTER_INITIALIZER_PROPERTY,
|
||||
DummyFilterInitializer.class.getName());
|
||||
|
||||
|
@ -468,6 +469,26 @@ public class TestHttpServer extends HttpServerFunctionalTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresAuthorizationAccess() throws Exception {
|
||||
Configuration conf = new Configuration();
|
||||
ServletContext context = Mockito.mock(ServletContext.class);
|
||||
Mockito.when(context.getAttribute(HttpServer.CONF_CONTEXT_ATTRIBUTE)).thenReturn(conf);
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
|
||||
|
||||
//requires admin access to instrumentation, FALSE by default
|
||||
Assert.assertTrue(HttpServer.isInstrumentationAccessAllowed(context, request, response));
|
||||
|
||||
//requires admin access to instrumentation, TRUE
|
||||
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_INSTRUMENTATION_REQUIRES_ADMIN, true);
|
||||
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, true);
|
||||
AccessControlList acls = Mockito.mock(AccessControlList.class);
|
||||
Mockito.when(acls.isUserAllowed(Mockito.<UserGroupInformation>any())).thenReturn(false);
|
||||
Mockito.when(context.getAttribute(HttpServer.ADMINS_ACL)).thenReturn(acls);
|
||||
Assert.assertFalse(HttpServer.isInstrumentationAccessAllowed(context, request, response));
|
||||
}
|
||||
|
||||
@Test public void testBindAddress() throws Exception {
|
||||
checkBindAddress("0.0.0.0", 0, false).stop();
|
||||
// hang onto this one for a bit more testing
|
||||
|
|
Loading…
Reference in New Issue