Skip to content

Commit 3bccc78

Browse files
committed
Merge branch 'main' of github.com:elastic/elasticsearch into esql-categorize-multiple-groupings
2 parents 0b0be87 + e7a4436 commit 3bccc78

File tree

18 files changed

+106
-81
lines changed

18 files changed

+106
-81
lines changed

libs/entitlement/qa/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ apply plugin: 'elasticsearch.internal-test-artifact'
1313

1414
dependencies {
1515
javaRestTestImplementation project(':libs:entitlement:qa:common')
16-
clusterPlugins project(':libs:entitlement:qa:entitlement-allowed')
17-
clusterPlugins project(':libs:entitlement:qa:entitlement-allowed-nonmodular')
16+
clusterModules project(':libs:entitlement:qa:entitlement-allowed')
17+
clusterModules project(':libs:entitlement:qa:entitlement-allowed-nonmodular')
1818
clusterPlugins project(':libs:entitlement:qa:entitlement-denied')
1919
clusterPlugins project(':libs:entitlement:qa:entitlement-denied-nonmodular')
2020
}

libs/entitlement/qa/src/javaRestTest/java/org/elasticsearch/entitlement/qa/EntitlementsAllowedIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public class EntitlementsAllowedIT extends ESRestTestCase {
2828

2929
@ClassRule
3030
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
31-
.plugin("entitlement-allowed")
32-
.plugin("entitlement-allowed-nonmodular")
31+
.module("entitlement-allowed")
32+
.module("entitlement-allowed-nonmodular")
3333
.systemProperty("es.entitlements.enabled", "true")
3434
.setting("xpack.security.enabled", "false")
3535
.build();

libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import com.sun.tools.attach.VirtualMachine;
1616

1717
import org.elasticsearch.core.SuppressForbidden;
18-
import org.elasticsearch.core.Tuple;
1918
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
2019
import org.elasticsearch.logging.LogManager;
2120
import org.elasticsearch.logging.Logger;
@@ -29,7 +28,9 @@
2928

3029
public class EntitlementBootstrap {
3130

32-
public record BootstrapArgs(Collection<Tuple<Path, Boolean>> pluginData, Function<Class<?>, String> pluginResolver) {}
31+
public record PluginData(Path pluginPath, boolean isModular, boolean isExternalPlugin) {}
32+
33+
public record BootstrapArgs(Collection<PluginData> pluginData, Function<Class<?>, String> pluginResolver) {}
3334

3435
private static BootstrapArgs bootstrapArgs;
3536

@@ -40,11 +41,11 @@ public static BootstrapArgs bootstrapArgs() {
4041
/**
4142
* Activates entitlement checking. Once this method returns, calls to methods protected by Entitlements from classes without a valid
4243
* policy will throw {@link org.elasticsearch.entitlement.runtime.api.NotEntitledException}.
43-
* @param pluginData a collection of (plugin path, boolean), that holds the paths of all the installed Elasticsearch modules and
44-
* plugins, and whether they are Java modular or not.
44+
* @param pluginData a collection of (plugin path, boolean, boolean), that holds the paths of all the installed Elasticsearch modules
45+
* and plugins, whether they are Java modular or not, and whether they are Elasticsearch modules or external plugins.
4546
* @param pluginResolver a functor to map a Java Class to the plugin it belongs to (the plugin name).
4647
*/
47-
public static void bootstrap(Collection<Tuple<Path, Boolean>> pluginData, Function<Class<?>, String> pluginResolver) {
48+
public static void bootstrap(Collection<PluginData> pluginData, Function<Class<?>, String> pluginResolver) {
4849
logger.debug("Loading entitlement agent");
4950
if (EntitlementBootstrap.bootstrapArgs != null) {
5051
throw new IllegalStateException("plugin data is already set");

libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
package org.elasticsearch.entitlement.initialization;
1111

12-
import org.elasticsearch.core.Tuple;
1312
import org.elasticsearch.core.internal.provider.ProviderLocator;
1413
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
1514
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
@@ -96,25 +95,25 @@ private static PolicyManager createPolicyManager() throws IOException {
9695
return new PolicyManager(serverPolicy, pluginPolicies, EntitlementBootstrap.bootstrapArgs().pluginResolver());
9796
}
9897

99-
private static Map<String, Policy> createPluginPolicies(Collection<Tuple<Path, Boolean>> pluginData) throws IOException {
98+
private static Map<String, Policy> createPluginPolicies(Collection<EntitlementBootstrap.PluginData> pluginData) throws IOException {
10099
Map<String, Policy> pluginPolicies = new HashMap<>(pluginData.size());
101-
for (Tuple<Path, Boolean> entry : pluginData) {
102-
Path pluginRoot = entry.v1();
103-
boolean isModular = entry.v2();
104-
100+
for (var entry : pluginData) {
101+
Path pluginRoot = entry.pluginPath();
105102
String pluginName = pluginRoot.getFileName().toString();
106-
final Policy policy = loadPluginPolicy(pluginRoot, isModular, pluginName);
103+
104+
final Policy policy = loadPluginPolicy(pluginRoot, entry.isModular(), pluginName, entry.isExternalPlugin());
107105

108106
pluginPolicies.put(pluginName, policy);
109107
}
110108
return pluginPolicies;
111109
}
112110

113-
private static Policy loadPluginPolicy(Path pluginRoot, boolean isModular, String pluginName) throws IOException {
111+
private static Policy loadPluginPolicy(Path pluginRoot, boolean isModular, String pluginName, boolean isExternalPlugin)
112+
throws IOException {
114113
Path policyFile = pluginRoot.resolve(POLICY_FILE_NAME);
115114

116115
final Set<String> moduleNames = getModuleNames(pluginRoot, isModular);
117-
final Policy policy = parsePolicyIfExists(pluginName, policyFile);
116+
final Policy policy = parsePolicyIfExists(pluginName, policyFile, isExternalPlugin);
118117

119118
// TODO: should this check actually be part of the parser?
120119
for (Scope scope : policy.scopes) {
@@ -125,9 +124,9 @@ private static Policy loadPluginPolicy(Path pluginRoot, boolean isModular, Strin
125124
return policy;
126125
}
127126

128-
private static Policy parsePolicyIfExists(String pluginName, Path policyFile) throws IOException {
127+
private static Policy parsePolicyIfExists(String pluginName, Path policyFile, boolean isExternalPlugin) throws IOException {
129128
if (Files.exists(policyFile)) {
130-
return new PolicyParser(Files.newInputStream(policyFile, StandardOpenOption.READ), pluginName).parsePolicy();
129+
return new PolicyParser(Files.newInputStream(policyFile, StandardOpenOption.READ), pluginName, isExternalPlugin).parsePolicy();
131130
}
132131
return new Policy(pluginName, List.of());
133132
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/ExternalEntitlement.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,12 @@
3333
* have to match the parameter names of the constructor.
3434
*/
3535
String[] parameterNames() default {};
36+
37+
/**
38+
* This flag indicates if this Entitlement can be used in external plugins,
39+
* or if it can be used only in Elasticsearch modules ("internal" plugins).
40+
* Using an entitlement that is not {@code pluginsAccessible} in an external
41+
* plugin policy will throw in exception while parsing.
42+
*/
43+
boolean esModulesOnly() default true;
3644
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileEntitlement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class FileEntitlement implements Entitlement {
2626
private final String path;
2727
private final int actions;
2828

29-
@ExternalEntitlement(parameterNames = { "path", "actions" })
29+
@ExternalEntitlement(parameterNames = { "path", "actions" }, esModulesOnly = false)
3030
public FileEntitlement(String path, List<String> actionsList) {
3131
this.path = path;
3232
int actionsInt = 0;

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class PolicyParser {
3939

4040
protected final XContentParser policyParser;
4141
protected final String policyName;
42+
private final boolean isExternalPlugin;
4243

4344
static String getEntitlementTypeName(Class<? extends Entitlement> entitlementClass) {
4445
var entitlementClassName = entitlementClass.getSimpleName();
@@ -56,9 +57,10 @@ static String getEntitlementTypeName(Class<? extends Entitlement> entitlementCla
5657
.collect(Collectors.joining("_"));
5758
}
5859

59-
public PolicyParser(InputStream inputStream, String policyName) throws IOException {
60+
public PolicyParser(InputStream inputStream, String policyName, boolean isExternalPlugin) throws IOException {
6061
this.policyParser = YamlXContent.yamlXContent.createParser(XContentParserConfiguration.EMPTY, Objects.requireNonNull(inputStream));
6162
this.policyName = policyName;
63+
this.isExternalPlugin = isExternalPlugin;
6264
}
6365

6466
public Policy parsePolicy() {
@@ -125,6 +127,10 @@ protected Entitlement parseEntitlement(String scopeName, String entitlementType)
125127
throw newPolicyParserException(scopeName, "unknown entitlement type [" + entitlementType + "]");
126128
}
127129

130+
if (entitlementMetadata.esModulesOnly() && isExternalPlugin) {
131+
throw newPolicyParserException("entitlement type [" + entitlementType + "] is allowed only on modules");
132+
}
133+
128134
Class<?>[] parameterTypes = entitlementConstructor.getParameterTypes();
129135
String[] parametersNames = entitlementMetadata.parameterNames();
130136

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserFailureTests.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class PolicyParserFailureTests extends ESTestCase {
1919
public void testParserSyntaxFailures() {
2020
PolicyParserException ppe = expectThrows(
2121
PolicyParserException.class,
22-
() -> new PolicyParser(new ByteArrayInputStream("[]".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml")
22+
() -> new PolicyParser(new ByteArrayInputStream("[]".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false)
2323
.parsePolicy()
2424
);
2525
assertEquals("[1:1] policy parsing error for [test-failure-policy.yaml]: expected object <scope name>", ppe.getMessage());
@@ -29,7 +29,7 @@ public void testEntitlementDoesNotExist() {
2929
PolicyParserException ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream("""
3030
entitlement-module-name:
3131
- does_not_exist: {}
32-
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml").parsePolicy());
32+
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy());
3333
assertEquals(
3434
"[2:5] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name]: "
3535
+ "unknown entitlement type [does_not_exist]",
@@ -41,7 +41,7 @@ public void testEntitlementMissingParameter() {
4141
PolicyParserException ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream("""
4242
entitlement-module-name:
4343
- file: {}
44-
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml").parsePolicy());
44+
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy());
4545
assertEquals(
4646
"[2:12] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] "
4747
+ "for entitlement type [file]: missing entitlement parameter [path]",
@@ -52,7 +52,7 @@ public void testEntitlementMissingParameter() {
5252
entitlement-module-name:
5353
- file:
5454
path: test-path
55-
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml").parsePolicy());
55+
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy());
5656
assertEquals(
5757
"[4:1] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] "
5858
+ "for entitlement type [file]: missing entitlement parameter [actions]",
@@ -68,11 +68,22 @@ public void testEntitlementExtraneousParameter() {
6868
actions:
6969
- read
7070
extra: test
71-
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml").parsePolicy());
71+
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", false).parsePolicy());
7272
assertEquals(
7373
"[7:1] policy parsing error for [test-failure-policy.yaml] in scope [entitlement-module-name] "
7474
+ "for entitlement type [file]: extraneous entitlement parameter(s) {extra=test}",
7575
ppe.getMessage()
7676
);
7777
}
78+
79+
public void testEntitlementIsNotForExternalPlugins() {
80+
PolicyParserException ppe = expectThrows(PolicyParserException.class, () -> new PolicyParser(new ByteArrayInputStream("""
81+
entitlement-module-name:
82+
- create_class_loader
83+
""".getBytes(StandardCharsets.UTF_8)), "test-failure-policy.yaml", true).parsePolicy());
84+
assertEquals(
85+
"[2:5] policy parsing error for [test-failure-policy.yaml]: entitlement type [create_class_loader] is allowed only on modules",
86+
ppe.getMessage()
87+
);
88+
}
7889
}

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@ public void testGetEntitlementTypeName() {
3737
}
3838

3939
public void testPolicyBuilder() throws IOException {
40-
Policy parsedPolicy = new PolicyParser(PolicyParserTests.class.getResourceAsStream("test-policy.yaml"), "test-policy.yaml")
40+
Policy parsedPolicy = new PolicyParser(PolicyParserTests.class.getResourceAsStream("test-policy.yaml"), "test-policy.yaml", false)
41+
.parsePolicy();
42+
Policy builtPolicy = new Policy(
43+
"test-policy.yaml",
44+
List.of(new Scope("entitlement-module-name", List.of(new FileEntitlement("test/path/to/file", List.of("read", "write")))))
45+
);
46+
assertEquals(parsedPolicy, builtPolicy);
47+
}
48+
49+
public void testPolicyBuilderOnExternalPlugin() throws IOException {
50+
Policy parsedPolicy = new PolicyParser(PolicyParserTests.class.getResourceAsStream("test-policy.yaml"), "test-policy.yaml", true)
4151
.parsePolicy();
4252
Policy builtPolicy = new Policy(
4353
"test-policy.yaml",
@@ -50,7 +60,7 @@ public void testParseCreateClassloader() throws IOException {
5060
Policy parsedPolicy = new PolicyParser(new ByteArrayInputStream("""
5161
entitlement-module-name:
5262
- create_class_loader
53-
""".getBytes(StandardCharsets.UTF_8)), "test-policy.yaml").parsePolicy();
63+
""".getBytes(StandardCharsets.UTF_8)), "test-policy.yaml", false).parsePolicy();
5464
Policy builtPolicy = new Policy(
5565
"test-policy.yaml",
5666
List.of(new Scope("entitlement-module-name", List.of(new CreateClassLoaderEntitlement())))

muted-tests.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,6 @@ tests:
276276
- class: org.elasticsearch.action.search.SearchQueryThenFetchAsyncActionTests
277277
method: testBottomFieldSort
278278
issue: https://github.com/elastic/elasticsearch/issues/118214
279-
- class: org.elasticsearch.xpack.esql.action.CrossClustersEnrichIT
280-
method: testTopNThenEnrichRemote
281-
issue: https://github.com/elastic/elasticsearch/issues/118307
282279
- class: org.elasticsearch.xpack.remotecluster.CrossClusterEsqlRCS1UnavailableRemotesIT
283280
method: testEsqlRcs1UnavailableRemoteScenarios
284281
issue: https://github.com/elastic/elasticsearch/issues/118350

0 commit comments

Comments
 (0)