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
6367public class PolicyManager {
6468 /**
6569 * Use this if you don't have a {@link ModuleEntitlements} in hand.
6670 */
6771 private static final Logger generalLogger = LogManager .getLogger (PolicyManager .class );
6872
69- static final String UNKNOWN_COMPONENT_NAME = "(unknown)" ;
70- static final String SERVER_COMPONENT_NAME = "(server)" ;
71- static final String APM_AGENT_COMPONENT_NAME = "(APM agent)" ;
72-
7373 static final Class <?> DEFAULT_FILESYSTEM_CLASS = PathUtils .getDefaultFileSystem ().getClass ();
7474
7575 static final Set <String > MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set .of ("java.desktop" );
7676
7777 /**
78- * @param componentName the plugin name; or else one of the special component names
79- * like {@link #SERVER_COMPONENT_NAME} or {@link #APM_AGENT_COMPONENT_NAME}.
78+ * Identifies a particular entitlement {@link Scope} within a {@link Policy}.
8079 */
80+ public record PolicyScope (ComponentKind kind , String componentName , String moduleName ) {
81+ public PolicyScope {
82+ requireNonNull (kind );
83+ requireNonNull (componentName );
84+ requireNonNull (moduleName );
85+ assert kind .componentName == null || kind .componentName .equals (componentName );
86+ }
87+
88+ public static PolicyScope unknown (String moduleName ) {
89+ return new PolicyScope (UNKNOWN , UNKNOWN .componentName , moduleName );
90+ }
91+
92+ public static PolicyScope server (String moduleName ) {
93+ return new PolicyScope (SERVER , SERVER .componentName , moduleName );
94+ }
95+
96+ public static PolicyScope apmAgent (String moduleName ) {
97+ return new PolicyScope (APM_AGENT , APM_AGENT .componentName , moduleName );
98+ }
99+
100+ public static PolicyScope plugin (String componentName , String moduleName ) {
101+ return new PolicyScope (PLUGIN , componentName , moduleName );
102+ }
103+ }
104+
105+ public enum ComponentKind {
106+ UNKNOWN ("(unknown)" ),
107+ SERVER ("(server)" ),
108+ APM_AGENT ("(APM agent)" ),
109+ PLUGIN (null );
110+
111+ /**
112+ * If this kind corresponds to a single component, this is that component's name;
113+ * otherwise null.
114+ */
115+ final String componentName ;
116+
117+ ComponentKind (String componentName ) {
118+ this .componentName = componentName ;
119+ }
120+ }
121+
81122 record ModuleEntitlements (
82123 String componentName ,
83124 Map <Class <? extends Entitlement >, List <Entitlement >> entitlementsByType ,
@@ -132,7 +173,7 @@ ModuleEntitlements policyEntitlements(String componentName, Path componentPath,
132173 private final Map <String , List <Entitlement >> serverEntitlements ;
133174 private final List <Entitlement > apmAgentEntitlements ;
134175 private final Map <String , Map <String , List <Entitlement >>> pluginsEntitlements ;
135- private final Function <Class <?>, String > pluginResolver ;
176+ private final Function <Class <?>, PolicyScope > scopeResolver ;
136177 private final PathLookup pathLookup ;
137178 private final Set <Class <?>> mutedClasses ;
138179
@@ -168,10 +209,6 @@ private static Set<Module> findSystemLayerModules() {
168209 .collect (Collectors .toUnmodifiableSet ());
169210
170211 private final Map <String , Path > sourcePaths ;
171- /**
172- * The package name containing classes from the APM agent.
173- */
174- private final String apmAgentPackageName ;
175212
176213 /**
177214 * Frames originating from this module are ignored in the permission logic.
@@ -189,9 +226,8 @@ public PolicyManager(
189226 Policy serverPolicy ,
190227 List <Entitlement > apmAgentEntitlements ,
191228 Map <String , Policy > pluginPolicies ,
192- Function <Class <?>, String > pluginResolver ,
229+ Function <Class <?>, PolicyScope > scopeResolver ,
193230 Map <String , Path > sourcePaths ,
194- String apmAgentPackageName ,
195231 Module entitlementsModule ,
196232 PathLookup pathLookup ,
197233 Set <Class <?>> suppressFailureLogClasses
@@ -201,18 +237,17 @@ public PolicyManager(
201237 this .pluginsEntitlements = requireNonNull (pluginPolicies ).entrySet ()
202238 .stream ()
203239 .collect (toUnmodifiableMap (Map .Entry ::getKey , e -> buildScopeEntitlementsMap (e .getValue ())));
204- this .pluginResolver = pluginResolver ;
240+ this .scopeResolver = scopeResolver ;
205241 this .sourcePaths = sourcePaths ;
206- this .apmAgentPackageName = apmAgentPackageName ;
207242 this .entitlementsModule = entitlementsModule ;
208243 this .pathLookup = requireNonNull (pathLookup );
209244 this .mutedClasses = suppressFailureLogClasses ;
210245
211246 List <ExclusiveFileEntitlement > exclusiveFileEntitlements = new ArrayList <>();
212247 for (var e : serverEntitlements .entrySet ()) {
213- validateEntitlementsPerModule (SERVER_COMPONENT_NAME , e .getKey (), e .getValue (), exclusiveFileEntitlements );
248+ validateEntitlementsPerModule (SERVER . componentName , e .getKey (), e .getValue (), exclusiveFileEntitlements );
214249 }
215- validateEntitlementsPerModule (APM_AGENT_COMPONENT_NAME , ALL_UNNAMED , apmAgentEntitlements , exclusiveFileEntitlements );
250+ validateEntitlementsPerModule (APM_AGENT . componentName , ALL_UNNAMED , apmAgentEntitlements , exclusiveFileEntitlements );
216251 for (var p : pluginsEntitlements .entrySet ()) {
217252 for (var m : p .getValue ().entrySet ()) {
218253 validateEntitlementsPerModule (p .getKey (), m .getKey (), m .getValue (), exclusiveFileEntitlements );
@@ -607,50 +642,40 @@ ModuleEntitlements getEntitlements(Class<?> requestingClass) {
607642 }
608643
609644 private ModuleEntitlements computeEntitlements (Class <?> requestingClass ) {
610- Module requestingModule = requestingClass .getModule ();
611- if (isServerModule (requestingModule )) {
612- return getModuleScopeEntitlements (
613- serverEntitlements ,
614- requestingModule .getName (),
615- SERVER_COMPONENT_NAME ,
616- getComponentPathFromClass (requestingClass )
617- );
618- }
645+ var policyScope = scopeResolver .apply (requestingClass );
646+ var componentName = policyScope .componentName ();
647+ var moduleName = policyScope .moduleName ();
619648
620- // plugins
621- var pluginName = pluginResolver .apply (requestingClass );
622- if (pluginName != null ) {
623- var pluginEntitlements = pluginsEntitlements .get (pluginName );
624- if (pluginEntitlements == null ) {
625- return defaultEntitlements (pluginName , sourcePaths .get (pluginName ), requestingModule .getName ());
626- } else {
649+ switch (policyScope .kind ()) {
650+ case SERVER -> {
627651 return getModuleScopeEntitlements (
628- pluginEntitlements ,
629- getScopeName ( requestingModule ) ,
630- pluginName ,
631- sourcePaths . get ( pluginName )
652+ serverEntitlements ,
653+ moduleName ,
654+ SERVER . componentName ,
655+ getComponentPathFromClass ( requestingClass )
632656 );
633657 }
634- }
635-
636- if (requestingModule .isNamed () == false && requestingClass .getPackageName ().startsWith (apmAgentPackageName )) {
637- // The APM agent is the only thing running non-modular in the system classloader
638- return policyEntitlements (
639- APM_AGENT_COMPONENT_NAME ,
640- getComponentPathFromClass (requestingClass ),
641- ALL_UNNAMED ,
642- apmAgentEntitlements
643- );
644- }
645-
646- return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null , requestingModule .getName ());
647- }
648-
649- private static String getScopeName (Module requestingModule ) {
650- if (requestingModule .isNamed () == false ) {
651- return ALL_UNNAMED ;
652- } else {
653- return requestingModule .getName ();
658+ case APM_AGENT -> {
659+ // The APM agent is the only thing running non-modular in the system classloader
660+ return policyEntitlements (
661+ APM_AGENT .componentName ,
662+ getComponentPathFromClass (requestingClass ),
663+ ALL_UNNAMED ,
664+ apmAgentEntitlements
665+ );
666+ }
667+ case UNKNOWN -> {
668+ return defaultEntitlements (UNKNOWN .componentName , null , moduleName );
669+ }
670+ default -> {
671+ assert policyScope .kind () == PLUGIN ;
672+ var pluginEntitlements = pluginsEntitlements .get (componentName );
673+ if (pluginEntitlements == null ) {
674+ return defaultEntitlements (componentName , sourcePaths .get (componentName ), moduleName );
675+ } else {
676+ return getModuleScopeEntitlements (pluginEntitlements , moduleName , componentName , sourcePaths .get (componentName ));
677+ }
678+ }
654679 }
655680 }
656681
@@ -686,10 +711,6 @@ private ModuleEntitlements getModuleScopeEntitlements(
686711 return policyEntitlements (componentName , componentPath , scopeName , entitlements );
687712 }
688713
689- private static boolean isServerModule (Module requestingModule ) {
690- return requestingModule .isNamed () && requestingModule .getLayer () == ModuleLayer .boot ();
691- }
692-
693714 /**
694715 * Walks the stack to determine which class should be checked for entitlements.
695716 *
0 commit comments