| 
41 | 41 | import org.elasticsearch.common.hash.MessageDigests;  | 
42 | 42 | import org.elasticsearch.common.io.FileSystemUtils;  | 
43 | 43 | import org.elasticsearch.common.settings.Settings;  | 
 | 44 | +import org.elasticsearch.core.CheckedConsumer;  | 
44 | 45 | import org.elasticsearch.core.PathUtils;  | 
45 | 46 | import org.elasticsearch.core.PathUtilsForTesting;  | 
46 | 47 | import org.elasticsearch.core.Strings;  | 
47 | 48 | import org.elasticsearch.core.SuppressForbidden;  | 
48 | 49 | import org.elasticsearch.core.Tuple;  | 
 | 50 | +import org.elasticsearch.entitlement.runtime.policy.PolicyUtils;  | 
49 | 51 | import org.elasticsearch.env.Environment;  | 
50 | 52 | import org.elasticsearch.env.TestEnvironment;  | 
51 |  | -import org.elasticsearch.jdk.RuntimeVersionFeature;  | 
52 | 53 | import org.elasticsearch.plugin.scanner.NamedComponentScanner;  | 
53 | 54 | import org.elasticsearch.plugins.Platforms;  | 
54 | 55 | import org.elasticsearch.plugins.PluginDescriptor;  | 
 | 
57 | 58 | import org.elasticsearch.test.PosixPermissionsResetter;  | 
58 | 59 | import org.elasticsearch.test.compiler.InMemoryJavaCompiler;  | 
59 | 60 | import org.elasticsearch.test.jar.JarUtils;  | 
 | 61 | +import org.elasticsearch.xcontent.XContentBuilder;  | 
 | 62 | +import org.elasticsearch.xcontent.yaml.YamlXContent;  | 
60 | 63 | import org.junit.After;  | 
61 | 64 | import org.junit.Before;  | 
62 | 65 | 
 
  | 
 | 
102 | 105 | import java.util.zip.ZipEntry;  | 
103 | 106 | import java.util.zip.ZipOutputStream;  | 
104 | 107 | 
 
  | 
 | 108 | +import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ALL_UNNAMED;  | 
105 | 109 | import static org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase.forEachFileRecursively;  | 
106 | 110 | import static org.hamcrest.CoreMatchers.equalTo;  | 
107 | 111 | import static org.hamcrest.Matchers.containsInAnyOrder;  | 
@@ -137,8 +141,6 @@ public class InstallPluginActionTests extends ESTestCase {  | 
137 | 141 | 
 
  | 
138 | 142 |     @SuppressForbidden(reason = "sets java.io.tmpdir")  | 
139 | 143 |     public InstallPluginActionTests(FileSystem fs, Function<String, Path> temp) {  | 
140 |  | -        assert "false".equals(System.getProperty("tests.security.manager")) : "-Dtests.security.manager=false has to be set";  | 
141 |  | - | 
142 | 144 |         this.temp = temp;  | 
143 | 145 |         this.isPosix = fs.supportedFileAttributeViews().contains("posix");  | 
144 | 146 |         this.isReal = fs == PathUtils.getDefaultFileSystem();  | 
@@ -309,15 +311,20 @@ private static String[] pluginProperties(String name, String[] additionalProps,  | 
309 | 311 |         ).flatMap(Function.identity()).toArray(String[]::new);  | 
310 | 312 |     }  | 
311 | 313 | 
 
  | 
312 |  | -    static void writePluginSecurityPolicy(Path pluginDir, String... permissions) throws IOException {  | 
313 |  | -        StringBuilder securityPolicyContent = new StringBuilder("grant {\n  ");  | 
314 |  | -        for (String permission : permissions) {  | 
315 |  | -            securityPolicyContent.append("permission java.lang.RuntimePermission \"");  | 
316 |  | -            securityPolicyContent.append(permission);  | 
317 |  | -            securityPolicyContent.append("\";");  | 
 | 314 | +    static void writePluginEntitlementPolicy(Path pluginDir, String moduleName, CheckedConsumer<XContentBuilder, IOException> policyBuilder)  | 
 | 315 | +        throws IOException {  | 
 | 316 | +        try (var builder = YamlXContent.contentBuilder()) {  | 
 | 317 | +            builder.startObject();  | 
 | 318 | +            builder.field(moduleName);  | 
 | 319 | +            builder.startArray();  | 
 | 320 | + | 
 | 321 | +            policyBuilder.accept(builder);  | 
 | 322 | +            builder.endArray();  | 
 | 323 | +            builder.endObject();  | 
 | 324 | + | 
 | 325 | +            String policy = org.elasticsearch.common.Strings.toString(builder);  | 
 | 326 | +            Files.writeString(pluginDir.resolve(PolicyUtils.POLICY_FILE_NAME), policy);  | 
318 | 327 |         }  | 
319 |  | -        securityPolicyContent.append("\n};\n");  | 
320 |  | -        Files.writeString(pluginDir.resolve("plugin-security.policy"), securityPolicyContent.toString());  | 
321 | 328 |     }  | 
322 | 329 | 
 
  | 
323 | 330 |     static InstallablePlugin createStablePlugin(String name, Path structure, boolean hasNamedComponentFile, String... additionalProps)  | 
@@ -892,9 +899,8 @@ public void testInstallMisspelledOfficialPlugins() {  | 
892 | 899 |     }  | 
893 | 900 | 
 
  | 
894 | 901 |     public void testBatchFlag() throws Exception {  | 
895 |  | -        assumeTrue("security policy validation only available with SecurityManager", RuntimeVersionFeature.isSecurityManagerAvailable());  | 
896 | 902 |         installPlugin(true);  | 
897 |  | -        assertThat(terminal.getErrorOutput(), containsString("WARNING: plugin requires additional permissions"));  | 
 | 903 | +        assertThat(terminal.getErrorOutput(), containsString("WARNING: plugin requires additional entitlements"));  | 
898 | 904 |         assertThat(terminal.getOutput(), containsString("-> Downloading"));  | 
899 | 905 |         // No progress bar in batch mode  | 
900 | 906 |         assertThat(terminal.getOutput(), not(containsString("100%")));  | 
@@ -942,12 +948,12 @@ public void testPluginHasDifferentNameThatDescriptor() throws Exception {  | 
942 | 948 |         assertThat(e.getMessage(), equalTo("Expected downloaded plugin to have ID [other-fake] but found [fake]"));  | 
943 | 949 |     }  | 
944 | 950 | 
 
  | 
945 |  | -    private void installPlugin(boolean isBatch, String... additionalProperties) throws Exception {  | 
946 |  | -        // if batch is enabled, we also want to add a security policy  | 
 | 951 | +    private void installPlugin(boolean isBatch) throws Exception {  | 
 | 952 | +        // if batch is enabled, we also want to add an entitlement policy  | 
947 | 953 |         if (isBatch) {  | 
948 |  | -            writePluginSecurityPolicy(pluginDir, "setFactory");  | 
 | 954 | +            writePluginEntitlementPolicy(pluginDir, ALL_UNNAMED, builder -> builder.value("manage_threads"));  | 
949 | 955 |         }  | 
950 |  | -        InstallablePlugin pluginZip = createPlugin("fake", pluginDir, additionalProperties);  | 
 | 956 | +        InstallablePlugin pluginZip = createPlugin("fake", pluginDir);  | 
951 | 957 |         skipJarHellAction.setEnvironment(env.v2());  | 
952 | 958 |         skipJarHellAction.setBatch(isBatch);  | 
953 | 959 |         skipJarHellAction.execute(List.of(pluginZip));  | 
@@ -1531,11 +1537,13 @@ private void assertPolicyConfirmation(Tuple<Path, Environment> pathEnvironmentTu  | 
1531 | 1537 |     }  | 
1532 | 1538 | 
 
  | 
1533 | 1539 |     public void testPolicyConfirmation() throws Exception {  | 
1534 |  | -        assumeTrue("security policy parsing only available with SecurityManager", RuntimeVersionFeature.isSecurityManagerAvailable());  | 
1535 |  | -        writePluginSecurityPolicy(pluginDir, "getClassLoader", "setFactory");  | 
 | 1540 | +        writePluginEntitlementPolicy(pluginDir, "test.plugin.module", builder -> {  | 
 | 1541 | +            builder.value("manage_threads");  | 
 | 1542 | +            builder.value("outbound_network");  | 
 | 1543 | +        });  | 
1536 | 1544 |         InstallablePlugin pluginZip = createPluginZip("fake", pluginDir);  | 
1537 | 1545 | 
 
  | 
1538 |  | -        assertPolicyConfirmation(env, pluginZip, "plugin requires additional permissions");  | 
 | 1546 | +        assertPolicyConfirmation(env, pluginZip, "plugin requires additional entitlements");  | 
1539 | 1547 |         assertPlugin("fake", pluginDir, env.v2());  | 
1540 | 1548 |     }  | 
1541 | 1549 | 
 
  | 
 | 
0 commit comments