mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 17:34:17 -04:00
Remove PrivilegedOperations (#127726)
With the SecurityManager gone, the PrivilegedOperations class is no longer needed, these operations can be called directly.
This commit is contained in:
parent
8bb7dc4058
commit
b78ac7c94c
11 changed files with 40 additions and 203 deletions
|
@ -9,11 +9,11 @@
|
||||||
|
|
||||||
package org.elasticsearch.core.internal.provider;
|
package org.elasticsearch.core.internal.provider;
|
||||||
|
|
||||||
|
import org.elasticsearch.core.IOUtils;
|
||||||
import org.elasticsearch.core.Strings;
|
import org.elasticsearch.core.Strings;
|
||||||
import org.elasticsearch.core.SuppressForbidden;
|
import org.elasticsearch.core.SuppressForbidden;
|
||||||
import org.elasticsearch.core.internal.provider.EmbeddedImplClassLoader.CompoundEnumeration;
|
import org.elasticsearch.core.internal.provider.EmbeddedImplClassLoader.CompoundEnumeration;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
|
@ -195,13 +195,10 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
||||||
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
try (URLClassLoader parent = loader(urls)) {
|
||||||
try {
|
|
||||||
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "x-foo");
|
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "x-foo");
|
||||||
Class<?> c = loader.loadClass("p.FooBar");
|
Class<?> c = loader.loadClass("p.FooBar");
|
||||||
return c.getConstructor().newInstance();
|
return c.getConstructor().newInstance();
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +242,7 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
||||||
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
try (URLClassLoader parent = loader(urls)) {
|
||||||
try {
|
|
||||||
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "res");
|
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "res");
|
||||||
// resource in a valid java package dir
|
// resource in a valid java package dir
|
||||||
URL url = loader.findResource("p/res.txt");
|
URL url = loader.findResource("p/res.txt");
|
||||||
|
@ -274,8 +270,6 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
hasToString(endsWith("impl.jar!/IMPL-JARS/res/zoo-impl.jar/A-C/res.txt"))
|
hasToString(endsWith("impl.jar!/IMPL-JARS/res/zoo-impl.jar/A-C/res.txt"))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,9 +320,7 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
containsInAnyOrder("Parent Resource", "Embedded Resource")
|
containsInAnyOrder("Parent Resource", "Embedded Resource")
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
for (URLClassLoader closeable : closeables) {
|
IOUtils.close(closeables);
|
||||||
PrivilegedOperations.closeURLClassLoader(closeable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,9 +455,7 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
assertThat(new String(is.readAllBytes(), UTF_8), is("Hello World" + expectedVersion));
|
assertThat(new String(is.readAllBytes(), UTF_8), is("Hello World" + expectedVersion));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
for (URLClassLoader closeable : closeables) {
|
IOUtils.close(closeables);
|
||||||
PrivilegedOperations.closeURLClassLoader(closeable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,8 +483,7 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
||||||
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
try (URLClassLoader parent = loader(urls)) {
|
||||||
try {
|
|
||||||
embedLoader = EmbeddedImplClassLoader.getInstance(parent, "res");
|
embedLoader = EmbeddedImplClassLoader.getInstance(parent, "res");
|
||||||
|
|
||||||
Class<?> c = embedLoader.loadClass("java.lang.Object");
|
Class<?> c = embedLoader.loadClass("java.lang.Object");
|
||||||
|
@ -514,8 +503,6 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
expectThrows(NPE, () -> embedLoader.getResourceAsStream(null));
|
expectThrows(NPE, () -> embedLoader.getResourceAsStream(null));
|
||||||
expectThrows(NPE, () -> embedLoader.resources(null));
|
expectThrows(NPE, () -> embedLoader.resources(null));
|
||||||
expectThrows(NPE, () -> embedLoader.loadClass(null));
|
expectThrows(NPE, () -> embedLoader.loadClass(null));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,8 +529,7 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
||||||
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
||||||
|
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
try (URLClassLoader parent = loader(urls)) {
|
||||||
try {
|
|
||||||
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "blah");
|
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "blah");
|
||||||
Class<?> c = loader.loadClass("p.Foo");
|
Class<?> c = loader.loadClass("p.Foo");
|
||||||
Object obj = c.getConstructor().newInstance();
|
Object obj = c.getConstructor().newInstance();
|
||||||
|
@ -555,8 +541,6 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
expectThrows(CNFE, () -> loader.loadClass("p.Unknown"));
|
expectThrows(CNFE, () -> loader.loadClass("p.Unknown"));
|
||||||
expectThrows(CNFE, () -> loader.loadClass("q.Unknown"));
|
expectThrows(CNFE, () -> loader.loadClass("q.Unknown"));
|
||||||
expectThrows(CNFE, () -> loader.loadClass("r.Unknown"));
|
expectThrows(CNFE, () -> loader.loadClass("r.Unknown"));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,18 +561,20 @@ public class EmbeddedImplClassLoaderTests extends ESTestCase {
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
JarUtils.createJarWithEntriesUTF(outerJar, jarEntries);
|
||||||
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
URL[] urls = new URL[] { outerJar.toUri().toURL() };
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
|
||||||
try {
|
try (URLClassLoader parent = loader(urls)) {
|
||||||
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "blah");
|
EmbeddedImplClassLoader loader = EmbeddedImplClassLoader.getInstance(parent, "blah");
|
||||||
var res = Collections.list(loader.getResources("res.txt"));
|
var res = Collections.list(loader.getResources("res.txt"));
|
||||||
assertThat(res, hasSize(3));
|
assertThat(res, hasSize(3));
|
||||||
List<String> l = res.stream().map(EmbeddedImplClassLoaderTests::urlToString).toList();
|
List<String> l = res.stream().map(EmbeddedImplClassLoaderTests::urlToString).toList();
|
||||||
assertThat(l, containsInAnyOrder("fooRes", "barRes", "bazRes"));
|
assertThat(l, containsInAnyOrder("fooRes", "barRes", "bazRes"));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static URLClassLoader loader(URL[] urls) {
|
||||||
|
return URLClassLoader.newInstance(urls, EmbeddedImplClassLoaderTests.class.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressForbidden(reason = "file urls")
|
@SuppressForbidden(reason = "file urls")
|
||||||
static String urlToString(URL url) {
|
static String urlToString(URL url) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
package org.elasticsearch.core.internal.provider;
|
package org.elasticsearch.core.internal.provider;
|
||||||
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -117,12 +117,8 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
Path topLevelDir = createTempDir(getTestName());
|
Path topLevelDir = createTempDir(getTestName());
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(
|
|
||||||
new URL[] { outerJar.toUri().toURL() },
|
|
||||||
ProviderLocatorTests.class.getClassLoader()
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try (URLClassLoader parent = loader(outerJar)) {
|
||||||
// test scenario
|
// test scenario
|
||||||
ProviderLocator<IntSupplier> locator = new ProviderLocator<>("x-foo", IntSupplier.class, parent, "x.foo.impl", Set.of(), true);
|
ProviderLocator<IntSupplier> locator = new ProviderLocator<>("x-foo", IntSupplier.class, parent, "x.foo.impl", Set.of(), true);
|
||||||
IntSupplier impl = locator.get();
|
IntSupplier impl = locator.get();
|
||||||
|
@ -139,8 +135,6 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
assertThat(md.exports(), containsInAnyOrder(exportsOf("p")));
|
assertThat(md.exports(), containsInAnyOrder(exportsOf("p")));
|
||||||
assertThat(md.opens(), containsInAnyOrder(opensOf("q")));
|
assertThat(md.opens(), containsInAnyOrder(opensOf("q")));
|
||||||
assertThat(md.packages(), containsInAnyOrder(equalTo("p"), equalTo("q"), equalTo("r")));
|
assertThat(md.packages(), containsInAnyOrder(equalTo("p"), equalTo("q"), equalTo("r")));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +166,8 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
Path topLevelDir = createTempDir(getTestName());
|
Path topLevelDir = createTempDir(getTestName());
|
||||||
Path outerJar = topLevelDir.resolve("impl.jar");
|
Path outerJar = topLevelDir.resolve("impl.jar");
|
||||||
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
JarUtils.createJarWithEntries(outerJar, jarEntries);
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(
|
|
||||||
new URL[] { outerJar.toUri().toURL() },
|
|
||||||
ProviderLocatorTests.class.getClassLoader()
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try (URLClassLoader parent = loader(outerJar)) {
|
||||||
// test scenario
|
// test scenario
|
||||||
ProviderLocator<LongSupplier> locator = new ProviderLocator<>("x-foo", LongSupplier.class, parent, "", Set.of(), false);
|
ProviderLocator<LongSupplier> locator = new ProviderLocator<>("x-foo", LongSupplier.class, parent, "", Set.of(), false);
|
||||||
LongSupplier impl = locator.get();
|
LongSupplier impl = locator.get();
|
||||||
|
@ -185,8 +175,6 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
assertThat(impl.toString(), equalTo("Hello from FooLongSupplier - non-modular!"));
|
assertThat(impl.toString(), equalTo("Hello from FooLongSupplier - non-modular!"));
|
||||||
assertThat(impl.getClass().getName(), equalTo("p.FooLongSupplier"));
|
assertThat(impl.getClass().getName(), equalTo("p.FooLongSupplier"));
|
||||||
assertThat(impl.getClass().getModule().isNamed(), is(false));
|
assertThat(impl.getClass().getModule().isNamed(), is(false));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,12 +203,7 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
Path pb = Files.createDirectories(barRoot.resolve("pb"));
|
Path pb = Files.createDirectories(barRoot.resolve("pb"));
|
||||||
Files.write(pb.resolve("BarIntSupplier.class"), classToBytes.get("pb.BarIntSupplier"));
|
Files.write(pb.resolve("BarIntSupplier.class"), classToBytes.get("pb.BarIntSupplier"));
|
||||||
|
|
||||||
URLClassLoader parent = URLClassLoader.newInstance(
|
try (URLClassLoader parent = loader(topLevelDir)) {
|
||||||
new URL[] { topLevelDir.toUri().toURL() },
|
|
||||||
ProviderLocatorTests.class.getClassLoader()
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// test scenario
|
// test scenario
|
||||||
ProviderLocator<IntSupplier> locator = new ProviderLocator<>("y-bar", IntSupplier.class, parent, "", Set.of(), false);
|
ProviderLocator<IntSupplier> locator = new ProviderLocator<>("y-bar", IntSupplier.class, parent, "", Set.of(), false);
|
||||||
IntSupplier impl = locator.get();
|
IntSupplier impl = locator.get();
|
||||||
|
@ -228,8 +211,10 @@ public class ProviderLocatorTests extends ESTestCase {
|
||||||
assertThat(impl.toString(), equalTo("Hello from BarIntSupplier - exploded non-modular!"));
|
assertThat(impl.toString(), equalTo("Hello from BarIntSupplier - exploded non-modular!"));
|
||||||
assertThat(impl.getClass().getName(), equalTo("pb.BarIntSupplier"));
|
assertThat(impl.getClass().getName(), equalTo("pb.BarIntSupplier"));
|
||||||
assertThat(impl.getClass().getModule().isNamed(), is(false));
|
assertThat(impl.getClass().getModule().isNamed(), is(false));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static URLClassLoader loader(Path jar) throws MalformedURLException {
|
||||||
|
return URLClassLoader.newInstance(new URL[] { jar.toUri().toURL() }, ProviderLocatorTests.class.getClassLoader());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class WhitelistLoaderTests extends ESTestCase {
|
||||||
JarUtils.createJarWithEntries(jar, jarEntries);
|
JarUtils.createJarWithEntries(jar, jarEntries);
|
||||||
|
|
||||||
try (var loader = JarUtils.loadJar(jar)) {
|
try (var loader = JarUtils.loadJar(jar)) {
|
||||||
Controller controller = JarUtils.loadModule(jar, loader.classloader(), "m");
|
Controller controller = JarUtils.loadModule(jar, loader, "m");
|
||||||
Module module = controller.layer().findModule("m").orElseThrow();
|
Module module = controller.layer().findModule("m").orElseThrow();
|
||||||
|
|
||||||
Class<?> ownerClass = module.getClassLoader().loadClass("p.TestOwner");
|
Class<?> ownerClass = module.getClassLoader().loadClass("p.TestOwner");
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
package org.elasticsearch.plugins;
|
package org.elasticsearch.plugins;
|
||||||
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations.ClosableURLClassLoader;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ public class ExtensionLoaderTests extends ESTestCase {
|
||||||
int getValue();
|
int getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClosableURLClassLoader buildProviderJar(Map<String, CharSequence> sources) throws Exception {
|
private URLClassLoader buildProviderJar(Map<String, CharSequence> sources) throws Exception {
|
||||||
var classToBytes = InMemoryJavaCompiler.compile(sources);
|
var classToBytes = InMemoryJavaCompiler.compile(sources);
|
||||||
|
|
||||||
Map<String, byte[]> jarEntries = new HashMap<>();
|
Map<String, byte[]> jarEntries = new HashMap<>();
|
||||||
|
@ -55,7 +54,7 @@ public class ExtensionLoaderTests extends ESTestCase {
|
||||||
JarUtils.createJarWithEntries(jar, jarEntries);
|
JarUtils.createJarWithEntries(jar, jarEntries);
|
||||||
URL[] urls = new URL[] { jar.toUri().toURL() };
|
URL[] urls = new URL[] { jar.toUri().toURL() };
|
||||||
|
|
||||||
return new ClosableURLClassLoader(URLClassLoader.newInstance(urls, this.getClass().getClassLoader()));
|
return URLClassLoader.newInstance(urls, this.getClass().getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String defineProvider(String name, int value) {
|
private String defineProvider(String name, int value) {
|
||||||
|
@ -79,7 +78,7 @@ public class ExtensionLoaderTests extends ESTestCase {
|
||||||
public void testOneProvider() throws Exception {
|
public void testOneProvider() throws Exception {
|
||||||
Map<String, CharSequence> sources = Map.of("p.FooService", defineProvider("FooService", 1));
|
Map<String, CharSequence> sources = Map.of("p.FooService", defineProvider("FooService", 1));
|
||||||
try (var loader = buildProviderJar(sources)) {
|
try (var loader = buildProviderJar(sources)) {
|
||||||
TestService service = ExtensionLoader.loadSingleton(ServiceLoader.load(TestService.class, loader.classloader()))
|
TestService service = ExtensionLoader.loadSingleton(ServiceLoader.load(TestService.class, loader))
|
||||||
.orElseThrow(AssertionError::new);
|
.orElseThrow(AssertionError::new);
|
||||||
assertThat(service, not(nullValue()));
|
assertThat(service, not(nullValue()));
|
||||||
assertThat(service.getValue(), equalTo(1));
|
assertThat(service.getValue(), equalTo(1));
|
||||||
|
@ -96,7 +95,7 @@ public class ExtensionLoaderTests extends ESTestCase {
|
||||||
try (var loader = buildProviderJar(sources)) {
|
try (var loader = buildProviderJar(sources)) {
|
||||||
var e = expectThrows(
|
var e = expectThrows(
|
||||||
IllegalStateException.class,
|
IllegalStateException.class,
|
||||||
() -> ExtensionLoader.loadSingleton(ServiceLoader.load(TestService.class, loader.classloader()))
|
() -> ExtensionLoader.loadSingleton(ServiceLoader.load(TestService.class, loader))
|
||||||
);
|
);
|
||||||
assertThat(e.getMessage(), containsString("More than one extension found"));
|
assertThat(e.getMessage(), containsString("More than one extension found"));
|
||||||
assertThat(e.getMessage(), containsString("TestService"));
|
assertThat(e.getMessage(), containsString("TestService"));
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.elasticsearch.indices.recovery.plan.RecoveryPlannerService;
|
||||||
import org.elasticsearch.indices.recovery.plan.ShardSnapshotsService;
|
import org.elasticsearch.indices.recovery.plan.ShardSnapshotsService;
|
||||||
import org.elasticsearch.ingest.Processor;
|
import org.elasticsearch.ingest.Processor;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
|
@ -233,11 +232,8 @@ public class PluginIntrospectorTests extends ESTestCase {
|
||||||
JarUtils.createJarWithEntries(jar, jarEntries);
|
JarUtils.createJarWithEntries(jar, jarEntries);
|
||||||
URL[] urls = new URL[] { jar.toUri().toURL() };
|
URL[] urls = new URL[] { jar.toUri().toURL() };
|
||||||
|
|
||||||
URLClassLoader loader = URLClassLoader.newInstance(urls, PluginIntrospectorTests.class.getClassLoader());
|
try (URLClassLoader loader = URLClassLoader.newInstance(urls, PluginIntrospectorTests.class.getClassLoader())) {
|
||||||
try {
|
|
||||||
assertThat(pluginIntrospector.interfaces(loader.loadClass("r.FooPlugin")), contains("ActionPlugin"));
|
assertThat(pluginIntrospector.interfaces(loader.loadClass("r.FooPlugin")), contains("ActionPlugin"));
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(loader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.elasticsearch.logging.Logger;
|
||||||
import org.elasticsearch.nativeaccess.NativeAccessUtil;
|
import org.elasticsearch.nativeaccess.NativeAccessUtil;
|
||||||
import org.elasticsearch.plugin.analysis.CharFilterFactory;
|
import org.elasticsearch.plugin.analysis.CharFilterFactory;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
|
@ -351,13 +350,13 @@ public class PluginsLoaderTests extends ESTestCase {
|
||||||
pluginsLoader.pluginLayers().forEach(lp -> {
|
pluginsLoader.pluginLayers().forEach(lp -> {
|
||||||
if (lp.pluginClassLoader() instanceof URLClassLoader urlClassLoader) {
|
if (lp.pluginClassLoader() instanceof URLClassLoader urlClassLoader) {
|
||||||
try {
|
try {
|
||||||
PrivilegedOperations.closeURLClassLoader(urlClassLoader);
|
urlClassLoader.close();
|
||||||
} catch (IOException unexpected) {
|
} catch (IOException unexpected) {
|
||||||
throw new UncheckedIOException(unexpected);
|
throw new UncheckedIOException(unexpected);
|
||||||
}
|
}
|
||||||
} else if (lp.pluginClassLoader() instanceof UberModuleClassLoader loader) {
|
} else if (lp.pluginClassLoader() instanceof UberModuleClassLoader loader) {
|
||||||
try {
|
try {
|
||||||
PrivilegedOperations.closeURLClassLoader(loader.getInternalLoader());
|
loader.getInternalLoader().close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.elasticsearch.plugins.spi.BarPlugin;
|
||||||
import org.elasticsearch.plugins.spi.BarTestService;
|
import org.elasticsearch.plugins.spi.BarTestService;
|
||||||
import org.elasticsearch.plugins.spi.TestService;
|
import org.elasticsearch.plugins.spi.TestService;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
import org.elasticsearch.test.compiler.InMemoryJavaCompiler;
|
||||||
import org.elasticsearch.test.jar.JarUtils;
|
import org.elasticsearch.test.jar.JarUtils;
|
||||||
|
|
||||||
|
@ -671,9 +670,11 @@ public class PluginsServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testLoadServiceProviders() throws Exception {
|
public void testLoadServiceProviders() throws Exception {
|
||||||
|
|
||||||
|
try (
|
||||||
URLClassLoader fakeClassLoader = buildTestProviderPlugin("integer");
|
URLClassLoader fakeClassLoader = buildTestProviderPlugin("integer");
|
||||||
URLClassLoader fakeClassLoader1 = buildTestProviderPlugin("string");
|
URLClassLoader fakeClassLoader1 = buildTestProviderPlugin("string")
|
||||||
try {
|
) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<? extends Plugin> fakePluginClass = (Class<? extends Plugin>) fakeClassLoader.loadClass("r.FooPlugin");
|
Class<? extends Plugin> fakePluginClass = (Class<? extends Plugin>) fakeClassLoader.loadClass("r.FooPlugin");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -699,9 +700,6 @@ public class PluginsServiceTests extends ESTestCase {
|
||||||
providers = service.loadServiceProviders(TestService.class);
|
providers = service.loadServiceProviders(TestService.class);
|
||||||
|
|
||||||
assertEquals(0, providers.size());
|
assertEquals(0, providers.size());
|
||||||
} finally {
|
|
||||||
PrivilegedOperations.closeURLClassLoader(fakeClassLoader);
|
|
||||||
PrivilegedOperations.closeURLClassLoader(fakeClassLoader1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,13 +875,13 @@ public class PluginsServiceTests extends ESTestCase {
|
||||||
for (var lp : pluginService.plugins()) {
|
for (var lp : pluginService.plugins()) {
|
||||||
if (lp.classLoader() instanceof URLClassLoader urlClassLoader) {
|
if (lp.classLoader() instanceof URLClassLoader urlClassLoader) {
|
||||||
try {
|
try {
|
||||||
PrivilegedOperations.closeURLClassLoader(urlClassLoader);
|
urlClassLoader.close();
|
||||||
} catch (IOException unexpected) {
|
} catch (IOException unexpected) {
|
||||||
throw new UncheckedIOException(unexpected);
|
throw new UncheckedIOException(unexpected);
|
||||||
}
|
}
|
||||||
} else if (lp.classLoader() instanceof UberModuleClassLoader loader) {
|
} else if (lp.classLoader() instanceof UberModuleClassLoader loader) {
|
||||||
try {
|
try {
|
||||||
PrivilegedOperations.closeURLClassLoader(loader.getInternalLoader());
|
loader.getInternalLoader().close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,9 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.core.Booleans;
|
import org.elasticsearch.core.Booleans;
|
||||||
import org.elasticsearch.core.PathUtils;
|
import org.elasticsearch.core.PathUtils;
|
||||||
import org.elasticsearch.jdk.JarHell;
|
import org.elasticsearch.jdk.JarHell;
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
import org.elasticsearch.test.mockito.SecureMockMaker;
|
import org.elasticsearch.test.mockito.SecureMockMaker;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -75,13 +73,6 @@ public class BootstrapForTesting {
|
||||||
// init mockito
|
// init mockito
|
||||||
SecureMockMaker.init();
|
SecureMockMaker.init();
|
||||||
|
|
||||||
// init the privileged operation
|
|
||||||
try {
|
|
||||||
MethodHandles.publicLookup().ensureInitialized(PrivilegedOperations.class);
|
|
||||||
} catch (IllegalAccessException unexpected) {
|
|
||||||
throw new AssertionError(unexpected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log ifconfig output before SecurityManager is installed
|
// Log ifconfig output before SecurityManager is installed
|
||||||
IfConfig.logIfNecessary();
|
IfConfig.logIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the "Elastic License
|
|
||||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
|
||||||
* Public License v 1"; you may not use this file except in compliance with, at
|
|
||||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
|
||||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.test;
|
|
||||||
|
|
||||||
import org.elasticsearch.core.SuppressForbidden;
|
|
||||||
|
|
||||||
import java.io.FilePermission;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.security.AccessControlContext;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.CodeSigner;
|
|
||||||
import java.security.CodeSource;
|
|
||||||
import java.security.DomainCombiner;
|
|
||||||
import java.security.Permission;
|
|
||||||
import java.security.PermissionCollection;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.security.PrivilegedActionException;
|
|
||||||
import java.security.PrivilegedExceptionAction;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
import javax.tools.JavaCompiler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A small set of privileged operations that can be executed by unprivileged test code.
|
|
||||||
* The set of operations is deliberately small, and the permissions narrow.
|
|
||||||
*/
|
|
||||||
public final class PrivilegedOperations {
|
|
||||||
|
|
||||||
private PrivilegedOperations() {}
|
|
||||||
|
|
||||||
public static void closeURLClassLoader(URLClassLoader loader) throws IOException {
|
|
||||||
try {
|
|
||||||
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
|
|
||||||
loader.close();
|
|
||||||
return null;
|
|
||||||
}, context, new RuntimePermission("closeClassLoader"));
|
|
||||||
} catch (PrivilegedActionException pae) {
|
|
||||||
Exception e = pae.getException();
|
|
||||||
if (e instanceof IOException ioe) {
|
|
||||||
throw ioe;
|
|
||||||
} else {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ClosableURLClassLoader(URLClassLoader classloader) implements AutoCloseable {
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
closeURLClassLoader(classloader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Boolean compilationTaskCall(JavaCompiler.CompilationTask compilationTask) {
|
|
||||||
return AccessController.doPrivileged(
|
|
||||||
(PrivilegedAction<Boolean>) () -> compilationTask.call(),
|
|
||||||
context,
|
|
||||||
new RuntimePermission("createClassLoader"),
|
|
||||||
new RuntimePermission("closeClassLoader"),
|
|
||||||
new RuntimePermission("accessSystemModules"),
|
|
||||||
newAllFilesReadPermission()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressForbidden(reason = "need to create file permission")
|
|
||||||
private static FilePermission newAllFilesReadPermission() {
|
|
||||||
return new FilePermission("<<ALL FILES>>", "read");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- security manager related stuff, to facilitate asserting permissions for test operations.
|
|
||||||
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
private static AccessControlContext getContext() {
|
|
||||||
ProtectionDomain[] pda = new ProtectionDomain[] {
|
|
||||||
new ProtectionDomain(new CodeSource(null, (CodeSigner[]) null), new PermissivePermissionCollection()) };
|
|
||||||
DomainCombiner combiner = (ignoreCurrent, ignoreAssigned) -> pda;
|
|
||||||
AccessControlContext acc = new AccessControlContext(AccessController.getContext(), combiner);
|
|
||||||
// getContext must be called with the new acc so that a combined context will be created
|
|
||||||
return AccessController.doPrivileged((PrivilegedAction<AccessControlContext>) AccessController::getContext, acc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// An all-powerful context for wrapping calls
|
|
||||||
@SuppressWarnings("removal")
|
|
||||||
private static final AccessControlContext context = getContext();
|
|
||||||
|
|
||||||
// A permissive permission collection - implies all permissions.
|
|
||||||
private static final class PermissivePermissionCollection extends PermissionCollection {
|
|
||||||
|
|
||||||
private PermissivePermissionCollection() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(Permission permission) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean implies(Permission permission) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Enumeration<Permission> elements() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.test.compiler;
|
package org.elasticsearch.test.compiler;
|
||||||
|
|
||||||
import org.elasticsearch.test.PrivilegedOperations;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -137,7 +135,7 @@ public class InMemoryJavaCompiler {
|
||||||
try (FileManagerWrapper wrapper = new FileManagerWrapper(files)) {
|
try (FileManagerWrapper wrapper = new FileManagerWrapper(files)) {
|
||||||
CompilationTask task = getCompilationTask(wrapper, options);
|
CompilationTask task = getCompilationTask(wrapper, options);
|
||||||
|
|
||||||
boolean result = PrivilegedOperations.compilationTaskCall(task);
|
boolean result = task.call();
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
throw new RuntimeException("Could not compile " + sources.entrySet().stream().toList());
|
throw new RuntimeException("Could not compile " + sources.entrySet().stream().toList());
|
||||||
}
|
}
|
||||||
|
@ -162,7 +160,7 @@ public class InMemoryJavaCompiler {
|
||||||
try (FileManagerWrapper wrapper = new FileManagerWrapper(file)) {
|
try (FileManagerWrapper wrapper = new FileManagerWrapper(file)) {
|
||||||
CompilationTask task = getCompilationTask(wrapper, options);
|
CompilationTask task = getCompilationTask(wrapper, options);
|
||||||
|
|
||||||
boolean result = PrivilegedOperations.compilationTaskCall(task);
|
boolean result = task.call();
|
||||||
if (result == false) {
|
if (result == false) {
|
||||||
throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode);
|
throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.test.jar;
|
package org.elasticsearch.test.jar;
|
||||||
|
|
||||||
import org.elasticsearch.test.PrivilegedOperations.ClosableURLClassLoader;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -101,10 +99,10 @@ public final class JarUtils {
|
||||||
* @param path Path to the jar file to load
|
* @param path Path to the jar file to load
|
||||||
* @return A URLClassLoader that will load classes from the jar. It should be closed when no longer needed.
|
* @return A URLClassLoader that will load classes from the jar. It should be closed when no longer needed.
|
||||||
*/
|
*/
|
||||||
public static ClosableURLClassLoader loadJar(Path path) {
|
public static URLClassLoader loadJar(Path path) {
|
||||||
try {
|
try {
|
||||||
URL[] urls = new URL[] { path.toUri().toURL() };
|
URL[] urls = new URL[] { path.toUri().toURL() };
|
||||||
return new ClosableURLClassLoader(URLClassLoader.newInstance(urls, JarUtils.class.getClassLoader()));
|
return URLClassLoader.newInstance(urls, JarUtils.class.getClassLoader());
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue