Skip to content

Commit 857ba64

Browse files
committed
update to use path instead of string and component and module for
exclusive path validation
1 parent 0978447 commit 857ba64

File tree

4 files changed

+48
-29
lines changed

4 files changed

+48
-29
lines changed

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

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

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

12+
import org.elasticsearch.entitlement.runtime.policy.PolicyManager.ExclusivePath;
1213
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1314

1415
import java.nio.file.Path;
@@ -27,7 +28,13 @@ public final class FileAccessTree {
2728
private final String[] readPaths;
2829
private final String[] writePaths;
2930

30-
private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup, List<String> exclusivePaths) {
31+
private FileAccessTree(
32+
String componentName,
33+
String moduleName,
34+
FilesEntitlement filesEntitlement,
35+
PathLookup pathLookup,
36+
List<ExclusivePath> exclusivePaths
37+
) {
3138
List<String> updatedExclusivePaths = new ArrayList<>();
3239
List<String> readPaths = new ArrayList<>();
3340
List<String> writePaths = new ArrayList<>();
@@ -36,12 +43,13 @@ private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup,
3643
var paths = fileData.resolvePaths(pathLookup);
3744
paths.forEach(path -> {
3845
var normalized = normalizePath(path);
39-
for (String exclusivePath : exclusivePaths) {
40-
if (normalized.equals(exclusivePath) == false) {
41-
if (normalized.startsWith(exclusivePath)) {
46+
for (ExclusivePath exclusivePath : exclusivePaths) {
47+
if (exclusivePath.componentName().equals(componentName) == false
48+
|| exclusivePath.moduleName().equals(moduleName) == false) {
49+
if (path.startsWith(exclusivePath.path())) {
4250
// TODO: throw
4351
}
44-
updatedExclusivePaths.add(exclusivePath);
52+
updatedExclusivePaths.add(normalizePath(exclusivePath.path()));
4553
}
4654
}
4755
if (mode == FilesEntitlement.Mode.READ_WRITE) {
@@ -62,6 +70,8 @@ private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup,
6270
this.exclusivePaths = updatedExclusivePaths.toArray(new String[0]);
6371
this.readPaths = pruneSortedPaths(readPaths).toArray(new String[0]);
6472
this.writePaths = pruneSortedPaths(writePaths).toArray(new String[0]);
73+
// if (true) throw new IllegalStateException("EXCLUSIVE: " + Arrays.toString(this.exclusivePaths) +
74+
// "\n READ: " + Arrays.toString(this.readPaths) + "\n WRITE: " + Arrays.toString(this.writePaths));
6575
}
6676

6777
private static List<String> pruneSortedPaths(List<String> paths) {
@@ -81,8 +91,14 @@ private static List<String> pruneSortedPaths(List<String> paths) {
8191

8292
}
8393

84-
public static FileAccessTree of(FilesEntitlement filesEntitlement, PathLookup pathLookup, List<String> exclusivePaths) {
85-
return new FileAccessTree(filesEntitlement, pathLookup, exclusivePaths);
94+
public static FileAccessTree of(
95+
String componentName,
96+
String moduleName,
97+
FilesEntitlement filesEntitlement,
98+
PathLookup pathLookup,
99+
List<ExclusivePath> exclusivePaths
100+
) {
101+
return new FileAccessTree(componentName, moduleName, filesEntitlement, pathLookup, exclusivePaths);
86102
}
87103

88104
boolean canRead(Path path) {

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ ModuleEntitlements defaultEntitlements(String componentName) {
9595
}
9696

9797
// pkg private for testing
98-
ModuleEntitlements policyEntitlements(String componentName, List<Entitlement> entitlements) {
98+
ModuleEntitlements policyEntitlements(String componentName, String moduleName, List<Entitlement> entitlements) {
9999
FilesEntitlement filesEntitlement = FilesEntitlement.EMPTY;
100100
for (Entitlement entitlement : entitlements) {
101101
if (entitlement instanceof FilesEntitlement) {
@@ -105,7 +105,7 @@ ModuleEntitlements policyEntitlements(String componentName, List<Entitlement> en
105105
return new ModuleEntitlements(
106106
componentName,
107107
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
108-
FileAccessTree.of(filesEntitlement, pathLookup, List.of())
108+
FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, exclusivePaths)
109109
);
110110
}
111111

@@ -150,7 +150,7 @@ private static Set<Module> findSystemModules() {
150150
* structures to indicate other modules aren't allowed to use these
151151
* files in {@link FileAccessTree}s.
152152
*/
153-
private final List<String> exclusivePaths;
153+
private final List<ExclusivePath> exclusivePaths;
154154

155155
public PolicyManager(
156156
Policy serverPolicy,
@@ -170,15 +170,15 @@ public PolicyManager(
170170
this.apmAgentPackageName = apmAgentPackageName;
171171
this.entitlementsModule = entitlementsModule;
172172
this.pathLookup = requireNonNull(pathLookup);
173-
this.defaultFileAccess = FileAccessTree.of(FilesEntitlement.EMPTY, pathLookup, List.of());
173+
this.defaultFileAccess = FileAccessTree.of("", "", FilesEntitlement.EMPTY, pathLookup, List.of());
174174

175175
List<ExclusivePath> exclusivePaths = new ArrayList<>();
176176
for (var e : serverEntitlements.entrySet()) {
177177
validateEntitlementsPerModule(SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
178178
buildExclusivePathList(exclusivePaths, pathLookup, SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
179179
}
180-
validateEntitlementsPerModule(APM_AGENT_COMPONENT_NAME, "unnamed", apmAgentEntitlements);
181-
buildExclusivePathList(exclusivePaths, pathLookup, APM_AGENT_COMPONENT_NAME, "unnamed", apmAgentEntitlements);
180+
validateEntitlementsPerModule(APM_AGENT_COMPONENT_NAME, ALL_UNNAMED, apmAgentEntitlements);
181+
buildExclusivePathList(exclusivePaths, pathLookup, APM_AGENT_COMPONENT_NAME, ALL_UNNAMED, apmAgentEntitlements);
182182
for (var p : pluginsEntitlements.entrySet()) {
183183
for (var m : p.getValue().entrySet()) {
184184
validateEntitlementsPerModule(p.getKey(), m.getKey(), m.getValue());
@@ -187,7 +187,7 @@ public PolicyManager(
187187
}
188188
exclusivePaths.sort(Comparator.comparing(ExclusivePath::path));
189189
validateExclusivePaths(exclusivePaths);
190-
this.exclusivePaths = exclusivePaths.stream().map(ExclusivePath::path).toList();
190+
this.exclusivePaths = exclusivePaths;
191191
}
192192

193193
private static Map<String, List<Entitlement>> buildScopeEntitlementsMap(Policy policy) {
@@ -206,7 +206,7 @@ private static void validateEntitlementsPerModule(String componentName, String m
206206
}
207207
}
208208

209-
private record ExclusivePath(String componentName, String moduleName, String path) {}
209+
record ExclusivePath(String componentName, String moduleName, Path path) {}
210210

211211
private static void buildExclusivePathList(
212212
List<ExclusivePath> exclusivePaths,
@@ -221,8 +221,7 @@ private static void buildExclusivePathList(
221221
if (fd.exclusive()) {
222222
List<Path> paths = fd.resolvePaths(pathLookup).toList();
223223
for (Path path : paths) {
224-
String pathStr = FileAccessTree.normalizePath(path);
225-
exclusivePaths.add(new ExclusivePath(componentName, moduleName, pathStr));
224+
exclusivePaths.add(new ExclusivePath(componentName, moduleName, path));
226225
}
227226
}
228227
}
@@ -551,7 +550,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
551550

552551
if (requestingModule.isNamed() == false && requestingClass.getPackageName().startsWith(apmAgentPackageName)) {
553552
// The APM agent is the only thing running non-modular in the system classloader
554-
return policyEntitlements(APM_AGENT_COMPONENT_NAME, apmAgentEntitlements);
553+
return policyEntitlements(APM_AGENT_COMPONENT_NAME, ALL_UNNAMED, apmAgentEntitlements);
555554
}
556555

557556
return defaultEntitlements(UNKNOWN_COMPONENT_NAME);
@@ -566,7 +565,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
566565
if (entitlements == null) {
567566
return defaultEntitlements(componentName);
568567
}
569-
return policyEntitlements(componentName, entitlements);
568+
return policyEntitlements(componentName, moduleName, entitlements);
570569
}
571570

572571
private static boolean isServerModule(Module requestingModule) {

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.entitlement.runtime.policy;
1111

1212
import org.elasticsearch.common.settings.Settings;
13+
import org.elasticsearch.entitlement.runtime.policy.PolicyManager.ExclusivePath;
1314
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
1415
import org.elasticsearch.test.ESTestCase;
1516
import org.junit.BeforeClass;
@@ -191,19 +192,19 @@ public void testForwardSlashes() {
191192
}
192193

193194
public void testTempDirAccess() {
194-
var tree = FileAccessTree.of(FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, List.of());
195+
var tree = FileAccessTree.of("test-component", "test-module", FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, List.of());
195196
assertThat(tree.canRead(TEST_PATH_LOOKUP.tempDir()), is(true));
196197
assertThat(tree.canWrite(TEST_PATH_LOOKUP.tempDir()), is(true));
197198
}
198199

199200
public void testExclusiveAccess() {
200-
var tree = accessTree(entitlement("foo", "read"), exclusivePaths("foo"));
201+
var tree = accessTree(entitlement("foo", "read"), exclusivePaths("test-component", "test-module", "foo"));
201202
assertThat(tree.canRead(path("foo")), is(true));
202203
assertThat(tree.canWrite(path("foo")), is(false));
203-
tree = accessTree(entitlement("foo", "read_write"), exclusivePaths("foo"));
204+
tree = accessTree(entitlement("foo", "read_write"), exclusivePaths("test-component", "test-module", "foo"));
204205
assertThat(tree.canRead(path("foo")), is(true));
205206
assertThat(tree.canWrite(path("foo")), is(true));
206-
tree = accessTree(entitlement("foo", "read"), exclusivePaths("foo/bar"));
207+
tree = accessTree(entitlement("foo", "read"), exclusivePaths("test-component", "diff-module", "foo/bar"));
207208
assertThat(tree.canRead(path("foo")), is(true));
208209
assertThat(tree.canWrite(path("foo")), is(false));
209210
assertThat(tree.canRead(path("foo/baz")), is(true));
@@ -212,8 +213,8 @@ public void testExclusiveAccess() {
212213
assertThat(tree.canWrite(path("foo/bar")), is(false));
213214
}
214215

215-
FileAccessTree accessTree(FilesEntitlement entitlement, List<String> exclusivePaths) {
216-
return FileAccessTree.of(entitlement, TEST_PATH_LOOKUP, exclusivePaths);
216+
FileAccessTree accessTree(FilesEntitlement entitlement, List<ExclusivePath> exclusivePaths) {
217+
return FileAccessTree.of("test-component", "test-module", entitlement, TEST_PATH_LOOKUP, exclusivePaths);
217218
}
218219

219220
static FilesEntitlement entitlement(String... values) {
@@ -231,10 +232,10 @@ static FilesEntitlement entitlement(Map<String, String> value) {
231232
return FilesEntitlement.build(List.of(value));
232233
}
233234

234-
static List<String> exclusivePaths(String... paths) {
235-
List<String> exclusivePaths = new ArrayList<>();
235+
static List<ExclusivePath> exclusivePaths(String componentName, String moduleName, String... paths) {
236+
List<ExclusivePath> exclusivePaths = new ArrayList<>();
236237
for (String path : paths) {
237-
exclusivePaths.add(FileAccessTree.normalizePath(path(path)));
238+
exclusivePaths.add(new ExclusivePath(componentName, moduleName, path(path)));
238239
}
239240
return exclusivePaths;
240241
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,10 @@ public void testDuplicateEntitlements() {
356356
)
357357
);
358358
assertEquals(
359-
"[(APM agent)] using module [unnamed] found duplicate entitlement " + "[" + CreateClassLoaderEntitlement.class.getName() + "]",
359+
"[(APM agent)] using module [ALL-UNNAMED] found duplicate entitlement "
360+
+ "["
361+
+ CreateClassLoaderEntitlement.class.getName()
362+
+ "]",
360363
iae.getMessage()
361364
);
362365

0 commit comments

Comments
 (0)