Skip to content

Commit 13a063e

Browse files
authored
HBASE-27923 NettyRpcServer may hange if it should skip initial sasl handshake (#5284)
Signed-off-by: Duo Zhang <[email protected]> Signed-off-by: Wellington Chevreuil <[email protected]>
1 parent 7d78979 commit 13a063e

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.ipc;
19+
20+
import static org.apache.hadoop.hbase.ipc.TestProtobufRpcServiceImpl.SERVICE;
21+
import static org.apache.hadoop.hbase.ipc.TestProtobufRpcServiceImpl.newBlockingStub;
22+
import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getKeytabFileForTesting;
23+
import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getPrincipalForTesting;
24+
import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.setSecuredConfiguration;
25+
import static org.junit.Assert.assertFalse;
26+
import static org.junit.Assert.assertTrue;
27+
28+
import java.io.File;
29+
import java.net.InetSocketAddress;
30+
import java.util.concurrent.atomic.AtomicBoolean;
31+
import org.apache.hadoop.conf.Configuration;
32+
import org.apache.hadoop.fs.CommonConfigurationKeys;
33+
import org.apache.hadoop.hbase.HBaseClassTestRule;
34+
import org.apache.hadoop.hbase.HBaseTestingUtility;
35+
import org.apache.hadoop.hbase.HConstants;
36+
import org.apache.hadoop.hbase.security.HBaseKerberosUtils;
37+
import org.apache.hadoop.hbase.security.SecurityInfo;
38+
import org.apache.hadoop.hbase.security.User;
39+
import org.apache.hadoop.hbase.testclassification.MediumTests;
40+
import org.apache.hadoop.hbase.testclassification.RPCTests;
41+
import org.apache.hadoop.minikdc.MiniKdc;
42+
import org.apache.hadoop.security.UserGroupInformation;
43+
import org.junit.AfterClass;
44+
import org.junit.Before;
45+
import org.junit.BeforeClass;
46+
import org.junit.ClassRule;
47+
import org.junit.Test;
48+
import org.junit.experimental.categories.Category;
49+
import org.mockito.Mockito;
50+
51+
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
52+
import org.apache.hbase.thirdparty.io.netty.buffer.ByteBuf;
53+
import org.apache.hbase.thirdparty.io.netty.channel.Channel;
54+
import org.apache.hbase.thirdparty.io.netty.channel.ChannelHandlerContext;
55+
56+
import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestProtos;
57+
import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface;
58+
59+
@Category({ RPCTests.class, MediumTests.class })
60+
public class TestRpcSkipInitialSaslHandshake {
61+
62+
@ClassRule
63+
public static final HBaseClassTestRule CLASS_RULE =
64+
HBaseClassTestRule.forClass(TestRpcSkipInitialSaslHandshake.class);
65+
66+
protected static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
67+
68+
protected static final File KEYTAB_FILE =
69+
new File(TEST_UTIL.getDataTestDir("keytab").toUri().getPath());
70+
71+
protected static MiniKdc KDC;
72+
protected static String HOST = "localhost";
73+
protected static String PRINCIPAL;
74+
75+
protected String krbKeytab;
76+
protected String krbPrincipal;
77+
protected UserGroupInformation ugi;
78+
protected Configuration clientConf;
79+
protected Configuration serverConf;
80+
81+
protected static void initKDCAndConf() throws Exception {
82+
KDC = TEST_UTIL.setupMiniKdc(KEYTAB_FILE);
83+
PRINCIPAL = "hbase/" + HOST;
84+
KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL);
85+
HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm());
86+
// set a smaller timeout and retry to speed up tests
87+
TEST_UTIL.getConfiguration().setInt(RpcClient.SOCKET_TIMEOUT_READ, 2000000000);
88+
TEST_UTIL.getConfiguration().setInt("hbase.security.relogin.maxretries", 1);
89+
}
90+
91+
protected static void stopKDC() throws InterruptedException {
92+
if (KDC != null) {
93+
KDC.stop();
94+
}
95+
}
96+
97+
protected final void setUpPrincipalAndConf() throws Exception {
98+
krbKeytab = getKeytabFileForTesting();
99+
krbPrincipal = getPrincipalForTesting();
100+
ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal);
101+
clientConf = new Configuration(TEST_UTIL.getConfiguration());
102+
setSecuredConfiguration(clientConf);
103+
clientConf.setBoolean(RpcClient.IPC_CLIENT_FALLBACK_TO_SIMPLE_AUTH_ALLOWED_KEY, true);
104+
serverConf = new Configuration(TEST_UTIL.getConfiguration());
105+
}
106+
107+
@BeforeClass
108+
public static void setUp() throws Exception {
109+
initKDCAndConf();
110+
}
111+
112+
@AfterClass
113+
public static void tearDown() throws Exception {
114+
stopKDC();
115+
TEST_UTIL.cleanupTestDir();
116+
}
117+
118+
@Before
119+
public void setUpTest() throws Exception {
120+
setUpPrincipalAndConf();
121+
}
122+
123+
private UserGroupInformation loginKerberosPrincipal(String krbKeytab, String krbPrincipal)
124+
throws Exception {
125+
Configuration cnf = new Configuration();
126+
cnf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
127+
UserGroupInformation.setConfiguration(cnf);
128+
UserGroupInformation.loginUserFromKeytab(krbPrincipal, krbKeytab);
129+
return UserGroupInformation.getLoginUser();
130+
}
131+
132+
/**
133+
* This test is for HBASE-27923,which NettyRpcServer may hange if it should skip initial sasl
134+
* handshake.
135+
*/
136+
@Test
137+
public void test() throws Exception {
138+
SecurityInfo securityInfoMock = Mockito.mock(SecurityInfo.class);
139+
Mockito.when(securityInfoMock.getServerPrincipal())
140+
.thenReturn(HBaseKerberosUtils.KRB_PRINCIPAL);
141+
SecurityInfo.addInfo("TestProtobufRpcProto", securityInfoMock);
142+
143+
final AtomicBoolean useSaslRef = new AtomicBoolean(false);
144+
NettyRpcServer rpcServer = new NettyRpcServer(null, getClass().getSimpleName(),
145+
Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)),
146+
new InetSocketAddress(HOST, 0), serverConf, new FifoRpcScheduler(serverConf, 1), true) {
147+
148+
@Override
149+
protected NettyRpcServerPreambleHandler createNettyRpcServerPreambleHandler() {
150+
return new NettyRpcServerPreambleHandler(this) {
151+
private NettyServerRpcConnection conn;
152+
153+
@Override
154+
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
155+
super.channelRead0(ctx, msg);
156+
useSaslRef.set(conn.useSasl);
157+
158+
}
159+
160+
@Override
161+
protected NettyServerRpcConnection createNettyServerRpcConnection(Channel channel) {
162+
conn = super.createNettyServerRpcConnection(channel);
163+
return conn;
164+
}
165+
};
166+
}
167+
};
168+
169+
rpcServer.start();
170+
try (NettyRpcClient rpcClient =
171+
new NettyRpcClient(clientConf, HConstants.DEFAULT_CLUSTER_ID.toString(), null, null)) {
172+
BlockingInterface stub = newBlockingStub(rpcClient, rpcServer.getListenerAddress(),
173+
User.create(UserGroupInformation.getCurrentUser()));
174+
175+
String response =
176+
stub.echo(null, TestProtos.EchoRequestProto.newBuilder().setMessage("test").build())
177+
.getMessage();
178+
assertTrue("test".equals(response));
179+
assertFalse(useSaslRef.get());
180+
181+
} finally {
182+
rpcServer.stop();
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)