PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/jmhsieh/hbase
Java | 384 lines | 300 code | 50 blank | 34 comment | 6 complexity | 1145f3839975cb509e67bbdbb36ad840 MD5 | raw file
  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.security.token;
  19. import static org.junit.Assert.assertEquals;
  20. import static org.junit.Assert.assertTrue;
  21. import java.io.IOException;
  22. import java.net.InetSocketAddress;
  23. import java.security.PrivilegedExceptionAction;
  24. import java.util.concurrent.ConcurrentMap;
  25. import com.google.protobuf.RpcController;
  26. import com.google.protobuf.ServiceException;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.apache.hadoop.conf.Configuration;
  30. import org.apache.hadoop.hbase.ClusterId;
  31. import org.apache.hadoop.hbase.IpcProtocol;
  32. import org.apache.hadoop.hbase.Coprocessor;
  33. import org.apache.hadoop.hbase.HBaseTestingUtility;
  34. import org.apache.hadoop.hbase.HConstants;
  35. import org.apache.hadoop.hbase.MediumTests;
  36. import org.apache.hadoop.hbase.Server;
  37. import org.apache.hadoop.hbase.ServerName;
  38. import org.apache.hadoop.hbase.catalog.CatalogTracker;
  39. import org.apache.hadoop.hbase.client.HTableInterface;
  40. import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
  41. import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
  42. import org.apache.hadoop.hbase.ipc.HBaseClientRPC;
  43. import org.apache.hadoop.hbase.ipc.HBaseServer;
  44. import org.apache.hadoop.hbase.ipc.HBaseServerRPC;
  45. import org.apache.hadoop.hbase.ipc.RequestContext;
  46. import org.apache.hadoop.hbase.ipc.RpcServer;
  47. import org.apache.hadoop.hbase.ipc.ServerRpcController;
  48. import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
  49. import org.apache.hadoop.hbase.regionserver.HRegion;
  50. import org.apache.hadoop.hbase.regionserver.RegionServerServices;
  51. import org.apache.hadoop.hbase.security.KerberosInfo;
  52. import org.apache.hadoop.hbase.security.TokenInfo;
  53. import org.apache.hadoop.hbase.security.User;
  54. import org.apache.hadoop.hbase.util.Bytes;
  55. import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
  56. import org.apache.hadoop.hbase.util.MockRegionServerServices;
  57. import org.apache.hadoop.hbase.util.Sleeper;
  58. import org.apache.hadoop.hbase.util.Strings;
  59. import org.apache.hadoop.hbase.util.Threads;
  60. import org.apache.hadoop.hbase.util.Writables;
  61. import org.apache.hadoop.hbase.zookeeper.ZKClusterId;
  62. import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
  63. import org.apache.hadoop.net.DNS;
  64. import org.apache.hadoop.security.UserGroupInformation;
  65. import org.apache.hadoop.security.token.SecretManager;
  66. import org.apache.hadoop.security.token.Token;
  67. import org.apache.hadoop.security.token.TokenIdentifier;
  68. import org.junit.AfterClass;
  69. import org.junit.BeforeClass;
  70. import org.junit.Test;
  71. import org.junit.experimental.categories.Category;
  72. /**
  73. * Tests for authentication token creation and usage
  74. */
  75. @Category(MediumTests.class)
  76. public class TestTokenAuthentication {
  77. private static Log LOG = LogFactory.getLog(TestTokenAuthentication.class);
  78. @KerberosInfo(
  79. serverPrincipal = "hbase.test.kerberos.principal")
  80. @TokenInfo("HBASE_AUTH_TOKEN")
  81. private static interface BlockingAuthenticationService
  82. extends AuthenticationProtos.AuthenticationService.BlockingInterface, IpcProtocol {
  83. }
  84. /**
  85. * Basic server process for RPC authentication testing
  86. */
  87. private static class TokenServer extends TokenProvider
  88. implements BlockingAuthenticationService, Runnable, Server {
  89. private static Log LOG = LogFactory.getLog(TokenServer.class);
  90. private Configuration conf;
  91. private RpcServer rpcServer;
  92. private InetSocketAddress isa;
  93. private ZooKeeperWatcher zookeeper;
  94. private Sleeper sleeper;
  95. private boolean started = false;
  96. private boolean aborted = false;
  97. private boolean stopped = false;
  98. private long startcode;
  99. private AuthenticationProtos.AuthenticationService.BlockingInterface blockingService;
  100. public TokenServer(Configuration conf) throws IOException {
  101. this.conf = conf;
  102. this.startcode = EnvironmentEdgeManager.currentTimeMillis();
  103. // Server to handle client requests.
  104. String hostname = Strings.domainNamePointerToHostName(
  105. DNS.getDefaultHost("default", "default"));
  106. int port = 0;
  107. // Creation of an ISA will force a resolve.
  108. InetSocketAddress initialIsa = new InetSocketAddress(hostname, port);
  109. if (initialIsa.getAddress() == null) {
  110. throw new IllegalArgumentException("Failed resolve of " + initialIsa);
  111. }
  112. this.rpcServer = HBaseServerRPC.getServer(TokenServer.class, this,
  113. new Class<?>[]{AuthenticationProtos.AuthenticationService.Interface.class},
  114. initialIsa.getHostName(), // BindAddress is IP we got for this server.
  115. initialIsa.getPort(),
  116. 3, // handlers
  117. 1, // meta handlers (not used)
  118. true,
  119. this.conf, HConstants.QOS_THRESHOLD);
  120. // Set our address.
  121. this.isa = this.rpcServer.getListenerAddress();
  122. this.sleeper = new Sleeper(1000, this);
  123. }
  124. @Override
  125. public Configuration getConfiguration() {
  126. return conf;
  127. }
  128. @Override
  129. public CatalogTracker getCatalogTracker() {
  130. return null;
  131. }
  132. @Override
  133. public ZooKeeperWatcher getZooKeeper() {
  134. return zookeeper;
  135. }
  136. @Override
  137. public boolean isAborted() {
  138. return aborted;
  139. }
  140. @Override
  141. public ServerName getServerName() {
  142. return new ServerName(isa.getHostName(), isa.getPort(), startcode);
  143. }
  144. @Override
  145. public void abort(String reason, Throwable error) {
  146. LOG.fatal("Aborting on: "+reason, error);
  147. this.aborted = true;
  148. this.stopped = true;
  149. sleeper.skipSleepCycle();
  150. }
  151. private void initialize() throws IOException {
  152. // ZK configuration must _not_ have hbase.security.authentication or it will require SASL auth
  153. Configuration zkConf = new Configuration(conf);
  154. zkConf.set(User.HBASE_SECURITY_CONF_KEY, "simple");
  155. this.zookeeper = new ZooKeeperWatcher(zkConf, TokenServer.class.getSimpleName(),
  156. this, true);
  157. this.rpcServer.start();
  158. // mock RegionServerServices to provide to coprocessor environment
  159. final RegionServerServices mockServices = new MockRegionServerServices() {
  160. @Override
  161. public RpcServer getRpcServer() { return rpcServer; }
  162. };
  163. // mock up coprocessor environment
  164. super.start(new RegionCoprocessorEnvironment() {
  165. @Override
  166. public HRegion getRegion() { return null; }
  167. @Override
  168. public RegionServerServices getRegionServerServices() {
  169. return mockServices;
  170. }
  171. @Override
  172. public ConcurrentMap<String, Object> getSharedData() { return null; }
  173. @Override
  174. public int getVersion() { return 0; }
  175. @Override
  176. public String getHBaseVersion() { return null; }
  177. @Override
  178. public Coprocessor getInstance() { return null; }
  179. @Override
  180. public int getPriority() { return 0; }
  181. @Override
  182. public int getLoadSequence() { return 0; }
  183. @Override
  184. public Configuration getConfiguration() { return conf; }
  185. @Override
  186. public HTableInterface getTable(byte[] tableName) throws IOException { return null; }
  187. });
  188. started = true;
  189. }
  190. public void run() {
  191. try {
  192. initialize();
  193. while (!stopped) {
  194. this.sleeper.sleep();
  195. }
  196. } catch (Exception e) {
  197. abort(e.getMessage(), e);
  198. }
  199. this.rpcServer.stop();
  200. }
  201. public boolean isStarted() {
  202. return started;
  203. }
  204. @Override
  205. public void stop(String reason) {
  206. LOG.info("Stopping due to: "+reason);
  207. this.stopped = true;
  208. sleeper.skipSleepCycle();
  209. }
  210. @Override
  211. public boolean isStopped() {
  212. return stopped;
  213. }
  214. public InetSocketAddress getAddress() {
  215. return isa;
  216. }
  217. public SecretManager<? extends TokenIdentifier> getSecretManager() {
  218. return ((HBaseServer)rpcServer).getSecretManager();
  219. }
  220. @Override
  221. public AuthenticationProtos.TokenResponse getAuthenticationToken(
  222. RpcController controller, AuthenticationProtos.TokenRequest request)
  223. throws ServiceException {
  224. LOG.debug("Authentication token request from "+RequestContext.getRequestUserName());
  225. // ignore passed in controller -- it's always null
  226. ServerRpcController serverController = new ServerRpcController();
  227. BlockingRpcCallback<AuthenticationProtos.TokenResponse> callback =
  228. new BlockingRpcCallback<AuthenticationProtos.TokenResponse>();
  229. getAuthenticationToken(serverController, request, callback);
  230. try {
  231. serverController.checkFailed();
  232. return callback.get();
  233. } catch (IOException ioe) {
  234. throw new ServiceException(ioe);
  235. }
  236. }
  237. @Override
  238. public AuthenticationProtos.WhoAmIResponse whoami(
  239. RpcController controller, AuthenticationProtos.WhoAmIRequest request)
  240. throws ServiceException {
  241. LOG.debug("whoami() request from "+RequestContext.getRequestUserName());
  242. // ignore passed in controller -- it's always null
  243. ServerRpcController serverController = new ServerRpcController();
  244. BlockingRpcCallback<AuthenticationProtos.WhoAmIResponse> callback =
  245. new BlockingRpcCallback<AuthenticationProtos.WhoAmIResponse>();
  246. whoami(serverController, request, callback);
  247. try {
  248. serverController.checkFailed();
  249. return callback.get();
  250. } catch (IOException ioe) {
  251. throw new ServiceException(ioe);
  252. }
  253. }
  254. }
  255. private static HBaseTestingUtility TEST_UTIL;
  256. private static TokenServer server;
  257. private static Thread serverThread;
  258. private static AuthenticationTokenSecretManager secretManager;
  259. private static ClusterId clusterId = new ClusterId();
  260. @BeforeClass
  261. public static void setupBeforeClass() throws Exception {
  262. TEST_UTIL = new HBaseTestingUtility();
  263. TEST_UTIL.startMiniZKCluster();
  264. // security settings only added after startup so that ZK does not require SASL
  265. Configuration conf = TEST_UTIL.getConfiguration();
  266. conf.set("hadoop.security.authentication", "kerberos");
  267. conf.set("hbase.security.authentication", "kerberos");
  268. server = new TokenServer(conf);
  269. serverThread = new Thread(server);
  270. Threads.setDaemonThreadRunning(serverThread,
  271. "TokenServer:"+server.getServerName().toString());
  272. // wait for startup
  273. while (!server.isStarted() && !server.isStopped()) {
  274. Thread.sleep(10);
  275. }
  276. ZKClusterId.setClusterId(server.getZooKeeper(), clusterId);
  277. secretManager = (AuthenticationTokenSecretManager)server.getSecretManager();
  278. while(secretManager.getCurrentKey() == null) {
  279. Thread.sleep(1);
  280. }
  281. }
  282. @AfterClass
  283. public static void tearDownAfterClass() throws Exception {
  284. server.stop("Test complete");
  285. Threads.shutdown(serverThread);
  286. TEST_UTIL.shutdownMiniZKCluster();
  287. }
  288. @Test
  289. public void testTokenCreation() throws Exception {
  290. Token<AuthenticationTokenIdentifier> token =
  291. secretManager.generateToken("testuser");
  292. AuthenticationTokenIdentifier ident = new AuthenticationTokenIdentifier();
  293. Writables.getWritable(token.getIdentifier(), ident);
  294. assertEquals("Token username should match", "testuser",
  295. ident.getUsername());
  296. byte[] passwd = secretManager.retrievePassword(ident);
  297. assertTrue("Token password and password from secret manager should match",
  298. Bytes.equals(token.getPassword(), passwd));
  299. }
  300. @Test
  301. public void testTokenAuthentication() throws Exception {
  302. UserGroupInformation testuser =
  303. UserGroupInformation.createUserForTesting("testuser", new String[]{"testgroup"});
  304. testuser.setAuthenticationMethod(
  305. UserGroupInformation.AuthenticationMethod.TOKEN);
  306. final Configuration conf = TEST_UTIL.getConfiguration();
  307. UserGroupInformation.setConfiguration(conf);
  308. Token<AuthenticationTokenIdentifier> token =
  309. secretManager.generateToken("testuser");
  310. LOG.debug("Got token: " + token.toString());
  311. testuser.addToken(token);
  312. // verify the server authenticates us as this token user
  313. testuser.doAs(new PrivilegedExceptionAction<Object>() {
  314. public Object run() throws Exception {
  315. Configuration c = server.getConfiguration();
  316. c.set(HConstants.CLUSTER_ID, clusterId.toString());
  317. AuthenticationProtos.AuthenticationService.BlockingInterface proxy =
  318. (AuthenticationProtos.AuthenticationService.BlockingInterface)
  319. HBaseClientRPC.waitForProxy(BlockingAuthenticationService.class,
  320. server.getAddress(), c,
  321. HConstants.DEFAULT_HBASE_CLIENT_RPC_MAXATTEMPTS,
  322. HConstants.DEFAULT_HBASE_RPC_TIMEOUT,
  323. HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
  324. AuthenticationProtos.WhoAmIResponse response =
  325. proxy.whoami(null, AuthenticationProtos.WhoAmIRequest.getDefaultInstance());
  326. String myname = response.getUsername();
  327. assertEquals("testuser", myname);
  328. String authMethod = response.getAuthMethod();
  329. assertEquals("TOKEN", authMethod);
  330. return null;
  331. }
  332. });
  333. }
  334. }