You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ar...@apache.org on 2015/06/26 23:39:00 UTC

[05/19] hadoop git commit: HADOOP-12049. Control http authentication cookie persistence via configuration. Contributed by Huizhi Lu.

HADOOP-12049. Control http authentication cookie persistence via configuration. Contributed by Huizhi Lu.


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

Branch: refs/heads/HDFS-7240
Commit: a815cc157ceb24e02189634a85abed8e874568e0
Parents: afe9ea3
Author: Benoy Antony <be...@apache.org>
Authored: Wed Jun 24 15:59:39 2015 -0700
Committer: Benoy Antony <be...@apache.org>
Committed: Wed Jun 24 15:59:39 2015 -0700

----------------------------------------------------------------------
 .../server/AuthenticationFilter.java            |  28 ++-
 .../http/TestAuthenticationSessionCookie.java   | 187 +++++++++++++++++++
 .../apache/hadoop/http/TestHttpCookieFlag.java  |   2 +-
 3 files changed, 213 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/a815cc15/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 0f86623..bf44f48 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
@@ -161,6 +161,12 @@ public class AuthenticationFilter implements Filter {
   public static final String COOKIE_PATH = "cookie.path";
 
   /**
+   * Constant for the configuration property
+   * that indicates the persistence of the HTTP cookie.
+   */
+  public static final String COOKIE_PERSISTENT = "cookie.persistent";
+
+  /**
    * Constant for the configuration property that indicates the name of the
    * SignerSecretProvider class to use.
    * Possible values are: "string", "random", "zookeeper", or a classname.
@@ -187,6 +193,7 @@ public class AuthenticationFilter implements Filter {
   private long validity;
   private String cookieDomain;
   private String cookiePath;
+  private boolean isCookiePersistent;
   private boolean isInitializedByTomcat;
 
   /**
@@ -228,6 +235,9 @@ public class AuthenticationFilter implements Filter {
 
     cookieDomain = config.getProperty(COOKIE_DOMAIN, null);
     cookiePath = config.getProperty(COOKIE_PATH, null);
+    isCookiePersistent = Boolean.parseBoolean(
+            config.getProperty(COOKIE_PERSISTENT, "false"));
+
   }
 
   protected void initializeAuthHandler(String authHandlerClassName, FilterConfig filterConfig)
@@ -372,6 +382,15 @@ public class AuthenticationFilter implements Filter {
   }
 
   /**
+   * Returns the cookie persistence to use for the HTTP cookie.
+   *
+   * @return the cookie persistence to use for the HTTP cookie.
+   */
+  protected boolean isCookiePersistent() {
+    return isCookiePersistent;
+  }
+
+  /**
    * Destroys the filter.
    * <p>
    * It invokes the {@link AuthenticationHandler#destroy()} method to release any resources it may hold.
@@ -549,7 +568,8 @@ public class AuthenticationFilter implements Filter {
           if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) {
             String signedToken = signer.sign(token.toString());
             createAuthCookie(httpResponse, signedToken, getCookieDomain(),
-                    getCookiePath(), token.getExpires(), isHttps);
+                    getCookiePath(), token.getExpires(),
+                    isCookiePersistent(), isHttps);
           }
           doFilter(filterChain, httpRequest, httpResponse);
         }
@@ -569,7 +589,7 @@ public class AuthenticationFilter implements Filter {
     if (unauthorizedResponse) {
       if (!httpResponse.isCommitted()) {
         createAuthCookie(httpResponse, "", getCookieDomain(),
-                getCookiePath(), 0, isHttps);
+                getCookiePath(), 0, isCookiePersistent(), isHttps);
         // If response code is 401. Then WWW-Authenticate Header should be
         // present.. reset to 403 if not found..
         if ((errCode == HttpServletResponse.SC_UNAUTHORIZED)
@@ -614,6 +634,7 @@ public class AuthenticationFilter implements Filter {
    * @param isSecure is the cookie secure?
    * @param token the token.
    * @param expires the cookie expiration time.
+   * @param isCookiePersistent whether the cookie is persistent or not.
    *
    * XXX the following code duplicate some logic in Jetty / Servlet API,
    * because of the fact that Hadoop is stuck at servlet 2.5 and jetty 6
@@ -621,6 +642,7 @@ public class AuthenticationFilter implements Filter {
    */
   public static void createAuthCookie(HttpServletResponse resp, String token,
                                       String domain, String path, long expires,
+                                      boolean isCookiePersistent,
                                       boolean isSecure) {
     StringBuilder sb = new StringBuilder(AuthenticatedURL.AUTH_COOKIE)
                            .append("=");
@@ -636,7 +658,7 @@ public class AuthenticationFilter implements Filter {
       sb.append("; Domain=").append(domain);
     }
 
-    if (expires >= 0) {
+    if (expires >= 0 && isCookiePersistent) {
       Date date = new Date(expires);
       SimpleDateFormat df = new SimpleDateFormat("EEE, " +
               "dd-MMM-yyyy HH:mm:ss zzz");

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a815cc15/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestAuthenticationSessionCookie.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestAuthenticationSessionCookie.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestAuthenticationSessionCookie.java
new file mode 100644
index 0000000..e435034
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestAuthenticationSessionCookie.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.hadoop.http;
+
+import org.junit.Assert;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
+import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
+import org.junit.After;
+import org.junit.Test;
+import org.mortbay.log.Log;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.net.HttpCookie;
+import java.util.List;
+
+public class TestAuthenticationSessionCookie {
+  private static final String BASEDIR = System.getProperty("test.build.dir",
+          "target/test-dir") + "/" + TestHttpCookieFlag.class.getSimpleName();
+  private static boolean isCookiePersistent;
+  private static final long TOKEN_VALIDITY_SEC = 1000;
+  private static long expires;
+  private static String keystoresDir;
+  private static String sslConfDir;
+  private static HttpServer2 server;
+
+  public static class DummyAuthenticationFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+      isCookiePersistent = false;
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain) throws IOException,
+                                                   ServletException {
+      HttpServletResponse resp = (HttpServletResponse) response;
+      AuthenticationFilter.createAuthCookie(resp, "token", null, null, expires,
+              isCookiePersistent, true);
+      chain.doFilter(request, resp);
+    }
+
+    @Override
+    public void destroy() {
+    }
+  }
+
+  public static class DummyFilterInitializer extends FilterInitializer {
+    @Override
+    public void initFilter(FilterContainer container, Configuration conf) {
+      container.addFilter("DummyAuth", DummyAuthenticationFilter.class
+              .getName(), null);
+    }
+  }
+
+  public static class Dummy2AuthenticationFilter
+  extends DummyAuthenticationFilter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+      isCookiePersistent = true;
+      expires = System.currentTimeMillis() + TOKEN_VALIDITY_SEC;
+    }
+
+    @Override
+    public void destroy() {
+    }
+  }
+
+  public static class Dummy2FilterInitializer extends FilterInitializer {
+    @Override
+    public void initFilter(FilterContainer container, Configuration conf) {
+      container.addFilter("Dummy2Auth", Dummy2AuthenticationFilter.class
+              .getName(), null);
+    }
+  }
+
+  public void startServer(boolean isTestSessionCookie) throws Exception {
+    Configuration conf = new Configuration();
+    if (isTestSessionCookie) {
+      conf.set(HttpServer2.FILTER_INITIALIZER_PROPERTY,
+            DummyFilterInitializer.class.getName());
+    } else {
+      conf.set(HttpServer2.FILTER_INITIALIZER_PROPERTY,
+            Dummy2FilterInitializer.class.getName());
+    }
+
+    File base = new File(BASEDIR);
+    FileUtil.fullyDelete(base);
+    base.mkdirs();
+    keystoresDir = new File(BASEDIR).getAbsolutePath();
+    sslConfDir = KeyStoreTestUtil.getClasspathDir(TestSSLHttpServer.class);
+
+    KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir, conf, false);
+    Configuration sslConf = new Configuration(false);
+    sslConf.addResource("ssl-server.xml");
+    sslConf.addResource("ssl-client.xml");
+
+
+    server = new HttpServer2.Builder()
+            .setName("test")
+            .addEndpoint(new URI("http://localhost"))
+            .addEndpoint(new URI("https://localhost"))
+            .setConf(conf)
+            .keyPassword(sslConf.get("ssl.server.keystore.keypassword"))
+            .keyStore(sslConf.get("ssl.server.keystore.location"),
+                    sslConf.get("ssl.server.keystore.password"),
+                    sslConf.get("ssl.server.keystore.type", "jks"))
+            .trustStore(sslConf.get("ssl.server.truststore.location"),
+                    sslConf.get("ssl.server.truststore.password"),
+                    sslConf.get("ssl.server.truststore.type", "jks")).build();
+    server.addServlet("echo", "/echo", TestHttpServer.EchoServlet.class);
+    server.start();
+  }
+
+  @Test
+  public void testSessionCookie() throws IOException {
+    try {
+        startServer(true);
+    } catch (Exception e) {
+        // Auto-generated catch block
+        e.printStackTrace();
+    }
+
+    URL base = new URL("http://" + NetUtils.getHostPortString(server
+            .getConnectorAddress(0)));
+    HttpURLConnection conn = (HttpURLConnection) new URL(base,
+            "/echo").openConnection();
+
+    String header = conn.getHeaderField("Set-Cookie");
+    List<HttpCookie> cookies = HttpCookie.parse(header);
+    Assert.assertTrue(!cookies.isEmpty());
+    Log.info(header);
+    Assert.assertFalse(header.contains("; Expires="));
+    Assert.assertTrue("token".equals(cookies.get(0).getValue()));
+  }
+  
+  @Test
+  public void testPersistentCookie() throws IOException {
+    try {
+        startServer(false);
+    } catch (Exception e) {
+        // Auto-generated catch block
+        e.printStackTrace();
+    }
+
+    URL base = new URL("http://" + NetUtils.getHostPortString(server
+            .getConnectorAddress(0)));
+    HttpURLConnection conn = (HttpURLConnection) new URL(base,
+            "/echo").openConnection();
+
+    String header = conn.getHeaderField("Set-Cookie");
+    List<HttpCookie> cookies = HttpCookie.parse(header);
+    Assert.assertTrue(!cookies.isEmpty());
+    Log.info(header);
+    Assert.assertTrue(header.contains("; Expires="));
+    Assert.assertTrue("token".equals(cookies.get(0).getValue()));
+  }
+
+  @After
+  public void cleanup() throws Exception {
+    server.stop();
+    FileUtil.fullyDelete(new File(BASEDIR));
+    KeyStoreTestUtil.cleanupSSLConfig(keystoresDir, sslConfDir);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/a815cc15/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpCookieFlag.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpCookieFlag.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpCookieFlag.java
index 75a9480..5c5ed48 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpCookieFlag.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestHttpCookieFlag.java
@@ -60,7 +60,7 @@ public class TestHttpCookieFlag {
       HttpServletResponse resp = (HttpServletResponse) response;
       boolean isHttps = "https".equals(request.getScheme());
       AuthenticationFilter.createAuthCookie(resp, "token", null, null, -1,
-              isHttps);
+              true, isHttps);
       chain.doFilter(request, resp);
     }