59
59
import static java .util .zip .ZipFile .OPEN_READ ;
60
60
61
61
public 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 );
63
66
64
67
static final String UNKNOWN_COMPONENT_NAME = "(unknown)" ;
65
68
static final String SERVER_COMPONENT_NAME = "(server)" ;
@@ -76,7 +79,8 @@ public class PolicyManager {
76
79
record ModuleEntitlements (
77
80
String componentName ,
78
81
Map <Class <? extends Entitlement >, List <Entitlement >> entitlementsByType ,
79
- FileAccessTree fileAccess
82
+ FileAccessTree fileAccess ,
83
+ Logger logger
80
84
) {
81
85
82
86
ModuleEntitlements {
@@ -101,8 +105,13 @@ private FileAccessTree getDefaultFileAccess(String componentName, Path component
101
105
}
102
106
103
107
// 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
+ );
106
115
}
107
116
108
117
// pkg private for testing
@@ -116,7 +125,8 @@ ModuleEntitlements policyEntitlements(String componentName, Path componentPath,
116
125
return new ModuleEntitlements (
117
126
componentName ,
118
127
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 )
120
130
);
121
131
}
122
132
@@ -255,17 +265,17 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
255
265
return ;
256
266
}
257
267
258
- String componentName = getEntitlements (requestingClass ). componentName ( );
268
+ ModuleEntitlements entitlements = getEntitlements (requestingClass );
259
269
notEntitled (
260
270
Strings .format (
261
271
"component [%s], module [%s], class [%s], operation [%s]" ,
262
- componentName ,
272
+ entitlements . componentName () ,
263
273
requestingClass .getModule ().getName (),
264
274
requestingClass ,
265
275
operationDescription .get ()
266
276
),
267
277
callerClass ,
268
- componentName
278
+ entitlements
269
279
);
270
280
}
271
281
@@ -323,7 +333,7 @@ public void checkFileRead(Class<?> callerClass, File file) {
323
333
private static boolean isPathOnDefaultFilesystem (Path path ) {
324
334
var pathFileSystemClass = path .getFileSystem ().getClass ();
325
335
if (path .getFileSystem ().getClass () != DEFAULT_FILESYSTEM_CLASS ) {
326
- logger .trace (
336
+ generalLogger .trace (
327
337
() -> Strings .format (
328
338
"File entitlement trivially allowed: path [%s] is for a different FileSystem class [%s], default is [%s]" ,
329
339
path .toString (),
@@ -383,7 +393,7 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
383
393
realPath == null ? path : Strings .format ("%s -> %s" , path , realPath )
384
394
),
385
395
callerClass ,
386
- entitlements . componentName ()
396
+ entitlements
387
397
);
388
398
}
389
399
}
@@ -413,7 +423,7 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
413
423
path
414
424
),
415
425
callerClass ,
416
- entitlements . componentName ()
426
+ entitlements
417
427
);
418
428
}
419
429
}
@@ -502,18 +512,19 @@ private void checkFlagEntitlement(
502
512
PolicyParser .getEntitlementTypeName (entitlementClass )
503
513
),
504
514
callerClass ,
505
- classEntitlements . componentName ()
515
+ classEntitlements
506
516
);
507
517
}
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
+ );
517
528
}
518
529
519
530
public void checkWriteProperty (Class <?> callerClass , String property ) {
@@ -524,15 +535,16 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
524
535
525
536
ModuleEntitlements entitlements = getEntitlements (requestingClass );
526
537
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
+ );
536
548
return ;
537
549
}
538
550
notEntitled (
@@ -544,22 +556,34 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
544
556
property
545
557
),
546
558
callerClass ,
547
- entitlements . componentName ()
559
+ entitlements
548
560
);
549
561
}
550
562
551
- private void notEntitled (String message , Class <?> callerClass , String componentName ) {
563
+ private void notEntitled (String message , Class <?> callerClass , ModuleEntitlements entitlements ) {
552
564
var exception = new NotEntitledException (message );
553
565
// Don't emit a log for muted classes, e.g. classes containing self tests
554
566
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 );
559
568
}
560
569
throw exception ;
561
570
}
562
571
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
+
563
587
public void checkManageThreadsEntitlement (Class <?> callerClass ) {
564
588
checkEntitlementPresent (callerClass , ManageThreadsEntitlement .class );
565
589
}
@@ -592,7 +616,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
592
616
if (pluginName != null ) {
593
617
var pluginEntitlements = pluginsEntitlements .get (pluginName );
594
618
if (pluginEntitlements == null ) {
595
- return defaultEntitlements (pluginName , sourcePaths .get (pluginName ));
619
+ return defaultEntitlements (pluginName , sourcePaths .get (pluginName ), requestingModule . getName () );
596
620
} else {
597
621
return getModuleScopeEntitlements (
598
622
pluginEntitlements ,
@@ -613,7 +637,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
613
637
);
614
638
}
615
639
616
- return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null );
640
+ return defaultEntitlements (UNKNOWN_COMPONENT_NAME , null , requestingModule . getName () );
617
641
}
618
642
619
643
private static String getScopeName (Module requestingModule ) {
@@ -634,7 +658,7 @@ static Path getComponentPathFromClass(Class<?> requestingClass) {
634
658
return Paths .get (codeSource .getLocation ().toURI ());
635
659
} catch (Exception e ) {
636
660
// 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 (
638
662
"Cannot get component path for [{}]: [{}] cannot be converted to a valid Path" ,
639
663
requestingClass .getName (),
640
664
codeSource .getLocation ().toString ()
@@ -651,7 +675,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
651
675
) {
652
676
var entitlements = scopeEntitlements .get (scopeName );
653
677
if (entitlements == null ) {
654
- return defaultEntitlements (componentName , componentPath );
678
+ return defaultEntitlements (componentName , componentPath , scopeName );
655
679
}
656
680
return policyEntitlements (componentName , componentPath , scopeName , entitlements );
657
681
}
@@ -694,18 +718,18 @@ Optional<StackFrame> findRequestingFrame(Stream<StackFrame> frames) {
694
718
* @return true if permission is granted regardless of the entitlement
695
719
*/
696
720
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 ());
699
723
}
700
724
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" );
702
726
return true ;
703
727
}
704
728
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 ());
706
730
return true ;
707
731
}
708
- logger .trace ("Entitlement not trivially allowed" );
732
+ generalLogger .trace ("Entitlement not trivially allowed" );
709
733
return false ;
710
734
}
711
735
0 commit comments