Skip to content

Commit 03d15d4

Browse files
authored
Merge branch 'main' into refactoring/dry_search_shard_iterator
2 parents f470830 + 144ff0c commit 03d15d4

File tree

40 files changed

+722
-204
lines changed

40 files changed

+722
-204
lines changed

docs/changelog/121196.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 121196
2+
summary: Fix geoip databases index access after system feature migration
3+
area: Ingest Node
4+
type: bug
5+
issues: []

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,17 @@ public abstract class AbstractEntitlementsIT extends ESRestTestCase {
3434
Map.of("properties", List.of("es.entitlements.checkSetSystemProperty", "es.entitlements.checkClearSystemProperty"))
3535
)
3636
);
37-
38-
builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_dir"), "mode", "read")));
39-
builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write")));
40-
builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_file"), "mode", "read")));
41-
builder.value(Map.of("file", Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write")));
37+
builder.value(
38+
Map.of(
39+
"files",
40+
List.of(
41+
Map.of("path", tempDir.resolve("read_dir"), "mode", "read"),
42+
Map.of("path", tempDir.resolve("read_write_dir"), "mode", "read_write"),
43+
Map.of("path", tempDir.resolve("read_file"), "mode", "read"),
44+
Map.of("path", tempDir.resolve("read_write_file"), "mode", "read_write")
45+
)
46+
)
47+
);
4248
};
4349

4450
private final String actionName;

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

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

1010
package org.elasticsearch.entitlement.runtime.policy;
1111

12-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement;
12+
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1313

1414
import java.nio.file.Path;
1515
import java.util.ArrayList;
@@ -20,18 +20,19 @@
2020
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
2121

2222
public final class FileAccessTree {
23-
public static final FileAccessTree EMPTY = new FileAccessTree(List.of());
23+
public static final FileAccessTree EMPTY = new FileAccessTree(FilesEntitlement.EMPTY);
2424
private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator();
2525

2626
private final String[] readPaths;
2727
private final String[] writePaths;
2828

29-
private FileAccessTree(List<FileEntitlement> fileEntitlements) {
29+
private FileAccessTree(FilesEntitlement filesEntitlement) {
3030
List<String> readPaths = new ArrayList<>();
3131
List<String> writePaths = new ArrayList<>();
32-
for (FileEntitlement fileEntitlement : fileEntitlements) {
33-
String path = normalizePath(Path.of(fileEntitlement.path()));
34-
if (fileEntitlement.mode() == FileEntitlement.Mode.READ_WRITE) {
32+
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
33+
var path = normalizePath(Path.of(fileData.path()));
34+
var mode = fileData.mode();
35+
if (mode == FilesEntitlement.Mode.READ_WRITE) {
3536
writePaths.add(path);
3637
}
3738
readPaths.add(path);
@@ -44,8 +45,8 @@ private FileAccessTree(List<FileEntitlement> fileEntitlements) {
4445
this.writePaths = writePaths.toArray(new String[0]);
4546
}
4647

47-
public static FileAccessTree of(List<FileEntitlement> fileEntitlements) {
48-
return new FileAccessTree(fileEntitlements);
48+
public static FileAccessTree of(FilesEntitlement filesEntitlement) {
49+
return new FileAccessTree(filesEntitlement);
4950
}
5051

5152
boolean canRead(Path path) {

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

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
1717
import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
1818
import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement;
19-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement;
19+
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
2020
import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement;
2121
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
2222
import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
@@ -73,14 +73,16 @@ public static ModuleEntitlements none(String componentName) {
7373
}
7474

7575
public static ModuleEntitlements from(String componentName, List<Entitlement> entitlements) {
76-
var fileEntitlements = entitlements.stream()
77-
.filter(e -> e.getClass().equals(FileEntitlement.class))
78-
.map(e -> (FileEntitlement) e)
79-
.toList();
76+
FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY;
77+
for (Entitlement entitlement : entitlements) {
78+
if (entitlement instanceof FilesEntitlement) {
79+
filesEntitlement = (FilesEntitlement) entitlement;
80+
}
81+
}
8082
return new ModuleEntitlements(
8183
componentName,
8284
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
83-
FileAccessTree.of(fileEntitlements)
85+
FileAccessTree.of(filesEntitlement)
8486
);
8587
}
8688

@@ -164,23 +166,14 @@ private static Map<String, List<Entitlement>> buildScopeEntitlementsMap(Policy p
164166
}
165167

166168
private static void validateEntitlementsPerModule(String componentName, String moduleName, List<Entitlement> entitlements) {
167-
Set<Class<? extends Entitlement>> flagEntitlements = new HashSet<>();
169+
Set<Class<? extends Entitlement>> found = new HashSet<>();
168170
for (var e : entitlements) {
169-
if (e instanceof FileEntitlement) {
170-
continue;
171-
}
172-
if (flagEntitlements.contains(e.getClass())) {
171+
if (found.contains(e.getClass())) {
173172
throw new IllegalArgumentException(
174-
"["
175-
+ componentName
176-
+ "] using module ["
177-
+ moduleName
178-
+ "] found duplicate flag entitlements ["
179-
+ e.getClass().getName()
180-
+ "]"
173+
"[" + componentName + "] using module [" + moduleName + "] found duplicate entitlement [" + e.getClass().getName() + "]"
181174
);
182175
}
183-
flagEntitlements.add(e.getClass());
176+
found.add(e.getClass());
184177
}
185178
}
186179

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

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
1313
import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
14-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement;
14+
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1515
import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement;
1616
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
1717
import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
@@ -46,7 +46,7 @@
4646
public class PolicyParser {
4747

4848
private static final Map<String, Class<?>> EXTERNAL_ENTITLEMENTS = Stream.of(
49-
FileEntitlement.class,
49+
FilesEntitlement.class,
5050
CreateClassLoaderEntitlement.class,
5151
SetHttpsConnectionPropertiesEntitlement.class,
5252
OutboundNetworkEntitlement.class,
@@ -197,34 +197,41 @@ protected Entitlement parseEntitlement(String scopeName, String entitlementType)
197197
? entitlementConstructor.getParameterTypes()
198198
: entitlementMethod.getParameterTypes();
199199
String[] parametersNames = entitlementMetadata.parameterNames();
200+
Object[] parameterValues = new Object[parameterTypes.length];
200201

201202
if (parameterTypes.length != 0 || parametersNames.length != 0) {
202-
if (policyParser.nextToken() != XContentParser.Token.START_OBJECT) {
203-
throw newPolicyParserException(scopeName, entitlementType, "expected entitlement parameters");
204-
}
205-
}
206-
207-
Map<String, Object> parsedValues = policyParser.map();
203+
if (policyParser.nextToken() == XContentParser.Token.START_OBJECT) {
204+
Map<String, Object> parsedValues = policyParser.map();
208205

209-
Object[] parameterValues = new Object[parameterTypes.length];
210-
for (int parameterIndex = 0; parameterIndex < parameterTypes.length; ++parameterIndex) {
211-
String parameterName = parametersNames[parameterIndex];
212-
Object parameterValue = parsedValues.remove(parameterName);
213-
if (parameterValue == null) {
214-
throw newPolicyParserException(scopeName, entitlementType, "missing entitlement parameter [" + parameterName + "]");
215-
}
216-
Class<?> parameterType = parameterTypes[parameterIndex];
217-
if (parameterType.isAssignableFrom(parameterValue.getClass()) == false) {
218-
throw newPolicyParserException(
219-
scopeName,
220-
entitlementType,
221-
"unexpected parameter type [" + parameterType.getSimpleName() + "] for entitlement parameter [" + parameterName + "]"
222-
);
206+
for (int parameterIndex = 0; parameterIndex < parameterTypes.length; ++parameterIndex) {
207+
String parameterName = parametersNames[parameterIndex];
208+
Object parameterValue = parsedValues.remove(parameterName);
209+
if (parameterValue == null) {
210+
throw newPolicyParserException(scopeName, entitlementType, "missing entitlement parameter [" + parameterName + "]");
211+
}
212+
Class<?> parameterType = parameterTypes[parameterIndex];
213+
if (parameterType.isAssignableFrom(parameterValue.getClass()) == false) {
214+
throw newPolicyParserException(
215+
scopeName,
216+
entitlementType,
217+
"unexpected parameter type ["
218+
+ parameterType.getSimpleName()
219+
+ "] for entitlement parameter ["
220+
+ parameterName
221+
+ "]"
222+
);
223+
}
224+
parameterValues[parameterIndex] = parameterValue;
225+
}
226+
if (parsedValues.isEmpty() == false) {
227+
throw newPolicyParserException(scopeName, entitlementType, "extraneous entitlement parameter(s) " + parsedValues);
228+
}
229+
} else if (policyParser.currentToken() == XContentParser.Token.START_ARRAY) {
230+
List<Object> parsedValues = policyParser.list();
231+
parameterValues[0] = parsedValues;
232+
} else {
233+
throw newPolicyParserException(scopeName, entitlementType, "expected entitlement parameters");
223234
}
224-
parameterValues[parameterIndex] = parameterValue;
225-
}
226-
if (parsedValues.isEmpty() == false) {
227-
throw newPolicyParserException(scopeName, entitlementType, "extraneous entitlement parameter(s) " + parsedValues);
228235
}
229236

230237
try {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.entitlement.runtime.policy.entitlements;
11+
12+
import org.elasticsearch.entitlement.runtime.policy.ExternalEntitlement;
13+
import org.elasticsearch.entitlement.runtime.policy.PolicyValidationException;
14+
15+
import java.util.ArrayList;
16+
import java.util.HashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
/**
21+
* Describes a file entitlement with a path and mode.
22+
*/
23+
public record FilesEntitlement(List<FileData> filesData) implements Entitlement {
24+
25+
public static final FilesEntitlement EMPTY = new FilesEntitlement(List.of());
26+
27+
public enum Mode {
28+
READ,
29+
READ_WRITE
30+
}
31+
32+
public record FileData(String path, Mode mode) {
33+
34+
}
35+
36+
private static Mode parseMode(String mode) {
37+
if (mode.equals("read")) {
38+
return Mode.READ;
39+
} else if (mode.equals("read_write")) {
40+
return Mode.READ_WRITE;
41+
} else {
42+
throw new PolicyValidationException("invalid mode: " + mode + ", valid values: [read, read_write]");
43+
}
44+
}
45+
46+
@ExternalEntitlement(parameterNames = { "paths" }, esModulesOnly = false)
47+
@SuppressWarnings("unchecked")
48+
public static FilesEntitlement build(List<Object> paths) {
49+
if (paths == null || paths.isEmpty()) {
50+
throw new PolicyValidationException("must specify at least one path");
51+
}
52+
List<FileData> filesData = new ArrayList<>();
53+
for (Object object : paths) {
54+
Map<String, String> file = new HashMap<>((Map<String, String>) object);
55+
String path = file.remove("path");
56+
if (path == null) {
57+
throw new PolicyValidationException("files entitlement must contain path for every listed file");
58+
}
59+
String mode = file.remove("mode");
60+
if (mode == null) {
61+
throw new PolicyValidationException("files entitlement must contain mode for every listed file");
62+
}
63+
if (file.isEmpty() == false) {
64+
throw new PolicyValidationException("unknown key(s) " + file + " in a listed file for files entitlement");
65+
}
66+
filesData.add(new FileData(path, parseMode(mode)));
67+
}
68+
return new FilesEntitlement(filesData);
69+
}
70+
}

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99

1010
package org.elasticsearch.entitlement.runtime.policy;
1111

12-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FileEntitlement;
12+
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1313
import org.elasticsearch.test.ESTestCase;
1414
import org.junit.BeforeClass;
1515

1616
import java.nio.file.Path;
17+
import java.util.ArrayList;
18+
import java.util.HashMap;
1719
import java.util.List;
20+
import java.util.Map;
1821

1922
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
2023
import static org.hamcrest.Matchers.is;
@@ -33,13 +36,13 @@ private static Path path(String s) {
3336
}
3437

3538
public void testEmpty() {
36-
var tree = FileAccessTree.of(List.of());
39+
var tree = FileAccessTree.of(FilesEntitlement.EMPTY);
3740
assertThat(tree.canRead(path("path")), is(false));
3841
assertThat(tree.canWrite(path("path")), is(false));
3942
}
4043

4144
public void testRead() {
42-
var tree = FileAccessTree.of(List.of(entitlement("foo", "read")));
45+
var tree = FileAccessTree.of(entitlement("foo", "read"));
4346
assertThat(tree.canRead(path("foo")), is(true));
4447
assertThat(tree.canRead(path("foo/subdir")), is(true));
4548
assertThat(tree.canRead(path("food")), is(false));
@@ -51,7 +54,7 @@ public void testRead() {
5154
}
5255

5356
public void testWrite() {
54-
var tree = FileAccessTree.of(List.of(entitlement("foo", "read_write")));
57+
var tree = FileAccessTree.of(entitlement("foo", "read_write"));
5558
assertThat(tree.canWrite(path("foo")), is(true));
5659
assertThat(tree.canWrite(path("foo/subdir")), is(true));
5760
assertThat(tree.canWrite(path("food")), is(false));
@@ -63,7 +66,7 @@ public void testWrite() {
6366
}
6467

6568
public void testTwoPaths() {
66-
var tree = FileAccessTree.of(List.of(entitlement("foo", "read"), entitlement("bar", "read")));
69+
var tree = FileAccessTree.of(entitlement("foo", "read", "bar", "read"));
6770
assertThat(tree.canRead(path("a")), is(false));
6871
assertThat(tree.canRead(path("bar")), is(true));
6972
assertThat(tree.canRead(path("bar/subdir")), is(true));
@@ -74,23 +77,23 @@ public void testTwoPaths() {
7477
}
7578

7679
public void testReadWriteUnderRead() {
77-
var tree = FileAccessTree.of(List.of(entitlement("foo", "read"), entitlement("foo/bar", "read_write")));
80+
var tree = FileAccessTree.of(entitlement("foo", "read", "foo/bar", "read_write"));
7881
assertThat(tree.canRead(path("foo")), is(true));
7982
assertThat(tree.canWrite(path("foo")), is(false));
8083
assertThat(tree.canRead(path("foo/bar")), is(true));
8184
assertThat(tree.canWrite(path("foo/bar")), is(true));
8285
}
8386

8487
public void testNormalizePath() {
85-
var tree = FileAccessTree.of(List.of(entitlement("foo/../bar", "read")));
88+
var tree = FileAccessTree.of(entitlement("foo/../bar", "read"));
8689
assertThat(tree.canRead(path("foo/../bar")), is(true));
8790
assertThat(tree.canRead(path("foo")), is(false));
8891
assertThat(tree.canRead(path("")), is(false));
8992
}
9093

9194
public void testForwardSlashes() {
9295
String sep = getDefaultFileSystem().getSeparator();
93-
var tree = FileAccessTree.of(List.of(entitlement("a/b", "read"), entitlement("m" + sep + "n", "read")));
96+
var tree = FileAccessTree.of(entitlement("a/b", "read", "m" + sep + "n", "read"));
9497

9598
// Native separators work
9699
assertThat(tree.canRead(path("a" + sep + "b")), is(true));
@@ -104,8 +107,14 @@ public void testForwardSlashes() {
104107
assertThat(tree.canRead(path("m\n")), is(false));
105108
}
106109

107-
FileEntitlement entitlement(String path, String mode) {
108-
Path p = path(path);
109-
return FileEntitlement.create(p.toString(), mode);
110+
FilesEntitlement entitlement(String... values) {
111+
List<Object> filesData = new ArrayList<>();
112+
for (int i = 0; i < values.length; i += 2) {
113+
Map<String, String> fileData = new HashMap<>();
114+
fileData.put("path", path(values[i]).toString());
115+
fileData.put("mode", values[i + 1]);
116+
filesData.add(fileData);
117+
}
118+
return FilesEntitlement.build(filesData);
110119
}
111120
}

0 commit comments

Comments
 (0)