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.security; 019 020import static org.apache.hadoop.hbase.ipc.TestProtobufRpcServiceImpl.SERVICE; 021import static org.apache.hadoop.hbase.ipc.TestProtobufRpcServiceImpl.newBlockingStub; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertNull; 024import static org.mockito.Mockito.mock; 025import static org.mockito.Mockito.when; 026 027import java.io.File; 028import java.io.IOException; 029import java.net.InetSocketAddress; 030import java.security.GeneralSecurityException; 031import java.security.Security; 032import java.util.ArrayList; 033import java.util.List; 034import org.apache.commons.io.FileUtils; 035import org.apache.hadoop.conf.Configuration; 036import org.apache.hadoop.hbase.HBaseClassTestRule; 037import org.apache.hadoop.hbase.HBaseCommonTestingUtil; 038import org.apache.hadoop.hbase.HBaseConfiguration; 039import org.apache.hadoop.hbase.HBaseServerBase; 040import org.apache.hadoop.hbase.ServerName; 041import org.apache.hadoop.hbase.io.crypto.tls.KeyStoreFileType; 042import org.apache.hadoop.hbase.io.crypto.tls.X509KeyType; 043import org.apache.hadoop.hbase.io.crypto.tls.X509TestContext; 044import org.apache.hadoop.hbase.io.crypto.tls.X509TestContextProvider; 045import org.apache.hadoop.hbase.io.crypto.tls.X509Util; 046import org.apache.hadoop.hbase.ipc.AbstractRpcClient; 047import org.apache.hadoop.hbase.ipc.FifoRpcScheduler; 048import org.apache.hadoop.hbase.ipc.HBaseRpcController; 049import org.apache.hadoop.hbase.ipc.HBaseRpcControllerImpl; 050import org.apache.hadoop.hbase.ipc.NettyRpcClient; 051import org.apache.hadoop.hbase.ipc.NettyRpcServer; 052import org.apache.hadoop.hbase.ipc.RpcScheduler; 053import org.apache.hadoop.hbase.ipc.RpcServer; 054import org.apache.hadoop.hbase.net.Address; 055import org.apache.hadoop.hbase.testclassification.MediumTests; 056import org.apache.hadoop.hbase.testclassification.RPCTests; 057import org.apache.hadoop.hbase.util.NettyEventLoopGroupConfig; 058import org.bouncycastle.jce.provider.BouncyCastleProvider; 059import org.bouncycastle.operator.OperatorCreationException; 060import org.junit.After; 061import org.junit.AfterClass; 062import org.junit.Before; 063import org.junit.BeforeClass; 064import org.junit.ClassRule; 065import org.junit.Test; 066import org.junit.experimental.categories.Category; 067import org.junit.runner.RunWith; 068import org.junit.runners.Parameterized; 069 070import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 071import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; 072 073import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestProtos; 074import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestRpcServiceProtos; 075 076@RunWith(Parameterized.class) 077@Category({ RPCTests.class, MediumTests.class }) 078public class TestNettyTLSIPCFileWatcher { 079 080 @ClassRule 081 public static final HBaseClassTestRule CLASS_RULE = 082 HBaseClassTestRule.forClass(TestNettyTLSIPCFileWatcher.class); 083 084 private static final Configuration CONF = HBaseConfiguration.create(); 085 private static final HBaseCommonTestingUtil UTIL = new HBaseCommonTestingUtil(CONF); 086 private static HBaseServerBase<?> SERVER; 087 private static X509TestContextProvider PROVIDER; 088 private static NettyEventLoopGroupConfig EVENT_LOOP_GROUP_CONFIG; 089 090 private X509TestContext x509TestContext; 091 092 @Parameterized.Parameter(0) 093 public X509KeyType keyType; 094 095 @Parameterized.Parameter(1) 096 public KeyStoreFileType storeFileType; 097 098 @Parameterized.Parameters(name = "{index}: keyType={0}, storeFileType={1}") 099 public static List<Object[]> data() { 100 List<Object[]> params = new ArrayList<>(); 101 for (X509KeyType caKeyType : X509KeyType.values()) { 102 for (KeyStoreFileType ks : KeyStoreFileType.values()) { 103 params.add(new Object[] { caKeyType, ks }); 104 } 105 } 106 return params; 107 } 108 109 @BeforeClass 110 public static void setUpBeforeClass() throws IOException { 111 Security.addProvider(new BouncyCastleProvider()); 112 File dir = 113 new File(UTIL.getDataTestDir(TestNettyTLSIPCFileWatcher.class.getSimpleName()).toString()) 114 .getCanonicalFile(); 115 FileUtils.forceMkdir(dir); 116 // server must enable tls 117 CONF.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_ENABLED, true); 118 PROVIDER = new X509TestContextProvider(CONF, dir); 119 EVENT_LOOP_GROUP_CONFIG = 120 NettyEventLoopGroupConfig.setup(CONF, TestNettyTLSIPCFileWatcher.class.getSimpleName()); 121 SERVER = mock(HBaseServerBase.class); 122 when(SERVER.getEventLoopGroupConfig()).thenReturn(EVENT_LOOP_GROUP_CONFIG); 123 } 124 125 @AfterClass 126 public static void tearDownAfterClass() throws InterruptedException { 127 Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); 128 EVENT_LOOP_GROUP_CONFIG.group().shutdownGracefully().sync(); 129 UTIL.cleanupTestDir(); 130 } 131 132 @Before 133 public void setUp() throws IOException { 134 x509TestContext = PROVIDER.get(keyType, keyType, "keyPa$$word".toCharArray()); 135 x509TestContext.setConfigurations(storeFileType, storeFileType); 136 CONF.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_SUPPORTPLAINTEXT, false); 137 CONF.setBoolean(X509Util.HBASE_CLIENT_NETTY_TLS_ENABLED, true); 138 CONF.setBoolean(X509Util.TLS_CERT_RELOAD, true); 139 } 140 141 @After 142 public void tearDown() { 143 x509TestContext.clearConfigurations(); 144 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP); 145 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR); 146 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL); 147 System.clearProperty("com.sun.net.ssl.checkRevocation"); 148 System.clearProperty("com.sun.security.enableCRLDP"); 149 Security.setProperty("ocsp.enable", Boolean.FALSE.toString()); 150 Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString()); 151 } 152 153 @Test 154 public void testReplaceServerKeystore() 155 throws IOException, ServiceException, GeneralSecurityException, OperatorCreationException { 156 Configuration clientConf = new Configuration(CONF); 157 RpcServer rpcServer = createRpcServer("testRpcServer", 158 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), 159 new InetSocketAddress("localhost", 0), CONF, new FifoRpcScheduler(CONF, 1)); 160 161 try { 162 rpcServer.start(); 163 164 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 165 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 166 newBlockingStub(client, rpcServer.getListenerAddress()); 167 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 168 String message = "hello"; 169 assertEquals(message, 170 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 171 .getMessage()); 172 assertNull(pcrc.cellScanner()); 173 } 174 175 // Replace keystore 176 x509TestContext.regenerateStores(keyType, keyType, storeFileType, storeFileType); 177 178 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 179 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 180 newBlockingStub(client, rpcServer.getListenerAddress()); 181 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 182 String message = "hello"; 183 assertEquals(message, 184 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 185 .getMessage()); 186 assertNull(pcrc.cellScanner()); 187 } 188 189 } finally { 190 rpcServer.stop(); 191 } 192 } 193 194 @Test 195 public void testReplaceClientAndServerKeystore() 196 throws GeneralSecurityException, IOException, OperatorCreationException, ServiceException { 197 Configuration clientConf = new Configuration(CONF); 198 RpcServer rpcServer = createRpcServer("testRpcServer", 199 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), 200 new InetSocketAddress("localhost", 0), CONF, new FifoRpcScheduler(CONF, 1)); 201 202 try { 203 rpcServer.start(); 204 205 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 206 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 207 newBlockingStub(client, rpcServer.getListenerAddress()); 208 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 209 String message = "hello"; 210 assertEquals(message, 211 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 212 .getMessage()); 213 assertNull(pcrc.cellScanner()); 214 215 // Replace keystore and cancel client connections 216 x509TestContext.regenerateStores(keyType, keyType, storeFileType, storeFileType); 217 client.cancelConnections( 218 ServerName.valueOf(Address.fromSocketAddress(rpcServer.getListenerAddress()), 0L)); 219 220 assertEquals(message, 221 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 222 .getMessage()); 223 assertNull(pcrc.cellScanner()); 224 } 225 } finally { 226 rpcServer.stop(); 227 } 228 } 229 230 private RpcServer createRpcServer(String name, 231 List<RpcServer.BlockingServiceAndInterface> services, InetSocketAddress bindAddress, 232 Configuration conf, RpcScheduler scheduler) throws IOException { 233 return new NettyRpcServer(SERVER, name, services, bindAddress, conf, scheduler, true); 234 } 235}