commit adafbdd5c35b999de40d07348af4d3662f4f7779 Author: Vihang Karajgaonkar Date: Wed Oct 5 11:58:23 2016 -0700 HIVE-14889 : Beeline leaks environment variables of HiveServer2 when you type set diff --git a/ql/src/java/org/apache/hadoop/hive/ql/processors/SetProcessor.java b/ql/src/java/org/apache/hadoop/hive/ql/processors/SetProcessor.java index c9d06ba33d02d678819933737ba200e278f226cc..9aa7138f1464ba337628ac0285b918f475bdef23 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/processors/SetProcessor.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/processors/SetProcessor.java @@ -54,6 +54,10 @@ private static final String prefix = "set: "; private static final Set removedConfigs = Sets.newHashSet("hive.mapred.supports.subdirectories","hive.enforce.sorting","hive.enforce.bucketing", "hive.outerjoin.supports.filters"); + static final String PASSWD_MASK = "*****"; + + private static final String[] PASSWORD_STRINGS = new String[] {"password", "paswd", "pswd"}; + public static boolean getBoolean(String value) { if (value.equals("on") || value.equals("true")) { return true; @@ -88,16 +92,29 @@ private void dumpOptions(Properties p) { } for (Map.Entry entry : mapToSortedMap(System.getenv()).entrySet()) { - ss.out.println(ENV_PREFIX+entry.getKey() + "=" + entry.getValue()); + ss.out.println(ENV_PREFIX+entry.getKey() + "=" + mask(entry.getKey(), entry.getValue())); } for (Map.Entry entry : propertiesToSortedMap(System.getProperties()).entrySet() ) { - ss.out.println(SYSTEM_PREFIX+entry.getKey() + "=" + entry.getValue()); + ss.out.println(SYSTEM_PREFIX+entry.getKey() + "=" + mask(entry.getKey(), entry.getValue())); } } + /* + * Checks if the value contains any of the PASSWORD_STRINGS and if yes + * return the PASWD_MASK. Else returns the original value + */ + private String mask(String key, String value) { + for(String p : PASSWORD_STRINGS) { + if(key.toLowerCase().contains(p)) { + return PASSWD_MASK; + } + } + return value; + } + private void dumpOption(String s) { SessionState ss = SessionState.get(); @@ -249,7 +266,7 @@ private CommandProcessorResponse getVariable(String varname) throws Exception { String propName = varname.substring(SYSTEM_PREFIX.length()); String result = System.getProperty(propName); if (result != null) { - ss.out.println(SYSTEM_PREFIX + propName + "=" + result); + ss.out.println(SYSTEM_PREFIX + propName + "=" + mask(propName, result)); return createProcessorSuccessResponse(); } else { ss.out.println(propName + " is undefined as a system property"); @@ -258,7 +275,7 @@ private CommandProcessorResponse getVariable(String varname) throws Exception { } else if (varname.indexOf(ENV_PREFIX) == 0) { String var = varname.substring(ENV_PREFIX.length()); if (System.getenv(var) != null) { - ss.out.println(ENV_PREFIX + var + "=" + System.getenv(var)); + ss.out.println(ENV_PREFIX + var + "=" + mask(var, System.getenv(var))); return createProcessorSuccessResponse(); } else { ss.out.println(varname + " is undefined as an environmental variable"); diff --git a/ql/src/test/org/apache/hadoop/hive/ql/processors/TestSetProcessor.java b/ql/src/test/org/apache/hadoop/hive/ql/processors/TestSetProcessor.java index bff643abc47f6eb01cf8cda6e0277c3008ece505..2ed8924f318b3fa946f00e4b357b8564b30a3852 100644 --- a/ql/src/test/org/apache/hadoop/hive/ql/processors/TestSetProcessor.java +++ b/ql/src/test/org/apache/hadoop/hive/ql/processors/TestSetProcessor.java @@ -20,35 +20,139 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; - -import junit.framework.Assert; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.conf.SystemVariables; import org.apache.hadoop.hive.ql.session.SessionState; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; public class TestSetProcessor { - @Test - public void testHiddenConfig() throws Exception { + private static final String TEST_SYSTEM_PROPERTY = "testSystemPropertyPassword"; + private static final String TEST_SYSTEM_PROPERTY_VALUE = "testSystemPropertyValue"; + private static final String TEST_ENV_VAR_PASSWORD_VAL = "testEnvPasswordValue"; + private static final String TEST_ENV_VAR_PASSWORD = "testEnvPasswordValue"; + private ByteArrayOutputStream baos; + private static SessionState state; + private SetProcessor processor; + + @BeforeClass + public static void before() throws Exception { + Map env = new HashMap<>(); + env.put(TEST_ENV_VAR_PASSWORD, TEST_ENV_VAR_PASSWORD_VAL); + setEnv(env); + System.setProperty(TEST_SYSTEM_PROPERTY, TEST_SYSTEM_PROPERTY_VALUE); HiveConf conf = new HiveConf(); SessionState.start(conf); - SessionState state = SessionState.get(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - state.out = new PrintStream(baos); - SetProcessor processor = new SetProcessor(); - processor.run(""); - state.out.flush(); - String ret = baos.toString(); - Assert.assertFalse(ret.contains(HiveConf.ConfVars.METASTOREPWD.varname + "=")); - Assert.assertFalse(ret.contains(HiveConf.ConfVars.HIVE_SERVER2_SSL_KEYSTORE_PASSWORD.varname + "=")); + state = SessionState.get(); + } + @Before + public void setupTest() { baos = new ByteArrayOutputStream(); state.out = new PrintStream(baos); - processor.run(HiveConf.ConfVars.METASTOREPWD.varname); + processor = new SetProcessor(); + } + + @Test + public void testHiddenConfig() throws Exception { + runSetProcessor(""); + String output = baos.toString(); + Assert.assertFalse(output.contains(HiveConf.ConfVars.METASTOREPWD.varname + "=")); + Assert.assertFalse(output.contains(HiveConf.ConfVars.HIVE_SERVER2_SSL_KEYSTORE_PASSWORD.varname + "=")); + } + + @Test + public void testHiddenConfigSetVarName() { + runSetProcessor(HiveConf.ConfVars.METASTOREPWD.varname); + String output = baos.toString(); + Assert.assertTrue(output.contains("hidden")); + } + + @Test + public void testEnvPasswordMask() throws Exception { + runSetProcessor(""); + String output = baos.toString(); + String value = getValue(output, TEST_ENV_VAR_PASSWORD, true); + Assert.assertEquals(SetProcessor.PASSWD_MASK, value); + } + + @Test + public void testEnvPasswordMaskIndividual() throws Exception { + runSetProcessor(SystemVariables.ENV_PREFIX + TEST_ENV_VAR_PASSWORD); + String output = baos.toString(); + String value = getValue(output, TEST_ENV_VAR_PASSWORD, true); + Assert.assertEquals(SetProcessor.PASSWD_MASK, value); + } + + @Test + public void testSystemProperty() throws Exception { + runSetProcessor(""); + String output = baos.toString(); + String value = getValue(output, TEST_SYSTEM_PROPERTY, false); + Assert.assertEquals(SetProcessor.PASSWD_MASK, value); + } + + @Test + public void testSystemPropertyIndividual() throws Exception { + runSetProcessor(SystemVariables.SYSTEM_PREFIX + TEST_SYSTEM_PROPERTY); + String output = baos.toString(); + String value = getValue(output, TEST_SYSTEM_PROPERTY, false); + Assert.assertEquals(SetProcessor.PASSWD_MASK, value); + } + + private String getValue(String output, String key, boolean isEnvironmentVar) { + String[] lines = output.split("\n"); + String prefix; + if(isEnvironmentVar) { + prefix = SystemVariables.ENV_PREFIX; + } else { + prefix = SystemVariables.SYSTEM_PREFIX; + } + for(String line : lines) { + if(line.toLowerCase().startsWith(prefix)) { + line = line.substring(line.indexOf(':')+1); + String[] words = line.split("="); + if(words != null && words[0].equals(key)) { + return words[1]; + } + } + } + return null; + } + + /* + * Simulates the set ; + */ + private void runSetProcessor(String command) { + processor.run(command); state.out.flush(); - ret = new String(baos.toByteArray()); - Assert.assertTrue(baos.toString().contains("hidden")); + } + + /* + * 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 newenv) throws Exception { + Class[] classes = Collections.class.getDeclaredClasses(); + Map 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 map = (Map) obj; + map.clear(); + map.putAll(newenv); + } + } } }