Return-Path: X-Original-To: apmail-hadoop-common-commits-archive@www.apache.org Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0FB0A17A71 for ; Thu, 25 Jun 2015 01:07:52 +0000 (UTC) Received: (qmail 81058 invoked by uid 500); 25 Jun 2015 01:07:36 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 80818 invoked by uid 500); 25 Jun 2015 01:07:36 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 79228 invoked by uid 99); 25 Jun 2015 01:07:35 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Jun 2015 01:07:35 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id B54C1E3659; Thu, 25 Jun 2015 01:07:35 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: wheat9@apache.org To: common-commits@hadoop.apache.org Date: Thu, 25 Jun 2015 01:08:22 -0000 Message-Id: <4cbc9a21d7b047fba2f198e1c9bf336f@git.apache.org> In-Reply-To: <846a4567e75944c39b6257b66ede2c0a@git.apache.org> References: <846a4567e75944c39b6257b66ede2c0a@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [49/50] [abbrv] 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-7966 Commit: a815cc157ceb24e02189634a85abed8e874568e0 Parents: afe9ea3 Author: Benoy Antony Authored: Wed Jun 24 15:59:39 2015 -0700 Committer: Benoy Antony 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. *

* 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 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 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); }