Skip to content

Commit c99c46f

Browse files
committed
Changed to pass down a DirectoryResolver; added DATA and TEMP base dir types
1 parent b54bd99 commit c99c46f

File tree

7 files changed

+129
-44
lines changed

7 files changed

+129
-44
lines changed

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.entitlement.instrumentation.MethodKey;
1919
import org.elasticsearch.entitlement.instrumentation.Transformer;
2020
import org.elasticsearch.entitlement.runtime.api.ElasticsearchEntitlementChecker;
21+
import org.elasticsearch.entitlement.runtime.policy.DirectoryResolver;
2122
import org.elasticsearch.entitlement.runtime.policy.Policy;
2223
import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
2324
import org.elasticsearch.entitlement.runtime.policy.Scope;
@@ -37,6 +38,7 @@
3738
import java.nio.file.Path;
3839
import java.nio.file.spi.FileSystemProvider;
3940
import java.util.ArrayList;
41+
import java.util.Arrays;
4042
import java.util.HashMap;
4143
import java.util.List;
4244
import java.util.Map;
@@ -110,7 +112,23 @@ private static Class<?>[] findClassesToRetransform(Class<?>[] loadedClasses, Set
110112
private static PolicyManager createPolicyManager() {
111113
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
112114
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
113-
Path configDir = bootstrapArgs.configDir();
115+
116+
var directoryResolver = new DirectoryResolver() {
117+
@Override
118+
public Path resolveConfig(Path path) {
119+
return bootstrapArgs.configDir().resolve(path);
120+
}
121+
122+
@Override
123+
public Stream<Path> resolveData(Path path) {
124+
return Arrays.stream(bootstrapArgs.dataDirs());
125+
}
126+
127+
@Override
128+
public Path resolveTemp(Path path) {
129+
return bootstrapArgs.tempDir();
130+
}
131+
};
114132

115133
// TODO(ES-10031): Decide what goes in the elasticsearch default policy and extend it
116134
var serverPolicy = new Policy(
@@ -145,7 +163,7 @@ private static PolicyManager createPolicyManager() {
145163
resolver,
146164
AGENTS_PACKAGE_NAME,
147165
ENTITLEMENTS_MODULE,
148-
configDir
166+
directoryResolver
149167
);
150168
}
151169

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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;
11+
12+
import java.nio.file.Path;
13+
import java.util.stream.Stream;
14+
15+
public interface DirectoryResolver {
16+
Path resolveConfig(Path path);
17+
18+
Stream<Path> resolveData(Path path);
19+
20+
Path resolveTemp(Path path);
21+
}

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

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,73 @@
1616
import java.util.Arrays;
1717
import java.util.List;
1818
import java.util.Objects;
19+
import java.util.function.Consumer;
20+
import java.util.stream.Stream;
1921

2022
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
2123

2224
public final class FileAccessTree {
23-
public static final FileAccessTree EMPTY = new FileAccessTree(FilesEntitlement.EMPTY, null);
25+
26+
private static final DirectoryResolver NULL_DIRECTORY_RESOLVER = new DirectoryResolver() {
27+
@Override
28+
public Path resolveConfig(Path path) {
29+
throw new UnsupportedOperationException();
30+
}
31+
32+
@Override
33+
public Stream<Path> resolveData(Path path) {
34+
throw new UnsupportedOperationException();
35+
}
36+
37+
@Override
38+
public Path resolveTemp(Path path) {
39+
throw new UnsupportedOperationException();
40+
}
41+
};
42+
43+
public static final FileAccessTree EMPTY = new FileAccessTree(FilesEntitlement.EMPTY, NULL_DIRECTORY_RESOLVER);
2444
private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator();
2545

2646
private final String[] readPaths;
2747
private final String[] writePaths;
2848

29-
private FileAccessTree(FilesEntitlement filesEntitlement, Path configFile) {
49+
private static void resolvePath(
50+
FilesEntitlement.FileData fileData,
51+
DirectoryResolver directoryResolver,
52+
Consumer<String> resolvedPathReceiver
53+
) {
54+
Path path = Path.of(fileData.path());
55+
switch (fileData.baseDir()) {
56+
case NONE:
57+
resolvedPathReceiver.accept(normalizePath(path));
58+
break;
59+
case CONFIG:
60+
resolvedPathReceiver.accept(normalizePath(directoryResolver.resolveConfig(path)));
61+
break;
62+
case DATA:
63+
directoryResolver.resolveData(path).forEach(p -> resolvedPathReceiver.accept(normalizePath(p)));
64+
break;
65+
case TEMP:
66+
resolvedPathReceiver.accept(normalizePath(directoryResolver.resolveTemp(path)));
67+
break;
68+
default:
69+
throw new IllegalArgumentException();
70+
}
71+
}
72+
73+
private FileAccessTree(FilesEntitlement filesEntitlement, DirectoryResolver directoryResolver) {
74+
Objects.requireNonNull(directoryResolver);
75+
3076
List<String> readPaths = new ArrayList<>();
3177
List<String> writePaths = new ArrayList<>();
3278
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
33-
Path path = Path.of(fileData.path());
34-
if (fileData.baseDir() == FilesEntitlement.BaseDir.CONFIG) {
35-
path = configFile.resolve(path);
36-
}
37-
String pathStr = normalizePath(path);
3879
var mode = fileData.mode();
39-
if (mode == FilesEntitlement.Mode.READ_WRITE) {
40-
writePaths.add(pathStr);
41-
}
42-
readPaths.add(pathStr);
80+
resolvePath(fileData, directoryResolver, pathStr -> {
81+
if (mode == FilesEntitlement.Mode.READ_WRITE) {
82+
writePaths.add(pathStr);
83+
}
84+
readPaths.add(pathStr);
85+
});
4386
}
4487

4588
readPaths.sort(String::compareTo);
@@ -49,8 +92,8 @@ private FileAccessTree(FilesEntitlement filesEntitlement, Path configFile) {
4992
this.writePaths = writePaths.toArray(new String[0]);
5093
}
5194

52-
public static FileAccessTree of(FilesEntitlement filesEntitlement, Path configFile) {
53-
return new FileAccessTree(filesEntitlement, configFile);
95+
public static FileAccessTree of(FilesEntitlement filesEntitlement, DirectoryResolver directoryResolver) {
96+
return new FileAccessTree(filesEntitlement, directoryResolver);
5497
}
5598

5699
boolean canRead(Path path) {

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public static ModuleEntitlements none(String componentName) {
7272
return new ModuleEntitlements(componentName, Map.of(), FileAccessTree.EMPTY);
7373
}
7474

75-
public static ModuleEntitlements from(String componentName, List<Entitlement> entitlements, Path configPath) {
75+
public static ModuleEntitlements from(String componentName, List<Entitlement> entitlements, DirectoryResolver directoryResolver) {
7676
FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY;
7777
for (Entitlement entitlement : entitlements) {
7878
if (entitlement instanceof FilesEntitlement) {
@@ -82,7 +82,7 @@ public static ModuleEntitlements from(String componentName, List<Entitlement> en
8282
return new ModuleEntitlements(
8383
componentName,
8484
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
85-
FileAccessTree.of(filesEntitlement, configPath)
85+
FileAccessTree.of(filesEntitlement, directoryResolver)
8686
);
8787
}
8888

@@ -105,6 +105,7 @@ public <E extends Entitlement> Stream<E> getEntitlements(Class<E> entitlementCla
105105
protected final List<Entitlement> apmAgentEntitlements;
106106
protected final Map<String, Map<String, List<Entitlement>>> pluginsEntitlements;
107107
private final Function<Class<?>, String> pluginResolver;
108+
private final DirectoryResolver directoryResolver;
108109

109110
public static final String ALL_UNNAMED = "ALL-UNNAMED";
110111

@@ -133,16 +134,14 @@ private static Set<Module> findSystemModules() {
133134
*/
134135
private final Module entitlementsModule;
135136

136-
private final Path configDir;
137-
138137
public PolicyManager(
139138
Policy serverPolicy,
140139
List<Entitlement> apmAgentEntitlements,
141140
Map<String, Policy> pluginPolicies,
142141
Function<Class<?>, String> pluginResolver,
143142
String apmAgentPackageName,
144143
Module entitlementsModule,
145-
Path configDir
144+
DirectoryResolver directoryResolver
146145
) {
147146
this.serverEntitlements = buildScopeEntitlementsMap(requireNonNull(serverPolicy));
148147
this.apmAgentEntitlements = apmAgentEntitlements;
@@ -152,7 +151,7 @@ public PolicyManager(
152151
this.pluginResolver = pluginResolver;
153152
this.apmAgentPackageName = apmAgentPackageName;
154153
this.entitlementsModule = entitlementsModule;
155-
this.configDir = configDir;
154+
this.directoryResolver = directoryResolver;
156155

157156
for (var e : serverEntitlements.entrySet()) {
158157
validateEntitlementsPerModule(SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
@@ -414,7 +413,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
414413

415414
if (requestingModule.isNamed() == false && requestingClass.getPackageName().startsWith(apmAgentPackageName)) {
416415
// The APM agent is the only thing running non-modular in the system classloader
417-
return ModuleEntitlements.from(APM_AGENT_COMPONENT_NAME, apmAgentEntitlements, configDir);
416+
return ModuleEntitlements.from(APM_AGENT_COMPONENT_NAME, apmAgentEntitlements, directoryResolver);
418417
}
419418

420419
return ModuleEntitlements.none(UNKNOWN_COMPONENT_NAME);
@@ -429,7 +428,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
429428
if (entitlements == null) {
430429
return ModuleEntitlements.none(componentName);
431430
}
432-
return ModuleEntitlements.from(componentName, entitlements, configDir);
431+
return ModuleEntitlements.from(componentName, entitlements, directoryResolver);
433432
}
434433

435434
private static boolean isServerModule(Module requestingModule) {

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public enum Mode {
3131

3232
public enum BaseDir {
3333
NONE,
34-
CONFIG
34+
CONFIG,
35+
DATA,
36+
TEMP
3537
}
3638

3739
public record FileData(String path, Mode mode, BaseDir baseDir) {

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1313
import org.elasticsearch.test.ESTestCase;
1414
import org.junit.BeforeClass;
15+
import org.mockito.Mockito;
1516

1617
import java.nio.file.Path;
1718
import java.util.ArrayList;
@@ -36,13 +37,13 @@ private static Path path(String s) {
3637
}
3738

3839
public void testEmpty() {
39-
var tree = FileAccessTree.of(FilesEntitlement.EMPTY);
40+
var tree = FileAccessTree.of(FilesEntitlement.EMPTY, Mockito.mock(DirectoryResolver.class));
4041
assertThat(tree.canRead(path("path")), is(false));
4142
assertThat(tree.canWrite(path("path")), is(false));
4243
}
4344

4445
public void testRead() {
45-
var tree = FileAccessTree.of(entitlement("foo", "read"));
46+
var tree = FileAccessTree.of(entitlement("foo", "read"), Mockito.mock(DirectoryResolver.class));
4647
assertThat(tree.canRead(path("foo")), is(true));
4748
assertThat(tree.canRead(path("foo/subdir")), is(true));
4849
assertThat(tree.canRead(path("food")), is(false));
@@ -54,7 +55,7 @@ public void testRead() {
5455
}
5556

5657
public void testWrite() {
57-
var tree = FileAccessTree.of(entitlement("foo", "read_write"));
58+
var tree = FileAccessTree.of(entitlement("foo", "read_write"), Mockito.mock(DirectoryResolver.class));
5859
assertThat(tree.canWrite(path("foo")), is(true));
5960
assertThat(tree.canWrite(path("foo/subdir")), is(true));
6061
assertThat(tree.canWrite(path("food")), is(false));
@@ -66,7 +67,7 @@ public void testWrite() {
6667
}
6768

6869
public void testTwoPaths() {
69-
var tree = FileAccessTree.of(entitlement("foo", "read", "bar", "read"));
70+
var tree = FileAccessTree.of(entitlement("foo", "read", "bar", "read"), Mockito.mock(DirectoryResolver.class));
7071
assertThat(tree.canRead(path("a")), is(false));
7172
assertThat(tree.canRead(path("bar")), is(true));
7273
assertThat(tree.canRead(path("bar/subdir")), is(true));
@@ -77,23 +78,23 @@ public void testTwoPaths() {
7778
}
7879

7980
public void testReadWriteUnderRead() {
80-
var tree = FileAccessTree.of(entitlement("foo", "read", "foo/bar", "read_write"));
81+
var tree = FileAccessTree.of(entitlement("foo", "read", "foo/bar", "read_write"), Mockito.mock(DirectoryResolver.class));
8182
assertThat(tree.canRead(path("foo")), is(true));
8283
assertThat(tree.canWrite(path("foo")), is(false));
8384
assertThat(tree.canRead(path("foo/bar")), is(true));
8485
assertThat(tree.canWrite(path("foo/bar")), is(true));
8586
}
8687

8788
public void testNormalizePath() {
88-
var tree = FileAccessTree.of(entitlement("foo/../bar", "read"));
89+
var tree = FileAccessTree.of(entitlement("foo/../bar", "read"), Mockito.mock(DirectoryResolver.class));
8990
assertThat(tree.canRead(path("foo/../bar")), is(true));
9091
assertThat(tree.canRead(path("foo")), is(false));
9192
assertThat(tree.canRead(path("")), is(false));
9293
}
9394

9495
public void testForwardSlashes() {
9596
String sep = getDefaultFileSystem().getSeparator();
96-
var tree = FileAccessTree.of(entitlement("a/b", "read", "m" + sep + "n", "read"));
97+
var tree = FileAccessTree.of(entitlement("a/b", "read", "m" + sep + "n", "read"), Mockito.mock(DirectoryResolver.class));
9798

9899
// Native separators work
99100
assertThat(tree.canRead(path("a" + sep + "b")), is(true));

0 commit comments

Comments
 (0)