Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,17 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
return;
}

String componentName = getEntitlements(requestingClass).componentName();
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], operation [%s]",
getEntitlements(requestingClass).componentName(),
"component [%s], module [%s], class [%s], operation [%s]",
componentName,
requestingClass.getModule().getName(),
requestingClass,
operationDescription.get()
),
callerClass
callerClass,
componentName
);
}

Expand Down Expand Up @@ -366,13 +368,14 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
if (canRead == false) {
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], entitlement [file], operation [read], path [%s]",
"component [%s], module [%s], class [%s], entitlement [file], operation [read], path [%s]",
entitlements.componentName(),
requestingClass.getModule().getName(),
requestingClass,
realPath == null ? path : Strings.format("%s -> %s", path, realPath)
),
callerClass
callerClass,
entitlements.componentName()
);
}
}
Expand All @@ -395,13 +398,14 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
if (entitlements.fileAccess().canWrite(path) == false) {
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], entitlement [file], operation [write], path [%s]",
"component [%s], module [%s], class [%s], entitlement [file], operation [write], path [%s]",
entitlements.componentName(),
requestingClass.getModule().getName(),
requestingClass,
path
),
callerClass
callerClass,
entitlements.componentName()
);
}
}
Expand Down Expand Up @@ -483,13 +487,14 @@ private void checkFlagEntitlement(
if (classEntitlements.hasEntitlement(entitlementClass) == false) {
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], entitlement [%s]",
"component [%s], module [%s], class [%s], entitlement [%s]",
classEntitlements.componentName(),
requestingClass.getModule().getName(),
requestingClass,
PolicyParser.getEntitlementTypeName(entitlementClass)
),
callerClass
callerClass,
classEntitlements.componentName()
);
}
logger.debug(
Expand Down Expand Up @@ -524,21 +529,29 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
}
notEntitled(
Strings.format(
"Not entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
"component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
entitlements.componentName(),
requestingClass.getModule().getName(),
requestingClass,
property
),
callerClass
callerClass,
entitlements.componentName()
);
}

private void notEntitled(String message, Class<?> callerClass) {
private void notEntitled(String message, Class<?> callerClass, String componentName) {
var exception = new NotEntitledException(message);
// Don't emit a log for muted classes, e.g. classes containing self tests
if (mutedClasses.contains(callerClass) == false) {
logger.warn(message, exception);
var moduleName = callerClass.getModule().getName();
var loggerSuffix = "." + componentName + "." + ((moduleName == null) ? ALL_UNNAMED : moduleName);
var notEntitledLogger = LogManager.getLogger(PolicyManager.class.getName() + loggerSuffix);
String frameInfoSuffix = StackWalker.getInstance(RETAIN_CLASS_REFERENCE)
.walk(this::findRequestingFrame)
.map(frame -> "\n\tat " + frame)
.orElse("");
notEntitledLogger.warn("Not entitled: " + message + frameInfoSuffix);
}
throw exception;
}
Expand Down Expand Up @@ -658,19 +671,18 @@ Class<?> requestingClass(Class<?> callerClass) {
return callerClass;
}
Optional<Class<?>> result = StackWalker.getInstance(RETAIN_CLASS_REFERENCE)
.walk(frames -> findRequestingClass(frames.map(StackFrame::getDeclaringClass)));
.walk(frames -> findRequestingFrame(frames).map(StackFrame::getDeclaringClass));
return result.orElse(null);
}

/**
* Given a stream of classes corresponding to the frames from a {@link StackWalker},
* returns the module whose entitlements should be checked.
* Given a stream of {@link StackFrame}s, identify the one whose entitlements should be checked.
*
* @throws NullPointerException if the requesting module is {@code null}
*/
Optional<Class<?>> findRequestingClass(Stream<Class<?>> classes) {
return classes.filter(c -> c.getModule() != entitlementsModule) // Ignore the entitlements library
.skip(1) // Skip the sensitive caller method
Optional<StackFrame> findRequestingFrame(Stream<StackFrame> frames) {
return frames.filter(f -> f.getDeclaringClass().getModule() != entitlementsModule) // ignore entitlements library
.skip(1) // Skip the sensitive caller method
.findFirst();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.junit.BeforeClass;

import java.io.IOException;
import java.lang.StackWalker.StackFrame;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.net.URL;
Expand Down Expand Up @@ -320,18 +321,21 @@ public void testRequestingModuleWithStackWalk() throws IOException, ClassNotFoun
assertEquals(
"Skip entitlement library and the instrumented method",
requestingClass,
policyManager.findRequestingClass(Stream.of(entitlementsClass, instrumentedClass, requestingClass, ignorableClass)).orElse(null)
policyManager.findRequestingFrame(
Stream.of(entitlementsClass, instrumentedClass, requestingClass, ignorableClass).map(MockFrame::new)
).map(StackFrame::getDeclaringClass).orElse(null)
);
assertEquals(
"Skip multiple library frames",
requestingClass,
policyManager.findRequestingClass(Stream.of(entitlementsClass, entitlementsClass, instrumentedClass, requestingClass))
.orElse(null)
policyManager.findRequestingFrame(
Stream.of(entitlementsClass, entitlementsClass, instrumentedClass, requestingClass).map(MockFrame::new)
).map(StackFrame::getDeclaringClass).orElse(null)
);
assertThrows(
"Non-modular caller frames are not supported",
NullPointerException.class,
() -> policyManager.findRequestingClass(Stream.of(entitlementsClass, null))
() -> policyManager.findRequestingFrame(Stream.of(entitlementsClass, null).map(MockFrame::new))
);
}

Expand Down Expand Up @@ -657,4 +661,47 @@ private static ModuleLayer createLayerForJar(Path jar, String moduleName) {
);
return moduleController.layer();
}

record MockFrame(Class<?> declaringClass) implements StackFrame {
@Override
public String getClassName() {
return getDeclaringClass().getName();
}

@Override
public String getMethodName() {
throw new UnsupportedOperationException();
}

@Override
public Class<?> getDeclaringClass() {
return declaringClass;
}

@Override
public int getByteCodeIndex() {
throw new UnsupportedOperationException();
}

@Override
public String getFileName() {
throw new UnsupportedOperationException();
}

@Override
public int getLineNumber() {
throw new UnsupportedOperationException();
}

@Override
public boolean isNativeMethod() {
throw new UnsupportedOperationException();
}

@Override
public StackTraceElement toStackTraceElement() {
throw new UnsupportedOperationException();
}
}

}
3 changes: 3 additions & 0 deletions modules/repository-gcs/src/main/config/log4j2.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
logger.org_elasticsearch_entitlement_runtime_policy_PolicyManager.name = org.elasticsearch.entitlement.runtime.policy.PolicyManager.repository-gcs.ALL-UNNAMED
logger.org_elasticsearch_entitlement_runtime_policy_PolicyManager.level = error

4 changes: 4 additions & 0 deletions modules/repository-s3/src/main/config/log4j2.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ logger.com_amazonaws_auth_profile_internal_BasicProfileConfigFileLoader.level =

logger.com_amazonaws_services_s3_internal_UseArnRegionResolver.name = com.amazonaws.services.s3.internal.UseArnRegionResolver
logger.com_amazonaws_services_s3_internal_UseArnRegionResolver.level = error

logger.org_elasticsearch_entitlement_runtime_policy_PolicyManager.name = org.elasticsearch.entitlement.runtime.policy.PolicyManager.repository-s3.software.amazon.awssdk.profiles
logger.org_elasticsearch_entitlement_runtime_policy_PolicyManager.level = error