Plugins: Add validation to plugin descriptor parsing (#27951)

This commit checks there are no leftover unparsed elements when parsing
a plugin descriptor.
This commit is contained in:
Ryan Ernst 2017-12-22 10:02:11 -08:00 committed by GitHub
parent 0423155fc6
commit 0375d887f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 13 deletions

View File

@ -34,7 +34,10 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* An in-memory representation of the plugin descriptor.
@ -119,27 +122,33 @@ public class PluginInfo implements Writeable, ToXContentObject {
*/
public static PluginInfo readFromProperties(final Path path) throws IOException {
final Path descriptor = path.resolve(ES_PLUGIN_PROPERTIES);
final Properties props = new Properties();
try (InputStream stream = Files.newInputStream(descriptor)) {
props.load(stream);
final Map<String, String> propsMap;
{
final Properties props = new Properties();
try (InputStream stream = Files.newInputStream(descriptor)) {
props.load(stream);
}
propsMap = props.stringPropertyNames().stream().collect(Collectors.toMap(Function.identity(), props::getProperty));
}
final String name = props.getProperty("name");
final String name = propsMap.remove("name");
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException(
"property [name] is missing in [" + descriptor + "]");
}
final String description = props.getProperty("description");
final String description = propsMap.remove("description");
if (description == null) {
throw new IllegalArgumentException(
"property [description] is missing for plugin [" + name + "]");
}
final String version = props.getProperty("version");
final String version = propsMap.remove("version");
if (version == null) {
throw new IllegalArgumentException(
"property [version] is missing for plugin [" + name + "]");
}
final String esVersionString = props.getProperty("elasticsearch.version");
final String esVersionString = propsMap.remove("elasticsearch.version");
if (esVersionString == null) {
throw new IllegalArgumentException(
"property [elasticsearch.version] is missing for plugin [" + name + "]");
@ -154,20 +163,20 @@ public class PluginInfo implements Writeable, ToXContentObject {
esVersionString);
throw new IllegalArgumentException(message);
}
final String javaVersionString = props.getProperty("java.version");
final String javaVersionString = propsMap.remove("java.version");
if (javaVersionString == null) {
throw new IllegalArgumentException(
"property [java.version] is missing for plugin [" + name + "]");
}
JarHell.checkVersionFormat(javaVersionString);
JarHell.checkJavaVersion(name, javaVersionString);
final String classname = props.getProperty("classname");
final String classname = propsMap.remove("classname");
if (classname == null) {
throw new IllegalArgumentException(
"property [classname] is missing for plugin [" + name + "]");
}
final String hasNativeControllerValue = props.getProperty("has.native.controller");
final String hasNativeControllerValue = propsMap.remove("has.native.controller");
final boolean hasNativeController;
if (hasNativeControllerValue == null) {
hasNativeController = false;
@ -191,7 +200,10 @@ public class PluginInfo implements Writeable, ToXContentObject {
}
}
final String requiresKeystoreValue = props.getProperty("requires.keystore", "false");
String requiresKeystoreValue = propsMap.remove("requires.keystore");
if (requiresKeystoreValue == null) {
requiresKeystoreValue = "false";
}
final boolean requiresKeystore;
try {
requiresKeystore = Booleans.parseBoolean(requiresKeystoreValue);
@ -200,6 +212,10 @@ public class PluginInfo implements Writeable, ToXContentObject {
" but was [" + requiresKeystoreValue + "]", e);
}
if (propsMap.isEmpty() == false) {
throw new IllegalArgumentException("Unknown properties in plugin descriptor: " + propsMap.keySet());
}
return new PluginInfo(name, description, version, classname, hasNativeController, requiresKeystore);
}

View File

@ -31,7 +31,7 @@ import java.util.stream.Collectors;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.Matchers.equalTo;
public class PluginInfoTests extends ESTestCase {
@ -170,10 +170,24 @@ public class PluginInfoTests extends ESTestCase {
plugins.add(new PluginInfo("d", "foo", "dummy", "dummyclass", randomBoolean(), randomBoolean()));
PluginsAndModules pluginsInfo = new PluginsAndModules(plugins, Collections.emptyList());
final List<PluginInfo> infos = pluginsInfo.getPluginInfos();
List<String> names = infos.stream().map(PluginInfo::getName).collect(Collectors.toList());
assertThat(names, contains("a", "b", "c", "d", "e"));
}
public void testUnknownProperties() throws Exception {
Path pluginDir = createTempDir().resolve("fake-plugin");
PluginTestUtil.writeProperties(pluginDir,
"extra", "property",
"unknown", "property",
"description", "fake desc",
"classname", "Foo",
"name", "my_plugin",
"version", "1.0",
"elasticsearch.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"));
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> PluginInfo.readFromProperties(pluginDir));
assertThat(e.getMessage(), containsString("Unknown properties in plugin descriptor"));
}
}