HADOOP-14077. Add ability to access jmx via proxy.  Contributed by Yuanbo Liu.


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/172b23af
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/172b23af
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/172b23af

Branch: refs/heads/YARN-5734
Commit: 172b23af33554b7d58fd41b022d983bcc2433da7
Parents: 3a2e30f
Author: Eric Yang <ey...@apache.org>
Authored: Sat Feb 18 18:34:13 2017 -0800
Committer: Eric Yang <ey...@apache.org>
Committed: Sat Feb 18 18:34:13 2017 -0800

----------------------------------------------------------------------
 .../AuthenticationWithProxyUserFilter.java      |  43 +++---
 .../hadoop/http/TestHttpServerWithSpengo.java   |  15 ++-
 .../mapreduce/v2/app/webapp/AppController.java  |   7 +-
 .../hadoop/yarn/server/webapp/AppBlock.java     | 135 ++++++++++---------
 4 files changed, 114 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/172b23af/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationWithProxyUserFilter.java
----------------------------------------------------------------------
diff --git 
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationWithProxyUserFilter.java
 
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationWithProxyUserFilter.java
index ea9b282..751cf02 100644
--- 
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationWithProxyUserFilter.java
+++ 
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/AuthenticationWithProxyUserFilter.java
@@ -17,10 +17,11 @@
  */
 package org.apache.hadoop.security;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
 import org.apache.hadoop.security.authorize.AuthorizationException;
 import org.apache.hadoop.security.authorize.ProxyUsers;
-import org.apache.hadoop.util.HttpExceptionUtils;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.utils.URLEncodedUtils;
 
@@ -41,6 +42,9 @@ import java.util.List;
  */
 public class AuthenticationWithProxyUserFilter extends AuthenticationFilter {
 
+  public static final Log LOG =
+      LogFactory.getLog(AuthenticationWithProxyUserFilter.class);
+
   /**
    * Constant used in URL's query string to perform a proxy user request, the
    * value of the <code>DO_AS</code> parameter is the user the request will be
@@ -66,29 +70,30 @@ public class AuthenticationWithProxyUserFilter extends 
AuthenticationFilter {
   protected void doFilter(FilterChain filterChain, HttpServletRequest request,
       HttpServletResponse response) throws IOException, ServletException {
 
-    // authorize proxy user before calling next filter.
-    String proxyUser = getDoAs(request);
+    final String proxyUser = getDoAs(request);
     if (proxyUser != null) {
-      UserGroupInformation realUser =
-          UserGroupInformation.createRemoteUser(request.getRemoteUser());
-      UserGroupInformation proxyUserInfo =
-          UserGroupInformation.createProxyUser(proxyUser, realUser);
-
-      try {
-        ProxyUsers.authorize(proxyUserInfo, request.getRemoteAddr());
-      } catch (AuthorizationException ex) {
-        HttpExceptionUtils.createServletExceptionResponse(response,
-            HttpServletResponse.SC_FORBIDDEN, ex);
-        // stop filter chain if there is an Authorization Exception.
-        return;
-      }
 
-      final UserGroupInformation finalProxyUser = proxyUserInfo;
       // Change the remote user after proxy user is authorized.
-      request = new HttpServletRequestWrapper(request) {
+      final HttpServletRequest finalReq = request;
+      request = new HttpServletRequestWrapper(finalReq) {
+
+        private String getRemoteOrProxyUser() throws AuthorizationException {
+          UserGroupInformation realUser =
+              UserGroupInformation.createRemoteUser(finalReq.getRemoteUser());
+          UserGroupInformation proxyUserInfo =
+              UserGroupInformation.createProxyUser(proxyUser, realUser);
+          ProxyUsers.authorize(proxyUserInfo, finalReq.getRemoteAddr());
+          return proxyUserInfo.getUserName();
+        }
+
         @Override
         public String getRemoteUser() {
-          return finalProxyUser.getUserName();
+          try {
+            return getRemoteOrProxyUser();
+          } catch (AuthorizationException ex) {
+            LOG.error("Unable to verify proxy user: " + ex.getMessage(), ex);
+          }
+          return null;
         }
       };
 

http://git-wip-us.apache.org/repos/asf/hadoop/blob/172b23af/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpengo.java
----------------------------------------------------------------------
diff --git 
a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpengo.java
 
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpengo.java
index cbdda90..3d3e020 100644
--- 
a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpengo.java
+++ 
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpServerWithSpengo.java
@@ -157,12 +157,25 @@ public class TestHttpServerWithSpengo {
         Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
       }
 
-      // userA cannot impersonate userC, it fails.
+      // userA cannot impersonate userC, but for /stacks, /jmx and /conf,
+      // they doesn't require users to authorize by default, so they
+      // can be accessed.
       for (String servlet :
           new String[]{"stacks", "jmx", "conf"}){
         HttpURLConnection conn = authUrl
             .openConnection(new URL(serverURL + servlet + "?doAs=userC"),
                 token);
+        Assert.assertEquals(HttpURLConnection.HTTP_OK,
+            conn.getResponseCode());
+      }
+
+      // "/logs" and "/logLevel" require admin authorization,
+      // only userA has the access.
+      for (String servlet :
+          new String[]{"logLevel", "logs"}) {
+        HttpURLConnection conn = authUrl
+            .openConnection(new URL(serverURL + servlet + "?doAs=userC"),
+                token);
         Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
             conn.getResponseCode());
       }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/172b23af/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java
----------------------------------------------------------------------
diff --git 
a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java
 
b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java
index e30e1b9..1c90cb9 100644
--- 
a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java
+++ 
b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/main/java/org/apache/hadoop/mapreduce/v2/app/webapp/AppController.java
@@ -392,10 +392,11 @@ public class AppController extends Controller implements 
AMParams {
    */
   boolean checkAccess(Job job) {
     String remoteUser = request().getRemoteUser();
-    UserGroupInformation callerUGI = null;
-    if (remoteUser != null) {
-      callerUGI = UserGroupInformation.createRemoteUser(remoteUser);
+    if (remoteUser == null) {
+      return false;
     }
+    UserGroupInformation callerUGI =
+        UserGroupInformation.createRemoteUser(remoteUser);
     if (callerUGI != null && !job.checkAccess(callerUGI, JobACL.VIEW_JOB)) {
       return false;
     }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/172b23af/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java
----------------------------------------------------------------------
diff --git 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java
 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java
index 349a98c..11bd9b4 100644
--- 
a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java
+++ 
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java
@@ -31,6 +31,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.security.UserGroupInformation;
+import 
org.apache.hadoop.security.authentication.client.AuthenticationException;
 import org.apache.hadoop.security.http.RestCsrfPreventionFilter;
 import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
@@ -100,8 +101,8 @@ public class AppBlock extends HtmlBlock {
       final GetApplicationReportRequest request =
           GetApplicationReportRequest.newInstance(appID);
       if (callerUGI == null) {
-        appReport =
-            appBaseProt.getApplicationReport(request).getApplicationReport();
+        throw new AuthenticationException(
+            "Failed to get user name from request");
       } else {
         appReport = callerUGI.doAs(
             new PrivilegedExceptionAction<ApplicationReport> () {
@@ -165,36 +166,76 @@ public class AppBlock extends HtmlBlock {
     String schedulerPath = WebAppUtils.getResolvedRMWebAppURLWithScheme(conf) +
         "/cluster/scheduler?openQueues=" + app.getQueue();
 
+    generateOverviewTable(app, schedulerPath, webUiType, appReport);
+
+    Collection<ApplicationAttemptReport> attempts;
+    try {
+      final GetApplicationAttemptsRequest request =
+          GetApplicationAttemptsRequest.newInstance(appID);
+      attempts = callerUGI.doAs(
+          new PrivilegedExceptionAction<Collection<
+              ApplicationAttemptReport>>() {
+            @Override
+            public Collection<ApplicationAttemptReport> run() throws Exception 
{
+              return appBaseProt.getApplicationAttempts(request)
+                  .getApplicationAttemptList();
+            }
+          });
+    } catch (Exception e) {
+      String message =
+          "Failed to read the attempts of the application " + appID + ".";
+      LOG.error(message, e);
+      html.p()._(message)._();
+      return;
+    }
+
+    createApplicationMetricsTable(html);
+
+    html._(InfoBlock.class);
+
+    generateApplicationTable(html, callerUGI, attempts);
+
+  }
+
+  /**
+   * Generate overview table for app web page.
+   * @param app app info.
+   * @param schedulerPath schedule path.
+   * @param webUiType web ui type.
+   * @param appReport app report.
+   */
+  private void generateOverviewTable(AppInfo app, String schedulerPath,
+      String webUiType, ApplicationReport appReport) {
     ResponseInfo overviewTable = info("Application Overview")
-      ._("User:", schedulerPath, app.getUser())
-      ._("Name:", app.getName())
-      ._("Application Type:", app.getType())
-      ._("Application Tags:",
-        app.getApplicationTags() == null ? "" : app.getApplicationTags())
-      ._("Application Priority:", clarifyAppPriority(app.getPriority()))
-      ._(
-        "YarnApplicationState:",
-        app.getAppState() == null ? UNAVAILABLE : clarifyAppState(app
-          .getAppState()))
-      ._("Queue:", schedulerPath, app.getQueue())
-      ._("FinalStatus Reported by AM:",
-        clairfyAppFinalStatus(app.getFinalAppStatus()))
-      ._("Started:", Times.format(app.getStartedTime()))
-      ._(
-        "Elapsed:",
-        StringUtils.formatTime(Times.elapsed(app.getStartedTime(),
-          app.getFinishedTime())))
-      ._(
-        "Tracking URL:",
-        app.getTrackingUrl() == null
-            || app.getTrackingUrl().equals(UNAVAILABLE) ? null : root_url(app
-          .getTrackingUrl()),
-        app.getTrackingUrl() == null
-            || app.getTrackingUrl().equals(UNAVAILABLE) ? "Unassigned" : app
-          .getAppState() == YarnApplicationState.FINISHED
-            || app.getAppState() == YarnApplicationState.FAILED
-            || app.getAppState() == YarnApplicationState.KILLED ? "History"
-            : "ApplicationMaster");
+        ._("User:", schedulerPath, app.getUser())
+        ._("Name:", app.getName())
+        ._("Application Type:", app.getType())
+        ._("Application Tags:",
+            app.getApplicationTags() == null ? "" : app.getApplicationTags())
+        ._("Application Priority:", clarifyAppPriority(app.getPriority()))
+        ._(
+            "YarnApplicationState:",
+            app.getAppState() == null ? UNAVAILABLE : clarifyAppState(app
+                .getAppState()))
+        ._("Queue:", schedulerPath, app.getQueue())
+        ._("FinalStatus Reported by AM:",
+            clairfyAppFinalStatus(app.getFinalAppStatus()))
+        ._("Started:", Times.format(app.getStartedTime()))
+        ._(
+            "Elapsed:",
+            StringUtils.formatTime(Times.elapsed(app.getStartedTime(),
+                app.getFinishedTime())))
+        ._(
+            "Tracking URL:",
+            app.getTrackingUrl() == null
+                || app.getTrackingUrl().equals(UNAVAILABLE) ? null : 
root_url(app
+                .getTrackingUrl()),
+            app.getTrackingUrl() == null
+                || app.getTrackingUrl().equals(UNAVAILABLE) ? "Unassigned" : 
app
+                .getAppState() == YarnApplicationState.FINISHED
+                || app.getAppState() == YarnApplicationState.FAILED
+                || app.getAppState() == YarnApplicationState.KILLED ? "History"
+                : "ApplicationMaster");
     if (webUiType != null
         && webUiType.equals(YarnWebParams.RM_WEB_UI)) {
       LogAggregationStatus status = getLogAggregationStatus();
@@ -226,38 +267,6 @@ public class AppBlock extends HtmlBlock {
     overviewTable._("AM container Node Label expression:",
         app.getAmNodeLabelExpression() == null ? "<Not set>"
             : app.getAmNodeLabelExpression());
-
-    Collection<ApplicationAttemptReport> attempts;
-    try {
-      final GetApplicationAttemptsRequest request =
-          GetApplicationAttemptsRequest.newInstance(appID);
-      if (callerUGI == null) {
-        attempts = appBaseProt.getApplicationAttempts(request)
-            .getApplicationAttemptList();
-      } else {
-        attempts = callerUGI.doAs(
-            new 
PrivilegedExceptionAction<Collection<ApplicationAttemptReport>> () {
-          @Override
-          public Collection<ApplicationAttemptReport> run() throws Exception {
-            return appBaseProt.getApplicationAttempts(request)
-                .getApplicationAttemptList();
-          }
-        });
-      }
-    } catch (Exception e) {
-      String message =
-          "Failed to read the attempts of the application " + appID + ".";
-      LOG.error(message, e);
-      html.p()._(message)._();
-      return;
-    }
-
-    createApplicationMetricsTable(html);
-
-    html._(InfoBlock.class);
-
-    generateApplicationTable(html, callerUGI, attempts);
-
   }
 
   protected void generateApplicationTable(Block html,


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org
For additional commands, e-mail: common-commits-h...@hadoop.apache.org

Reply via email to