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.rest; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import java.io.File; 024import java.security.KeyPair; 025import java.security.cert.X509Certificate; 026import java.util.Optional; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil; 031import org.apache.hadoop.hbase.rest.client.Client; 032import org.apache.hadoop.hbase.rest.client.Cluster; 033import org.apache.hadoop.hbase.rest.client.Response; 034import org.apache.hadoop.hbase.testclassification.MediumTests; 035import org.apache.hadoop.hbase.testclassification.RestTests; 036import org.junit.After; 037import org.junit.AfterClass; 038import org.junit.Before; 039import org.junit.BeforeClass; 040import org.junit.ClassRule; 041import org.junit.Test; 042import org.junit.experimental.categories.Category; 043 044@Category({ RestTests.class, MediumTests.class}) 045public class TestRESTServerSSL { 046 047 @ClassRule 048 public static final HBaseClassTestRule CLASS_RULE = 049 HBaseClassTestRule.forClass(TestRESTServerSSL.class); 050 051 private static final String KEY_STORE_PASSWORD = "myKSPassword"; 052 private static final String TRUST_STORE_PASSWORD = "myTSPassword"; 053 054 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 055 private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility(); 056 private static Client sslClient; 057 private static File keyDir; 058 private Configuration conf; 059 060 @BeforeClass 061 public static void beforeClass() throws Exception { 062 keyDir = initKeystoreDir(); 063 KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA"); 064 X509Certificate serverCertificate = KeyStoreTestUtil.generateCertificate( 065 "CN=localhost, O=server", keyPair, 30, "SHA1withRSA"); 066 067 generateTrustStore("jks", serverCertificate); 068 generateTrustStore("jceks", serverCertificate); 069 generateTrustStore("pkcs12", serverCertificate); 070 071 generateKeyStore("jks", keyPair, serverCertificate); 072 generateKeyStore("jceks", keyPair, serverCertificate); 073 generateKeyStore("pkcs12", keyPair, serverCertificate); 074 075 TEST_UTIL.startMiniCluster(); 076 } 077 078 @AfterClass 079 public static void afterClass() throws Exception { 080 // this will also delete the generated test keystore / teststore files, 081 // as we were placing them under the dataTestDir used by the minicluster 082 TEST_UTIL.shutdownMiniCluster(); 083 } 084 085 @Before 086 public void beforeEachTest() { 087 conf = new Configuration(TEST_UTIL.getConfiguration()); 088 conf.set(Constants.REST_SSL_ENABLED, "true"); 089 conf.set(Constants.REST_SSL_KEYSTORE_KEYPASSWORD, KEY_STORE_PASSWORD); 090 conf.set(Constants.REST_SSL_KEYSTORE_PASSWORD, KEY_STORE_PASSWORD); 091 conf.set(Constants.REST_SSL_TRUSTSTORE_PASSWORD, TRUST_STORE_PASSWORD); 092 } 093 094 @After 095 public void tearDownAfterTest() { 096 REST_TEST_UTIL.shutdownServletContainer(); 097 } 098 099 @Test 100 public void testSslConnection() throws Exception { 101 startRESTServerWithDefaultKeystoreType(); 102 103 Response response = sslClient.get("/version", Constants.MIMETYPE_TEXT); 104 assertEquals(200, response.getCode()); 105 } 106 107 @Test(expected = org.apache.http.client.ClientProtocolException.class) 108 public void testNonSslClientDenied() throws Exception { 109 startRESTServerWithDefaultKeystoreType(); 110 111 Cluster localCluster = new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()); 112 Client nonSslClient = new Client(localCluster, false); 113 114 nonSslClient.get("/version"); 115 } 116 117 @Test 118 public void testSslConnectionUsingKeystoreFormatJKS() throws Exception { 119 startRESTServer("jks"); 120 121 Response response = sslClient.get("/version", Constants.MIMETYPE_TEXT); 122 assertEquals(200, response.getCode()); 123 } 124 125 @Test 126 public void testSslConnectionUsingKeystoreFormatJCEKS() throws Exception { 127 startRESTServer("jceks"); 128 129 Response response = sslClient.get("/version", Constants.MIMETYPE_TEXT); 130 assertEquals(200, response.getCode()); 131 } 132 133 @Test 134 public void testSslConnectionUsingKeystoreFormatPKCS12() throws Exception { 135 startRESTServer("pkcs12"); 136 137 Response response = sslClient.get("/version", Constants.MIMETYPE_TEXT); 138 assertEquals(200, response.getCode()); 139 } 140 141 142 143 private static File initKeystoreDir() { 144 String dataTestDir = TEST_UTIL.getDataTestDir().toString(); 145 File keystoreDir = new File(dataTestDir, TestRESTServerSSL.class.getSimpleName() + "_keys"); 146 keystoreDir.mkdirs(); 147 return keystoreDir; 148 } 149 150 private static void generateKeyStore(String keyStoreType, KeyPair keyPair, 151 X509Certificate serverCertificate) throws Exception { 152 String keyStorePath = getKeystoreFilePath(keyStoreType); 153 KeyStoreTestUtil.createKeyStore(keyStorePath, KEY_STORE_PASSWORD, KEY_STORE_PASSWORD, 154 "serverKS", keyPair.getPrivate(), serverCertificate, keyStoreType); 155 } 156 157 private static void generateTrustStore(String trustStoreType, X509Certificate serverCertificate) 158 throws Exception { 159 String trustStorePath = getTruststoreFilePath(trustStoreType); 160 KeyStoreTestUtil.createTrustStore(trustStorePath, TRUST_STORE_PASSWORD, "serverTS", 161 serverCertificate, trustStoreType); 162 } 163 164 private static String getKeystoreFilePath(String keyStoreType) { 165 return String.format("%s/serverKS.%s", keyDir.getAbsolutePath(), keyStoreType); 166 } 167 168 private static String getTruststoreFilePath(String trustStoreType) { 169 return String.format("%s/serverTS.%s", keyDir.getAbsolutePath(), trustStoreType); 170 } 171 172 private void startRESTServerWithDefaultKeystoreType() throws Exception { 173 conf.set(Constants.REST_SSL_KEYSTORE_STORE, getKeystoreFilePath("jks")); 174 conf.set(Constants.REST_SSL_TRUSTSTORE_STORE, getTruststoreFilePath("jks")); 175 176 REST_TEST_UTIL.startServletContainer(conf); 177 Cluster localCluster = new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()); 178 sslClient = new Client(localCluster, getTruststoreFilePath("jks"), 179 Optional.of(TRUST_STORE_PASSWORD), Optional.empty()); 180 } 181 182 private void startRESTServer(String storeType) throws Exception { 183 conf.set(Constants.REST_SSL_KEYSTORE_TYPE, storeType); 184 conf.set(Constants.REST_SSL_KEYSTORE_STORE, getKeystoreFilePath(storeType)); 185 186 conf.set(Constants.REST_SSL_TRUSTSTORE_STORE, getTruststoreFilePath(storeType)); 187 conf.set(Constants.REST_SSL_TRUSTSTORE_TYPE, storeType); 188 189 REST_TEST_UTIL.startServletContainer(conf); 190 Cluster localCluster = new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()); 191 sslClient = new Client(localCluster, getTruststoreFilePath(storeType), 192 Optional.of(TRUST_STORE_PASSWORD), Optional.of(storeType)); 193 } 194 195}