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 = new File(UTIL.getDataTestDir(TestNettyTlsIPC.class.getSimpleName()).toString()) 113 .getCanonicalFile(); 114 FileUtils.forceMkdir(dir); 115 // server must enable tls 116 CONF.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_ENABLED, true); 117 PROVIDER = new X509TestContextProvider(CONF, dir); 118 EVENT_LOOP_GROUP_CONFIG = 119 NettyEventLoopGroupConfig.setup(CONF, TestNettyTlsIPC.class.getSimpleName()); 120 SERVER = mock(HBaseServerBase.class); 121 when(SERVER.getEventLoopGroupConfig()).thenReturn(EVENT_LOOP_GROUP_CONFIG); 122 } 123 124 @AfterClass 125 public static void tearDownAfterClass() throws InterruptedException { 126 Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); 127 EVENT_LOOP_GROUP_CONFIG.group().shutdownGracefully().sync(); 128 UTIL.cleanupTestDir(); 129 } 130 131 @Before 132 public void setUp() throws IOException { 133 x509TestContext = PROVIDER.get(keyType, keyType, "keyPa$$word".toCharArray()); 134 x509TestContext.setConfigurations(storeFileType, storeFileType); 135 CONF.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_SUPPORTPLAINTEXT, false); 136 CONF.setBoolean(X509Util.HBASE_CLIENT_NETTY_TLS_ENABLED, true); 137 CONF.setBoolean(X509Util.TLS_CERT_RELOAD, true); 138 } 139 140 @After 141 public void tearDown() { 142 x509TestContext.clearConfigurations(); 143 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP); 144 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR); 145 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL); 146 System.clearProperty("com.sun.net.ssl.checkRevocation"); 147 System.clearProperty("com.sun.security.enableCRLDP"); 148 Security.setProperty("ocsp.enable", Boolean.FALSE.toString()); 149 Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString()); 150 } 151 152 @Test 153 public void testReplaceServerKeystore() 154 throws IOException, ServiceException, GeneralSecurityException, OperatorCreationException { 155 Configuration clientConf = new Configuration(CONF); 156 RpcServer rpcServer = createRpcServer("testRpcServer", 157 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), 158 new InetSocketAddress("localhost", 0), CONF, new FifoRpcScheduler(CONF, 1)); 159 160 try { 161 rpcServer.start(); 162 163 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 164 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 165 newBlockingStub(client, rpcServer.getListenerAddress()); 166 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 167 String message = "hello"; 168 assertEquals(message, 169 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 170 .getMessage()); 171 assertNull(pcrc.cellScanner()); 172 } 173 174 // Replace keystore 175 x509TestContext.regenerateStores(keyType, keyType, storeFileType, storeFileType); 176 177 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 178 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 179 newBlockingStub(client, rpcServer.getListenerAddress()); 180 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 181 String message = "hello"; 182 assertEquals(message, 183 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 184 .getMessage()); 185 assertNull(pcrc.cellScanner()); 186 } 187 188 } finally { 189 rpcServer.stop(); 190 } 191 } 192 193 @Test 194 public void testReplaceClientAndServerKeystore() 195 throws GeneralSecurityException, IOException, OperatorCreationException, ServiceException { 196 Configuration clientConf = new Configuration(CONF); 197 RpcServer rpcServer = createRpcServer("testRpcServer", 198 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), 199 new InetSocketAddress("localhost", 0), CONF, new FifoRpcScheduler(CONF, 1)); 200 201 try { 202 rpcServer.start(); 203 204 try (AbstractRpcClient<?> client = new NettyRpcClient(clientConf)) { 205 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub = 206 newBlockingStub(client, rpcServer.getListenerAddress()); 207 HBaseRpcController pcrc = new HBaseRpcControllerImpl(); 208 String message = "hello"; 209 assertEquals(message, 210 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 211 .getMessage()); 212 assertNull(pcrc.cellScanner()); 213 214 // Replace keystore and cancel client connections 215 x509TestContext.regenerateStores(keyType, keyType, storeFileType, storeFileType); 216 client.cancelConnections( 217 ServerName.valueOf(Address.fromSocketAddress(rpcServer.getListenerAddress()), 0L)); 218 219 assertEquals(message, 220 stub.echo(pcrc, TestProtos.EchoRequestProto.newBuilder().setMessage(message).build()) 221 .getMessage()); 222 assertNull(pcrc.cellScanner()); 223 } 224 } finally { 225 rpcServer.stop(); 226 } 227 } 228 229 private RpcServer createRpcServer(String name, 230 List<RpcServer.BlockingServiceAndInterface> services, InetSocketAddress bindAddress, 231 Configuration conf, RpcScheduler scheduler) throws IOException { 232 return new NettyRpcServer(SERVER, name, services, bindAddress, conf, scheduler, true); 233 } 234}