commit 1a029c77c2be8cda42bfe6ef7935a97fa9731daa Author: Vihang Karajgaonkar Date: Wed Oct 5 11:58:23 2016 -0700 HIVE-14889 : Beeline leaks sensitive 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..eab18865d9772cc37d0ef5c19cbe2473055cd330 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,8 @@ 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"); + 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 +90,35 @@ private void dumpOptions(Properties p) { } for (Map.Entry entry : mapToSortedMap(System.getenv()).entrySet()) { + if(isHidden(entry.getKey())) { + continue; + } ss.out.println(ENV_PREFIX+entry.getKey() + "=" + entry.getValue()); } for (Map.Entry entry : propertiesToSortedMap(System.getProperties()).entrySet() ) { + if(isHidden(entry.getKey())) { + continue; + } ss.out.println(SYSTEM_PREFIX+entry.getKey() + "=" + entry.getValue()); } } + /* + * Checks if the value contains any of the PASSWORD_STRINGS and if yes + * return true + */ + private boolean isHidden(String key) { + for(String p : PASSWORD_STRINGS) { + if(key.toLowerCase().contains(p)) { + return true; + } + } + return false; + } + private void dumpOption(String s) { SessionState ss = SessionState.get(); @@ -249,7 +270,11 @@ 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); + if(isHidden(propName)) { + ss.out.println(SYSTEM_PREFIX + propName + " is a hidden config"); + } else { + ss.out.println(SYSTEM_PREFIX + propName + "=" + result); + } return createProcessorSuccessResponse(); } else { ss.out.println(propName + " is undefined as a system property"); @@ -258,7 +283,11 @@ 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)); + if(isHidden(var)) { + ss.out.println(ENV_PREFIX + var + " is a hidden config"); + } else { + ss.out.println(ENV_PREFIX + 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..4eb4941079e932fd93d2172b4ca78baf68b8b9a9 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,117 @@ 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_VALUE = "testEnvPasswordValue"; + private static final String TEST_ENV_VAR_PASSWORD = "testEnvPassword"; + 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_VALUE); + 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(); + Assert.assertFalse(output.contains(TEST_ENV_VAR_PASSWORD + "=")); + } + + @Test + public void testEnvPasswordMaskIndividual() throws Exception { + runSetProcessor(SystemVariables.ENV_PREFIX + TEST_ENV_VAR_PASSWORD); + String output = baos.toString(); + Assert.assertFalse(output.contains(TEST_ENV_VAR_PASSWORD_VALUE)); + Assert.assertTrue(output.contains("hidden")); + } + + @Test + public void testSystemProperty() throws Exception { + runSetProcessor(""); + String output = baos.toString(); + Assert.assertFalse(output.contains(TEST_SYSTEM_PROPERTY + "=")); + } + + @Test + public void testSystemPropertyIndividual() throws Exception { + runSetProcessor(SystemVariables.SYSTEM_PREFIX + TEST_SYSTEM_PROPERTY); + String output = baos.toString(); + Assert.assertFalse(output.contains(TEST_SYSTEM_PROPERTY_VALUE)); + Assert.assertTrue(output.contains("hidden")); + } + + /* + * 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); + } + } } }