HADOOP-8343. Allow configuration of authorization for JmxJsonServlet and MetricsServlet (tucu)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1333750 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alejandro Abdelnur 2012-05-04 03:31:44 +00:00
parent 0fca4fbaf3
commit a70587f368
9 changed files with 89 additions and 16 deletions

View File

@ -163,6 +163,9 @@ Release 2.0.0 - UNRELEASED
HADOOP-8210. Common side of HDFS-3148: The client should be able HADOOP-8210. Common side of HDFS-3148: The client should be able
to use multiple local interfaces for data transfer. (eli) to use multiple local interfaces for data transfer. (eli)
HADOOP-8343. Allow configuration of authorization for JmxJsonServlet and
MetricsServlet (tucu)
IMPROVEMENTS IMPROVEMENTS
HADOOP-7524. Change RPC to allow multiple protocols including multuple HADOOP-7524. Change RPC to allow multiple protocols including multuple

View File

@ -18,7 +18,6 @@
package org.apache.hadoop.conf; package org.apache.hadoop.conf;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import javax.servlet.ServletException; import javax.servlet.ServletException;
@ -57,9 +56,8 @@ public class ConfServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
// Do the authorization if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
if (!HttpServer.hasAdministratorAccess(getServletContext(), request, request, response)) {
response)) {
return; return;
} }

View File

@ -228,6 +228,9 @@ public class CommonConfigurationKeysPublic {
public static final String HADOOP_SECURITY_AUTHORIZATION = public static final String HADOOP_SECURITY_AUTHORIZATION =
"hadoop.security.authorization"; "hadoop.security.authorization";
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */ /** 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 = public static final String HADOOP_SECURITY_SERVICE_USER_NAME_KEY =
"hadoop.security.service.user.name.key"; "hadoop.security.service.user.name.key";
} }

View File

@ -779,6 +779,37 @@ public class HttpServer implements FilterContainer {
: "Inactive HttpServer"; : "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 * 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. * it isn't the case, response will be modified to send an error to the user.
@ -794,7 +825,6 @@ public class HttpServer implements FilterContainer {
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
Configuration conf = Configuration conf =
(Configuration) servletContext.getAttribute(CONF_CONTEXT_ATTRIBUTE); (Configuration) servletContext.getAttribute(CONF_CONTEXT_ATTRIBUTE);
// If there is no authorization, anybody has administrator access. // If there is no authorization, anybody has administrator access.
if (!conf.getBoolean( if (!conf.getBoolean(
CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, false)) { CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, false)) {
@ -834,12 +864,11 @@ public class HttpServer implements FilterContainer {
@Override @Override
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
response.setContentType("text/plain; charset=UTF-8"); if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
// Do the authorization request, response)) {
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
response)) {
return; return;
} }
response.setContentType("text/plain; charset=UTF-8");
PrintWriter out = response.getWriter(); PrintWriter out = response.getWriter();
ReflectionUtils.printThreadInfo(out, ""); ReflectionUtils.printThreadInfo(out, "");
out.close(); out.close();

View File

@ -148,9 +148,8 @@ public class JMXJsonServlet extends HttpServlet {
@Override @Override
public void doGet(HttpServletRequest request, HttpServletResponse response) { public void doGet(HttpServletRequest request, HttpServletResponse response) {
try { try {
// Do the authorization if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
if (!HttpServer.hasAdministratorAccess(getServletContext(), request, request, response)) {
response)) {
return; return;
} }
JsonGenerator jg = null; JsonGenerator jg = null;

View File

@ -106,9 +106,8 @@ public class MetricsServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
// Do the authorization if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
if (!HttpServer.hasAdministratorAccess(getServletContext(), request, request, response)) {
response)) {
return; return;
} }

View File

@ -62,6 +62,15 @@
<description>Is service-level authorization enabled?</description> <description>Is service-level authorization enabled?</description>
</property> </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> <property>
<name>hadoop.security.authentication</name> <name>hadoop.security.authentication</name>
<value>simple</value> <value>simple</value>

View File

@ -19,6 +19,7 @@
package org.apache.hadoop.http; package org.apache.hadoop.http;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.junit.Assert; import org.junit.Assert;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
@ -70,6 +71,12 @@ public class HttpServerFunctionalTest extends Assert {
return createServer(TEST, conf); 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 * Create but do not start the test webapp server. The test webapp dir is
* prepared/checked in advance. * prepared/checked in advance.
@ -132,6 +139,11 @@ public class HttpServerFunctionalTest extends Assert {
throws IOException { throws IOException {
return new HttpServer(webapp, "0.0.0.0", 0, true, conf); 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 * Create an HttpServer instance for the given webapp
* @param webapp the webapp to work with * @param webapp the webapp to work with

View File

@ -60,7 +60,6 @@ import org.apache.hadoop.security.authorize.AccessControlList;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mortbay.util.ajax.JSON; import org.mortbay.util.ajax.JSON;
@ -360,6 +359,8 @@ public class TestHttpServer extends HttpServerFunctionalTest {
Configuration conf = new Configuration(); Configuration conf = new Configuration();
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
true); true);
conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_INSTRUMENTATION_REQUIRES_ADMIN,
true);
conf.set(HttpServer.FILTER_INITIALIZER_PROPERTY, conf.set(HttpServer.FILTER_INITIALIZER_PROPERTY,
DummyFilterInitializer.class.getName()); 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 { @Test public void testBindAddress() throws Exception {
checkBindAddress("0.0.0.0", 0, false).stop(); checkBindAddress("0.0.0.0", 0, false).stop();
// hang onto this one for a bit more testing // hang onto this one for a bit more testing