2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.http
;
20 import java
.io
.ByteArrayOutputStream
;
22 import java
.io
.IOException
;
23 import java
.io
.InputStream
;
26 import java
.security
.GeneralSecurityException
;
27 import javax
.net
.ssl
.HttpsURLConnection
;
28 import org
.apache
.hadoop
.conf
.Configuration
;
29 import org
.apache
.hadoop
.fs
.FileUtil
;
30 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
31 import org
.apache
.hadoop
.hbase
.HBaseCommonTestingUtil
;
32 import org
.apache
.hadoop
.hbase
.HBaseConfiguration
;
33 import org
.apache
.hadoop
.hbase
.http
.ssl
.KeyStoreTestUtil
;
34 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
35 import org
.apache
.hadoop
.hbase
.testclassification
.MiscTests
;
36 import org
.apache
.hadoop
.io
.IOUtils
;
37 import org
.apache
.hadoop
.net
.NetUtils
;
38 import org
.apache
.hadoop
.security
.ssl
.SSLFactory
;
39 import org
.junit
.AfterClass
;
40 import org
.junit
.BeforeClass
;
41 import org
.junit
.ClassRule
;
42 import org
.junit
.Test
;
43 import org
.junit
.experimental
.categories
.Category
;
44 import org
.slf4j
.Logger
;
45 import org
.slf4j
.LoggerFactory
;
48 * This testcase issues SSL certificates configures the HttpServer to serve
49 * HTTPS using the created certficates and calls an echo servlet using the
50 * corresponding HTTPS URL.
52 @Category({MiscTests
.class, MediumTests
.class})
53 public class TestSSLHttpServer
extends HttpServerFunctionalTest
{
56 public static final HBaseClassTestRule CLASS_RULE
=
57 HBaseClassTestRule
.forClass(TestSSLHttpServer
.class);
59 private static final String BASEDIR
= System
.getProperty("test.build.dir",
60 "target/test-dir") + "/" + TestSSLHttpServer
.class.getSimpleName();
62 private static final Logger LOG
= LoggerFactory
.getLogger(TestSSLHttpServer
.class);
63 private static Configuration serverConf
;
64 private static HttpServer server
;
65 private static URL baseUrl
;
66 private static File keystoresDir
;
67 private static String sslConfDir
;
68 private static SSLFactory clientSslFactory
;
69 private static HBaseCommonTestingUtil HTU
;
72 public static void setup() throws Exception
{
74 HTU
= new HBaseCommonTestingUtil();
75 serverConf
= HTU
.getConfiguration();
77 serverConf
.setInt(HttpServer
.HTTP_MAX_THREADS
, TestHttpServer
.MAX_THREADS
);
78 serverConf
.setBoolean(ServerConfigurationKeys
.HBASE_SSL_ENABLED_KEY
, true);
80 keystoresDir
= new File(HTU
.getDataTestDir("keystore").toString());
81 keystoresDir
.mkdirs();
83 sslConfDir
= KeyStoreTestUtil
.getClasspathDir(TestSSLHttpServer
.class);
85 KeyStoreTestUtil
.setupSSLConfig(keystoresDir
.getAbsolutePath(), sslConfDir
, serverConf
, false);
86 Configuration clientConf
= new Configuration(false);
87 clientConf
.addResource(serverConf
.get(SSLFactory
.SSL_CLIENT_CONF_KEY
));
88 serverConf
.addResource(serverConf
.get(SSLFactory
.SSL_SERVER_CONF_KEY
));
89 clientConf
.set(SSLFactory
.SSL_CLIENT_CONF_KEY
, serverConf
.get(SSLFactory
.SSL_CLIENT_CONF_KEY
));
91 clientSslFactory
= new SSLFactory(SSLFactory
.Mode
.CLIENT
, clientConf
);
92 clientSslFactory
.init();
94 server
= new HttpServer
.Builder()
96 .addEndpoint(new URI("https://localhost"))
98 .keyPassword(HBaseConfiguration
.getPassword(serverConf
, "ssl.server.keystore.keypassword",
100 .keyStore(serverConf
.get("ssl.server.keystore.location"),
101 HBaseConfiguration
.getPassword(serverConf
, "ssl.server.keystore.password", null),
102 clientConf
.get("ssl.server.keystore.type", "jks"))
103 .trustStore(serverConf
.get("ssl.server.truststore.location"),
104 HBaseConfiguration
.getPassword(serverConf
, "ssl.server.truststore.password", null),
105 serverConf
.get("ssl.server.truststore.type", "jks")).build();
106 server
.addUnprivilegedServlet("echo", "/echo", TestHttpServer
.EchoServlet
.class);
108 baseUrl
= new URL("https://"
109 + NetUtils
.getHostPortString(server
.getConnectorAddress(0)));
110 LOG
.info("HTTP server started: " + baseUrl
);
114 public static void cleanup() throws Exception
{
116 FileUtil
.fullyDelete(new File(HTU
.getDataTestDir().toString()));
117 KeyStoreTestUtil
.cleanupSSLConfig(serverConf
);
118 clientSslFactory
.destroy();
122 public void testEcho() throws Exception
{
123 assertEquals("a:b\nc:d\n", readOut(new URL(baseUrl
, "/echo?a=b&c=d")));
124 assertEquals("a:b\nc<:d\ne:>\n", readOut(new URL(baseUrl
,
125 "/echo?a=b&c<=d&e=>")));
129 public void testSecurityHeaders() throws IOException
, GeneralSecurityException
{
130 HttpsURLConnection conn
= (HttpsURLConnection
) baseUrl
.openConnection();
131 conn
.setSSLSocketFactory(clientSslFactory
.createSSLSocketFactory());
132 assertEquals(HttpsURLConnection
.HTTP_OK
, conn
.getResponseCode());
133 assertEquals("max-age=63072000;includeSubDomains;preload",
134 conn
.getHeaderField("Strict-Transport-Security"));
135 assertEquals("default-src https: data: 'unsafe-inline' 'unsafe-eval'",
136 conn
.getHeaderField("Content-Security-Policy"));
139 private static String
readOut(URL url
) throws Exception
{
140 HttpsURLConnection conn
= (HttpsURLConnection
) url
.openConnection();
141 conn
.setSSLSocketFactory(clientSslFactory
.createSSLSocketFactory());
142 InputStream in
= conn
.getInputStream();
143 ByteArrayOutputStream out
= new ByteArrayOutputStream();
144 IOUtils
.copyBytes(in
, out
, 1024);
145 return out
.toString();