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.ByteArrayOutputStream; 021import java.io.File; 022import java.io.InputStream; 023import java.net.URI; 024import java.net.URL; 025import javax.net.ssl.HttpsURLConnection; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.fs.FileUtil; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseCommonTestingUtility; 030import org.apache.hadoop.hbase.HBaseConfiguration; 031import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.io.IOUtils; 035import org.apache.hadoop.net.NetUtils; 036import org.apache.hadoop.security.ssl.SSLFactory; 037import org.junit.AfterClass; 038import org.junit.BeforeClass; 039import org.junit.ClassRule; 040import org.junit.Test; 041import org.junit.experimental.categories.Category; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045/** 046 * This testcase issues SSL certificates configures the HttpServer to serve 047 * HTTPS using the created certficates and calls an echo servlet using the 048 * corresponding HTTPS URL. 049 */ 050@Category({MiscTests.class, MediumTests.class}) 051public class TestSSLHttpServer extends HttpServerFunctionalTest { 052 053 @ClassRule 054 public static final HBaseClassTestRule CLASS_RULE = 055 HBaseClassTestRule.forClass(TestSSLHttpServer.class); 056 057 private static final String BASEDIR = System.getProperty("test.build.dir", 058 "target/test-dir") + "/" + TestSSLHttpServer.class.getSimpleName(); 059 060 private static final Logger LOG = LoggerFactory.getLogger(TestSSLHttpServer.class); 061 private static Configuration serverConf; 062 private static HttpServer server; 063 private static URL baseUrl; 064 private static File keystoresDir; 065 private static String sslConfDir; 066 private static SSLFactory clientSslFactory; 067 private static HBaseCommonTestingUtility HTU; 068 069 @BeforeClass 070 public static void setup() throws Exception { 071 072 HTU = new HBaseCommonTestingUtility(); 073 serverConf = HTU.getConfiguration(); 074 075 serverConf.setInt(HttpServer.HTTP_MAX_THREADS, TestHttpServer.MAX_THREADS); 076 077 keystoresDir = new File(HTU.getDataTestDir("keystore").toString()); 078 keystoresDir.mkdirs(); 079 080 sslConfDir = KeyStoreTestUtil.getClasspathDir(TestSSLHttpServer.class); 081 082 KeyStoreTestUtil.setupSSLConfig(keystoresDir.getAbsolutePath(), sslConfDir, serverConf, false); 083 Configuration clientConf = new Configuration(false); 084 clientConf.addResource(serverConf.get(SSLFactory.SSL_CLIENT_CONF_KEY)); 085 serverConf.addResource(serverConf.get(SSLFactory.SSL_SERVER_CONF_KEY)); 086 clientConf.set(SSLFactory.SSL_CLIENT_CONF_KEY, serverConf.get(SSLFactory.SSL_CLIENT_CONF_KEY)); 087 088 clientSslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, clientConf); 089 clientSslFactory.init(); 090 091 server = new HttpServer.Builder() 092 .setName("test") 093 .addEndpoint(new URI("https://localhost")) 094 .setConf(serverConf) 095 .keyPassword(HBaseConfiguration.getPassword(serverConf, "ssl.server.keystore.keypassword", 096 null)) 097 .keyStore(serverConf.get("ssl.server.keystore.location"), 098 HBaseConfiguration.getPassword(serverConf, "ssl.server.keystore.password", null), 099 clientConf.get("ssl.server.keystore.type", "jks")) 100 .trustStore(serverConf.get("ssl.server.truststore.location"), 101 HBaseConfiguration.getPassword(serverConf, "ssl.server.truststore.password", null), 102 serverConf.get("ssl.server.truststore.type", "jks")).build(); 103 server.addUnprivilegedServlet("echo", "/echo", TestHttpServer.EchoServlet.class); 104 server.start(); 105 baseUrl = new URL("https://" 106 + NetUtils.getHostPortString(server.getConnectorAddress(0))); 107 LOG.info("HTTP server started: " + baseUrl); 108 } 109 110 @AfterClass 111 public static void cleanup() throws Exception { 112 server.stop(); 113 FileUtil.fullyDelete(new File(HTU.getDataTestDir().toString())); 114 KeyStoreTestUtil.cleanupSSLConfig(serverConf); 115 clientSslFactory.destroy(); 116 } 117 118 @Test 119 public void testEcho() throws Exception { 120 assertEquals("a:b\nc:d\n", readOut(new URL(baseUrl, "/echo?a=b&c=d"))); 121 assertEquals("a:b\nc<:d\ne:>\n", readOut(new URL(baseUrl, 122 "/echo?a=b&c<=d&e=>"))); 123 } 124 125 private static String readOut(URL url) throws Exception { 126 HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 127 conn.setSSLSocketFactory(clientSslFactory.createSSLSocketFactory()); 128 InputStream in = conn.getInputStream(); 129 ByteArrayOutputStream out = new ByteArrayOutputStream(); 130 IOUtils.copyBytes(in, out, 1024); 131 return out.toString(); 132 } 133 134}