diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 78990334e6e..37a4a04f2d7 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -241,6 +241,9 @@ Release 0.23.6 - UNRELEASED YARN-266. RM and JHS Web UIs are blank because AppsBlock is not escaping string properly (Ravi Prakash via jlowe) + YARN-280. RM does not reject app submission with invalid tokens + (Daryn Sharp via tgraves) + Release 0.23.5 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/DelegationTokenRenewer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/DelegationTokenRenewer.java index e5abbb7ede9..9232190ba3b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/DelegationTokenRenewer.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/DelegationTokenRenewer.java @@ -276,21 +276,26 @@ public synchronized void addApplication( Collection > tokens = ts.getAllTokens(); long now = System.currentTimeMillis(); + // find tokens for renewal, but don't add timers until we know + // all renewable tokens are valid + Set dtrs = new HashSet(); for(Token token : tokens) { // first renew happens immediately if (token.isManaged()) { DelegationTokenToRenew dtr = new DelegationTokenToRenew(applicationId, token, getConfig(), now, shouldCancelAtEnd); - - addTokenToList(dtr); - - setTimerForTokenRenewal(dtr, true); - if (LOG.isDebugEnabled()) { - LOG.debug("Registering token for renewal for:" + - " service = " + token.getService() + - " for appId = " + applicationId); - } + renewToken(dtr); + dtrs.add(dtr); + } + } + for (DelegationTokenToRenew dtr : dtrs) { + addTokenToList(dtr); + setTimerForTokenRenewal(dtr); + if (LOG.isDebugEnabled()) { + LOG.debug("Registering token for renewal for:" + + " service = " + dtr.token.getService() + + " for appId = " + applicationId); } } } @@ -315,22 +320,13 @@ public synchronized void run() { Token token = dttr.token; try { - // need to use doAs so that http can find the kerberos tgt - dttr.expirationDate = UserGroupInformation.getLoginUser() - .doAs(new PrivilegedExceptionAction(){ - - @Override - public Long run() throws Exception { - return dttr.token.renew(dttr.conf); - } - }); - + renewToken(dttr); if (LOG.isDebugEnabled()) { LOG.debug("Renewing delegation-token for:" + token.getService() + "; new expiration;" + dttr.expirationDate); } - setTimerForTokenRenewal(dttr, false);// set the next one + setTimerForTokenRenewal(dttr);// set the next one } catch (Exception e) { LOG.error("Exception renewing token" + token + ". Not rescheduled", e); removeFailedDelegationToken(dttr); @@ -347,19 +343,12 @@ public synchronized boolean cancel() { /** * set task to renew the token */ - private - void setTimerForTokenRenewal(DelegationTokenToRenew token, - boolean firstTime) throws IOException { + private void setTimerForTokenRenewal(DelegationTokenToRenew token) + throws IOException { // calculate timer time - long now = System.currentTimeMillis(); - long renewIn; - if(firstTime) { - renewIn = now; - } else { - long expiresIn = (token.expirationDate - now); - renewIn = now + expiresIn - expiresIn/10; // little bit before the expiration - } + long expiresIn = token.expirationDate - System.currentTimeMillis(); + long renewIn = token.expirationDate - expiresIn/10; // little bit before the expiration // need to create new task every time TimerTask tTask = new RenewalTimerTask(token); @@ -368,6 +357,24 @@ void setTimerForTokenRenewal(DelegationTokenToRenew token, renewalTimer.schedule(token.timerTask, new Date(renewIn)); } + // renew a token + private void renewToken(final DelegationTokenToRenew dttr) + throws IOException { + // need to use doAs so that http can find the kerberos tgt + // NOTE: token renewers should be responsible for the correct UGI! + try { + dttr.expirationDate = UserGroupInformation.getLoginUser().doAs( + new PrivilegedExceptionAction(){ + @Override + public Long run() throws Exception { + return dttr.token.renew(dttr.conf); + } + }); + } catch (InterruptedException e) { + throw new IOException(e); + } + } + // cancel a token private void cancelToken(DelegationTokenToRenew t) { if(t.shouldCancelAtEnd) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestDelegationTokenRenewer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestDelegationTokenRenewer.java index 1c3614e46df..ad127a9264d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestDelegationTokenRenewer.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestDelegationTokenRenewer.java @@ -357,6 +357,27 @@ public void testDTRenewal () throws Exception { } } + @Test + public void testInvalidDTWithAddApplication() throws Exception { + MyFS dfs = (MyFS)FileSystem.get(conf); + LOG.info("dfs="+(Object)dfs.hashCode() + ";conf="+conf.hashCode()); + + MyToken token = dfs.getDelegationToken(new Text("user1")); + token.cancelToken(); + + Credentials ts = new Credentials(); + ts.addToken(token.getKind(), token); + + // register the tokens for renewal + ApplicationId appId = BuilderUtils.newApplicationId(0, 0); + try { + delegationTokenRenewer.addApplication(appId, ts, true); + fail("App submission with a cancelled token should have failed"); + } catch (InvalidToken e) { + // expected + } + } + /** * Basic idea of the test: * 1. register a token for 2 seconds with no cancel at the end