From e3d954c6a5944dc68fff209fc4cae196c5b04936 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Mon, 16 Apr 2018 12:27:34 -0700 Subject: [PATCH] Plugins: Fix native controller confirmation for non-meta plugin (#29434) This commit fixes plugin warning confirmation to include native controller confirmation when no security policy exists. The case was already covered for meta plugins, but not for normal plugins. Tests are also added for all cases. --- .../plugins/InstallPluginCommand.java | 7 +- .../plugins/InstallPluginCommandTests.java | 125 +++++++++++++++--- 2 files changed, 108 insertions(+), 24 deletions(-) diff --git a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java index 5a14d041c763b..e1733e478b8c2 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java +++ b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java @@ -698,10 +698,13 @@ private void installPlugin(Terminal terminal, boolean isBatch, Path tmpRoot, final PluginInfo info = loadPluginInfo(terminal, tmpRoot, isBatch, env); // read optional security policy (extra permissions), if it exists, confirm or warn the user Path policy = tmpRoot.resolve(PluginInfo.ES_PLUGIN_POLICY); + final Set permissions; if (Files.exists(policy)) { - Set permissions = PluginSecurity.parsePermissions(policy, env.tmpFile()); - PluginSecurity.confirmPolicyExceptions(terminal, permissions, info.hasNativeController(), isBatch); + permissions = PluginSecurity.parsePermissions(policy, env.tmpFile()); + } else { + permissions = Collections.emptySet(); } + PluginSecurity.confirmPolicyExceptions(terminal, permissions, info.hasNativeController(), isBatch); final Path destination = env.pluginsFile().resolve(info.getName()); deleteOnFailure.add(destination); diff --git a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java index d799cb0407f58..96e009b3462f1 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java @@ -1153,6 +1153,59 @@ private Function checksumAndString(final MessageDigest digest, f return bytes -> MessageDigests.toHexString(digest.digest(bytes)) + s; } + // checks the plugin requires a policy confirmation, and does not install when that is rejected by the user + // the plugin is installed after this method completes + private void assertPolicyConfirmation(Tuple env, String pluginZip, String... warnings) throws Exception { + for (int i = 0; i < warnings.length; ++i) { + String warning = warnings[i]; + for (int j = 0; j < i; ++j) { + terminal.addTextInput("y"); // accept warnings we have already tested + } + // default answer, does not install + terminal.addTextInput(""); + UserException e = expectThrows(UserException.class, () -> installPlugin(pluginZip, env.v1())); + assertEquals("installation aborted by user", e.getMessage()); + + assertThat(terminal.getOutput(), containsString("WARNING: " + warning)); + try (Stream fileStream = Files.list(env.v2().pluginsFile())) { + assertThat(fileStream.collect(Collectors.toList()), empty()); + } + + // explicitly do not install + terminal.reset(); + for (int j = 0; j < i; ++j) { + terminal.addTextInput("y"); // accept warnings we have already tested + } + terminal.addTextInput("n"); + e = expectThrows(UserException.class, () -> installPlugin(pluginZip, env.v1())); + assertEquals("installation aborted by user", e.getMessage()); + assertThat(terminal.getOutput(), containsString("WARNING: " + warning)); + try (Stream fileStream = Files.list(env.v2().pluginsFile())) { + assertThat(fileStream.collect(Collectors.toList()), empty()); + } + } + + // allow installation + terminal.reset(); + for (int j = 0; j < warnings.length; ++j) { + terminal.addTextInput("y"); + } + installPlugin(pluginZip, env.v1()); + for (String warning : warnings) { + assertThat(terminal.getOutput(), containsString("WARNING: " + warning)); + } + } + + public void testPolicyConfirmation() throws Exception { + Tuple env = createEnv(fs, temp); + Path pluginDir = createPluginDir(temp); + writePluginSecurityPolicy(pluginDir, "setAccessible", "setFactory"); + String pluginZip = createPluginUrl("fake", pluginDir); + + assertPolicyConfirmation(env, pluginZip, "plugin requires additional permissions"); + assertPlugin("fake", pluginDir, env.v2()); + } + public void testMetaPluginPolicyConfirmation() throws Exception { Tuple env = createEnv(fs, temp); Path metaDir = createPluginDir(temp); @@ -1166,32 +1219,60 @@ public void testMetaPluginPolicyConfirmation() throws Exception { writePlugin("fake2", fake2Dir); String pluginZip = createMetaPluginUrl("meta-plugin", metaDir); - // default answer, does not install - terminal.addTextInput(""); - UserException e = expectThrows(UserException.class, () -> installPlugin(pluginZip, env.v1())); - assertEquals("installation aborted by user", e.getMessage()); - assertThat(terminal.getOutput(), containsString("WARNING: plugin requires additional permissions")); - try (Stream fileStream = Files.list(env.v2().pluginsFile())) { - assertThat(fileStream.collect(Collectors.toList()), empty()); - } + assertPolicyConfirmation(env, pluginZip, "plugin requires additional permissions"); + assertMetaPlugin("meta-plugin", "fake1", metaDir, env.v2()); + assertMetaPlugin("meta-plugin", "fake2", metaDir, env.v2()); + } - // explicitly do not install - terminal.reset(); - terminal.addTextInput("n"); - e = expectThrows(UserException.class, () -> installPlugin(pluginZip, env.v1())); - assertEquals("installation aborted by user", e.getMessage()); - assertThat(terminal.getOutput(), containsString("WARNING: plugin requires additional permissions")); - try (Stream fileStream = Files.list(env.v2().pluginsFile())) { - assertThat(fileStream.collect(Collectors.toList()), empty()); - } + public void testNativeControllerConfirmation() throws Exception { + Tuple env = createEnv(fs, temp); + Path pluginDir = createPluginDir(temp); + String pluginZip = createPluginUrl("fake", pluginDir, "has.native.controller", "true"); - // allow installation - terminal.reset(); - terminal.addTextInput("y"); - installPlugin(pluginZip, env.v1()); - assertThat(terminal.getOutput(), containsString("WARNING: plugin requires additional permissions")); + assertPolicyConfirmation(env, pluginZip, "plugin forks a native controller"); + assertPlugin("fake", pluginDir, env.v2()); + } + + public void testMetaPluginNativeControllerConfirmation() throws Exception { + Tuple env = createEnv(fs, temp); + Path metaDir = createPluginDir(temp); + Path fake1Dir = metaDir.resolve("fake1"); + Files.createDirectory(fake1Dir); + writePlugin("fake1", fake1Dir, "has.native.controller", "true"); + Path fake2Dir = metaDir.resolve("fake2"); + Files.createDirectory(fake2Dir); + writePlugin("fake2", fake2Dir); + String pluginZip = createMetaPluginUrl("meta-plugin", metaDir); + + assertPolicyConfirmation(env, pluginZip, "plugin forks a native controller"); assertMetaPlugin("meta-plugin", "fake1", metaDir, env.v2()); assertMetaPlugin("meta-plugin", "fake2", metaDir, env.v2()); } + public void testNativeControllerAndPolicyConfirmation() throws Exception { + Tuple env = createEnv(fs, temp); + Path pluginDir = createPluginDir(temp); + writePluginSecurityPolicy(pluginDir, "setAccessible", "setFactory"); + String pluginZip = createPluginUrl("fake", pluginDir, "has.native.controller", "true"); + + assertPolicyConfirmation(env, pluginZip, "plugin requires additional permissions", "plugin forks a native controller"); + assertPlugin("fake", pluginDir, env.v2()); + } + + public void testMetaPluginNativeControllerAndPolicyConfirmation() throws Exception { + Tuple env = createEnv(fs, temp); + Path metaDir = createPluginDir(temp); + Path fake1Dir = metaDir.resolve("fake1"); + Files.createDirectory(fake1Dir); + writePluginSecurityPolicy(fake1Dir, "setAccessible", "setFactory"); + writePlugin("fake1", fake1Dir); + Path fake2Dir = metaDir.resolve("fake2"); + Files.createDirectory(fake2Dir); + writePlugin("fake2", fake2Dir, "has.native.controller", "true"); + String pluginZip = createMetaPluginUrl("meta-plugin", metaDir); + + assertPolicyConfirmation(env, pluginZip, "plugin requires additional permissions", "plugin forks a native controller"); + assertMetaPlugin("meta-plugin", "fake1", metaDir, env.v2()); + assertMetaPlugin("meta-plugin", "fake2", metaDir, env.v2()); + } }