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