PageRenderTime 25ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/hbase-server/src/test/java/org/apache/hadoop/hbase/security/AbstractTestSecureIPC.java

http://github.com/apache/hbase
Java | 325 lines | 251 code | 40 blank | 34 comment | 13 complexity | ad6094233a780a2ab497d5af49fb9597 MD5 | raw file
Possible License(s): Apache-2.0, MIT
  1. /**
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. package org.apache.hadoop.hbase.security;
  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. import java.io.File;
  27. import java.io.IOException;
  28. import java.net.InetSocketAddress;
  29. import java.util.ArrayList;
  30. import java.util.Collections;
  31. import java.util.List;
  32. import java.util.Properties;
  33. import java.util.concurrent.ThreadLocalRandom;
  34. import com.google.protobuf.RpcController;
  35. import com.google.protobuf.ServiceException;
  36. import org.apache.commons.lang.RandomStringUtils;
  37. import org.apache.hadoop.conf.Configuration;
  38. import org.apache.hadoop.fs.CommonConfigurationKeys;
  39. import org.apache.hadoop.hbase.Cell;
  40. import org.apache.hadoop.hbase.CellScanner;
  41. import org.apache.hadoop.hbase.CellUtil;
  42. import org.apache.hadoop.hbase.HBaseTestingUtility;
  43. import org.apache.hadoop.hbase.HConstants;
  44. import org.apache.hadoop.hbase.ServerName;
  45. import org.apache.hadoop.hbase.ipc.FifoRpcScheduler;
  46. import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
  47. import org.apache.hadoop.hbase.ipc.RpcClient;
  48. import org.apache.hadoop.hbase.ipc.RpcClientFactory;
  49. import org.apache.hadoop.hbase.ipc.RpcServer;
  50. import org.apache.hadoop.hbase.ipc.RpcServerInterface;
  51. import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos;
  52. import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
  53. import org.apache.hadoop.minikdc.MiniKdc;
  54. import org.apache.hadoop.security.UserGroupInformation;
  55. import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
  56. import org.junit.AfterClass;
  57. import org.junit.Before;
  58. import org.junit.BeforeClass;
  59. import org.junit.Rule;
  60. import org.junit.Test;
  61. import org.junit.rules.ExpectedException;
  62. import org.mockito.Mockito;
  63. import com.google.common.collect.Lists;
  64. import com.google.protobuf.BlockingRpcChannel;
  65. import com.google.protobuf.BlockingService;
  66. import javax.security.sasl.SaslException;
  67. public abstract class AbstractTestSecureIPC {
  68. private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
  69. private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri()
  70. .getPath());
  71. static final BlockingService SERVICE =
  72. TestRpcServiceProtos.TestProtobufRpcProto.newReflectiveBlockingService(
  73. new TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface() {
  74. @Override
  75. public TestProtos.EmptyResponseProto ping(RpcController controller,
  76. TestProtos.EmptyRequestProto request)
  77. throws ServiceException {
  78. return null;
  79. }
  80. @Override
  81. public TestProtos.EmptyResponseProto error(RpcController controller,
  82. TestProtos.EmptyRequestProto request)
  83. throws ServiceException {
  84. return null;
  85. }
  86. @Override
  87. public TestProtos.EchoResponseProto echo(RpcController controller,
  88. TestProtos.EchoRequestProto request)
  89. throws ServiceException {
  90. if (controller instanceof PayloadCarryingRpcController) {
  91. PayloadCarryingRpcController pcrc = (PayloadCarryingRpcController) controller;
  92. // If cells, scan them to check we are able to iterate what we were given and since
  93. // this is
  94. // an echo, just put them back on the controller creating a new block. Tests our
  95. // block
  96. // building.
  97. CellScanner cellScanner = pcrc.cellScanner();
  98. List<Cell> list = null;
  99. if (cellScanner != null) {
  100. list = new ArrayList<Cell>();
  101. try {
  102. while (cellScanner.advance()) {
  103. list.add(cellScanner.current());
  104. }
  105. } catch (IOException e) {
  106. throw new ServiceException(e);
  107. }
  108. }
  109. cellScanner = CellUtil.createCellScanner(list);
  110. ((PayloadCarryingRpcController) controller).setCellScanner(cellScanner);
  111. }
  112. return TestProtos.EchoResponseProto.newBuilder()
  113. .setMessage(request.getMessage()).build();
  114. }
  115. });
  116. private static MiniKdc KDC;
  117. private static String HOST = "localhost";
  118. private static String PRINCIPAL;
  119. String krbKeytab;
  120. String krbPrincipal;
  121. UserGroupInformation ugi;
  122. Configuration clientConf;
  123. Configuration serverConf;
  124. abstract Class<? extends RpcClient> getRpcClientClass();
  125. @Rule
  126. public ExpectedException exception = ExpectedException.none();
  127. @BeforeClass
  128. public static void setUp() throws Exception {
  129. Properties conf = MiniKdc.createConf();
  130. conf.put(MiniKdc.DEBUG, true);
  131. KDC = new MiniKdc(conf, new File(TEST_UTIL.getDataTestDir("kdc").toUri().getPath()));
  132. KDC.start();
  133. PRINCIPAL = "hbase/" + HOST;
  134. KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL);
  135. HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath());
  136. HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm());
  137. }
  138. @AfterClass
  139. public static void tearDown() throws IOException {
  140. if (KDC != null) {
  141. KDC.stop();
  142. }
  143. TEST_UTIL.cleanupTestDir();
  144. }
  145. @Before
  146. public void setUpTest() throws Exception {
  147. krbKeytab = getKeytabFileForTesting();
  148. krbPrincipal = getPrincipalForTesting();
  149. ugi = loginKerberosPrincipal(krbKeytab, krbPrincipal);
  150. clientConf = getSecuredConfiguration();
  151. clientConf.set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, getRpcClientClass().getName());
  152. serverConf = getSecuredConfiguration();
  153. }
  154. @Test
  155. public void testRpcCallWithEnabledKerberosSaslAuth() throws Exception {
  156. UserGroupInformation ugi2 = UserGroupInformation.getCurrentUser();
  157. // check that the login user is okay:
  158. assertSame(ugi, ugi2);
  159. assertEquals(AuthenticationMethod.KERBEROS, ugi.getAuthenticationMethod());
  160. assertEquals(krbPrincipal, ugi.getUserName());
  161. callRpcService(User.create(ugi2));
  162. }
  163. @Test
  164. public void testRpcFallbackToSimpleAuth() throws Exception {
  165. String clientUsername = "testuser";
  166. UserGroupInformation clientUgi = UserGroupInformation.createUserForTesting(clientUsername,
  167. new String[]{clientUsername});
  168. // check that the client user is insecure
  169. assertNotSame(ugi, clientUgi);
  170. assertEquals(AuthenticationMethod.SIMPLE, clientUgi.getAuthenticationMethod());
  171. assertEquals(clientUsername, clientUgi.getUserName());
  172. clientConf.set(User.HBASE_SECURITY_CONF_KEY, "simple");
  173. serverConf.setBoolean(RpcServer.FALLBACK_TO_INSECURE_CLIENT_AUTH, true);
  174. callRpcService(User.create(clientUgi));
  175. }
  176. void setRpcProtection(String clientProtection, String serverProtection) {
  177. clientConf.set("hbase.rpc.protection", clientProtection);
  178. serverConf.set("hbase.rpc.protection", serverProtection);
  179. }
  180. /**
  181. * Test various combinations of Server and Client qops.
  182. * @throws Exception
  183. */
  184. @Test
  185. public void testSaslWithCommonQop() throws Exception {
  186. setRpcProtection("privacy,authentication", "authentication");
  187. callRpcService(User.create(ugi));
  188. setRpcProtection("authentication", "privacy,authentication");
  189. callRpcService(User.create(ugi));
  190. setRpcProtection("integrity,authentication", "privacy,authentication");
  191. callRpcService(User.create(ugi));
  192. setRpcProtection("integrity,authentication", "integrity,authentication");
  193. callRpcService(User.create(ugi));
  194. setRpcProtection("privacy,authentication", "privacy,authentication");
  195. callRpcService(User.create(ugi));
  196. }
  197. @Test
  198. public void testSaslNoCommonQop() throws Exception {
  199. exception.expect(SaslException.class);
  200. exception.expectMessage("No common protection layer between client and server");
  201. setRpcProtection("integrity", "privacy");
  202. callRpcService(User.create(ugi));
  203. }
  204. private UserGroupInformation loginKerberosPrincipal(String krbKeytab, String krbPrincipal)
  205. throws Exception {
  206. Configuration cnf = new Configuration();
  207. cnf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
  208. UserGroupInformation.setConfiguration(cnf);
  209. UserGroupInformation.loginUserFromKeytab(krbPrincipal, krbKeytab);
  210. return UserGroupInformation.getLoginUser();
  211. }
  212. /**
  213. * Sets up a RPC Server and a Client. Does a RPC checks the result. If an exception is thrown
  214. * from the stub, this function will throw root cause of that exception.
  215. */
  216. private void callRpcService(User clientUser) throws Exception {
  217. SecurityInfo securityInfoMock = Mockito.mock(SecurityInfo.class);
  218. Mockito.when(securityInfoMock.getServerPrincipal())
  219. .thenReturn(HBaseKerberosUtils.KRB_PRINCIPAL);
  220. SecurityInfo.addInfo("TestProtobufRpcProto", securityInfoMock);
  221. InetSocketAddress isa = new InetSocketAddress(HOST, 0);
  222. RpcServerInterface rpcServer =
  223. new RpcServer(null, "AbstractTestSecureIPC",
  224. Lists.newArrayList(new RpcServer.BlockingServiceAndInterface(SERVICE, null)), isa,
  225. serverConf, new FifoRpcScheduler(serverConf, 1));
  226. rpcServer.start();
  227. try (RpcClient rpcClient = RpcClientFactory.createClient(clientConf,
  228. HConstants.DEFAULT_CLUSTER_ID.toString())) {
  229. InetSocketAddress address = rpcServer.getListenerAddress();
  230. if (address == null) {
  231. throw new IOException("Listener channel is closed");
  232. }
  233. BlockingRpcChannel channel =
  234. rpcClient.createBlockingRpcChannel(
  235. ServerName.valueOf(address.getHostName(), address.getPort(),
  236. System.currentTimeMillis()), clientUser, 0);
  237. TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub =
  238. TestRpcServiceProtos.TestProtobufRpcProto.newBlockingStub(channel);
  239. List<String> results = new ArrayList<>();
  240. TestThread th1 = new TestThread(stub, results);
  241. final Throwable exception[] = new Throwable[1];
  242. Collections.synchronizedList(new ArrayList<Throwable>());
  243. Thread.UncaughtExceptionHandler exceptionHandler =
  244. new Thread.UncaughtExceptionHandler() {
  245. public void uncaughtException(Thread th, Throwable ex) {
  246. exception[0] = ex;
  247. }
  248. };
  249. th1.setUncaughtExceptionHandler(exceptionHandler);
  250. th1.start();
  251. th1.join();
  252. if (exception[0] != null) {
  253. // throw root cause.
  254. while (exception[0].getCause() != null) {
  255. exception[0] = exception[0].getCause();
  256. }
  257. throw (Exception) exception[0];
  258. }
  259. } finally {
  260. rpcServer.stop();
  261. }
  262. }
  263. public static class TestThread extends Thread {
  264. private final TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub;
  265. private final List<String> results;
  266. public TestThread(TestRpcServiceProtos.TestProtobufRpcProto.BlockingInterface stub, List<String> results) {
  267. this.stub = stub;
  268. this.results = results;
  269. }
  270. @Override
  271. public void run() {
  272. try {
  273. int[] messageSize = new int[] {100, 1000, 10000};
  274. for (int i = 0; i < messageSize.length; i++) {
  275. String input = RandomStringUtils.random(messageSize[i]);
  276. String result = stub.echo(null, TestProtos.EchoRequestProto.newBuilder()
  277. .setMessage(input).build()).getMessage();
  278. assertEquals(input, result);
  279. }
  280. } catch (ServiceException e) {
  281. throw new RuntimeException(e);
  282. }
  283. }
  284. }
  285. }