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
4947@ ESTestCase .WithoutSecurityManager
5048public class PolicyManagerTests extends ESTestCase {
@@ -89,223 +87,81 @@ public static void beforeClass() {
8987 }
9088 }
9189
92- public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule () {
93- var plugin1SourcePath = Path .of ("modules" , "plugin1" );
94- var policyManager = new PolicyManager (
95- createEmptyTestServerPolicy (),
96- List .of (),
97- Map .of ("plugin1" , createPluginPolicy ("plugin.module" )),
98- c -> PolicyScope .plugin ("plugin1" , moduleName (c )),
99- Map .of ("plugin1" , plugin1SourcePath ),
100- NO_ENTITLEMENTS_MODULE ,
101- TEST_PATH_LOOKUP ,
102- Set .of ()
103- );
104-
105- // Any class from the current module (unnamed) will do
106- var callerClass = this .getClass ();
107- var requestingModule = callerClass .getModule ();
108-
109- assertEquals (
110- "No policy for the unnamed module" ,
111- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
112- policyManager .getEntitlements (callerClass )
113- );
114-
115- assertEquals (
116- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
117- policyManager .moduleEntitlementsMap
118- );
119- }
120-
121- public void testGetEntitlementsThrowsOnMissingPolicyForPlugin () {
122- var plugin1SourcePath = Path .of ("modules" , "plugin1" );
123- var policyManager = new PolicyManager (
124- createEmptyTestServerPolicy (),
125- List .of (),
126- Map .of (),
127- c -> PolicyScope .plugin ("plugin1" , moduleName (c )),
128- Map .of ("plugin1" , plugin1SourcePath ),
129- NO_ENTITLEMENTS_MODULE ,
130- TEST_PATH_LOOKUP ,
131- Set .of ()
132- );
133-
134- // Any class from the current module (unnamed) will do
135- var callerClass = this .getClass ();
136- var requestingModule = callerClass .getModule ();
137-
138- assertEquals (
139- "No policy for this plugin" ,
140- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
141- policyManager .getEntitlements (callerClass )
142- );
90+ public void testGetEntitlements () {
91+ // A mutable policyScope we can use to program specific replies
92+ AtomicReference <PolicyScope > policyScope = new AtomicReference <>();
14393
144- assertEquals (
145- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
146- policyManager .moduleEntitlementsMap
147- );
148- }
149-
150- public void testGetEntitlementsFailureIsCached () {
94+ // A common policy with a variety of entitlements to test
95+ Path thisSourcePath = PolicyManager .getComponentPathFromClass (getClass ());
15196 var plugin1SourcePath = Path .of ("modules" , "plugin1" );
15297 var policyManager = new PolicyManager (
153- createEmptyTestServerPolicy ( ),
98+ new Policy ( "server" , List . of ( new Scope ( "org.example.httpclient" , List . of ( new OutboundNetworkEntitlement ()))) ),
15499 List .of (),
155- Map .of (),
156- c -> PolicyScope . plugin ( "plugin1" , moduleName ( c ) ),
100+ Map .of ("plugin1" , new Policy ( "plugin1" , List . of ( new Scope ( "plugin.module1" , List . of ( new ExitVMEntitlement ())))) ),
101+ c -> policyScope . get ( ),
157102 Map .of ("plugin1" , plugin1SourcePath ),
158103 NO_ENTITLEMENTS_MODULE ,
159104 TEST_PATH_LOOKUP ,
160105 Set .of ()
161106 );
162107
163- // Any class from the current module (unnamed) will do
164- var callerClass = this .getClass ();
165- var requestingModule = callerClass .getModule ();
108+ // "Unspecified" below means that the module is not named in the policy
166109
167- assertEquals (
168- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
169- policyManager .getEntitlements (callerClass )
170- );
171- assertEquals (
172- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
173- policyManager .moduleEntitlementsMap
110+ policyScope .set (PolicyScope .server ("org.example.httpclient" ));
111+ resetAndCheckEntitlements (
112+ "Specified entitlements for server" ,
113+ getClass (),
114+ policyManager .policyEntitlements (
115+ SERVER .componentName ,
116+ thisSourcePath ,
117+ "org.example.httpclient" ,
118+ List .of (new OutboundNetworkEntitlement ())
119+ ),
120+ policyManager
174121 );
175122
176- // A second time
177- assertEquals (
178- policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ()),
179- policyManager .getEntitlements (callerClass )
123+ policyScope .set (PolicyScope .server ("plugin.unspecifiedModule" ));
124+ resetAndCheckEntitlements (
125+ "Default entitlements for unspecified module" ,
126+ getClass (),
127+ policyManager .defaultEntitlements (SERVER .componentName , thisSourcePath , "plugin.unspecifiedModule" ),
128+ policyManager
180129 );
181130
182- // Nothing new in the map
183- assertEquals (
184- Map .of (requestingModule , policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , requestingModule .getName ())),
185- policyManager .moduleEntitlementsMap
131+ policyScope .set (PolicyScope .plugin ("plugin1" , "plugin.module1" ));
132+ resetAndCheckEntitlements (
133+ "Specified entitlements for plugin" ,
134+ getClass (),
135+ policyManager .policyEntitlements ("plugin1" , plugin1SourcePath , "plugin.module1" , List .of (new ExitVMEntitlement ())),
136+ policyManager
186137 );
187- }
188138
189- public void testGetEntitlementsReturnsEntitlementsForPluginUnnamedModule () {
190- var policyManager = new PolicyManager (
191- createEmptyTestServerPolicy (),
192- List .of (),
193- Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
194- c -> PolicyScope .plugin ("plugin2" , moduleName (c )),
195- Map .of ("plugin2" , Path .of ("modules" , "plugin2" )),
196- NO_ENTITLEMENTS_MODULE ,
197- TEST_PATH_LOOKUP ,
198- Set .of ()
139+ policyScope .set (PolicyScope .plugin ("plugin1" , "plugin.unspecifiedModule" ));
140+ resetAndCheckEntitlements (
141+ "Default entitlements for plugin" ,
142+ getClass (),
143+ policyManager .defaultEntitlements ("plugin1" , plugin1SourcePath , "plugin.unspecifiedModule" ),
144+ policyManager
199145 );
200-
201- // Any class from the current module (unnamed) will do
202- var callerClass = this .getClass ();
203-
204- var entitlements = policyManager .getEntitlements (callerClass );
205- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
206146 }
207147
208- public void testGetEntitlementsReturnsDefaultOnMissingPolicyForServer () throws ClassNotFoundException {
209- var policyManager = new PolicyManager (
210- createTestServerPolicy ("example" ),
211- List .of (),
212- Map .of (),
213- c -> PolicyScope .server (moduleName (c )),
214- Map .of (),
215- NO_ENTITLEMENTS_MODULE ,
216- TEST_PATH_LOOKUP ,
217- Set .of ()
218- );
219-
220- // Any class will do, since our resolver is hardcoded to use SERVER_COMPONENT_NAME.
221- // Let's pick one with a known module name.
222- String httpserverModuleName = "jdk.httpserver" ;
223- var mockServerClass = ModuleLayer .boot ().findLoader (httpserverModuleName ).loadClass ("com.sun.net.httpserver.HttpServer" );
224- var mockServerSourcePath = PolicyManager .getComponentPathFromClass (mockServerClass );
225- var requestingModule = mockServerClass .getModule ();
226-
148+ private void resetAndCheckEntitlements (
149+ String message ,
150+ Class <?> requestingClass ,
151+ ModuleEntitlements expectedEntitlements ,
152+ PolicyManager policyManager
153+ ) {
154+ policyManager .moduleEntitlementsMap .clear ();
155+ assertEquals (message , expectedEntitlements , policyManager .getEntitlements (requestingClass ));
227156 assertEquals (
228- "No policy for this module in server" ,
229- policyManager .defaultEntitlements (SERVER .componentName , mockServerSourcePath , httpserverModuleName ),
230- policyManager .getEntitlements (mockServerClass )
231- );
232-
233- assertEquals (
234- Map .of (requestingModule , policyManager .defaultEntitlements (SERVER .componentName , mockServerSourcePath , httpserverModuleName )),
157+ "Map has precisely the one expected entry" ,
158+ Map .of (requestingClass .getModule (), expectedEntitlements ),
235159 policyManager .moduleEntitlementsMap
236160 );
237- }
238161
239- public void testGetEntitlementsReturnsEntitlementsForServerModule () throws ClassNotFoundException {
240- String httpserverModuleName = "jdk.httpserver" ;
241- var policyManager = new PolicyManager (
242- createTestServerPolicy (httpserverModuleName ),
243- List .of (),
244- Map .of (),
245- c -> PolicyScope .server (moduleName (c )),
246- Map .of (),
247- NO_ENTITLEMENTS_MODULE ,
248- TEST_PATH_LOOKUP ,
249- Set .of ()
250- );
251-
252- // Any class will do, since our resolver is hardcoded to use SERVER_COMPONENT_NAME.
253- // Let's pick one with a known module name.
254- var mockServerClass = ModuleLayer .boot ().findLoader (httpserverModuleName ).loadClass ("com.sun.net.httpserver.HttpServer" );
255-
256- var entitlements = policyManager .getEntitlements (mockServerClass );
257- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
258- assertThat (entitlements .hasEntitlement (ExitVMEntitlement .class ), is (true ));
259- }
260-
261- public void testGetEntitlementsReturnsEntitlementsForPluginModule () throws IOException , ClassNotFoundException {
262- final Path home = createTempDir ();
263-
264- Path jar = createMockPluginJar (home );
265-
266- var policyManager = new PolicyManager (
267- createEmptyTestServerPolicy (),
268- List .of (),
269- Map .of ("mock-plugin" , createPluginPolicy ("org.example.plugin" )),
270- c -> PolicyScope .plugin ("mock-plugin" , moduleName (c )),
271- Map .of ("mock-plugin" , Path .of ("modules" , "mock-plugin" )),
272- NO_ENTITLEMENTS_MODULE ,
273- TEST_PATH_LOOKUP ,
274- Set .of ()
275- );
276-
277- var layer = createLayerForJar (jar , "org.example.plugin" );
278- var mockPluginClass = layer .findLoader ("org.example.plugin" ).loadClass ("q.B" );
279-
280- var entitlements = policyManager .getEntitlements (mockPluginClass );
281- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
282- assertThat (entitlements .fileAccess ().canRead (TEST_BASE_DIR ), is (true ));
283- }
284-
285- public void testGetEntitlementsResultIsCached () {
286- var policyManager = new PolicyManager (
287- createEmptyTestServerPolicy (),
288- List .of (),
289- Map .ofEntries (entry ("plugin2" , createPluginPolicy (ALL_UNNAMED ))),
290- c -> PolicyScope .plugin ("plugin2" , moduleName (c )),
291- Map .of ("plugin2" , Path .of ("modules" , "plugin2" )),
292- NO_ENTITLEMENTS_MODULE ,
293- TEST_PATH_LOOKUP ,
294- Set .of ()
295- );
296-
297- // Any class from the current module (unnamed) will do
298- var callerClass = this .getClass ();
299-
300- var entitlements = policyManager .getEntitlements (callerClass );
301- assertThat (entitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (true ));
302- assertThat (policyManager .moduleEntitlementsMap , aMapWithSize (1 ));
303- var cachedResult = policyManager .moduleEntitlementsMap .values ().stream ().findFirst ().orElseThrow ();
304- var entitlementsAgain = policyManager .getEntitlements (callerClass );
305-
306- // Nothing new in the map
307- assertThat (policyManager .moduleEntitlementsMap , aMapWithSize (1 ));
308- assertThat (entitlementsAgain , sameInstance (cachedResult ));
162+ // Fetch a second time and verify the map is unchanged
163+ policyManager .getEntitlements (requestingClass );
164+ assertEquals ("Map is unchanged" , Map .of (requestingClass .getModule (), expectedEntitlements ), policyManager .moduleEntitlementsMap );
309165 }
310166
311167 public void testRequestingClassFastPath () throws IOException , ClassNotFoundException {
@@ -560,24 +416,6 @@ public void testFilesEntitlementsWithExclusive() {
560416 );
561417 }
562418
563- /**
564- * If the plugin resolver tells us a class is in a plugin, don't conclude that it's in an agent.
565- */
566- public void testPluginResolverOverridesAgents () {
567- var policyManager = new PolicyManager (
568- createEmptyTestServerPolicy (),
569- List .of (new CreateClassLoaderEntitlement ()),
570- Map .of (),
571- c -> PolicyScope .plugin ("test" , moduleName (c )), // Insist that the class is in a plugin
572- Map .of (),
573- NO_ENTITLEMENTS_MODULE ,
574- TEST_PATH_LOOKUP ,
575- Set .of ()
576- );
577- ModuleEntitlements notAgentsEntitlements = policyManager .getEntitlements (TestAgent .class );
578- assertThat (notAgentsEntitlements .hasEntitlement (CreateClassLoaderEntitlement .class ), is (false ));
579- }
580-
581419 private static Class <?> makeClassInItsOwnModule () throws IOException , ClassNotFoundException {
582420 final Path home = createTempDir ();
583421 Path jar = createMockPluginJar (home );
@@ -602,27 +440,6 @@ private static Policy createEmptyTestServerPolicy() {
602440 return new Policy ("server" , List .of ());
603441 }
604442
605- private static Policy createTestServerPolicy (String scopeName ) {
606- return new Policy ("server" , List .of (new Scope (scopeName , List .of (new ExitVMEntitlement (), new CreateClassLoaderEntitlement ()))));
607- }
608-
609- private static Policy createPluginPolicy (String ... pluginModules ) {
610- return new Policy (
611- "plugin" ,
612- Arrays .stream (pluginModules )
613- .map (
614- name -> new Scope (
615- name ,
616- List .of (
617- new FilesEntitlement (List .of (FilesEntitlement .FileData .ofPath (TEST_BASE_DIR , FilesEntitlement .Mode .READ ))),
618- new CreateClassLoaderEntitlement ()
619- )
620- )
621- )
622- .toList ()
623- );
624- }
625-
626443 private static Path createMockPluginJarForUnnamedModule (Path home ) throws IOException {
627444 Path jar = home .resolve ("unnamed-mock-plugin.jar" );
628445
0 commit comments