diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index b8d1f530cc7..4ce9f9fafc4 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -150,6 +150,9 @@ Release 2.6.1 - UNRELEASED YARN-2900. Application (Attempt and Container) Not Found in AHS results in InternalServer Error (500). (Zhijie Shen and Mit Desai via xgong) + YARN-3725. App submission via REST API is broken in secure mode due to + Timeline DT service address is empty. (Zhijie Shen via wangda) + Release 2.6.0 - 2014-11-18 INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineClientImpl.java index f5c85c15932..6bf858a37c3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/client/api/impl/TimelineClientImpl.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.net.ConnectException; import java.net.HttpURLConnection; +import java.net.InetSocketAddress; import java.net.URI; import java.net.URL; import java.net.URLConnection; @@ -44,6 +45,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.client.AuthenticationException; import org.apache.hadoop.security.authentication.client.ConnectionConfigurator; @@ -362,6 +364,12 @@ public class TimelineClientImpl extends TimelineClient { public long renewDelegationToken( final Token timelineDT) throws IOException, YarnException { + final boolean isTokenServiceAddrEmpty = + timelineDT.getService().toString().isEmpty(); + final String scheme = isTokenServiceAddrEmpty ? null + : (YarnConfiguration.useHttps(this.getConfig()) ? "https" : "http"); + final InetSocketAddress address = isTokenServiceAddrEmpty ? null + : SecurityUtil.getTokenServiceAddr(timelineDT); PrivilegedExceptionAction renewDTAction = new PrivilegedExceptionAction() { @@ -377,6 +385,11 @@ public class TimelineClientImpl extends TimelineClient { DelegationTokenAuthenticatedURL authUrl = new DelegationTokenAuthenticatedURL(authenticator, connConfigurator); + // If the token service address is not available, fall back to use + // the configured service address. + final URI serviceURI = isTokenServiceAddrEmpty ? resURI + : new URI(scheme, null, address.getHostName(), + address.getPort(), RESOURCE_URI_STR, null, null); return authUrl .renewDelegationToken(resURI.toURL(), token, doAsUser); } @@ -389,6 +402,12 @@ public class TimelineClientImpl extends TimelineClient { public void cancelDelegationToken( final Token timelineDT) throws IOException, YarnException { + final boolean isTokenServiceAddrEmpty = + timelineDT.getService().toString().isEmpty(); + final String scheme = isTokenServiceAddrEmpty ? null + : (YarnConfiguration.useHttps(this.getConfig()) ? "https" : "http"); + final InetSocketAddress address = isTokenServiceAddrEmpty ? null + : SecurityUtil.getTokenServiceAddr(timelineDT); PrivilegedExceptionAction cancelDTAction = new PrivilegedExceptionAction() { @@ -404,7 +423,12 @@ public class TimelineClientImpl extends TimelineClient { DelegationTokenAuthenticatedURL authUrl = new DelegationTokenAuthenticatedURL(authenticator, connConfigurator); - authUrl.cancelDelegationToken(resURI.toURL(), token, doAsUser); + // If the token service address is not available, fall back to use + // the configured service address. + final URI serviceURI = isTokenServiceAddrEmpty ? resURI + : new URI(scheme, null, address.getHostName(), + address.getPort(), RESOURCE_URI_STR, null, null); + authUrl.cancelDelegationToken(serviceURI.toURL(), token, doAsUser); return null; } }; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/timeline/security/TestTimelineAuthenticationFilter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/timeline/security/TestTimelineAuthenticationFilter.java index c93e8f2bc9f..063f5121e50 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/timeline/security/TestTimelineAuthenticationFilter.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/timeline/security/TestTimelineAuthenticationFilter.java @@ -240,12 +240,21 @@ public class TestTimelineAuthenticationFilter { Assert.assertEquals(new Text(HTTP_USER), tDT.getOwner()); // Renew token + Assert.assertFalse(token.getService().toString().isEmpty()); + // Renew the token from the token service address long renewTime1 = httpUserClient.renewDelegationToken(token); Thread.sleep(100); + token.setService(new Text()); + Assert.assertTrue(token.getService().toString().isEmpty()); + // If the token service address is not avaiable, it still can be renewed + // from the configured address long renewTime2 = httpUserClient.renewDelegationToken(token); Assert.assertTrue(renewTime1 < renewTime2); // Cancel token + Assert.assertTrue(token.getService().toString().isEmpty()); + // If the token service address is not avaiable, it still can be canceled + // from the configured address httpUserClient.cancelDelegationToken(token); // Renew should not be successful because the token is canceled try { @@ -280,6 +289,8 @@ public class TestTimelineAuthenticationFilter { Assert.assertTrue(renewTime1 < renewTime2); // Cancel token + Assert.assertFalse(tokenToRenew.getService().toString().isEmpty()); + // Cancel the token from the token service address fooUserClient.cancelDelegationToken(tokenToRenew); // Renew should not be successful because the token is canceled