/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hive.minikdc;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.shims.Utils;
import org.apache.hadoop.minikdc.MiniKdc;
import org.apache.hadoop.security.GroupMappingServiceProvider;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hive.jdbc.miniHS2.MiniHS2;
import com.google.common.io.Files;
/**
* Wrapper around Hadoop's MiniKdc for use in hive tests.
* Has functions to manager users and their keytabs. This includes a hive service principal,
* a superuser principal for testing proxy user privilegs.
* Has a set of default users that it initializes.
* See hive-minikdc/src/test/resources/core-site.xml for users granted proxy user privileges.
*/
public class MiniHiveKdc {
public static String HIVE_SERVICE_PRINCIPAL = "hive";
public static String HIVE_TEST_USER_1 = "user1";
public static String HIVE_TEST_USER_2 = "user2";
public static String HIVE_TEST_SUPER_USER = "superuser";
public static String AUTHENTICATION_TYPE = "KERBEROS";
private final MiniKdc miniKdc;
private final File workDir;
private final Configuration conf;
private final Map<String, String> userPrincipals =
new HashMap<String, String>();
private final Properties kdcConf = MiniKdc.createConf();
private int keyTabCounter = 1;
// hadoop group mapping that maps user to same group
public static class HiveTestSimpleGroupMapping implements GroupMappingServiceProvider {
@Override
public List<String> getGroups(String user) throws IOException {
List<String> results = new ArrayList<String>();
results.add(user);
return results;
}
@Override
public void cacheGroupsRefresh() throws IOException {
}
@Override
public void cacheGroupsAdd(List<String> groups) throws IOException {
}
}
public static MiniHiveKdc getMiniHiveKdc (Configuration conf) throws Exception {
return new MiniHiveKdc(conf);
}
public MiniHiveKdc(Configuration conf)
throws Exception {
File baseDir = Files.createTempDir();
baseDir.deleteOnExit();
workDir = new File (baseDir, "HiveMiniKdc");
this.conf = conf;
/**
* Hadoop security classes read the default realm via static initialization,
* before miniKdc is initialized. Hence we set the realm via a test configuration
* and propagate that to miniKdc.
*/
assertNotNull("java.security.krb5.conf is needed for hadoop security",
System.getProperty("java.security.krb5.conf"));
System.clearProperty("java.security.krb5.conf");
miniKdc = new MiniKdc(kdcConf, new File(workDir, "miniKdc"));
miniKdc.start();
// create default users
addUserPrincipal(getServicePrincipalForUser(HIVE_SERVICE_PRINCIPAL));
addUserPrincipal(HIVE_TEST_USER_1);
addUserPrincipal(HIVE_TEST_USER_2);
addUserPrincipal(HIVE_TEST_SUPER_USER);
}
public String getKeyTabFile(String principalName) {
return userPrincipals.get(principalName);
}
public void shutDown() {
miniKdc.stop();
}
public void addUserPrincipal(String principal) throws Exception {
File keytab = new File(workDir, "miniKdc" + keyTabCounter++ + ".keytab");
miniKdc.createPrincipal(keytab, principal);
userPrincipals.put(principal, keytab.getPath());
}
/**
* Login the given principal, using corresponding keytab file from internal map
* @param principal
* @return
* @throws Exception
*/
public UserGroupInformation loginUser(String principal)
throws Exception {
UserGroupInformation.loginUserFromKeytab(principal,
getKeyTabFile(principal));
return Utils.getUGI();
}
public Properties getKdcConf() {
return kdcConf;
}
public String getFullyQualifiedUserPrincipal(String shortUserName) {
return shortUserName + "@" + miniKdc.getRealm();
}
public String getFullyQualifiedServicePrincipal(String shortUserName) {
return getServicePrincipalForUser(shortUserName) + "@" + miniKdc.getRealm();
}
public String getServicePrincipalForUser(String shortUserName) {
return shortUserName + "/" + miniKdc.getHost();
}
public String getHiveServicePrincipal() {
return getServicePrincipalForUser(HIVE_SERVICE_PRINCIPAL);
}
public String getFullHiveServicePrincipal() {
return getServicePrincipalForUser(HIVE_SERVICE_PRINCIPAL) + "@" + miniKdc.getRealm();
}
public String getDefaultUserPrincipal() {
return HIVE_TEST_USER_1;
}
/**
* Create a MiniHS2 with the hive service principal and keytab in MiniHiveKdc
* @param miniHiveKdc
* @param hiveConf
* @return new MiniHS2 instance
* @throws Exception
*/
public static MiniHS2 getMiniHS2WithKerb(MiniHiveKdc miniHiveKdc, HiveConf hiveConf) throws Exception {
return getMiniHS2WithKerb(miniHiveKdc, hiveConf, AUTHENTICATION_TYPE);
}
/**
* Create a MiniHS2 with the hive service principal and keytab in MiniHiveKdc
* @param miniHiveKdc
* @param hiveConf
* @param authType
* @return new MiniHS2 instance
* @throws Exception
*/
public static MiniHS2 getMiniHS2WithKerb(MiniHiveKdc miniHiveKdc, HiveConf hiveConf,
String authType) throws Exception {
String hivePrincipal =
miniHiveKdc.getFullyQualifiedServicePrincipal(MiniHiveKdc.HIVE_SERVICE_PRINCIPAL);
String hiveKeytab = miniHiveKdc.getKeyTabFile(
miniHiveKdc.getServicePrincipalForUser(MiniHiveKdc.HIVE_SERVICE_PRINCIPAL));
return new MiniHS2.Builder().withConf(hiveConf).withMiniKdc(hivePrincipal, hiveKeytab).
withAuthenticationType(authType).build();
}
/**
* Create a MiniHS2 with the hive service principal and keytab in MiniHiveKdc
* @param miniHiveKdc
* @param hiveConf
* @return new MiniHS2 instance
* @throws Exception
*/
public static MiniHS2 getMiniHS2WithKerbWithRemoteHMS(MiniHiveKdc miniHiveKdc, HiveConf hiveConf) throws Exception {
return getMiniHS2WithKerbWithRemoteHMS(miniHiveKdc, hiveConf, AUTHENTICATION_TYPE);
}
/**
* Create a MiniHS2 with the hive service principal and keytab in MiniHiveKdc. It uses remote HMS
* and can support a different Sasl authType
* @param miniHiveKdc
* @param hiveConf
* @param authType
* @return new MiniHS2 instance
* @throws Exception
*/
public static MiniHS2 getMiniHS2WithKerbWithRemoteHMS(MiniHiveKdc miniHiveKdc, HiveConf hiveConf,
String authType) throws Exception {
String hivePrincipal =
miniHiveKdc.getFullyQualifiedServicePrincipal(MiniHiveKdc.HIVE_SERVICE_PRINCIPAL);
String hiveKeytab = miniHiveKdc.getKeyTabFile(
miniHiveKdc.getServicePrincipalForUser(MiniHiveKdc.HIVE_SERVICE_PRINCIPAL));
return new MiniHS2.Builder().withConf(hiveConf).withRemoteMetastore().
withMiniKdc(hivePrincipal, hiveKeytab).withAuthenticationType(authType).build();
}
}