1919import org .elasticsearch .entitlement .runtime .policy .entitlements .CreateClassLoaderEntitlement ;
2020import org .elasticsearch .entitlement .runtime .policy .entitlements .ExitVMEntitlement ;
2121import org .elasticsearch .entitlement .runtime .policy .entitlements .FilesEntitlement ;
22+ import org .elasticsearch .entitlement .runtime .policy .entitlements .OutboundNetworkEntitlement ;
2223import org .elasticsearch .test .ESTestCase ;
2324import org .elasticsearch .test .compiler .InMemoryJavaCompiler ;
2425import org .elasticsearch .test .jar .JarUtils ;
3132import java .net .URL ;
3233import java .net .URLClassLoader ;
3334import java .nio .file .Path ;
34- import java .util .Arrays ;
3535import java .util .List ;
3636import java .util .Map ;
3737import java .util .Set ;
38+ import java .util .concurrent .atomic .AtomicReference ;
3839import java .util .stream .Stream ;
3940
4041import static java .util .Map .entry ;
41- import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ALL_UNNAMED ;
4242import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ComponentKind .SERVER ;
43- import static org .hamcrest .Matchers .aMapWithSize ;
4443import static org .hamcrest .Matchers .allOf ;
4544import static org .hamcrest .Matchers .containsString ;
4645import static org .hamcrest .Matchers .is ;
47- import static org .hamcrest .Matchers .sameInstance ;
4846
4947public class PolicyManagerTests extends ESTestCase {
5048
@@ -88,223 +86,81 @@ public static void beforeClass() {
8886 }
8987 }
9088
91- public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule () {
92- var plugin1SourcePath = Path .of ("modules" , "plugin1" );
93- var policyManager = new PolicyManager (
94- createEmptyTestServerPolicy (),
95- List .of (),
96- Map .of ("plugin1" , createPluginPolicy ("plugin.module" )),
97- c -> PolicyScope .plugin ("plugin1" , moduleName (c )),
98- Map .of ("plugin1" , plugin1SourcePath ),
99- NO_ENTITLEMENTS_MODULE ,
100- TEST_PATH_LOOKUP ,
101- Set .of ()
102- );
103-
104- // Any class from the current module (unnamed) will do
105- var callerClass = this .getClass ();
106- var requestingModule = callerClass .getModule ();
107-
108- assertEquals (
109- "No policy for the unnamed module" ,
110- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
111- policyManager .getEntitlements (callerClass )
112- );
113-
114- assertEquals (
115- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
116- policyManager .moduleEntitlementsMap
117- );
118- }
119-
120- public void testGetEntitlementsThrowsOnMissingPolicyForPlugin () {
121- var plugin1SourcePath = Path .of ("modules" , "plugin1" );
122- var policyManager = new PolicyManager (
123- createEmptyTestServerPolicy (),
124- List .of (),
125- Map .of (),
126- c -> PolicyScope .plugin ("plugin1" , moduleName (c )),
127- Map .of ("plugin1" , plugin1SourcePath ),
128- NO_ENTITLEMENTS_MODULE ,
129- TEST_PATH_LOOKUP ,
130- Set .of ()
131- );
132-
133- // Any class from the current module (unnamed) will do
134- var callerClass = this .getClass ();
135- var requestingModule = callerClass .getModule ();
136-
137- assertEquals (
138- "No policy for this plugin" ,
139- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
140- policyManager .getEntitlements (callerClass )
141- );
89+ public void testGetEntitlements () {
90+ // A mutable policyScope we can use to program specific replies
91+ AtomicReference <PolicyScope > policyScope = new AtomicReference <>();
14292
143- assertEquals (
144- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
145- policyManager .moduleEntitlementsMap
146- );
147- }
148-
149- public void testGetEntitlementsFailureIsCached () {
93+ // A common policy with a variety of entitlements to test
94+ Path thisSourcePath = PolicyManager .getComponentPathFromClass (getClass ());
15095 var plugin1SourcePath = Path .of ("modules" , "plugin1" );
15196 var policyManager = new PolicyManager (
152- createEmptyTestServerPolicy ( ),
97+ new Policy ( "server" , List . of ( new Scope ( "org.example.httpclient" , List . of ( new OutboundNetworkEntitlement ()))) ),
15398 List .of (),
154- Map .of (),
155- c -> PolicyScope . plugin ( "plugin1" , moduleName ( c ) ),
99+ Map .of ("plugin1" , new Policy ( "plugin1" , List . of ( new Scope ( "plugin.module1" , List . of ( new ExitVMEntitlement ())))) ),
100+ c -> policyScope . get ( ),
156101 Map .of ("plugin1" , plugin1SourcePath ),
157102 NO_ENTITLEMENTS_MODULE ,
158103 TEST_PATH_LOOKUP ,
159104 Set .of ()
160105 );
161106
162- // Any class from the current module (unnamed) will do
163- var callerClass = this .getClass ();
164- var requestingModule = callerClass .getModule ();
107+ // "Unspecified" below means that the module is not named in the policy
165108
166- assertEquals (
167- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
168- policyManager .getEntitlements (callerClass )
169- );
170- assertEquals (
171- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
172- policyManager .moduleEntitlementsMap
109+ policyScope .set (PolicyScope .server ("org.example.httpclient" ));
110+ resetAndCheckEntitlements (
111+ "Specified entitlements for server" ,
112+ getClass (),
113+ policyManager .policyEntitlements (
114+ SERVER .componentName ,
115+ thisSourcePath ,
116+ "org.example.httpclient" ,
117+ List .of (new OutboundNetworkEntitlement ())
118+ ),
119+ policyManager
173120 );
174121
175- // A second time
176- assertEquals (
177- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
178- policyManager .getEntitlements (callerClass )
122+ policyScope .set (PolicyScope .server ("plugin.unspecifiedModule" ));
123+ resetAndCheckEntitlements (
124+ "Default entitlements for unspecified module" ,
125+ getClass (),
126+ policyManager .defaultEntitlements (SERVER .componentName , thisSourcePath , "plugin.unspecifiedModule" ),
127+ policyManager
179128 );
180129
181- // Nothing new in the map
182- assertEquals (
183- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
184- policyManager .moduleEntitlementsMap
130+ policyScope .set (PolicyScope .plugin ("plugin1" , "plugin.module1" ));
131+ resetAndCheckEntitlements (
132+ "Specified entitlements for plugin" ,
133+ getClass (),
134+ policyManager .policyEntitlements ("plugin1" , plugin1SourcePath , "plugin.module1" , List .of (new ExitVMEntitlement ())),
135+ policyManager
185136 );
186- }
187137
188- public void testGetEntitlementsReturnsEntitlementsForPluginUnnamedModule () {
189- var policyManager = new PolicyManager (
190- createEmptyTestServerPolicy (),
191- List .of (),
192- Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
193- c -> PolicyScope .plugin ("plugin2" , moduleName (c )),
194- Map .of ("plugin2" , Path .of ("modules" , "plugin2" )),
195- NO_ENTITLEMENTS_MODULE ,
196- TEST_PATH_LOOKUP ,
197- Set .of ()
138+ policyScope .set (PolicyScope .plugin ("plugin1" , "plugin.unspecifiedModule" ));
139+ resetAndCheckEntitlements (
140+ "Default entitlements for plugin" ,
141+ getClass (),
142+ policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , "plugin.unspecifiedModule" ),
143+ policyManager
198144 );
199-
200- // Any class from the current module (unnamed) will do
201- var callerClass = this .getClass ();
202-
203- var entitlements = policyManager .getEntitlements (callerClass );
204- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
205145 }
206146
207- public void testGetEntitlementsReturnsDefaultOnMissingPolicyForServer () throws ClassNotFoundException {
208- var policyManager = new PolicyManager (
209- createTestServerPolicy ("example" ),
210- List .of (),
211- Map .of (),
212- c -> PolicyScope .server (moduleName (c )),
213- Map .of (),
214- NO_ENTITLEMENTS_MODULE ,
215- TEST_PATH_LOOKUP ,
216- Set .of ()
217- );
218-
219- // Any class will do, since our resolver is hardcoded to use SERVER_COMPONENT_NAME.
220- // Let's pick one with a known module name.
221- String httpserverModuleName = "jdk.httpserver" ;
222- var mockServerClass = ModuleLayer .boot ().findLoader (httpserverModuleName ).loadClass ("com.sun.net.httpserver.HttpServer" );
223- var mockServerSourcePath = PolicyManager .getComponentPathFromClass (mockServerClass );
224- var requestingModule = mockServerClass .getModule ();
225-
147+ private void resetAndCheckEntitlements (
148+ String message ,
149+ Class <?> requestingClass ,
150+ ModuleEntitlements expectedEntitlements ,
151+ PolicyManager policyManager
152+ ) {
153+ policyManager .moduleEntitlementsMap .clear ();
154+ assertEquals (message , expectedEntitlements , policyManager .getEntitlements (requestingClass ));
226155 assertEquals (
227- "No policy for this module in server" ,
228- policyManager .defaultEntitlements (SERVER .componentName , mockServerSourcePath , httpserverModuleName ),
229- policyManager .getEntitlements (mockServerClass )
230- );
231-
232- assertEquals (
233- Map .of (requestingModule , policyManager .defaultEntitlements (SERVER .componentName , mockServerSourcePath , httpserverModuleName )),
156+ "Map has precisely the one expected entry" ,
157+ Map .of (requestingClass .getModule (), expectedEntitlements ),
234158 policyManager .moduleEntitlementsMap
235159 );
236- }
237160
238- public void testGetEntitlementsReturnsEntitlementsForServerModule () throws ClassNotFoundException {
239- String httpserverModuleName = "jdk.httpserver" ;
240- var policyManager = new PolicyManager (
241- createTestServerPolicy (httpserverModuleName ),
242- List .of (),
243- Map .of (),
244- c -> PolicyScope .server (moduleName (c )),
245- Map .of (),
246- NO_ENTITLEMENTS_MODULE ,
247- TEST_PATH_LOOKUP ,
248- Set .of ()
249- );
250-
251- // Any class will do, since our resolver is hardcoded to use SERVER_COMPONENT_NAME.
252- // Let's pick one with a known module name.
253- var mockServerClass = ModuleLayer .boot ().findLoader (httpserverModuleName ).loadClass ("com.sun.net.httpserver.HttpServer" );
254-
255- var entitlements = policyManager .getEntitlements (mockServerClass );
256- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
257- assertThat (entitlements .hasEntitlement (ExitVMEntitlement .class ), is (true ));
258- }
259-
260- public void testGetEntitlementsReturnsEntitlementsForPluginModule () throws IOException , ClassNotFoundException {
261- final Path home = createTempDir ();
262-
263- Path jar = createMockPluginJar (home );
264-
265- var policyManager = new PolicyManager (
266- createEmptyTestServerPolicy (),
267- List .of (),
268- Map .of ("mock-plugin" , createPluginPolicy ("org.example.plugin" )),
269- c -> PolicyScope .plugin ("mock-plugin" , moduleName (c )),
270- Map .of ("mock-plugin" , Path .of ("modules" , "mock-plugin" )),
271- NO_ENTITLEMENTS_MODULE ,
272- TEST_PATH_LOOKUP ,
273- Set .of ()
274- );
275-
276- var layer = createLayerForJar (jar , "org.example.plugin" );
277- var mockPluginClass = layer .findLoader ("org.example.plugin" ).loadClass ("q.B" );
278-
279- var entitlements = policyManager .getEntitlements (mockPluginClass );
280- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
281- assertThat (entitlements .fileAccess ().canRead (TEST_BASE_DIR ), is (true ));
282- }
283-
284- public void testGetEntitlementsResultIsCached () {
285- var policyManager = new PolicyManager (
286- createEmptyTestServerPolicy (),
287- List .of (),
288- Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
289- c -> PolicyScope .plugin ("plugin2" , moduleName (c )),
290- Map .of ("plugin2" , Path .of ("modules" , "plugin2" )),
291- NO_ENTITLEMENTS_MODULE ,
292- TEST_PATH_LOOKUP ,
293- Set .of ()
294- );
295-
296- // Any class from the current module (unnamed) will do
297- var callerClass = this .getClass ();
298-
299- var entitlements = policyManager .getEntitlements (callerClass );
300- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
301- assertThat (policyManager .moduleEntitlementsMap , aMapWithSize (1 ));
302- var cachedResult = policyManager .moduleEntitlementsMap .values ().stream ().findFirst ().orElseThrow ();
303- var entitlementsAgain = policyManager .getEntitlements (callerClass );
304-
305- // Nothing new in the map
306- assertThat (policyManager .moduleEntitlementsMap , aMapWithSize (1 ));
307- assertThat (entitlementsAgain , sameInstance (cachedResult ));
161+ // Fetch a second time and verify the map is unchanged
162+ policyManager .getEntitlements (requestingClass );
163+ assertEquals ("Map is unchanged" , Map .of (requestingClass .getModule (), expectedEntitlements ), policyManager .moduleEntitlementsMap );
308164 }
309165
310166 public void testRequestingClassFastPath () throws IOException , ClassNotFoundException {
@@ -559,24 +415,6 @@ public void testFilesEntitlementsWithExclusive() {
559415 );
560416 }
561417
562- /**
563- * If the plugin resolver tells us a class is in a plugin, don't conclude that it's in an agent.
564- */
565- public void testPluginResolverOverridesAgents () {
566- var policyManager = new PolicyManager (
567- createEmptyTestServerPolicy (),
568- List .of (new CreateClassLoaderEntitlement ()),
569- Map .of (),
570- c -> PolicyScope .plugin ("test" , moduleName (c )), // Insist that the class is in a plugin
571- Map .of (),
572- NO_ENTITLEMENTS_MODULE ,
573- TEST_PATH_LOOKUP ,
574- Set .of ()
575- );
576- ModuleEntitlements notAgentsEntitlements = policyManager .getEntitlements (TestAgent .class );
577- assertThat (notAgentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (false ));
578- }
579-
580418 private static Class <?> makeClassInItsOwnModule () throws IOException , ClassNotFoundException {
581419 final Path home = createTempDir ();
582420 Path jar = createMockPluginJar (home );
@@ -601,27 +439,6 @@ private static Policy createEmptyTestServerPolicy() {
601439 return new Policy ("server" , List .of ());
602440 }
603441
604- private static Policy createTestServerPolicy (String scopeName ) {
605- return new Policy ("server" , List .of (new Scope (scopeName , List .of (new ExitVMEntitlement (), new CreateClassLoaderEntitlement ()))));
606- }
607-
608- private static Policy createPluginPolicy (String ... pluginModules ) {
609- return new Policy (
610- "plugin" ,
611- Arrays .stream (pluginModules )
612- .map (
613- name -> new Scope (
614- name ,
615- List .of (
616- new FilesEntitlement (List .of (FilesEntitlement .FileData .ofPath (TEST_BASE_DIR , FilesEntitlement .Mode .READ ))),
617- new CreateClassLoaderEntitlement ()
618- )
619- )
620- )
621- .toList ()
622- );
623- }
624-
625442 private static Path createMockPluginJarForUnnamedModule (Path home ) throws IOException {
626443 Path jar = home .resolve ("unnamed-mock-plugin.jar" );
627444
0 commit comments