Skip to content

Commit 7304580

Browse files
authored
Support file entitlements relative to the user's home directory (#122724) (#122794)
1 parent 92b5abf commit 7304580

File tree

6 files changed

+52
-32
lines changed

6 files changed

+52
-32
lines changed

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

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

1010
package org.elasticsearch.entitlement.initialization;
1111

12+
import org.elasticsearch.core.PathUtils;
1213
import org.elasticsearch.core.internal.provider.ProviderLocator;
1314
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
1415
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
@@ -133,7 +134,7 @@ private static Class<?>[] findClassesToRetransform(Class<?>[] loadedClasses, Set
133134
private static PolicyManager createPolicyManager() {
134135
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
135136
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
136-
var pathLookup = new PathLookup(bootstrapArgs.configDir(), bootstrapArgs.dataDirs(), bootstrapArgs.tempDir());
137+
var pathLookup = new PathLookup(getUserHome(), bootstrapArgs.configDir(), bootstrapArgs.dataDirs(), bootstrapArgs.tempDir());
137138
Path logsDir = EntitlementBootstrap.bootstrapArgs().logsDir();
138139

139140
// TODO(ES-10031): Decide what goes in the elasticsearch default policy and extend it
@@ -221,6 +222,14 @@ private static PolicyManager createPolicyManager() {
221222
);
222223
}
223224

225+
private static Path getUserHome() {
226+
String userHome = System.getProperty("user.home");
227+
if (userHome == null) {
228+
throw new IllegalStateException("user.home system property is required");
229+
}
230+
return PathUtils.get(userHome);
231+
}
232+
224233
private static Stream<InstrumentationService.InstrumentationInfo> fileSystemProviderChecks() throws ClassNotFoundException,
225234
NoSuchMethodException {
226235
var fileSystemProviderClass = FileSystems.getDefault().provider().getClass();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111

1212
import java.nio.file.Path;
1313

14-
public record PathLookup(Path configDir, Path[] dataDirs, Path tempDir) {}
14+
public record PathLookup(Path homeDir, Path configDir, Path[] dataDirs, Path tempDir) {}

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public enum Mode {
3636

3737
public enum BaseDir {
3838
CONFIG,
39-
DATA
39+
DATA,
40+
HOME
4041
}
4142

4243
public sealed interface FileData {
@@ -73,6 +74,8 @@ public Stream<Path> resolvePaths(PathLookup pathLookup) {
7374
return Stream.of(pathLookup.configDir().resolve(relativePath));
7475
case DATA:
7576
return Arrays.stream(pathLookup.dataDirs()).map(d -> d.resolve(relativePath));
77+
case HOME:
78+
return Stream.of(pathLookup.homeDir().resolve(relativePath));
7679
default:
7780
throw new IllegalArgumentException();
7881
}
@@ -90,12 +93,14 @@ private static Mode parseMode(String mode) {
9093
}
9194

9295
private static BaseDir parseBaseDir(String baseDir) {
93-
if (baseDir.equals("config")) {
94-
return BaseDir.CONFIG;
95-
} else if (baseDir.equals("data")) {
96-
return BaseDir.DATA;
97-
}
98-
throw new PolicyValidationException("invalid relative directory: " + baseDir + ", valid values: [config, data]");
96+
return switch (baseDir) {
97+
case "config" -> BaseDir.CONFIG;
98+
case "data" -> BaseDir.DATA;
99+
case "home" -> BaseDir.HOME;
100+
default -> throw new PolicyValidationException(
101+
"invalid relative directory: " + baseDir + ", valid values: [config, data, home]"
102+
);
103+
};
99104
}
100105

101106
@ExternalEntitlement(parameterNames = { "paths" }, esModulesOnly = false)

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

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private static Path path(String s) {
3636
}
3737

3838
private static final PathLookup TEST_PATH_LOOKUP = new PathLookup(
39+
Path.of("/home"),
3940
Path.of("/config"),
4041
new Path[] { Path.of("/data1"), Path.of("/data2") },
4142
Path.of("/tmp")
@@ -91,32 +92,36 @@ public void testReadWriteUnderRead() {
9192
}
9293

9394
public void testReadWithRelativePath() {
94-
var tree = accessTree(entitlement(Map.of("relative_path", "foo", "mode", "read", "relative_to", "config")));
95-
assertThat(tree.canRead(path("foo")), is(false));
95+
for (var dir : List.of("config", "home")) {
96+
var tree = accessTree(entitlement(Map.of("relative_path", "foo", "mode", "read", "relative_to", dir)));
97+
assertThat(tree.canRead(path("foo")), is(false));
9698

97-
assertThat(tree.canRead(path("/config/foo")), is(true));
99+
assertThat(tree.canRead(path("/" + dir + "/foo")), is(true));
98100

99-
assertThat(tree.canRead(path("/config/foo/subdir")), is(true));
100-
assertThat(tree.canRead(path("/config/food")), is(false));
101-
assertThat(tree.canWrite(path("/config/foo")), is(false));
101+
assertThat(tree.canRead(path("/" + dir + "/foo/subdir")), is(true));
102+
assertThat(tree.canRead(path("/" + dir + "/food")), is(false));
103+
assertThat(tree.canWrite(path("/" + dir + "/foo")), is(false));
102104

103-
assertThat(tree.canRead(path("/config")), is(false));
104-
assertThat(tree.canRead(path("/config/before")), is(false));
105-
assertThat(tree.canRead(path("/config/later")), is(false));
105+
assertThat(tree.canRead(path("/" + dir)), is(false));
106+
assertThat(tree.canRead(path("/" + dir + "/before")), is(false));
107+
assertThat(tree.canRead(path("/" + dir + "/later")), is(false));
108+
}
106109
}
107110

108111
public void testWriteWithRelativePath() {
109-
var tree = accessTree(entitlement(Map.of("relative_path", "foo", "mode", "read_write", "relative_to", "config")));
110-
assertThat(tree.canWrite(path("/config/foo")), is(true));
111-
assertThat(tree.canWrite(path("/config/foo/subdir")), is(true));
112-
assertThat(tree.canWrite(path("foo")), is(false));
113-
assertThat(tree.canWrite(path("/config/food")), is(false));
114-
assertThat(tree.canRead(path("/config/foo")), is(true));
115-
assertThat(tree.canRead(path("foo")), is(false));
116-
117-
assertThat(tree.canWrite(path("/config")), is(false));
118-
assertThat(tree.canWrite(path("/config/before")), is(false));
119-
assertThat(tree.canWrite(path("/config/later")), is(false));
112+
for (var dir : List.of("config", "home")) {
113+
var tree = accessTree(entitlement(Map.of("relative_path", "foo", "mode", "read_write", "relative_to", dir)));
114+
assertThat(tree.canWrite(path("/" + dir + "/foo")), is(true));
115+
assertThat(tree.canWrite(path("/" + dir + "/foo/subdir")), is(true));
116+
assertThat(tree.canWrite(path("/" + dir)), is(false));
117+
assertThat(tree.canWrite(path("/" + dir + "/food")), is(false));
118+
assertThat(tree.canRead(path("/" + dir + "/foo")), is(true));
119+
assertThat(tree.canRead(path("/" + dir)), is(false));
120+
121+
assertThat(tree.canWrite(path("/" + dir)), is(false));
122+
assertThat(tree.canWrite(path("/" + dir + "/before")), is(false));
123+
assertThat(tree.canWrite(path("/" + dir + "/later")), is(false));
124+
}
120125
}
121126

122127
public void testMultipleDataDirs() {
@@ -161,7 +166,7 @@ public void testTempDirAccess() {
161166
Path tempDir = createTempDir();
162167
var tree = FileAccessTree.of(
163168
FilesEntitlement.EMPTY,
164-
new PathLookup(Path.of("/config"), new Path[] { Path.of("/data1"), Path.of("/data2") }, tempDir)
169+
new PathLookup(Path.of("/home"), Path.of("/config"), new Path[] { Path.of("/data1"), Path.of("/data2") }, tempDir)
165170
);
166171
assertThat(tree.canRead(tempDir), is(true));
167172
assertThat(tree.canWrite(tempDir), is(true));

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public class PolicyManagerTests extends ESTestCase {
5454
private static Module NO_ENTITLEMENTS_MODULE;
5555

5656
private static final PathLookup TEST_PATH_LOOKUP = new PathLookup(
57+
Path.of("/user/home"),
5758
Path.of("/config"),
5859
new Path[] { Path.of("/data1/"), Path.of("/data2") },
5960
Path.of("/temp")

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ public void testInvalidRelativeDirectory() {
3535
PolicyValidationException.class,
3636
() -> FilesEntitlement.build(List.of((Map.of("relative_path", "foo", "mode", "read", "relative_to", "bar"))))
3737
);
38-
assertThat(ex.getMessage(), is("invalid relative directory: bar, valid values: [config, data]"));
38+
assertThat(ex.getMessage(), is("invalid relative directory: bar, valid values: [config, data, home]"));
3939
}
4040

4141
public void testFileDataRelativeWithEmptyDirectory() {
4242
var fileData = FilesEntitlement.FileData.ofRelativePath(Path.of(""), FilesEntitlement.BaseDir.DATA, READ_WRITE);
4343
var dataDirs = fileData.resolvePaths(
44-
new PathLookup(Path.of("/config"), new Path[] { Path.of("/data1/"), Path.of("/data2") }, Path.of("/temp"))
44+
new PathLookup(Path.of("/home"), Path.of("/config"), new Path[] { Path.of("/data1/"), Path.of("/data2") }, Path.of("/temp"))
4545
);
4646
assertThat(dataDirs.toList(), contains(Path.of("/data1/"), Path.of("/data2")));
4747
}

0 commit comments

Comments
 (0)