HADOOP-17631. Configuration ${env.VAR:-FALLBACK} to eval FALLBACK when restrictSystemProps=true (#2977)

Contributed by Steve Loughran.
This commit is contained in:
Steve Loughran 2021-06-08 21:56:40 +01:00 committed by GitHub
parent a2a0283c7b
commit 762a83e044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 29 deletions

View File

@ -1139,36 +1139,37 @@ public class Configuration implements Iterable<Map.Entry<String,String>>,
final String var = eval.substring(varBounds[SUB_START_IDX],
varBounds[SUB_END_IDX]);
String val = null;
if (!restrictSystemProps) {
try {
if (var.startsWith("env.") && 4 < var.length()) {
String v = var.substring(4);
int i = 0;
for (; i < v.length(); i++) {
char c = v.charAt(i);
if (c == ':' && i < v.length() - 1 && v.charAt(i + 1) == '-') {
val = getenv(v.substring(0, i));
if (val == null || val.length() == 0) {
val = v.substring(i + 2);
}
break;
} else if (c == '-') {
val = getenv(v.substring(0, i));
if (val == null) {
val = v.substring(i + 1);
}
break;
try {
// evaluate system properties or environment variables even when
// the configuration is restricted -the restrictions are enforced
// in the getenv/getProperty calls
if (var.startsWith("env.") && 4 < var.length()) {
String v = var.substring(4);
int i = 0;
for (; i < v.length(); i++) {
char c = v.charAt(i);
if (c == ':' && i < v.length() - 1 && v.charAt(i + 1) == '-') {
val = getenv(v.substring(0, i));
if (val == null || val.length() == 0) {
val = v.substring(i + 2);
}
break;
} else if (c == '-') {
val = getenv(v.substring(0, i));
if (val == null) {
val = v.substring(i + 1);
}
break;
}
if (i == v.length()) {
val = getenv(v);
}
} else {
val = getProperty(var);
}
} catch (SecurityException se) {
LOG.warn("Unexpected SecurityException in Configuration", se);
if (i == v.length()) {
val = getenv(v);
}
} else {
val = getProperty(var);
}
} catch (SecurityException se) {
LOG.warn("Unexpected SecurityException in Configuration", se);
}
if (val == null) {
val = getRaw(var);
@ -1194,13 +1195,33 @@ public class Configuration implements Iterable<Map.Entry<String,String>>,
throw new IllegalStateException("Variable substitution depth too large: "
+ MAX_SUBST + " " + expr);
}
/**
* Get the environment variable value if
* {@link #restrictSystemProps} does not block this.
* @param name environment variable name.
* @return the value or null if either it is unset or access forbidden.
*/
String getenv(String name) {
return System.getenv(name);
if (!restrictSystemProps) {
return System.getenv(name);
} else {
return null;
}
}
/**
* Get a system property value if
* {@link #restrictSystemProps} does not block this.
* @param key property key
* @return the value or null if either it is unset or access forbidden.
*/
String getProperty(String key) {
return System.getProperty(key);
if (!restrictSystemProps) {
return System.getProperty(key);
} else {
return null;
}
}
/**

View File

@ -485,6 +485,62 @@ public class TestConfiguration {
}
}
/**
* Verify that when a configuration is restricted, environment
* variables and system properties will be unresolved.
* The fallback patterns for the variables are still parsed.
*/
@Test
public void testRestrictedEnv() throws IOException {
// this test relies on env.PATH being set on all platforms a
// test run will take place on, and the java.version sysprop
// set in all JVMs.
// Restricted configurations will not get access to these values, so
// will either be unresolved or, for env vars with fallbacks: the fallback
// values.
conf.setRestrictSystemProperties(true);
out = new BufferedWriter(new FileWriter(CONFIG));
startConfig();
// a simple property to reference
declareProperty("d", "D", "D");
// system property evaluation stops working completely
declareProperty("system1", "${java.version}", "${java.version}");
// the env variable does not resolve
declareProperty("secret1", "${env.PATH}", "${env.PATH}");
// but all the fallback options do work
declareProperty("secret2", "${env.PATH-a}", "a");
declareProperty("secret3", "${env.PATH:-b}", "b");
declareProperty("secret4", "${env.PATH:-}", "");
declareProperty("secret5", "${env.PATH-}", "");
// special case
declareProperty("secret6", "${env.PATH:}", "${env.PATH:}");
// safety check
declareProperty("secret7", "${env.PATH:--}", "-");
// recursive eval of the fallback
declareProperty("secret8", "${env.PATH:-${d}}", "D");
// if the fallback doesn't resolve, the result is the whole variable raw.
declareProperty("secret9", "${env.PATH:-$d}}", "${env.PATH:-$d}}");
endConfig();
Path fileResource = new Path(CONFIG);
conf.addResource(fileResource);
for (Prop p : props) {
System.out.println("p=" + p.name);
String gotVal = conf.get(p.name);
String gotRawVal = conf.getRaw(p.name);
assertEq(p.val, gotRawVal);
assertEq(p.expectEval, gotVal);
}
}
@Test
public void testFinalParam() throws IOException {
out=new BufferedWriter(new FileWriter(CONFIG));