5959import static java .util .zip .ZipFile .OPEN_READ ;
6060
6161public class PolicyManager {
62- private static final Logger logger = LogManager .getLogger (PolicyManager .class );
62+ /**
63+ * Use this if you don't have a {@link ModuleEntitlements} in hand.
64+ */
65+ private static final Logger generalLogger = LogManager .getLogger (PolicyManager .class );
6366
6467 static final String UNKNOWN_COMPONENT_NAME = "(unknown)" ;
6568 static final String SERVER_COMPONENT_NAME = "(server)" ;
@@ -76,7 +79,8 @@ public class PolicyManager {
7679 record ModuleEntitlements (
7780 String componentName ,
7881 Map <Class <? extends Entitlement >, List <Entitlement >> entitlementsByType ,
79- FileAccessTree fileAccess
82+ FileAccessTree fileAccess ,
83+ Logger logger
8084 ) {
8185
8286 ModuleEntitlements {
@@ -101,8 +105,13 @@ private FileAccessTree getDefaultFileAccess(String componentName, Path component
101105 }
102106
103107 // pkg private for testing
104- ModuleEntitlements defaultEntitlements (String componentName , Path componentPath ) {
105- return new ModuleEntitlements (componentName , Map .of (), getDefaultFileAccess (componentName , componentPath ));
108+ ModuleEntitlements defaultEntitlements (String componentName , Path componentPath , String moduleName ) {
109+ return new ModuleEntitlements (
110+ componentName ,
111+ Map .of (),
112+ getDefaultFileAccess (componentName , componentPath ),
113+ getLogger (componentName , moduleName )
114+ );
106115 }
107116
108117 // pkg private for testing
@@ -116,7 +125,8 @@ ModuleEntitlements policyEntitlements(String componentName, Path componentPath,
116125 return new ModuleEntitlements (
117126 componentName ,
118127 entitlements .stream ().collect (groupingBy (Entitlement ::getClass )),
119- FileAccessTree .of (componentName , moduleName , filesEntitlement , pathLookup , componentPath , exclusivePaths )
128+ FileAccessTree .of (componentName , moduleName , filesEntitlement , pathLookup , componentPath , exclusivePaths ),
129+ getLogger (componentName , moduleName )
120130 );
121131 }
122132
@@ -255,17 +265,17 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
255265 return ;
256266 }
257267
258- String componentName = getEntitlements (requestingClass ). componentName ( );
268+ ModuleEntitlements entitlements = getEntitlements (requestingClass );
259269 notEntitled (
260270 Strings .format (
261271 "component [%s], module [%s], class [%s], operation [%s]" ,
262- componentName ,
272+ entitlements . componentName () ,
263273 requestingClass .getModule ().getName (),
264274 requestingClass ,
265275 operationDescription .get ()
266276 ),
267277 callerClass ,
268- componentName
278+ entitlements
269279 );
270280 }
271281
@@ -323,7 +333,7 @@ public void checkFileRead(Class<?> callerClass, File file) {
323333 private static boolean isPathOnDefaultFilesystem (Path path ) {
324334 var pathFileSystemClass = path .getFileSystem ().getClass ();
325335 if (path .getFileSystem ().getClass () != DEFAULT_FILESYSTEM_CLASS ) {
326- logger .trace (
336+ generalLogger .trace (
327337 () -> Strings .format (
328338 "File entitlement trivially allowed: path [%s] is for a different FileSystem class [%s], default is [%s]" ,
329339 path .toString (),
@@ -383,7 +393,7 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
383393 realPath == null ? path : Strings .format ("%s -> %s" , path , realPath )
384394 ),
385395 callerClass ,
386- entitlements . componentName ()
396+ entitlements
387397 );
388398 }
389399 }
@@ -413,7 +423,7 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
413423 path
414424 ),
415425 callerClass ,
416- entitlements . componentName ()
426+ entitlements
417427 );
418428 }
419429 }
@@ -502,18 +512,19 @@ private void checkFlagEntitlement(
502512 PolicyParser .getEntitlementTypeName (entitlementClass )
503513 ),
504514 callerClass ,
505- classEntitlements . componentName ()
515+ classEntitlements
506516 );
507517 }
508- logger .debug (
509- () -> Strings .format (
510- "Entitled: component [%s], module [%s], class [%s], entitlement [%s]" ,
511- classEntitlements .componentName (),
512- requestingClass .getModule ().getName (),
513- requestingClass ,
514- PolicyParser .getEntitlementTypeName (entitlementClass )
515- )
516- );
518+ classEntitlements .logger ()
519+ .debug (
520+ () -> Strings .format (
521+ "Entitled: component [%s], module [%s], class [%s], entitlement [%s]" ,
522+ classEntitlements .componentName (),
523+ requestingClass .getModule ().getName (),
524+ requestingClass ,
525+ PolicyParser .getEntitlementTypeName (entitlementClass )
526+ )
527+ );
517528 }
518529
519530 public void checkWriteProperty (Class <?> callerClass , String property ) {
@@ -524,15 +535,16 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
524535
525536 ModuleEntitlements entitlements = getEntitlements (requestingClass );
526537 if (entitlements .getEntitlements (WriteSystemPropertiesEntitlement .class ).anyMatch (e -> e .properties ().contains (property ))) {
527- logger .debug (
528- () -> Strings .format (
529- "Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]" ,
530- entitlements .componentName (),
531- requestingClass .getModule ().getName (),
532- requestingClass ,
533- property
534- )
535- );
538+ entitlements .logger ()
539+ .debug (
540+ () -> Strings .format (
541+ "Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]" ,
542+ entitlements .componentName (),
543+ requestingClass .getModule ().getName (),
544+ requestingClass ,
545+ property
546+ )
547+ );
536548 return ;
537549 }
538550 notEntitled (
@@ -544,22 +556,34 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
544556 property
545557 ),
546558 callerClass ,
547- entitlements . componentName ()
559+ entitlements
548560 );
549561 }
550562
551- private void notEntitled (String message , Class <?> callerClass , String componentName ) {
563+ private void notEntitled (String message , Class <?> callerClass , ModuleEntitlements entitlements ) {
552564 var exception = new NotEntitledException (message );
553565 // Don't emit a log for muted classes, e.g. classes containing self tests
554566 if (mutedClasses .contains (callerClass ) == false ) {
555- var moduleName = callerClass .getModule ().getName ();
556- var loggerSuffix = "." + componentName + "." + ((moduleName == null ) ? ALL_UNNAMED : moduleName );
557- var notEntitledLogger = LogManager .getLogger (PolicyManager .class .getName () + loggerSuffix );
558- notEntitledLogger .warn ("Not entitled:" , exception );
567+ entitlements .logger ().warn ("Not entitled:" , exception );
559568 }
560569 throw exception ;
561570 }
562571
572+ private static Logger getLogger (String componentName , String moduleName ) {
573+ var loggerSuffix = "." + componentName + "." + ((moduleName == null ) ? ALL_UNNAMED : moduleName );
574+ return MODULE_LOGGERS .computeIfAbsent (PolicyManager .class .getName () + loggerSuffix , LogManager ::getLogger );
575+ }
576+
577+ /**
578+ * We want to use the same {@link Logger} object for a given name, because we want {@link ModuleEntitlements}
579+ * {@code equals} and {@code hashCode} to work.
580+ * <p>
581+ * This would not be required if LogManager
582+ * <a href="https://github.com/elastic/elasticsearch/issues/87511">memoized the loggers</a>,
583+ * but here we are.
584+ */
585+ private static final ConcurrentHashMap <String , Logger > MODULE_LOGGERS = new ConcurrentHashMap <>();
586+
563587 public void checkManageThreadsEntitlement (Class <?> callerClass ) {
564588 checkEntitlementPresent (callerClass , ManageThreadsEntitlement .class );
565589 }
@@ -592,7 +616,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
592616 if (pluginName != null ) {
593617 var pluginEntitlements = pluginsEntitlements .get (pluginName );
594618 if (pluginEntitlements == null ) {
595- return defaultEntitlements (pluginName , sourcePaths .get (pluginName ));
619+ return defaultEntitlements (pluginName , sourcePaths .get (pluginName ), requestingModule . getName () );
596620 } else {
597621 return getModuleScopeEntitlements (
598622 pluginEntitlements ,
@@ -613,7 +637,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
613637 );
614638 }
615639
616- return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null );
640+ return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null , requestingModule . getName () );
617641 }
618642
619643 private static String getScopeName (Module requestingModule ) {
@@ -634,7 +658,7 @@ static Path getComponentPathFromClass(Class<?> requestingClass) {
634658 return Paths .get (codeSource .getLocation ().toURI ());
635659 } catch (Exception e ) {
636660 // If we get a URISyntaxException, or any other Exception due to an invalid URI, we return null to safely skip this location
637- logger .info (
661+ generalLogger .info (
638662 "Cannot get component path for [{}]: [{}] cannot be converted to a valid Path" ,
639663 requestingClass .getName (),
640664 codeSource .getLocation ().toString ()
@@ -651,7 +675,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
651675 ) {
652676 var entitlements = scopeEntitlements .get (scopeName );
653677 if (entitlements == null ) {
654- return defaultEntitlements (componentName , componentPath );
678+ return defaultEntitlements (componentName , componentPath , scopeName );
655679 }
656680 return policyEntitlements (componentName , componentPath , scopeName , entitlements );
657681 }
@@ -694,18 +718,18 @@ Optional<StackFrame> findRequestingFrame(Stream<StackFrame> frames) {
694718 * @return true if permission is granted regardless of the entitlement
695719 */
696720 private static boolean isTriviallyAllowed (Class <?> requestingClass ) {
697- if (logger .isTraceEnabled ()) {
698- logger .trace ("Stack trace for upcoming trivially-allowed check" , new Exception ());
721+ if (generalLogger .isTraceEnabled ()) {
722+ generalLogger .trace ("Stack trace for upcoming trivially-allowed check" , new Exception ());
699723 }
700724 if (requestingClass == null ) {
701- logger .debug ("Entitlement trivially allowed: no caller frames outside the entitlement library" );
725+ generalLogger .debug ("Entitlement trivially allowed: no caller frames outside the entitlement library" );
702726 return true ;
703727 }
704728 if (systemModules .contains (requestingClass .getModule ())) {
705- logger .debug ("Entitlement trivially allowed from system module [{}]" , requestingClass .getModule ().getName ());
729+ generalLogger .debug ("Entitlement trivially allowed from system module [{}]" , requestingClass .getModule ().getName ());
706730 return true ;
707731 }
708- logger .trace ("Entitlement not trivially allowed" );
732+ generalLogger .trace ("Entitlement not trivially allowed" );
709733 return false ;
710734 }
711735
0 commit comments