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 @@ -122,7 +122,7 @@ public static void bootstrap(
suppressFailureLogPackages
);
exportInitializationToAgent();
loadAgent(findAgentJar());
loadAgent(findAgentJar(), EntitlementInitialization.class.getName());
}

private static Path getUserHome() {
Expand All @@ -134,11 +134,11 @@ private static Path getUserHome() {
}

@SuppressForbidden(reason = "The VirtualMachine API is the only way to attach a java agent dynamically")
private static void loadAgent(String agentPath) {
static void loadAgent(String agentPath, String entitlementInitializationClassName) {
try {
VirtualMachine vm = VirtualMachine.attach(Long.toString(ProcessHandle.current().pid()));
try {
vm.loadAgent(agentPath, EntitlementInitialization.class.getName());
vm.loadAgent(agentPath, entitlementInitializationClassName);
} finally {
vm.detach();
}
Expand All @@ -154,7 +154,7 @@ private static void exportInitializationToAgent() {
EntitlementInitialization.class.getModule().addExports(initPkg, unnamedModule);
}

public static String findAgentJar() {
static String findAgentJar() {
String propertyName = "es.entitlement.agentJar";
String propertyValue = System.getProperty(propertyName);
if (propertyValue != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ public class EntitlementInitialization {

private static final Module ENTITLEMENTS_MODULE = PolicyManager.class.getModule();

private static ElasticsearchEntitlementChecker manager;
private static ElasticsearchEntitlementChecker checker;

// Note: referenced by bridge reflectively
public static EntitlementChecker checker() {
return manager;
return checker;
}

/**
Expand All @@ -63,18 +63,34 @@ public static EntitlementChecker checker() {
* @param inst the JVM instrumentation class instance
*/
public static void initialize(Instrumentation inst) throws Exception {
manager = initChecker();
checker = initChecker(inst, createPolicyManager());
}

var latestCheckerInterface = EntitlementCheckerUtils.getVersionSpecificCheckerClass(
EntitlementChecker.class,
Runtime.version().feature()
private static PolicyCheckerImpl createPolicyChecker(PolicyManager policyManager) {
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
return new PolicyCheckerImpl(
bootstrapArgs.suppressFailureLogPackages(),
ENTITLEMENTS_MODULE,
policyManager,
bootstrapArgs.pathLookup()
);
var verifyBytecode = Booleans.parseBoolean(System.getProperty("es.entitlements.verify_bytecode", "false"));
if (verifyBytecode) {
ensureClassesSensitiveToVerificationAreInitialized();
}
}

DynamicInstrumentation.initialize(inst, latestCheckerInterface, verifyBytecode);
private static PolicyManager createPolicyManager() {
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
PathLookup pathLookup = bootstrapArgs.pathLookup();

FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);

return new PolicyManager(
HardcodedEntitlements.serverPolicy(pathLookup.pidFile(), bootstrapArgs.serverPolicyPatch()),
HardcodedEntitlements.agentEntitlements(),
pluginPolicies,
EntitlementBootstrap.bootstrapArgs().scopeResolver(),
EntitlementBootstrap.bootstrapArgs().sourcePaths(),
pathLookup
);
}

/**
Expand All @@ -101,9 +117,8 @@ private static void ensureClassesSensitiveToVerificationAreInitialized() {
}
}

private static ElasticsearchEntitlementChecker initChecker() {
final PolicyChecker policyChecker = createPolicyChecker();

static ElasticsearchEntitlementChecker initChecker(Instrumentation inst, PolicyManager policyManager) throws Exception {
final PolicyChecker policyChecker = createPolicyChecker(policyManager);
final Class<?> clazz = EntitlementCheckerUtils.getVersionSpecificCheckerClass(
ElasticsearchEntitlementChecker.class,
Runtime.version().feature()
Expand All @@ -115,34 +130,25 @@ private static ElasticsearchEntitlementChecker initChecker() {
} catch (NoSuchMethodException e) {
throw new AssertionError("entitlement impl is missing required constructor: [" + clazz.getName() + "]", e);
}

ElasticsearchEntitlementChecker checker;
try {
return (ElasticsearchEntitlementChecker) constructor.newInstance(policyChecker);
checker = (ElasticsearchEntitlementChecker) constructor.newInstance(policyChecker);
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
throw new AssertionError(e);
}
}

private static PolicyCheckerImpl createPolicyChecker() {
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
PathLookup pathLookup = bootstrapArgs.pathLookup();

FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
var verifyBytecode = Booleans.parseBoolean(System.getProperty("es.entitlements.verify_bytecode", "false"));
if (verifyBytecode) {
ensureClassesSensitiveToVerificationAreInitialized();
}

PolicyManager policyManager = new PolicyManager(
HardcodedEntitlements.serverPolicy(pathLookup.pidFile(), bootstrapArgs.serverPolicyPatch()),
HardcodedEntitlements.agentEntitlements(),
pluginPolicies,
EntitlementBootstrap.bootstrapArgs().scopeResolver(),
EntitlementBootstrap.bootstrapArgs().sourcePaths(),
pathLookup
DynamicInstrumentation.initialize(
inst,
EntitlementCheckerUtils.getVersionSpecificCheckerClass(EntitlementChecker.class, Runtime.version().feature()),
verifyBytecode
);
return new PolicyCheckerImpl(
bootstrapArgs.suppressFailureLogPackages(),
ENTITLEMENTS_MODULE,
policyManager,
bootstrapArgs.pathLookup()
);
}

return checker;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,31 @@ public static PluginDescriptor readFromProperties(final Path pluginDir) throws I
return descriptor;
}

/**
* Reads the internal descriptor for a classic plugin.
*
* @param stream the InputStream from which to read the plugin data
* @return the plugin info
* @throws IOException if an I/O exception occurred reading the plugin descriptor
*/
public static PluginDescriptor readInternalDescriptorFromStream(InputStream stream) throws IOException {
final Map<String, String> propsMap;
{
final Properties props = new Properties();
props.load(stream);
propsMap = props.stringPropertyNames().stream().collect(Collectors.toMap(Function.identity(), props::getProperty));
}

PluginDescriptor descriptor = readerInternalDescriptor(propsMap, INTERNAL_DESCRIPTOR_FILENAME);
String name = descriptor.getName();

if (propsMap.isEmpty() == false) {
throw new IllegalArgumentException("Unknown properties for plugin [" + name + "] in plugin descriptor: " + propsMap.keySet());
}

return descriptor;
}

private static PluginDescriptor readerInternalDescriptor(Map<String, String> propsMap, String filename) {
String name = readNonEmptyString(propsMap, filename, "name");
String desc = readString(propsMap, name, "description");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void assertBothDescriptors(Consumer<DescriptorWriter> assertions) {
assertions.accept(PluginDescriptorTests::mockStableDescriptor);
}

public void testReadInternalDescriptor() throws Exception {
public void testReadInternalDescriptorFromStream() throws Exception {
PluginDescriptor info = mockInternalDescriptor();
assertEquals("my_plugin", info.getName());
assertEquals("fake desc", info.getDescription());
Expand Down
1 change: 1 addition & 0 deletions test/framework/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
api project(':libs:ssl-config')
api project(":server")
api project(":libs:cli")
api project(":libs:entitlement:bridge")
api "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}"
api "junit:junit:${versions.junit}"
api "org.hamcrest:hamcrest:${versions.hamcrest}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@

import java.util.List;

record TestBuildInfo(String component, List<TestBuildInfoLocation> locations) {}
public record TestBuildInfo(String component, List<TestBuildInfoLocation> locations) {}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import java.util.ArrayList;
import java.util.List;

class TestBuildInfoParser {
public class TestBuildInfoParser {

private static final String PLUGIN_TEST_BUILD_INFO_RESOURCES = "META-INF/plugin-test-build-info.json";
private static final String SERVER_TEST_BUILD_INFO_RESOURCE = "META-INF/server-test-build-info.json";
Expand Down Expand Up @@ -75,7 +75,7 @@ static TestBuildInfo fromXContent(final XContentParser parser) throws IOExceptio
return PARSER.parse(parser, null).build();
}

static List<TestBuildInfo> parseAllPluginTestBuildInfo() throws IOException {
public static List<TestBuildInfo> parseAllPluginTestBuildInfo() throws IOException {
var xContent = XContentFactory.xContent(XContentType.JSON);
List<TestBuildInfo> pluginsTestBuildInfos = new ArrayList<>();
var resources = TestBuildInfoParser.class.getClassLoader().getResources(PLUGIN_TEST_BUILD_INFO_RESOURCES);
Expand All @@ -88,7 +88,7 @@ static List<TestBuildInfo> parseAllPluginTestBuildInfo() throws IOException {
return pluginsTestBuildInfos;
}

static TestBuildInfo parseServerTestBuildInfo() throws IOException {
public static TestBuildInfo parseServerTestBuildInfo() throws IOException {
var xContent = XContentFactory.xContent(XContentType.JSON);
var resource = TestBuildInfoParser.class.getClassLoader().getResource(SERVER_TEST_BUILD_INFO_RESOURCE);
// No test-build-info for server: this might be a non-gradle build. Proceed without TestBuildInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.Map;
import java.util.function.Function;

record TestScopeResolver(Map<String, PolicyManager.PolicyScope> scopeMap) {
public record TestScopeResolver(Map<String, PolicyManager.PolicyScope> scopeMap) {

private static final Logger logger = LogManager.getLogger(TestScopeResolver.class);

Expand All @@ -38,7 +38,7 @@ PolicyManager.PolicyScope getScope(Class<?> callerClass) {
return scope;
}

static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
TestBuildInfo serverBuildInfo,
List<TestBuildInfo> pluginsBuildInfo
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.entitlement.bootstrap;

import org.elasticsearch.entitlement.initialization.TestEntitlementInitialization;
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
import org.elasticsearch.logging.LogManager;
import org.elasticsearch.logging.Logger;

public class TestEntitlementBootstrap {

private static final Logger logger = LogManager.getLogger(TestEntitlementBootstrap.class);
private static BootstrapArgs bootstrapArgs;

/**
* Activates entitlement checking in tests.
* @param bootstrapArgs arguments used for and passed to entitlement initialization
*/
public static void bootstrap(BootstrapArgs bootstrapArgs) {
assert bootstrapArgs != null;
TestEntitlementBootstrap.bootstrapArgs = bootstrapArgs;
logger.debug("Loading entitlement agent");
EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), TestEntitlementInitialization.class.getName());
}

public static BootstrapArgs bootstrapArgs() {
return bootstrapArgs;
}

public record BootstrapArgs(PathLookup pathLookup) {}
}
Loading