5959import static java .util .zip .ZipFile .OPEN_READ ;
6060import static org .elasticsearch .entitlement .bridge .Util .NO_CLASS ;
6161import static org .elasticsearch .entitlement .runtime .policy .PathLookup .BaseDir .TEMP ;
62+ import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ComponentKind .APM_AGENT ;
63+ import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ComponentKind .PLUGIN ;
64+ import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ComponentKind .SERVER ;
65+ import static org .elasticsearch .entitlement .runtime .policy .PolicyManager .ComponentKind .UNKNOWN ;
6266
6367/**
6468 * This class is responsible for finding the <strong>component</strong> (system, server, plugin, agent) for a caller class to check,
@@ -128,14 +132,55 @@ public class PolicyManager {
128132 */
129133 private static final Logger generalLogger = LogManager .getLogger (PolicyManager .class );
130134
131- static final String UNKNOWN_COMPONENT_NAME = "(unknown)" ;
132- static final String SERVER_COMPONENT_NAME = "(server)" ;
133- static final String APM_AGENT_COMPONENT_NAME = "(APM agent)" ;
134-
135135 static final Class <?> DEFAULT_FILESYSTEM_CLASS = PathUtils .getDefaultFileSystem ().getClass ();
136136
137137 static final Set <String > MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set .of ("java.desktop" );
138138
139+ /**
140+ * Identifies a particular entitlement {@link Scope} within a {@link Policy}.
141+ */
142+ public record PolicyScope (ComponentKind kind , String componentName , String moduleName ) {
143+ public PolicyScope {
144+ requireNonNull (kind );
145+ requireNonNull (componentName );
146+ requireNonNull (moduleName );
147+ assert kind .componentName == null || kind .componentName .equals (componentName );
148+ }
149+
150+ public static PolicyScope unknown (String moduleName ) {
151+ return new PolicyScope (UNKNOWN , UNKNOWN .componentName , moduleName );
152+ }
153+
154+ public static PolicyScope server (String moduleName ) {
155+ return new PolicyScope (SERVER , SERVER .componentName , moduleName );
156+ }
157+
158+ public static PolicyScope apmAgent (String moduleName ) {
159+ return new PolicyScope (APM_AGENT , APM_AGENT .componentName , moduleName );
160+ }
161+
162+ public static PolicyScope plugin (String componentName , String moduleName ) {
163+ return new PolicyScope (PLUGIN , componentName , moduleName );
164+ }
165+ }
166+
167+ public enum ComponentKind {
168+ UNKNOWN ("(unknown)" ),
169+ SERVER ("(server)" ),
170+ APM_AGENT ("(APM agent)" ),
171+ PLUGIN (null );
172+
173+ /**
174+ * If this kind corresponds to a single component, this is that component's name;
175+ * otherwise null.
176+ */
177+ final String componentName ;
178+
179+ ComponentKind (String componentName ) {
180+ this .componentName = componentName ;
181+ }
182+ }
183+
139184 /**
140185 * This class contains all the entitlements by type, plus the {@link FileAccessTree} for the special case of filesystem entitlements.
141186 * <p>
@@ -209,7 +254,7 @@ ModuleEntitlements policyEntitlements(String componentName, Path componentPath,
209254 private final Map <String , List <Entitlement >> serverEntitlements ;
210255 private final List <Entitlement > apmAgentEntitlements ;
211256 private final Map <String , Map <String , List <Entitlement >>> pluginsEntitlements ;
212- private final Function <Class <?>, String > pluginResolver ;
257+ private final Function <Class <?>, PolicyScope > scopeResolver ;
213258 private final PathLookup pathLookup ;
214259 private final Set <Class <?>> mutedClasses ;
215260
@@ -245,10 +290,6 @@ private static Set<Module> findSystemLayerModules() {
245290 .collect (Collectors .toUnmodifiableSet ());
246291
247292 private final Map <String , Path > sourcePaths ;
248- /**
249- * The package name containing classes from the APM agent.
250- */
251- private final String apmAgentPackageName ;
252293
253294 /**
254295 * Frames originating from this module are ignored in the permission logic.
@@ -266,9 +307,8 @@ public PolicyManager(
266307 Policy serverPolicy ,
267308 List <Entitlement > apmAgentEntitlements ,
268309 Map <String , Policy > pluginPolicies ,
269- Function <Class <?>, String > pluginResolver ,
310+ Function <Class <?>, PolicyScope > scopeResolver ,
270311 Map <String , Path > sourcePaths ,
271- String apmAgentPackageName ,
272312 Module entitlementsModule ,
273313 PathLookup pathLookup ,
274314 Set <Class <?>> suppressFailureLogClasses
@@ -278,18 +318,17 @@ public PolicyManager(
278318 this .pluginsEntitlements = requireNonNull (pluginPolicies ).entrySet ()
279319 .stream ()
280320 .collect (toUnmodifiableMap (Map .Entry ::getKey , e -> buildScopeEntitlementsMap (e .getValue ())));
281- this .pluginResolver = pluginResolver ;
321+ this .scopeResolver = scopeResolver ;
282322 this .sourcePaths = sourcePaths ;
283- this .apmAgentPackageName = apmAgentPackageName ;
284323 this .entitlementsModule = entitlementsModule ;
285324 this .pathLookup = requireNonNull (pathLookup );
286325 this .mutedClasses = suppressFailureLogClasses ;
287326
288327 List <ExclusiveFileEntitlement > exclusiveFileEntitlements = new ArrayList <>();
289328 for (var e : serverEntitlements .entrySet ()) {
290- validateEntitlementsPerModule (SERVER_COMPONENT_NAME , e .getKey (), e .getValue (), exclusiveFileEntitlements );
329+ validateEntitlementsPerModule (SERVER . componentName , e .getKey (), e .getValue (), exclusiveFileEntitlements );
291330 }
292- validateEntitlementsPerModule (APM_AGENT_COMPONENT_NAME , ALL_UNNAMED , apmAgentEntitlements , exclusiveFileEntitlements );
331+ validateEntitlementsPerModule (APM_AGENT . componentName , ALL_UNNAMED , apmAgentEntitlements , exclusiveFileEntitlements );
293332 for (var p : pluginsEntitlements .entrySet ()) {
294333 for (var m : p .getValue ().entrySet ()) {
295334 validateEntitlementsPerModule (p .getKey (), m .getKey (), m .getValue (), exclusiveFileEntitlements );
@@ -684,50 +723,40 @@ ModuleEntitlements getEntitlements(Class<?> requestingClass) {
684723 }
685724
686725 private ModuleEntitlements computeEntitlements (Class <?> requestingClass ) {
687- Module requestingModule = requestingClass .getModule ();
688- if (isServerModule (requestingModule )) {
689- return getModuleScopeEntitlements (
690- serverEntitlements ,
691- requestingModule .getName (),
692- SERVER_COMPONENT_NAME ,
693- getComponentPathFromClass (requestingClass )
694- );
695- }
726+ var policyScope = scopeResolver .apply (requestingClass );
727+ var componentName = policyScope .componentName ();
728+ var moduleName = policyScope .moduleName ();
696729
697- // plugins
698- var pluginName = pluginResolver .apply (requestingClass );
699- if (pluginName != null ) {
700- var pluginEntitlements = pluginsEntitlements .get (pluginName );
701- if (pluginEntitlements == null ) {
702- return defaultEntitlements (pluginName , sourcePaths .get (pluginName ), requestingModule .getName ());
703- } else {
730+ switch (policyScope .kind ()) {
731+ case SERVER -> {
704732 return getModuleScopeEntitlements (
705- pluginEntitlements ,
706- getScopeName ( requestingModule ) ,
707- pluginName ,
708- sourcePaths . get ( pluginName )
733+ serverEntitlements ,
734+ moduleName ,
735+ SERVER . componentName ,
736+ getComponentPathFromClass ( requestingClass )
709737 );
710738 }
711- }
712-
713- if (requestingModule .isNamed () == false && requestingClass .getPackageName ().startsWith (apmAgentPackageName )) {
714- // The APM agent is the only thing running non-modular in the system classloader
715- return policyEntitlements (
716- APM_AGENT_COMPONENT_NAME ,
717- getComponentPathFromClass (requestingClass ),
718- ALL_UNNAMED ,
719- apmAgentEntitlements
720- );
721- }
722-
723- return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null , requestingModule .getName ());
724- }
725-
726- private static String getScopeName (Module requestingModule ) {
727- if (requestingModule .isNamed () == false ) {
728- return ALL_UNNAMED ;
729- } else {
730- return requestingModule .getName ();
739+ case APM_AGENT -> {
740+ // The APM agent is the only thing running non-modular in the system classloader
741+ return policyEntitlements (
742+ APM_AGENT .componentName ,
743+ getComponentPathFromClass (requestingClass ),
744+ ALL_UNNAMED ,
745+ apmAgentEntitlements
746+ );
747+ }
748+ case UNKNOWN -> {
749+ return defaultEntitlements (UNKNOWN .componentName , null , moduleName );
750+ }
751+ default -> {
752+ assert policyScope .kind () == PLUGIN ;
753+ var pluginEntitlements = pluginsEntitlements .get (componentName );
754+ if (pluginEntitlements == null ) {
755+ return defaultEntitlements (componentName , sourcePaths .get (componentName ), moduleName );
756+ } else {
757+ return getModuleScopeEntitlements (pluginEntitlements , moduleName , componentName , sourcePaths .get (componentName ));
758+ }
759+ }
731760 }
732761 }
733762
@@ -763,10 +792,6 @@ private ModuleEntitlements getModuleScopeEntitlements(
763792 return policyEntitlements (componentName , componentPath , scopeName , entitlements );
764793 }
765794
766- private static boolean isServerModule (Module requestingModule ) {
767- return requestingModule .isNamed () && requestingModule .getLayer () == ModuleLayer .boot ();
768- }
769-
770795 /**
771796 * Walks the stack to determine which class should be checked for entitlements.
772797 *
0 commit comments