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 c97f8ad8144..ea9b282ab89 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 @@ -20,10 +20,9 @@ package org.apache.hadoop.security; 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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -42,9 +41,6 @@ import java.util.List; */ public class AuthenticationWithProxyUserFilter extends AuthenticationFilter { - public static final Logger LOG = - LoggerFactory.getLogger(AuthenticationWithProxyUserFilter.class); - /** * Constant used in URL's query string to perform a proxy user request, the * value of the DO_AS parameter is the user the request will be @@ -70,30 +66,29 @@ public class AuthenticationWithProxyUserFilter extends AuthenticationFilter { protected void doFilter(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - final String proxyUser = getDoAs(request); + // authorize proxy user before calling next filter. + 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. - 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(); - } - + request = new HttpServletRequestWrapper(request) { @Override public String getRemoteUser() { - try { - return getRemoteOrProxyUser(); - } catch (AuthorizationException ex) { - LOG.error("Unable to verify proxy user: " + ex.getMessage(), ex); - } - return null; + return finalProxyUser.getUserName(); } }; 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 e1d7302c9a2..95c5ecc81e5 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 @@ -178,25 +178,12 @@ public class TestHttpServerWithSpengo { Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); } - // userA cannot impersonate userC, but for /stacks, /jmx and /conf, - // they doesn't require users to authorize by default, so they - // can be accessed. + // userA cannot impersonate userC, it fails. 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()); } 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 1ba37c9ca87..ad5bc2a430f 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 @@ -393,11 +393,10 @@ public class AppController extends Controller implements AMParams { */ boolean checkAccess(Job job) { String remoteUser = request().getRemoteUser(); - if (remoteUser == null) { - return false; + UserGroupInformation callerUGI = null; + if (remoteUser != null) { + callerUGI = UserGroupInformation.createRemoteUser(remoteUser); } - UserGroupInformation callerUGI = - UserGroupInformation.createRemoteUser(remoteUser); if (callerUGI != null && !job.checkAccess(callerUGI, JobACL.VIEW_JOB)) { return false; } 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 a8810a9ec8c..4a47bf181c2 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 @@ -32,7 +32,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeys; 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; @@ -110,8 +109,8 @@ public class AppBlock extends HtmlBlock { final GetApplicationReportRequest request = GetApplicationReportRequest.newInstance(appID); if (callerUGI == null) { - throw new AuthenticationException( - "Failed to get user name from request"); + appReport = + appBaseProt.getApplicationReport(request).getApplicationReport(); } else { appReport = callerUGI.doAs( new PrivilegedExceptionAction () { @@ -205,55 +204,36 @@ public class AppBlock extends HtmlBlock { String schedulerPath = WebAppUtils.getResolvedRMWebAppURLWithScheme(conf) + "/cluster/scheduler?openQueues=" + app.getQueue(); - generateOverviewTable(app, schedulerPath, webUiType, appReport); - - 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(); @@ -285,6 +265,37 @@ public class AppBlock extends HtmlBlock { overviewTable.__("AM container Node Label expression:", app.getAmNodeLabelExpression() == null ? "" : app.getAmNodeLabelExpression()); + + try { + final GetApplicationAttemptsRequest request = + GetApplicationAttemptsRequest.newInstance(appID); + if (callerUGI == null) { + attempts = appBaseProt.getApplicationAttempts(request) + .getApplicationAttemptList(); + } else { + attempts = callerUGI.doAs( + new PrivilegedExceptionAction> () { + @Override + public Collection 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,