1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security;
19
20 import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getKeytabFileForTesting;
21 import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getPrincipalForTesting;
22 import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getSecuredConfiguration;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNotSame;
25 import static org.junit.Assert.assertSame;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.net.InetSocketAddress;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Properties;
34
35 import com.google.protobuf.RpcController;
36 import com.google.protobuf.ServiceException;
37 import org.apache.commons.lang.RandomStringUtils;
38 import org.apache.hadoop.conf.Configuration;
39 import org.apache.hadoop.fs.CommonConfigurationKeys;
40 import org.apache.hadoop.hbase.Cell;
41 import org.apache.hadoop.hbase.CellScanner;
42 import org.apache.hadoop.hbase.CellUtil;
43 import org.apache.hadoop.hbase.HBaseTestingUtility;
44 import org.apache.hadoop.hbase.HConstants;
45 import org.apache.hadoop.hbase.ServerName;
46 import org.apache.hadoop.hbase.ipc.FifoRpcScheduler;
47 import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
48 import org.apache.hadoop.hbase.ipc.RpcClient;
49 import org.apache.hadoop.hbase.ipc.RpcClientFactory;
50 import org.apache.hadoop.hbase.ipc.RpcServer;
51 import org.apache.hadoop.hbase.ipc.RpcServerInterface;
52 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos;
53 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
54 import org.apache.hadoop.minikdc.MiniKdc;
55 import org.apache.hadoop.security.UserGroupInformation;
56 import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
57 import org.junit.AfterClass;
58 import org.junit.Before;
59 import org.junit.BeforeClass;
60 import org.junit.Rule;
61 import org.junit.Test;
62 import org.junit.rules.ExpectedException;
63 import org.mockito.Mockito;
64
65 import com.google.common.collect.Lists;
66 import com.google.protobuf.BlockingRpcChannel;
67 import com.google.protobuf.BlockingService;
68
69 import javax.security.sasl.SaslException;
70
71 public abstract class AbstractTestSecureIPC {
72
73 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
74
75 private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri()
76 .getPath());
77
78 static final BlockingService SERVICE =
79 TestRpcServiceProtos.TestProtobufRpcProto.newReflectiveBlockingService(
80 new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
81
82 @Override
83 public TestProtos.EmptyResponseProto ping(RpcController controller,
84 TestProtos.EmptyRequestProto request)
85 throws ServiceException {
86 return null;
87 }
88
89 @Override
90 public TestProtos.EmptyResponseProto error(RpcController controller,
91 TestProtos.EmptyRequestProto request)
92 throws ServiceException {
93 return null;
94 }
95
96 @Override
97 public TestProtos.EchoResponseProto echo(RpcController controller,
98 TestProtos.EchoRequestProto request)
99 throws ServiceException {
100 if (controller instanceof PayloadCarryingRpcController) {
101 PayloadCarryingRpcController pcrc = (PayloadCarryingRpcController) controller;
102
103
104
105
106
107 CellScanner cellScanner = pcrc.cellScanner();
108 List<Cell> list = null;
109 if (cellScanner != null) {
110 list = new ArrayList<Cell>();
111 try {
112 while (cellScanner.advance()) {
113 list.add(cellScanner.current());
114 }
115 } catch (IOException e) {
116 throw new ServiceException(e);
117 }
118 }
119 cellScanner = CellUtil.createCellScanner(list);
120 ((PayloadCarryingRpcController) controller).setCellScanner(cellScanner);
121 }
122 return TestProtos.EchoResponseProto.newBuilder()
123 .setMessage(request.getMessage()).build();
124 }
125 });
126
127 private static MiniKdc KDC;
128 private static String HOST = "localhost";
129 private static String PRINCIPAL;
130
131 String krbKeytab;
132 String krbPrincipal;
133 UserGroupInformation ugi;
134 Configuration clientConf;
135 Configuration serverConf;
136
137 abstract Class<? extends RpcClient> getRpcClientClass();
138
139 @Rule
140 public ExpectedException exception = ExpectedException.none();
141
142 @BeforeClass
143 public static void setUp() throws Exception {
144 KDC = TEST_UTIL.setupMiniKdc(KEYTAB_FILE);
145 PRINCIPAL = "hbase/" + HOST;
146 KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL);
147 HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm());
148 }
149
150 @AfterClass
151 public static void tearDown() throws IOException {
152 if (KDC != null) {
153 KDC.stop();
154 }
155 TEST_UTIL.cleanupTestDir();
156 }
157
158 @Before
159 public void setUpTest() throws Exception {
160 krbKeytab = getKeytabFileForTesting();
161 krbPrincipal = getPrincipalForTesting();
162 ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal);
163 clientConf = getSecuredConfiguration();
164 clientConf.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, getRpcClientClass().getName());
165 serverConf = getSecuredConfiguration();
166 }
167
168 @Test
169 public void testRpcCallWithEnabledKerberosSaslAuth() throws Exception {
170 UserGroupInformation ugi2 = UserGroupInformation.getCurrentUser();
171
172
173 assertSame(ugi, ugi2);
174 assertEquals(AuthenticationMethod.KERBEROS, ugi.getAuthenticationMethod());
175 assertEquals(krbPrincipal, ugi.getUserName());
176
177 callRpcService(User.create(ugi2));
178 }
179
180 @Test
181 public void testRpcFallbackToSimpleAuth() throws Exception {
182 String clientUsername = "testuser";
183 UserGroupInformation clientUgi = UserGroupInformation.createUserForTesting(clientUsername,
184 new String[]{clientUsername});
185
186
187 assertNotSame(ugi, clientUgi);
188 assertEquals(AuthenticationMethod.SIMPLE, clientUgi.getAuthenticationMethod());
189 assertEquals(clientUsername, clientUgi.getUserName());
190
191 clientConf.set(User.HBASE_SECURITY_CONF_KEY, "simple");
192 serverConf.setBoolean(RpcServer.FALLBACK_TO_INSECURE_CLIENT_AUTH, true);
193 callRpcService(User.create(clientUgi));
194 }
195
196 void setRpcProtection(String clientProtection, String serverProtection) {
197 clientConf.set("hbase.rpc.protection", clientProtection);
198 serverConf.set("hbase.rpc.protection", serverProtection);
199 }
200
201
202
203
204
205 @Test
206 public void testSaslWithCommonQop() throws Exception {
207 setRpcProtection("authentication", "authentication");
208 callRpcService(User.create(ugi));
209
210 setRpcProtection("integrity", "integrity");
211 callRpcService(User.create(ugi));
212
213 setRpcProtection("privacy", "privacy");
214 callRpcService(User.create(ugi));
215 }
216
217 private UserGroupInformation loginKerberosPrincipal(String krbKeytab, String krbPrincipal)
218 throws Exception {
219 Configuration cnf = new Configuration();
220 cnf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
221 UserGroupInformation.setConfiguration(cnf);
222 UserGroupInformation.loginUserFromKeytab(krbPrincipal, krbKeytab);
223 return UserGroupInformation.getLoginUser();
224 }
225
226
227
228
229
230 private void callRpcService(User clientUser) throws Exception {
231 SecurityInfo securityInfoMock = Mockito.mock(SecurityInfo.class);
232 Mockito.when(securityInfoMock.getServerPrincipal())
233 .thenReturn(HBaseKerberosUtils.KRB_PRINCIPAL);
234 SecurityInfo.addInfo("TestProtobufRpcProto", securityInfoMock);
235
236 InetSocketAddress isa = new InetSocketAddress(HOST, 0);
237
238 RpcServerInterface rpcServer =
239 new RpcServer(null, "AbstractTestSecureIPC",
240 Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), isa,
241 serverConf, new FifoRpcScheduler(serverConf, 1));
242 rpcServer.start();
243 try (RpcClient rpcClient = RpcClientFactory.createClient(clientConf,
244 HConstants.DEFAULT_CLUSTER_ID.toString())) {
245 InetSocketAddress address = rpcServer.getListenerAddress();
246 if (address == null) {
247 throw new IOException("Listener channel is closed");
248 }
249 BlockingRpcChannel channel =
250 rpcClient.createBlockingRpcChannel(
251 ServerName.valueOf(address.getHostName(), address.getPort(),
252 System.currentTimeMillis()), clientUser, 0);
253 TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub =
254 TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(channel);
255 TestThread th1 = new TestThread(stub);
256 final Throwable exception[] = new Throwable[1];
257 Collections.synchronizedList(new ArrayList<Throwable>());
258 Thread.UncaughtExceptionHandler exceptionHandler =
259 new Thread.UncaughtExceptionHandler() {
260 public void uncaughtException(Thread th, Throwable ex) {
261 exception[0] = ex;
262 }
263 };
264 th1.setUncaughtExceptionHandler(exceptionHandler);
265 th1.start();
266 th1.join();
267 if (exception[0] != null) {
268
269 while (exception[0].getCause() != null) {
270 exception[0] = exception[0].getCause();
271 }
272 throw (Exception) exception[0];
273 }
274 } finally {
275 rpcServer.stop();
276 }
277 }
278
279 public static class TestThread extends Thread {
280 private final TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub;
281
282 public TestThread(TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub) {
283 this.stub = stub;
284 }
285
286 @Override
287 public void run() {
288 try {
289 int[] messageSize = new int[] {100, 1000, 10000};
290 for (int i = 0; i < messageSize.length; i++) {
291 String input = RandomStringUtils.random(messageSize[i]);
292 String result = stub.echo(null, TestProtos.EchoRequestProto.newBuilder()
293 .setMessage(input).build()).getMessage();
294 assertEquals(input, result);
295 }
296 } catch (ServiceException e) {
297 throw new RuntimeException(e);
298 }
299 }
300 }
301 }