1010package org .elasticsearch .entitlement .runtime .policy ;
1111
1212import org .elasticsearch .entitlement .runtime .policy .PolicyManager .ModuleEntitlements ;
13+ import org .elasticsearch .entitlement .runtime .policy .agent .TestAgent ;
14+ import org .elasticsearch .entitlement .runtime .policy .agent .inner .TestInnerAgent ;
1315import org .elasticsearch .test .ESTestCase ;
1416import org .elasticsearch .test .compiler .InMemoryJavaCompiler ;
1517import org .elasticsearch .test .jar .JarUtils ;
1820import java .io .IOException ;
1921import java .lang .module .Configuration ;
2022import java .lang .module .ModuleFinder ;
23+ import java .net .URL ;
24+ import java .net .URLClassLoader ;
2125import java .nio .file .Path ;
2226import java .util .Arrays ;
2327import java .util .List ;
3640
3741@ ESTestCase .WithoutSecurityManager
3842public class PolicyManagerTests extends ESTestCase {
43+
44+ /**
45+ * A test agent package name for use in tests.
46+ */
47+ private static final String TEST_AGENTS_PACKAGE_NAME = "org.elasticsearch.entitlement.runtime.policy.agent" ;
48+
3949 /**
4050 * A module you can use for test cases that don't actually care about the
4151 * entitlement module.
@@ -59,6 +69,7 @@ public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule() {
5969 List .of (),
6070 Map .of ("plugin1" , createPluginPolicy ("plugin.module" )),
6171 c -> "plugin1" ,
72+ TEST_AGENTS_PACKAGE_NAME ,
6273 NO_ENTITLEMENTS_MODULE
6374 );
6475
@@ -72,7 +83,14 @@ public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule() {
7283 }
7384
7485 public void testGetEntitlementsThrowsOnMissingPolicyForPlugin () {
75- var policyManager = new PolicyManager (createEmptyTestServerPolicy (), List .of (), Map .of (), c -> "plugin1" , NO_ENTITLEMENTS_MODULE );
86+ var policyManager = new PolicyManager (
87+ createEmptyTestServerPolicy (),
88+ List .of (),
89+ Map .of (),
90+ c -> "plugin1" ,
91+ TEST_AGENTS_PACKAGE_NAME ,
92+ NO_ENTITLEMENTS_MODULE
93+ );
7694
7795 // Any class from the current module (unnamed) will do
7896 var callerClass = this .getClass ();
@@ -84,7 +102,14 @@ public void testGetEntitlementsThrowsOnMissingPolicyForPlugin() {
84102 }
85103
86104 public void testGetEntitlementsFailureIsCached () {
87- var policyManager = new PolicyManager (createEmptyTestServerPolicy (), List .of (), Map .of (), c -> "plugin1" , NO_ENTITLEMENTS_MODULE );
105+ var policyManager = new PolicyManager (
106+ createEmptyTestServerPolicy (),
107+ List .of (),
108+ Map .of (),
109+ c -> "plugin1" ,
110+ TEST_AGENTS_PACKAGE_NAME ,
111+ NO_ENTITLEMENTS_MODULE
112+ );
88113
89114 // Any class from the current module (unnamed) will do
90115 var callerClass = this .getClass ();
@@ -106,6 +131,7 @@ public void testGetEntitlementsReturnsEntitlementsForPluginUnnamedModule() {
106131 List .of (),
107132 Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
108133 c -> "plugin2" ,
134+ TEST_AGENTS_PACKAGE_NAME ,
109135 NO_ENTITLEMENTS_MODULE
110136 );
111137
@@ -117,7 +143,14 @@ public void testGetEntitlementsReturnsEntitlementsForPluginUnnamedModule() {
117143 }
118144
119145 public void testGetEntitlementsThrowsOnMissingPolicyForServer () throws ClassNotFoundException {
120- var policyManager = new PolicyManager (createTestServerPolicy ("example" ), List .of (), Map .of (), c -> null , NO_ENTITLEMENTS_MODULE );
146+ var policyManager = new PolicyManager (
147+ createTestServerPolicy ("example" ),
148+ List .of (),
149+ Map .of (),
150+ c -> null ,
151+ TEST_AGENTS_PACKAGE_NAME ,
152+ NO_ENTITLEMENTS_MODULE
153+ );
121154
122155 // Tests do not run modular, so we cannot use a server class.
123156 // But we know that in production code the server module and its classes are in the boot layer.
@@ -137,6 +170,7 @@ public void testGetEntitlementsReturnsEntitlementsForServerModule() throws Class
137170 List .of (),
138171 Map .of (),
139172 c -> null ,
173+ TEST_AGENTS_PACKAGE_NAME ,
140174 NO_ENTITLEMENTS_MODULE
141175 );
142176
@@ -161,6 +195,7 @@ public void testGetEntitlementsReturnsEntitlementsForPluginModule() throws IOExc
161195 List .of (),
162196 Map .of ("mock-plugin" , createPluginPolicy ("org.example.plugin" )),
163197 c -> "mock-plugin" ,
198+ TEST_AGENTS_PACKAGE_NAME ,
164199 NO_ENTITLEMENTS_MODULE
165200 );
166201
@@ -181,6 +216,7 @@ public void testGetEntitlementsResultIsCached() {
181216 List .of (),
182217 Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
183218 c -> "plugin2" ,
219+ TEST_AGENTS_PACKAGE_NAME ,
184220 NO_ENTITLEMENTS_MODULE
185221 );
186222
@@ -200,16 +236,17 @@ public void testGetEntitlementsResultIsCached() {
200236
201237 public void testRequestingClassFastPath () throws IOException , ClassNotFoundException {
202238 var callerClass = makeClassInItsOwnModule ();
203- assertEquals (callerClass , policyManagerWithEntitlementsModule ( NO_ENTITLEMENTS_MODULE ).requestingClass (callerClass ));
239+ assertEquals (callerClass , policyManager ( TEST_AGENTS_PACKAGE_NAME , NO_ENTITLEMENTS_MODULE ).requestingClass (callerClass ));
204240 }
205241
206242 public void testRequestingModuleWithStackWalk () throws IOException , ClassNotFoundException {
243+ var agentsClass = new TestAgent ();
207244 var entitlementsClass = makeClassInItsOwnModule (); // A class in the entitlements library itself
208245 var requestingClass = makeClassInItsOwnModule (); // This guy is always the right answer
209246 var instrumentedClass = makeClassInItsOwnModule (); // The class that called the check method
210247 var ignorableClass = makeClassInItsOwnModule ();
211248
212- var policyManager = policyManagerWithEntitlementsModule ( entitlementsClass .getModule ());
249+ var policyManager = policyManager ( TEST_AGENTS_PACKAGE_NAME , entitlementsClass .getModule ());
213250
214251 assertEquals (
215252 "Skip entitlement library and the instrumented method" ,
@@ -229,15 +266,47 @@ public void testRequestingModuleWithStackWalk() throws IOException, ClassNotFoun
229266 );
230267 }
231268
269+ public void testAgentsEntitlements () throws IOException , ClassNotFoundException {
270+ Path home = createTempDir ();
271+ Path unnamedJar = createMockPluginJarForUnnamedModule (home );
272+ var notAgentClass = makeClassInItsOwnModule ();
273+ var policyManager = new PolicyManager (
274+ createEmptyTestServerPolicy (),
275+ List .of (new CreateClassLoaderEntitlement ()),
276+ Map .of (),
277+ c -> "test" ,
278+ TEST_AGENTS_PACKAGE_NAME ,
279+ NO_ENTITLEMENTS_MODULE
280+ );
281+ ModuleEntitlements agentsEntitlements = policyManager .getEntitlements (TestAgent .class );
282+ assertThat (agentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
283+ agentsEntitlements = policyManager .getEntitlements (TestInnerAgent .class );
284+ assertThat (agentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
285+ ModuleEntitlements notAgentsEntitlements = policyManager .getEntitlements (notAgentClass );
286+ assertThat (notAgentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (false ));
287+ try (URLClassLoader classLoader = new URLClassLoader (new URL [] { unnamedJar .toUri ().toURL () }, getClass ().getClassLoader ())) {
288+ var unnamedNotAgentClass = classLoader .loadClass ("q.B" );
289+ notAgentsEntitlements = policyManager .getEntitlements (unnamedNotAgentClass );
290+ assertThat (notAgentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (false ));
291+ }
292+ }
293+
232294 private static Class <?> makeClassInItsOwnModule () throws IOException , ClassNotFoundException {
233295 final Path home = createTempDir ();
234296 Path jar = createMockPluginJar (home );
235297 var layer = createLayerForJar (jar , "org.example.plugin" );
236298 return layer .findLoader ("org.example.plugin" ).loadClass ("q.B" );
237299 }
238300
239- private static PolicyManager policyManagerWithEntitlementsModule (Module entitlementsModule ) {
240- return new PolicyManager (createEmptyTestServerPolicy (), List .of (), Map .of (), c -> "test" , entitlementsModule );
301+ private static Class <?> makeClassInItsOwnUnnamedModule () throws IOException , ClassNotFoundException {
302+ final Path home = createTempDir ();
303+ Path jar = createMockPluginJar (home );
304+ var layer = createLayerForJar (jar , "org.example.plugin" );
305+ return layer .findLoader ("org.example.plugin" ).loadClass ("q.B" );
306+ }
307+
308+ private static PolicyManager policyManager (String agentsPackageName , Module entitlementsModule ) {
309+ return new PolicyManager (createEmptyTestServerPolicy (), List .of (), Map .of (), c -> "test" , agentsPackageName , entitlementsModule );
241310 }
242311
243312 private static Policy createEmptyTestServerPolicy () {
@@ -262,6 +331,16 @@ private static Policy createPluginPolicy(String... pluginModules) {
262331 );
263332 }
264333
334+ private static Path createMockPluginJarForUnnamedModule (Path home ) throws IOException {
335+ Path jar = home .resolve ("unnamed-mock-plugin.jar" );
336+
337+ Map <String , CharSequence > sources = Map .ofEntries (entry ("q.B" , "package q; public class B { }" ));
338+
339+ var classToBytes = InMemoryJavaCompiler .compile (sources );
340+ JarUtils .createJarWithEntries (jar , Map .ofEntries (entry ("q/B.class" , classToBytes .get ("q.B" ))));
341+ return jar ;
342+ }
343+
265344 private static Path createMockPluginJar (Path home ) throws IOException {
266345 Path jar = home .resolve ("mock-plugin.jar" );
267346
0 commit comments