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; 021 022import java.io.File; 023import java.io.IOException; 024import java.net.InetAddress; 025import java.net.InetSocketAddress; 026import java.security.GeneralSecurityException; 027import java.security.Security; 028import java.util.List; 029import org.apache.commons.io.FileUtils; 030import org.apache.hadoop.conf.Configuration; 031import org.apache.hadoop.hbase.HBaseClassTestRule; 032import org.apache.hadoop.hbase.HBaseCommonTestingUtil; 033import org.apache.hadoop.hbase.io.crypto.tls.KeyStoreFileType; 034import org.apache.hadoop.hbase.io.crypto.tls.X509KeyType; 035import org.apache.hadoop.hbase.io.crypto.tls.X509TestContext; 036import org.apache.hadoop.hbase.io.crypto.tls.X509TestContextProvider; 037import org.apache.hadoop.hbase.io.crypto.tls.X509Util; 038import org.apache.hadoop.hbase.ipc.FifoRpcScheduler; 039import org.apache.hadoop.hbase.ipc.NettyRpcClient; 040import org.apache.hadoop.hbase.ipc.NettyRpcServer; 041import org.apache.hadoop.hbase.ipc.RpcClient; 042import org.apache.hadoop.hbase.ipc.RpcClientFactory; 043import org.apache.hadoop.hbase.ipc.RpcServer; 044import org.apache.hadoop.hbase.ipc.RpcServerFactory; 045import org.apache.hadoop.hbase.ipc.TestProtobufRpcServiceImpl; 046import org.apache.hadoop.hbase.testclassification.MediumTests; 047import org.apache.hadoop.hbase.testclassification.RPCTests; 048import org.bouncycastle.jce.provider.BouncyCastleProvider; 049import org.bouncycastle.operator.OperatorCreationException; 050import org.junit.After; 051import org.junit.AfterClass; 052import org.junit.Before; 053import org.junit.BeforeClass; 054import org.junit.ClassRule; 055import org.junit.Test; 056import org.junit.experimental.categories.Category; 057import org.junit.runner.RunWith; 058import org.junit.runners.Parameterized; 059 060import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 061import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 062 063import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestProtos; 064import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestRpcServiceProtos; 065 066/** 067 * Tests for client-side mTLS focusing on client hostname verification in the case when client and 068 * server are on different hosts. We try to simulate this behaviour by querying the hostname with 069 * <p> 070 * InetAddress.getLocalHost() 071 * </p> 072 * Certificates are generated with the hostname in Subject Alternative Names, server binds 073 * non-localhost interface and client connects via remote IP address. Parameter is set to verify 074 * both TLS/plaintext and TLS-only cases. 075 */ 076@RunWith(Parameterized.class) 077@Category({ RPCTests.class, MediumTests.class }) 078public class TestMutualTlsClientSideNonLocalhost { 079 080 @ClassRule 081 public static final HBaseClassTestRule CLASS_RULE = 082 HBaseClassTestRule.forClass(TestMutualTlsClientSideNonLocalhost.class); 083 084 protected static HBaseCommonTestingUtil UTIL; 085 086 protected static File DIR; 087 088 protected static X509TestContextProvider PROVIDER; 089 090 private X509TestContext x509TestContext; 091 092 protected RpcServer rpcServer; 093 094 protected RpcClient rpcClient; 095 private TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub; 096 097 @Parameterized.Parameter(0) 098 public boolean supportPlaintext; 099 100 @Parameterized.Parameters(name = "{index}: supportPlaintext={0}") 101 public static List<Boolean> data() { 102 return List.of(true, false); 103 } 104 105 @BeforeClass 106 public static void setUpBeforeClass() throws IOException { 107 UTIL = new HBaseCommonTestingUtil(); 108 Security.addProvider(new BouncyCastleProvider()); 109 DIR = 110 new File(UTIL.getDataTestDir(AbstractTestTlsRejectPlainText.class.getSimpleName()).toString()) 111 .getCanonicalFile(); 112 FileUtils.forceMkdir(DIR); 113 Configuration conf = UTIL.getConfiguration(); 114 conf.setClass(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, NettyRpcClient.class, 115 RpcClient.class); 116 conf.setClass(RpcServerFactory.CUSTOM_RPC_SERVER_IMPL_CONF_KEY, NettyRpcServer.class, 117 RpcServer.class); 118 conf.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_ENABLED, true); 119 conf.setBoolean(X509Util.HBASE_CLIENT_NETTY_TLS_ENABLED, true); 120 PROVIDER = new X509TestContextProvider(conf, DIR); 121 } 122 123 @AfterClass 124 public static void cleanUp() { 125 Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); 126 UTIL.cleanupTestDir(); 127 } 128 129 @Before 130 public void setUp() throws Exception { 131 x509TestContext = PROVIDER.get(X509KeyType.RSA, X509KeyType.RSA, "keyPassword".toCharArray()); 132 x509TestContext.setConfigurations(KeyStoreFileType.JKS, KeyStoreFileType.JKS); 133 134 Configuration serverConf = new Configuration(UTIL.getConfiguration()); 135 Configuration clientConf = new Configuration(UTIL.getConfiguration()); 136 137 initialize(serverConf, clientConf); 138 139 InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), 0); 140 141 rpcServer = new NettyRpcServer(null, "testRpcServer", 142 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), isa, serverConf, 143 new FifoRpcScheduler(serverConf, 1), true); 144 rpcServer.start(); 145 146 rpcClient = new NettyRpcClient(clientConf); 147 stub = TestProtobufRpcServiceImpl.newBlockingStub(rpcClient, rpcServer.getListenerAddress()); 148 } 149 150 private void initialize(Configuration serverConf, Configuration clientConf) 151 throws GeneralSecurityException, IOException, OperatorCreationException { 152 serverConf.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_SUPPORTPLAINTEXT, supportPlaintext); 153 clientConf.setBoolean(X509Util.HBASE_CLIENT_NETTY_TLS_VERIFY_SERVER_HOSTNAME, true); 154 x509TestContext.regenerateStores(X509KeyType.RSA, X509KeyType.RSA, KeyStoreFileType.JKS, 155 KeyStoreFileType.JKS, InetAddress.getLocalHost().getHostName()); 156 } 157 158 @After 159 public void tearDown() throws IOException { 160 if (rpcServer != null) { 161 rpcServer.stop(); 162 } 163 Closeables.close(rpcClient, true); 164 x509TestContext.clearConfigurations(); 165 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP); 166 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR); 167 x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL); 168 System.clearProperty("com.sun.net.ssl.checkRevocation"); 169 System.clearProperty("com.sun.security.enableCRLDP"); 170 Security.setProperty("ocsp.enable", Boolean.FALSE.toString()); 171 Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString()); 172 } 173 174 @Test 175 public void testClientAuth() throws Exception { 176 stub.echo(null, TestProtos.EchoRequestProto.newBuilder().setMessage("hello world").build()); 177 } 178}