hadoop-common-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From be...@apache.org
Subject hadoop git commit: HADOOP-12587. Hadoop AuthToken refuses to work without a maxinactive attribute in issued token. (Benoy Antony)
Date Sat, 09 Jan 2016 21:45:39 GMT
Repository: hadoop
Updated Branches:
  refs/heads/branch-2 80734bc34 -> 4e5f77b7f


HADOOP-12587. Hadoop AuthToken refuses to work without a maxinactive attribute in issued token.
(Benoy Antony)

(cherry picked from commit dec8dfdfa66c37f8cc8c0900fd12f98c7529b99e)


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

Branch: refs/heads/branch-2
Commit: 4e5f77b7f5c9f1145743d960846233c06c304622
Parents: 80734bc
Author: Benoy Antony <benoy@apache.org>
Authored: Sat Jan 9 13:39:18 2016 -0800
Committer: Benoy Antony <benoy@apache.org>
Committed: Sat Jan 9 13:43:15 2016 -0800

----------------------------------------------------------------------
 .../server/AuthenticationFilter.java            |  11 +-
 .../security/authentication/util/AuthToken.java |  16 +-
 .../server/TestAuthenticationFilter.java        | 167 ++++++++++++++++---
 .../src/site/markdown/HttpAuthentication.md     |   2 +-
 4 files changed, 161 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/4e5f77b7/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
index e0da38b..4bdc808 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
@@ -150,7 +150,7 @@ public class AuthenticationFilter implements Filter {
    * that indicates the max inactive interval of the generated token.
    */
   public static final String
-      AUTH_TOKEN_MAX_INACTIVE_INTERVAL = "token.MaxInactiveInterval";
+      AUTH_TOKEN_MAX_INACTIVE_INTERVAL = "token.max-inactive-interval";
 
   /**
    * Constant for the configuration property that indicates the validity of the generated
token.
@@ -234,9 +234,11 @@ public class AuthenticationFilter implements Filter {
     } else {
       authHandlerClassName = authHandlerName;
     }
-
     maxInactiveInterval = Long.parseLong(config.getProperty(
-        AUTH_TOKEN_MAX_INACTIVE_INTERVAL, "1800")) * 1000; // 30 minutes;
+        AUTH_TOKEN_MAX_INACTIVE_INTERVAL, "-1")); // By default, disable.
+    if (maxInactiveInterval > 0) {
+      maxInactiveInterval *= 1000;
+    }
     validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, "36000"))
         * 1000; //10 hours
     initializeSecretProvider(filterConfig);
@@ -559,7 +561,7 @@ public class AuthenticationFilter implements Filter {
           }
           token = authHandler.authenticate(httpRequest, httpResponse);
           if (token != null && token != AuthenticationToken.ANONYMOUS) {
-            if (token.getMaxInactives() != 0) {
+            if (token.getMaxInactives() > 0) {
               token.setMaxInactives(System.currentTimeMillis()
                   + getMaxInactiveInterval() * 1000);
             }
@@ -603,6 +605,7 @@ public class AuthenticationFilter implements Filter {
               && getMaxInactiveInterval() > 0) {
             token.setMaxInactives(System.currentTimeMillis()
                 + getMaxInactiveInterval() * 1000);
+            token.setExpires(token.getExpires());
             newToken = true;
           }
           if (newToken && !token.isExpired()

http://git-wip-us.apache.org/repos/asf/hadoop/blob/4e5f77b7/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/AuthToken.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/AuthToken.java
b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/AuthToken.java
index 4fbe599..e959f65 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/AuthToken.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/AuthToken.java
@@ -39,8 +39,7 @@ public class AuthToken implements Principal {
   private static final String TYPE = "t";
 
   private final static Set<String> ATTRIBUTES =
-    new HashSet<String>(Arrays.asList(USER_NAME, PRINCIPAL,
-        MAX_INACTIVES, EXPIRES, TYPE));
+      new HashSet<>(Arrays.asList(USER_NAME, PRINCIPAL, EXPIRES, TYPE));
 
   private String userName;
   private String principal;
@@ -133,8 +132,10 @@ public class AuthToken implements Principal {
     sb.append(USER_NAME).append("=").append(getUserName()).append(ATTR_SEPARATOR);
     sb.append(PRINCIPAL).append("=").append(getName()).append(ATTR_SEPARATOR);
     sb.append(TYPE).append("=").append(getType()).append(ATTR_SEPARATOR);
-    sb.append(MAX_INACTIVES).append("=")
+    if (getMaxInactives() != -1) {
+      sb.append(MAX_INACTIVES).append("=")
       .append(getMaxInactives()).append(ATTR_SEPARATOR);
+    }
     sb.append(EXPIRES).append("=").append(getExpires());
     tokenStr = sb.toString();
   }
@@ -209,13 +210,16 @@ public class AuthToken implements Principal {
     // remove the signature part, since client doesn't care about it
     map.remove("s");
 
-    if (!map.keySet().equals(ATTRIBUTES)) {
+    if (!map.keySet().containsAll(ATTRIBUTES)) {
       throw new AuthenticationException("Invalid token string, missing attributes");
     }
-    long maxInactives = Long.parseLong(map.get(MAX_INACTIVES));
     long expires = Long.parseLong(map.get(EXPIRES));
     AuthToken token = new AuthToken(map.get(USER_NAME), map.get(PRINCIPAL), map.get(TYPE));
-    token.setMaxInactives(maxInactives);
+    //process optional attributes
+    if (map.containsKey(MAX_INACTIVES)) {
+      long maxInactives = Long.parseLong(map.get(MAX_INACTIVES));
+      token.setMaxInactives(maxInactives);
+    }
     token.setExpires(expires);
     return token;
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/4e5f77b7/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
index a617690..88702d9 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
@@ -34,7 +34,6 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
 import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
 import org.apache.hadoop.security.authentication.client.AuthenticationException;
 import org.apache.hadoop.security.authentication.util.Signer;
@@ -897,11 +896,117 @@ public class TestAuthenticationFilter {
                                                    authorized);
   }
 
+  @Test
+  public void testTokenWithValidActivityInterval() throws Exception {
+    // Provide token containing valid maxInactive value.
+    // The token is active.
+    // The server has maxInactiveInterval configured to -1.(disabled)
+    // The server shall authorize the access, but should not drop a new cookie
+    long maxInactives = System.currentTimeMillis()
+        + TOKEN_MAX_INACTIVE_INTERVAL;
+    long expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        maxInactives,
+        -1,
+        expires,
+        true, //authorized
+        false //newCookie
+        );
+    // Provide token containing valid maxInactive value.
+    // The token is active.
+    // The server has maxInactiveInterval configured to value
+    // greater than 0.(enabled)
+    // The server shall authorize the access and drop a new cookie
+    // with renewed activity interval
+    maxInactives = System.currentTimeMillis()
+        + TOKEN_MAX_INACTIVE_INTERVAL;
+    expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        maxInactives,
+        TOKEN_MAX_INACTIVE_INTERVAL,
+        expires,
+        true, //authorized
+        true //newCookie
+        );
+  }
+
+  @Test
+  public void testTokenWithExpiredActivityIntervaln() throws Exception {
+    // Provide token containing invalid maxInactive value.
+    // The token is inactive.
+    // The server has maxInactiveInterval configured to -1.(disabled)
+    // The server should deny access and expire the token.
+    long maxInactives = System.currentTimeMillis()
+        - TOKEN_MAX_INACTIVE_INTERVAL;
+    long expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        maxInactives,
+        -1,
+        expires,
+        false, //authorized
+        false //newCookie
+        );
+    // Provide token containing invalid maxInactive value.
+    // The token is inactive.
+    // The server has maxInactiveInterval configured to value
+    // greater than 0.(enabled)
+    // The server should deny access and expire the token.
+    maxInactives = System.currentTimeMillis()
+        + TOKEN_MAX_INACTIVE_INTERVAL;
+    expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        maxInactives,
+        -1,
+        expires,
+        true, //authorized
+        false //newCookie
+        );
+  }
+
+  @Test
+  public void testTokenWithNoActivityIntervals()
+      throws Exception {
+    // Provide token which does not contain maxInactive value.
+    // The server has maxInactiveInterval configured to -1.
+    // The server shall authorize the access, but should not drop a new cookie
+    long expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        -1,
+        -1,
+        expires,
+        true, //authorized
+        false //newCookie
+        );
+    // Provide token which does not contain  maxInactive value.
+    // The server has maxInactiveInterval to some value
+    // The server shall authorize the access and drop a new cookie
+    // with renewed activity interval
+    expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    _testDoFilterAuthenticationMaxInactiveInterval(
+        -1,
+        TOKEN_MAX_INACTIVE_INTERVAL,
+        expires,
+        true, //authorized
+        true //newCookie
+        );
+  }
+
   private void
-  _testDoFilterAuthenticationMaxInactiveInterval(long maxInactives,
+  _testDoFilterAuthenticationMaxInactiveInterval(long maxInactivesInToken,
                                                  long expires,
                                                  boolean authorized)
                                                      throws Exception {
+    _testDoFilterAuthenticationMaxInactiveInterval(maxInactivesInToken,
+        TOKEN_MAX_INACTIVE_INTERVAL, expires, authorized, true);
+  }
+
+  private void
+  _testDoFilterAuthenticationMaxInactiveInterval(long maxInactivesInToken,
+                                                 long maxInactivesOnServer,
+                                                 long expires,
+                                                 boolean authorized,
+                                                 boolean newCookie)
+                                                     throws Exception {
     String secret = "secret";
     AuthenticationFilter filter = new AuthenticationFilter();
     try {
@@ -913,10 +1018,14 @@ public class TestAuthenticationFilter {
               DummyAuthenticationHandler.class.getName());
       Mockito.when(config.getInitParameter(
           AuthenticationFilter.SIGNATURE_SECRET)).thenReturn(secret);
+      Mockito.when(config.getInitParameter(
+          AuthenticationFilter.AUTH_TOKEN_MAX_INACTIVE_INTERVAL)).thenReturn(
+              Long.toString(maxInactivesOnServer));
       Mockito.when(config.getInitParameterNames()).thenReturn(
         new Vector<String>(
           Arrays.asList(AuthenticationFilter.AUTH_TYPE,
                         AuthenticationFilter.SIGNATURE_SECRET,
+                        AuthenticationFilter.AUTH_TOKEN_MAX_INACTIVE_INTERVAL,
                         "management.operation.return")).elements());
       getMockedServletContextWithStringSigner(config);
       filter.init(config);
@@ -927,7 +1036,7 @@ public class TestAuthenticationFilter {
 
       AuthenticationToken token = new AuthenticationToken("u", "p",
           DummyAuthenticationHandler.TYPE);
-      token.setMaxInactives(maxInactives);
+      token.setMaxInactives(maxInactivesInToken);
       token.setExpires(expires);
 
       SignerSecretProvider secretProvider =
@@ -947,7 +1056,7 @@ public class TestAuthenticationFilter {
       FilterChain chain = Mockito.mock(FilterChain.class);
 
       if (authorized) {
-        verifyAuthorized(filter, request, response, chain);
+        verifyAuthorized(filter, request, response, chain, newCookie);
       } else {
         verifyUnauthorized(filter, request, response, chain);
       }
@@ -959,7 +1068,8 @@ public class TestAuthenticationFilter {
   private static void verifyAuthorized(AuthenticationFilter filter,
                                        HttpServletRequest request,
                                        HttpServletResponse response,
-                                       FilterChain chain) throws
+                                       FilterChain chain,
+                                       boolean newCookie) throws
                                                           Exception {
     final Map<String, String> cookieMap = new HashMap<>();
     Mockito.doAnswer(new Answer<Object>() {
@@ -973,26 +1083,34 @@ public class TestAuthenticationFilter {
 
     filter.doFilter(request, response, chain);
 
-    String v = cookieMap.get(AuthenticatedURL.AUTH_COOKIE);
-    Assert.assertNotNull("cookie missing", v);
-    Assert.assertTrue(v.contains("u=") && v.contains("p=") && v.contains
-            ("t=") && v.contains("i=") && v.contains("e=")
-            && v.contains("s="));
-    Mockito.verify(chain).doFilter(Mockito.any(ServletRequest.class),
-            Mockito.any(ServletResponse.class));
+    if (newCookie) {
+      // a new cookie should be dropped when maxInactiveInterval is enabled
+      String v = cookieMap.get(AuthenticatedURL.AUTH_COOKIE);
+      Assert.assertNotNull("cookie missing", v);
+      Assert.assertTrue(v.contains("u=") && v.contains("p=") && v.contains
+          ("t=") && v.contains("i=") && v.contains("e=")
+          && v.contains("s="));
+      Mockito.verify(chain).doFilter(Mockito.any(ServletRequest.class),
+          Mockito.any(ServletResponse.class));
 
-    SignerSecretProvider secretProvider =
-        StringSignerSecretProviderCreator.newStringSignerSecretProvider();
-    Properties secretProviderProps = new Properties();
-    secretProviderProps.setProperty(
-        AuthenticationFilter.SIGNATURE_SECRET, "secret");
-    secretProvider.init(secretProviderProps, null, TOKEN_VALIDITY_SEC);
-    Signer signer = new Signer(secretProvider);
-    String value = signer.verifyAndExtract(v);
-    AuthenticationToken token = AuthenticationToken.parse(value);
-    assertThat(token.getMaxInactives(), not(0L));
-    assertThat(token.getExpires(), not(0L));
-    Assert.assertFalse("Token is expired.", token.isExpired());
+      SignerSecretProvider secretProvider =
+          StringSignerSecretProviderCreator.newStringSignerSecretProvider();
+      Properties secretProviderProps = new Properties();
+      secretProviderProps.setProperty(
+          AuthenticationFilter.SIGNATURE_SECRET, "secret");
+      secretProvider.init(secretProviderProps, null, TOKEN_VALIDITY_SEC);
+      Signer signer = new Signer(secretProvider);
+      String value = signer.verifyAndExtract(v);
+      AuthenticationToken token = AuthenticationToken.parse(value);
+      assertThat(token.getMaxInactives(), not(0L));
+      assertThat(token.getExpires(), not(0L));
+      Assert.assertFalse("Token is expired.", token.isExpired());
+    } else {
+      //make sure that no auth cookie is dropped.
+      //For unauthorized response, auth cookie is dropped with empty value
+      Assert.assertTrue("cookie is present",
+          !cookieMap.containsKey(AuthenticatedURL.AUTH_COOKIE));
+    }
   }
 
   private static void verifyUnauthorized(AuthenticationFilter filter,
@@ -1001,6 +1119,7 @@ public class TestAuthenticationFilter {
                                          FilterChain chain) throws
                                                             IOException,
                                                             ServletException {
+    //For unauthorized response, a cookie is dropped with empty string as value
     final Map<String, String> cookieMap = new HashMap<String, String>();
     Mockito.doAnswer(new Answer<Object>() {
       @Override

http://git-wip-us.apache.org/repos/asf/hadoop/blob/4e5f77b7/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
index ae5c316..03f1d9d 100644
--- a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
+++ b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
@@ -44,7 +44,7 @@ The following properties should be in the `core-site.xml` of all the nodes
in th
 | `hadoop.http.filter.initializers`                      |                              
                 | Add to this property the `org.apache.hadoop.security.AuthenticationFilterInitializer`
initializer class.                                                                       
                                                                                         
                                                                                    |
 | `hadoop.http.authentication.type`                      | `simple`                     
                 | Defines authentication used for the HTTP web-consoles. The supported values
are: `simple` \| `kerberos` \| `#AUTHENTICATION_HANDLER_CLASSNAME#`.                     
                                                                                         
                                                                                         
    |
 | `hadoop.http.authentication.token.validity`            | `36000`                      
                 | Indicates how long (in seconds) an authentication token is valid before
it has to be renewed.                                                                    
                                                                                         
                                                                                         
        |
-| `hadoop.http.authentication.token.MaxInactiveInterval` | `1800` (30 minutes)          
                 | Specifies the time, in seconds, between client requests the server will
invalidate the token.                                                                    
                                                                                         
                                                                                         
        |
+| `hadoop.http.authentication.token.max-inactive-interval` | `-1` (disabled)            
               | Specifies the time, in seconds, between client requests the server will invalidate
the token.                                                                               
                                                                                         
                                                                                       |
 | `hadoop.http.authentication.signature.secret.file`     | `$user.home/hadoop-http-auth-signature-secret`
| The signature secret file for signing the authentication tokens. The same secret should
be used for all nodes in the cluster, JobTracker, NameNode, DataNode and TastTracker. This
file should be readable only by the Unix user running the daemons.                       
                                                                                 |
 | `hadoop.http.authentication.cookie.domain`             |                              
                 | The domain to use for the HTTP cookie that stores the authentication token.
For authentication to work correctly across all nodes in the cluster the domain must be correctly
set. There is no default value, the HTTP cookie will not have a domain working only with the
hostname issuing the HTTP cookie.                                                  |
 | `hadoop.http.authentication.cookie.persistent`         | `false` (session cookie)     
                 | Specifies the persistence of the HTTP cookie. If the value is true, the
cookie is a persistent one. Otherwise, it is a session cookie. *IMPORTANT*: when using IP
addresses, browsers ignore cookies with domain settings. For this setting to work properly
all nodes in the cluster must be configured to generate URLs with `hostname.domain` names
on it. |


Mime
View raw message