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:
parent
0fca4fbaf3
commit
a70587f368
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue