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 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertTrue; 22 23 import java.io.File; 24 import java.io.IOException; 25 import java.util.Properties; 26 27 import org.apache.hadoop.conf.Configuration; 28 import org.apache.hadoop.fs.Path; 29 import org.apache.hadoop.hbase.HBaseTestingUtility; 30 import org.apache.hadoop.hbase.HConstants; 31 import org.apache.hadoop.hbase.LocalHBaseCluster; 32 import org.apache.hadoop.hbase.TableName; 33 import org.apache.hadoop.hbase.client.Connection; 34 import org.apache.hadoop.hbase.client.ConnectionFactory; 35 import org.apache.hadoop.hbase.client.Table; 36 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 37 import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil; 38 import org.apache.hadoop.hbase.ipc.AsyncRpcClient; 39 import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel; 40 import org.apache.hadoop.hbase.ipc.RpcClient; 41 import org.apache.hadoop.hbase.ipc.RpcClientFactory; 42 import org.apache.hadoop.hbase.ipc.RpcClientImpl; 43 import org.apache.hadoop.hbase.protobuf.ProtobufUtil; 44 import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos; 45 import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.GetAuthenticationTokenRequest; 46 import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIRequest; 47 import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIResponse; 48 import org.apache.hadoop.hbase.security.AccessDeniedException; 49 import org.apache.hadoop.hbase.security.HBaseKerberosUtils; 50 import org.apache.hadoop.hbase.testclassification.MediumTests; 51 import org.apache.hadoop.hbase.util.FSUtils; 52 import org.apache.hadoop.hdfs.DFSConfigKeys; 53 import org.apache.hadoop.http.HttpConfig; 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.apache.hadoop.security.token.Token; 58 import org.apache.hadoop.security.token.TokenIdentifier; 59 import org.junit.AfterClass; 60 import org.junit.BeforeClass; 61 import org.junit.Test; 62 import org.junit.experimental.categories.Category; 63 64 import com.google.protobuf.ServiceException; 65 66 @Category(MediumTests.class) 67 public class TestGenerateDelegationToken { 68 69 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 70 71 private static LocalHBaseCluster CLUSTER; 72 73 private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri() 74 .getPath()); 75 private static MiniKdc KDC; 76 77 private static String HOST = "localhost"; 78 79 private static String USERNAME; 80 81 private static String PRINCIPAL; 82 83 private static String HTTP_PRINCIPAL; 84 setHdfsSecuredConfiguration(Configuration conf)85 private static void setHdfsSecuredConfiguration(Configuration conf) throws Exception { 86 // change XXX_USER_NAME_KEY to XXX_KERBEROS_PRINCIPAL_KEY after we drop support for hadoop-2.4.1 87 conf.set(DFSConfigKeys.DFS_NAMENODE_USER_NAME_KEY, PRINCIPAL + "@" + KDC.getRealm()); 88 conf.set(DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY, KEYTAB_FILE.getAbsolutePath()); 89 conf.set(DFSConfigKeys.DFS_DATANODE_USER_NAME_KEY, PRINCIPAL + "@" + KDC.getRealm()); 90 conf.set(DFSConfigKeys.DFS_DATANODE_KEYTAB_FILE_KEY, KEYTAB_FILE.getAbsolutePath()); 91 conf.set(DFSConfigKeys.DFS_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL_KEY, HTTP_PRINCIPAL + "@" 92 + KDC.getRealm()); 93 conf.setBoolean(DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY, true); 94 conf.set("dfs.http.policy", HttpConfig.Policy.HTTPS_ONLY.name()); 95 conf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0"); 96 conf.set(DFSConfigKeys.DFS_DATANODE_HTTPS_ADDRESS_KEY, "localhost:0"); 97 98 File keystoresDir = new File(TEST_UTIL.getDataTestDir("keystore").toUri().getPath()); 99 keystoresDir.mkdirs(); 100 String sslConfDir = KeyStoreTestUtil.getClasspathDir(TestGenerateDelegationToken.class); 101 KeyStoreTestUtil.setupSSLConfig(keystoresDir.getAbsolutePath(), sslConfDir, conf, false); 102 103 conf.setBoolean("ignore.secure.ports.for.testing", true); 104 } 105 106 @BeforeClass setUp()107 public static void setUp() throws Exception { 108 Properties conf = MiniKdc.createConf(); 109 conf.put(MiniKdc.DEBUG, true); 110 KDC = new MiniKdc(conf, new File(TEST_UTIL.getDataTestDir("kdc").toUri().getPath())); 111 KDC.start(); 112 USERNAME = UserGroupInformation.getLoginUser().getShortUserName(); 113 PRINCIPAL = USERNAME + "/" + HOST; 114 HTTP_PRINCIPAL = "HTTP/" + HOST; 115 KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL, HTTP_PRINCIPAL); 116 TEST_UTIL.startMiniZKCluster(); 117 118 HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath()); 119 HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm()); 120 HBaseKerberosUtils.setSecuredConfiguration(TEST_UTIL.getConfiguration()); 121 setHdfsSecuredConfiguration(TEST_UTIL.getConfiguration()); 122 UserGroupInformation.setConfiguration(TEST_UTIL.getConfiguration()); 123 TEST_UTIL.getConfiguration().setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 124 TokenProvider.class.getName()); 125 TEST_UTIL.startMiniDFSCluster(1); 126 Path rootdir = TEST_UTIL.getDataTestDirOnTestFS("TestGenerateDelegationToken"); 127 FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootdir); 128 CLUSTER = new LocalHBaseCluster(TEST_UTIL.getConfiguration(), 1); 129 CLUSTER.startup(); 130 } 131 132 @AfterClass tearDown()133 public static void tearDown() throws Exception { 134 if (CLUSTER != null) { 135 CLUSTER.shutdown(); 136 } 137 CLUSTER.join(); 138 if (KDC != null) { 139 KDC.stop(); 140 } 141 TEST_UTIL.shutdownMiniCluster(); 142 } 143 testTokenAuth(Class<? extends RpcClient> rpcImplClass)144 private void testTokenAuth(Class<? extends RpcClient> rpcImplClass) throws IOException, 145 ServiceException { 146 TEST_UTIL.getConfiguration().set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, 147 rpcImplClass.getName()); 148 try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration()); 149 Table table = conn.getTable(TableName.META_TABLE_NAME)) { 150 CoprocessorRpcChannel rpcChannel = table.coprocessorService(HConstants.EMPTY_START_ROW); 151 AuthenticationProtos.AuthenticationService.BlockingInterface service = 152 AuthenticationProtos.AuthenticationService.newBlockingStub(rpcChannel); 153 WhoAmIResponse response = service.whoAmI(null, WhoAmIRequest.getDefaultInstance()); 154 assertEquals(USERNAME, response.getUsername()); 155 assertEquals(AuthenticationMethod.TOKEN.name(), response.getAuthMethod()); 156 try { 157 service.getAuthenticationToken(null, GetAuthenticationTokenRequest.getDefaultInstance()); 158 } catch (ServiceException e) { 159 AccessDeniedException exc = (AccessDeniedException) ProtobufUtil.getRemoteException(e); 160 assertTrue(exc.getMessage().contains( 161 "Token generation only allowed for Kerberos authenticated clients")); 162 } 163 } 164 } 165 166 @Test test()167 public void test() throws Exception { 168 try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) { 169 Token<? extends TokenIdentifier> token = TokenUtil.obtainToken(conn); 170 UserGroupInformation.getCurrentUser().addToken(token); 171 testTokenAuth(RpcClientImpl.class); 172 testTokenAuth(AsyncRpcClient.class); 173 } 174 175 } 176 } 177