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 static org.junit.jupiter.api.Assertions.assertTrue; 021 022import java.io.File; 023import java.io.IOException; 024import java.net.HttpCookie; 025import java.net.HttpURLConnection; 026import java.net.URI; 027import java.net.URL; 028import java.security.GeneralSecurityException; 029import java.util.List; 030import javax.net.ssl.HttpsURLConnection; 031import javax.servlet.Filter; 032import javax.servlet.FilterChain; 033import javax.servlet.FilterConfig; 034import javax.servlet.ServletException; 035import javax.servlet.ServletRequest; 036import javax.servlet.ServletResponse; 037import javax.servlet.http.HttpServletResponse; 038import org.apache.hadoop.conf.Configuration; 039import org.apache.hadoop.fs.FileUtil; 040import org.apache.hadoop.hbase.testclassification.MiscTests; 041import org.apache.hadoop.hbase.testclassification.SmallTests; 042import org.apache.hadoop.net.NetUtils; 043import org.apache.hadoop.security.authentication.server.AuthenticationFilter; 044import org.apache.hadoop.security.ssl.KeyStoreTestUtil; 045import org.apache.hadoop.security.ssl.SSLFactory; 046import org.junit.jupiter.api.AfterAll; 047import org.junit.jupiter.api.BeforeAll; 048import org.junit.jupiter.api.Tag; 049import org.junit.jupiter.api.Test; 050 051@Tag(MiscTests.TAG) 052@Tag(SmallTests.TAG) 053public class TestHttpCookieFlag { 054 055 private static final String BASEDIR = System.getProperty("test.build.dir", "target/test-dir") 056 + "/" + org.apache.hadoop.hbase.http.TestHttpCookieFlag.class.getSimpleName(); 057 private static String keystoresDir; 058 private static String sslConfDir; 059 private static SSLFactory clientSslFactory; 060 private static HttpServer server; 061 062 public static class DummyAuthenticationFilter implements Filter { 063 064 @Override 065 public void init(FilterConfig filterConfig) throws ServletException { 066 } 067 068 @Override 069 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 070 throws IOException, ServletException { 071 HttpServletResponse resp = (HttpServletResponse) response; 072 boolean isHttps = "https".equals(request.getScheme()); 073 AuthenticationFilter.createAuthCookie(resp, "token", null, null, -1, true, isHttps); 074 chain.doFilter(request, resp); 075 } 076 077 @Override 078 public void destroy() { 079 } 080 } 081 082 public static class DummyFilterInitializer extends FilterInitializer { 083 @Override 084 public void initFilter(FilterContainer container, Configuration conf) { 085 container.addFilter("DummyAuth", DummyAuthenticationFilter.class.getName(), null); 086 } 087 } 088 089 @BeforeAll 090 public static void setUp() throws Exception { 091 Configuration conf = new Configuration(); 092 conf.set(HttpServer.FILTER_INITIALIZERS_PROPERTY, DummyFilterInitializer.class.getName()); 093 conf.setInt("hbase.http.max.threads", 19); /* acceptors=2 + selectors=16 + request=1 */ 094 System.setProperty("hadoop.log.dir", BASEDIR); /* needed for /logs */ 095 096 File base = new File(BASEDIR); 097 FileUtil.fullyDelete(base); 098 base.mkdirs(); 099 keystoresDir = new File(BASEDIR).getAbsolutePath(); 100 sslConfDir = KeyStoreTestUtil.getClasspathDir(TestSSLHttpServer.class); 101 102 KeyStoreTestUtil.setupSSLConfig(keystoresDir, sslConfDir, conf, false); 103 Configuration sslConf = KeyStoreTestUtil.getSslConfig(); 104 105 clientSslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, sslConf); 106 clientSslFactory.init(); 107 108 server = new HttpServer.Builder().setName("test").addEndpoint(new URI("http://localhost")) 109 .addEndpoint(new URI("https://localhost")).setConf(conf) 110 .keyPassword(sslConf.get("ssl.server.keystore.keypassword")) 111 .keyStore(sslConf.get("ssl.server.keystore.location"), 112 sslConf.get("ssl.server.keystore.password"), sslConf.get("ssl.server.keystore.type", "jks")) 113 .trustStore(sslConf.get("ssl.server.truststore.location"), 114 sslConf.get("ssl.server.truststore.password"), 115 sslConf.get("ssl.server.truststore.type", "jks")) 116 .build(); 117 server.addPrivilegedServlet("echo", "/echo", TestHttpServer.EchoServlet.class); 118 server.start(); 119 } 120 121 @Test 122 public void testHttpCookie() throws IOException { 123 URL base = new URL("http://" + NetUtils.getHostPortString(server.getConnectorAddress(0))); 124 HttpURLConnection conn = (HttpURLConnection) new URL(base, "/echo").openConnection(); 125 126 String header = conn.getHeaderField("Set-Cookie"); 127 assertTrue(header != null); 128 List<HttpCookie> cookies = HttpCookie.parse(header); 129 assertTrue(!cookies.isEmpty()); 130 assertTrue(header.contains("; HttpOnly")); 131 assertTrue("token".equals(cookies.get(0).getValue())); 132 } 133 134 @Test 135 public void testHttpsCookie() throws IOException, GeneralSecurityException { 136 URL base = new URL("https://" + NetUtils.getHostPortString(server.getConnectorAddress(1))); 137 HttpsURLConnection conn = (HttpsURLConnection) new URL(base, "/echo").openConnection(); 138 conn.setSSLSocketFactory(clientSslFactory.createSSLSocketFactory()); 139 140 String header = conn.getHeaderField("Set-Cookie"); 141 assertTrue(header != null); 142 143 List<HttpCookie> cookies = HttpCookie.parse(header); 144 assertTrue(!cookies.isEmpty()); 145 assertTrue(header.contains("; HttpOnly")); 146 assertTrue(cookies.get(0).getSecure()); 147 assertTrue("token".equals(cookies.get(0).getValue())); 148 } 149 150 @Test 151 public void testHttpsCookieDefaultServlets() throws Exception { 152 HttpsURLConnection conn = null; 153 154 URL base = 155 new URL("https://" + NetUtils.getHostPortString(server.getConnectorAddress(1)) + "/"); 156 157 for (String servlet : new String[] { "static", "stacks", "logLevel", "jmx", "logs" }) { 158 conn = (HttpsURLConnection) new URL(base, "/" + servlet).openConnection(); 159 conn.setSSLSocketFactory(clientSslFactory.createSSLSocketFactory()); 160 161 String header = conn.getHeaderField("Set-Cookie"); 162 assertTrue(header != null); 163 List<HttpCookie> cookies = HttpCookie.parse(header); 164 assertTrue(!cookies.isEmpty()); 165 assertTrue(header.contains("; HttpOnly")); 166 assertTrue(cookies.get(0).getSecure()); 167 assertTrue("token".equals(cookies.get(0).getValue())); 168 } 169 } 170 171 @AfterAll 172 public static void cleanup() throws Exception { 173 server.stop(); 174 FileUtil.fullyDelete(new File(BASEDIR)); 175 KeyStoreTestUtil.cleanupSSLConfig(keystoresDir, sslConfDir); 176 clientSslFactory.destroy(); 177 } 178}