001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.http; 019 020import java.io.File; 021import java.io.IOException; 022import java.net.HttpCookie; 023import java.net.HttpURLConnection; 024import java.net.URI; 025import java.net.URL; 026import java.security.GeneralSecurityException; 027import java.util.List; 028import javax.net.ssl.HttpsURLConnection; 029import javax.servlet.Filter; 030import javax.servlet.FilterChain; 031import javax.servlet.FilterConfig; 032import javax.servlet.ServletException; 033import javax.servlet.ServletRequest; 034import javax.servlet.ServletResponse; 035import javax.servlet.http.HttpServletResponse; 036import org.apache.hadoop.conf.Configuration; 037import org.apache.hadoop.fs.FileUtil; 038import org.apache.hadoop.hbase.HBaseClassTestRule; 039import org.apache.hadoop.hbase.testclassification.MiscTests; 040import org.apache.hadoop.hbase.testclassification.SmallTests; 041import org.apache.hadoop.net.NetUtils; 042import org.apache.hadoop.security.authentication.server.AuthenticationFilter; 043import org.apache.hadoop.security.ssl.KeyStoreTestUtil; 044import org.apache.hadoop.security.ssl.SSLFactory; 045import org.junit.AfterClass; 046import org.junit.Assert; 047import org.junit.BeforeClass; 048import org.junit.ClassRule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051 052@Category({ MiscTests.class, SmallTests.class }) 053public class TestHttpCookieFlag { 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestHttpCookieFlag.class); 057 058 private static final String BASEDIR = System.getProperty("test.build.dir", "target/test-dir") 059 + "/" + org.apache.hadoop.hbase.http.TestHttpCookieFlag.class.getSimpleName(); 060 private static String keystoresDir; 061 private static String sslConfDir; 062 private static SSLFactory clientSslFactory; 063 private static HttpServer server; 064 065 public static class DummyAuthenticationFilter implements Filter { 066 067 @Override 068 public void init(FilterConfig filterConfig) throws ServletException { 069 } 070 071 @Override 072 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 073 throws IOException, ServletException { 074 HttpServletResponse resp = (HttpServletResponse) response; 075 boolean isHttps = "https".equals(request.getScheme()); 076 AuthenticationFilter.createAuthCookie(resp, "token", null, null, -1, true, isHttps); 077 chain.doFilter(request, resp); 078 } 079 080 @Override 081 public void destroy() { 082 } 083 } 084 085 public static class DummyFilterInitializer extends FilterInitializer { 086 @Override 087 public void initFilter(FilterContainer container, Configuration conf) { 088 container.addFilter("DummyAuth", DummyAuthenticationFilter.class.getName(), null); 089 } 090 } 091 092 @BeforeClass 093 public static void setUp() throws Exception { 094 Configuration conf = new Configuration(); 095 conf.set(HttpServer.FILTER_INITIALIZERS_PROPERTY, DummyFilterInitializer.class.getName()); 096 conf.setInt("hbase.http.max.threads", 19); /* acceptors=2 + selectors=16 + request=1 */ 097 System.setProperty("hadoop.log.dir", BASEDIR); /* needed for /logs */ 098 099 File base = new File(BASEDIR); 100 FileUtil.fullyDelete(base); 101 base.mkdirs(); 102 keystoresDir = new File(BASEDIR).getAbsolutePath(); 103 sslConfDir = KeyStoreTestUtil.getClasspathDir(TestSSLHttpServer.class); 104 105 KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir, conf, false); 106 Configuration sslConf = KeyStoreTestUtil.getSslConfig(); 107 108 clientSslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, sslConf); 109 clientSslFactory.init(); 110 111 server = new HttpServer.Builder().setName("test").addEndpoint(new URI("http://localhost")) 112 .addEndpoint(new URI("https://localhost")).setConf(conf) 113 .keyPassword(sslConf.get("ssl.server.keystore.keypassword")) 114 .keyStore(sslConf.get("ssl.server.keystore.location"), 115 sslConf.get("ssl.server.keystore.password"), sslConf.get("ssl.server.keystore.type", "jks")) 116 .trustStore(sslConf.get("ssl.server.truststore.location"), 117 sslConf.get("ssl.server.truststore.password"), 118 sslConf.get("ssl.server.truststore.type", "jks")) 119 .build(); 120 server.addPrivilegedServlet("echo", "/echo", TestHttpServer.EchoServlet.class); 121 server.start(); 122 } 123 124 @Test 125 public void testHttpCookie() throws IOException { 126 URL base = new URL("http://" + NetUtils.getHostPortString(server.getConnectorAddress(0))); 127 HttpURLConnection conn = (HttpURLConnection) new URL(base, "/echo").openConnection(); 128 129 String header = conn.getHeaderField("Set-Cookie"); 130 Assert.assertTrue(header != null); 131 List<HttpCookie> cookies = HttpCookie.parse(header); 132 Assert.assertTrue(!cookies.isEmpty()); 133 Assert.assertTrue(header.contains("; HttpOnly")); 134 Assert.assertTrue("token".equals(cookies.get(0).getValue())); 135 } 136 137 @Test 138 public void testHttpsCookie() throws IOException, GeneralSecurityException { 139 URL base = new URL("https://" + NetUtils.getHostPortString(server.getConnectorAddress(1))); 140 HttpsURLConnection conn = (HttpsURLConnection) new URL(base, "/echo").openConnection(); 141 conn.setSSLSocketFactory(clientSslFactory.createSSLSocketFactory()); 142 143 String header = conn.getHeaderField("Set-Cookie"); 144 Assert.assertTrue(header != null); 145 146 List<HttpCookie> cookies = HttpCookie.parse(header); 147 Assert.assertTrue(!cookies.isEmpty()); 148 Assert.assertTrue(header.contains("; HttpOnly")); 149 Assert.assertTrue(cookies.get(0).getSecure()); 150 Assert.assertTrue("token".equals(cookies.get(0).getValue())); 151 } 152 153 @Test 154 public void testHttpsCookieDefaultServlets() throws Exception { 155 HttpsURLConnection conn = null; 156 157 URL base = 158 new URL("https://" + NetUtils.getHostPortString(server.getConnectorAddress(1)) + "/"); 159 160 for (String servlet : new String[] { "static", "stacks", "logLevel", "jmx", "logs" }) { 161 conn = (HttpsURLConnection) new URL(base, "/" + servlet).openConnection(); 162 conn.setSSLSocketFactory(clientSslFactory.createSSLSocketFactory()); 163 164 String header = conn.getHeaderField("Set-Cookie"); 165 Assert.assertTrue(header != null); 166 List<HttpCookie> cookies = HttpCookie.parse(header); 167 Assert.assertTrue(!cookies.isEmpty()); 168 Assert.assertTrue(header.contains("; HttpOnly")); 169 Assert.assertTrue(cookies.get(0).getSecure()); 170 Assert.assertTrue("token".equals(cookies.get(0).getValue())); 171 } 172 } 173 174 @AfterClass 175 public static void cleanup() throws Exception { 176 server.stop(); 177 FileUtil.fullyDelete(new File(BASEDIR)); 178 KeyStoreTestUtil.cleanupSSLConfig(keystoresDir, sslConfDir); 179 clientSslFactory.destroy(); 180 } 181}