/**
* 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.hadoop.hive.ql.exec;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConfUtil;
import org.apache.hadoop.mapred.JobConf;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.apache.hadoop.hive.conf.Constants.HADOOP_CREDENTIAL_PASSWORD_ENVVAR;
import static org.apache.hadoop.hive.conf.Constants.HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG;
import static org.apache.hadoop.hive.conf.Constants.HIVE_SERVER2_JOB_CREDSTORE_PASSWORD_ENVVAR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class TestHiveCredentialProviders {
private static final String HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL = "testhadoopCredStorePassword";
private static final String HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL = "testhiveJobCredPassword";
private static final String JOB_CREDSTORE_LOCATION = "jceks://hdfs/user/hive/creds.jceks";
private static final String HADOOP_CREDSTORE_LOCATION =
"localjceks://file/user/hive/localcreds.jceks";
private Configuration jobConf;
/*
* Dirty hack to set the environment variables using reflection code. This method is for testing
* purposes only and should not be used elsewhere
*/
private final static void setEnv(Map<String, String> newenv) throws Exception {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(newenv);
}
}
}
@Before
public void resetConfig() {
jobConf = new JobConf();
}
/*
* Tests whether credential provider is updated when HIVE_JOB_CREDSTORE_PASSWORD is set and when
* hiveConf sets HiveConf.ConfVars.HIVE_SERVER2_JOB_CREDSTORE_LOCATION
*
* JobConf should contain the mapred env variable equal to ${HIVE_JOB_CREDSTORE_PASSWORD} and the
* hadoop.security.credential.provider.path property should be equal to value of
* HiveConf.ConfVars.HIVE_SERVER2_JOB_CREDSTORE_LOCATION
*/
@Test
public void testJobCredentialProvider() throws Exception {
setupConfigs(true, true, true, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
// make sure credential provider path points to HIVE_SERVER2_JOB_CREDSTORE_LOCATION
Assert.assertEquals(JOB_CREDSTORE_LOCATION,
jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
// make sure MAP task environment points to HIVE_JOB_CREDSTORE_PASSWORD
Assert.assertEquals(HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
// make sure REDUCE task environment points to HIVE_JOB_CREDSTORE_PASSWORD
Assert.assertEquals(HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* If hive job credstore location is not set, but hadoop credential provider is set
* jobConf should contain hadoop credstore location and password should be from HADOOP_CREDSTORE_PASSWORD
*/
@Test
public void testHadoopCredentialProvider() throws Exception {
setupConfigs(true, true, true, false);
HiveConfUtil.updateJobCredentialProviders(jobConf);
Assert.assertEquals(HADOOP_CREDSTORE_LOCATION,
jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
// make sure MAP task environment points to HADOOP_CREDSTORE_PASSWORD
Assert.assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
// make sure REDUCE task environment points to HADOOP_CREDSTORE_PASSWORD
Assert.assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* If there is no credential provider configured for hadoop, jobConf should not contain
* credstore password and provider path even if HIVE_JOB_CRESTORE_PASSWORD env is set
*/
@Test
public void testNoCredentialProviderWithPassword() throws Exception {
setupConfigs(false, false, true, false);
Assert.assertTrue(StringUtils.isBlank(jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG)));
Assert.assertNull(getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV),
HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
Assert.assertNull(getValueFromJobConf(jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV),
HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* If hive job credential provider is set but HIVE_JOB_CREDSTORE_PASSWORD is not set, use
* HADOOP_CREDSTORE_PASSWORD in the jobConf
*/
@Test
public void testJobCredentialProviderWithDefaultPassword() throws Exception {
setupConfigs(false, true, false, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
Assert.assertEquals(JOB_CREDSTORE_LOCATION,
jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
Assert.assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
Assert.assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* When neither HADOOP_CREDSTORE_PASSWORD nor HIVE_JOB_CREDSTORE_PASSWORD
* are not set jobConf should contain only the credential provider path
*/
@Test
public void testCredentialProviderWithNoPasswords() throws Exception {
setupConfigs(true, false, false, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
Assert.assertEquals(JOB_CREDSTORE_LOCATION,
jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
Assert.assertNull(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV));
Assert.assertNull(jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV));
resetConfig();
setupConfigs(true, false, false, false);
HiveConfUtil.updateJobCredentialProviders(jobConf);
Assert.assertEquals(HADOOP_CREDSTORE_LOCATION,
jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
Assert.assertNull(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV));
Assert.assertNull(jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV));
}
/*
* default behavior when neither hive.job.credstore location is set nor
* HIVE_JOB_CREDSTORE_PASSWORD is. In this case if hadoop credential provider is configured job
* config should use that else it should remain unset
*/
@Test
public void testJobCredentialProviderUnset() throws Exception {
setupConfigs(true, true, false, false);
HiveConfUtil.updateJobCredentialProviders(jobConf);
assertEquals(HADOOP_CREDSTORE_LOCATION, jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG));
assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, getValueFromJobConf(
jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV), HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* Test the unsecure base case when neither hadoop nor job-specific
* credential provider is set
*/
@Test
public void testNoCredentialProvider() throws Exception {
setupConfigs(false, false, false, false);
assertTrue(StringUtils.isBlank(jobConf.get(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG)));
assertNull(getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV),
HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
assertNull(getValueFromJobConf(jobConf.get(JobConf.MAPRED_REDUCE_TASK_ENV),
HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
}
/*
* Test updateCredentialProviders does not corrupt existing values of
* Mapred env configs
*/
@Test
public void testExistingConfiguration() throws Exception {
jobConf.set(JobConf.MAPRED_MAP_TASK_ENV, "k1=v1, k2=v2, HADOOP_CREDSTORE_PASSWORD=test");
setupConfigs(false, true, false, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
assertEquals("v1", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k1"));
assertEquals("v2", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k2"));
resetConfig();
jobConf.set(JobConf.MAPRED_MAP_TASK_ENV, "k1=v1, HADOOP_CREDSTORE_PASSWORD=test, k2=v2");
setupConfigs(false, true, false, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
assertEquals("v1", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k1"));
assertEquals("v2", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k2"));
resetConfig();
jobConf.set(JobConf.MAPRED_MAP_TASK_ENV, "HADOOP_CREDSTORE_PASSWORD=test, k1=v1, k2=v2");
setupConfigs(false, true, false, true);
HiveConfUtil.updateJobCredentialProviders(jobConf);
assertEquals("v1", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k1"));
assertEquals("v2", getValueFromJobConf(jobConf.get(JobConf.MAPRED_MAP_TASK_ENV), "k2"));
}
/**
* Sets up the environment and configurations
*
* @param setHadoopCredProvider set hadoop credstore provider path
* @param setHadoopCredstorePassword set HADOOP_CREDSTORE_PASSWORD env variable
* @param setHiveCredPassword set HIVE_JOB_CREDSTORE_PASSWORD env variable
* @param setHiveProviderPath set HiveConf.ConfVars.HIVE_SERVER2_JOB_CREDSTORE_LOCATION in the
* hive config
* @throws Exception
*/
private void setupConfigs(boolean setHadoopCredProvider, boolean setHadoopCredstorePassword,
boolean setHiveCredPassword, boolean setHiveProviderPath) throws Exception {
Map<String, String> mockEnv = new HashMap<>();
// sets the env variable HADOOP_CREDSTORE_PASSWORD to value defined by HADOOP_CREDSTORE_PASSWORD
// sets hadoop.security.credential.provider.path property to simulate default credential
// provider setup
if (setHadoopCredProvider) {
jobConf.set(HADOOP_CREDENTIAL_PROVIDER_PATH_CONFIG, HADOOP_CREDSTORE_LOCATION);
}
if (setHadoopCredstorePassword) {
mockEnv.put(HADOOP_CREDENTIAL_PASSWORD_ENVVAR, HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL);
}
// sets the env variable HIVE_JOB_CREDSTORE_PASSWORD to value defined by
// HIVE_JOB_CREDSTORE_PASSWORD
if (setHiveCredPassword) {
mockEnv.put(HIVE_SERVER2_JOB_CREDSTORE_PASSWORD_ENVVAR, HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL);
}
TestHiveCredentialProviders.setEnv(mockEnv);
// set hive provider path in hiveConf if setHiveProviderPath is true
// simulates hive.server2.job.credstore.location property set in hive-site.xml/core-site.xml of
// HS2
if (setHiveProviderPath) {
jobConf.set(HiveConf.ConfVars.HIVE_SERVER2_JOB_CREDENTIAL_PROVIDER_PATH.varname,
JOB_CREDSTORE_LOCATION);
}
jobConf.set(HiveConf.ConfVars.HIVE_EXECUTION_ENGINE.varname, "mr");
}
/*
* Extract value from a comma-separated key=value pairs
*/
private String getValueFromJobConf(String keyValuePairs, String key) {
if (keyValuePairs == null) {
return null;
}
String[] keyValues = keyValuePairs.split(",");
for (String kv : keyValues) {
String[] parts = kv.split("=");
if (key.equals(parts[0].trim())) {
return parts[1].trim();
}
}
return null;
}
/*
* Test if the environment variables can be set. If this test fails
* all the other tests will also fail because environment is not getting setup
*/
@Test
public void testEnv() throws Exception {
Map<String, String> mockEnv = new HashMap<>();
mockEnv.put(HADOOP_CREDENTIAL_PASSWORD_ENVVAR, HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL);
mockEnv.put(HIVE_SERVER2_JOB_CREDSTORE_PASSWORD_ENVVAR, HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL);
TestHiveCredentialProviders.setEnv(mockEnv);
assertEquals(HADOOP_CREDSTORE_PASSWORD_ENVVAR_VAL, System.getenv(HADOOP_CREDENTIAL_PASSWORD_ENVVAR));
assertEquals(HIVE_JOB_CREDSTORE_PASSWORD_ENVVAR_VAL, System.getenv(HIVE_SERVER2_JOB_CREDSTORE_PASSWORD_ENVVAR));
}
}