Browse Source

YARN-280. RM does not reject app submission with invalid tokens (Daryn Sharp via tgraves)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1425085 13f79535-47bb-0310-9956-ffa450edef68
Thomas Graves 12 năm trước cách đây
mục cha
commit
c28831a0bd

+ 3 - 0
hadoop-yarn-project/CHANGES.txt

@@ -224,6 +224,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

+ 38 - 31
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 class DelegationTokenRenewer extends AbstractService {
     Collection <Token<?>> 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<DelegationTokenToRenew> dtrs = new HashSet<DelegationTokenToRenew>();
     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 class DelegationTokenRenewer extends AbstractService {
 
       Token<?> token = dttr.token;
       try {
-        // need to use doAs so that http can find the kerberos tgt
-        dttr.expirationDate = UserGroupInformation.getLoginUser()
-          .doAs(new PrivilegedExceptionAction<Long>(){
-
-          @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 class DelegationTokenRenewer extends AbstractService {
   /**
    * 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 @@ public class DelegationTokenRenewer extends AbstractService {
     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<Long>(){          
+            @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) {

+ 21 - 0
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 class TestDelegationTokenRenewer {
     }
   }
   
+  @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