Skip to content

Commit 81b1844

Browse files
committed
Move FilesEntitlements validation to a separate class (#127703)
Moves FilesEntitlements validation to a separate class. This is the final PR to make EntitlementsInitialization a simpler "orchestrator" of the various steps in the initialization phase.
1 parent ee01010 commit 81b1844

File tree

2 files changed

+103
-6
lines changed

2 files changed

+103
-6
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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.initialization;
11+
12+
import org.elasticsearch.core.Strings;
13+
import org.elasticsearch.entitlement.runtime.policy.FileAccessTree;
14+
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
15+
import org.elasticsearch.entitlement.runtime.policy.Policy;
16+
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
17+
18+
import java.nio.file.Path;
19+
import java.util.HashSet;
20+
import java.util.Map;
21+
import java.util.Set;
22+
23+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
24+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LIB;
25+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.MODULES;
26+
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.PLUGINS;
27+
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
28+
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
29+
30+
class FilesEntitlementsValidation {
31+
32+
static void validate(Map<String, Policy> pluginPolicies, PathLookup pathLookup) {
33+
Set<Path> readAccessForbidden = new HashSet<>();
34+
pathLookup.getBaseDirPaths(PLUGINS).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
35+
pathLookup.getBaseDirPaths(MODULES).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
36+
pathLookup.getBaseDirPaths(LIB).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
37+
Set<Path> writeAccessForbidden = new HashSet<>();
38+
pathLookup.getBaseDirPaths(CONFIG).forEach(p -> writeAccessForbidden.add(p.toAbsolutePath().normalize()));
39+
for (var pluginPolicy : pluginPolicies.entrySet()) {
40+
for (var scope : pluginPolicy.getValue().scopes()) {
41+
var filesEntitlement = scope.entitlements()
42+
.stream()
43+
.filter(x -> x instanceof FilesEntitlement)
44+
.map(x -> ((FilesEntitlement) x))
45+
.findFirst();
46+
if (filesEntitlement.isPresent()) {
47+
var fileAccessTree = FileAccessTree.withoutExclusivePaths(filesEntitlement.get(), pathLookup, null);
48+
validateReadFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, readAccessForbidden);
49+
validateWriteFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, writeAccessForbidden);
50+
}
51+
}
52+
}
53+
}
54+
55+
private static IllegalArgumentException buildValidationException(
56+
String componentName,
57+
String moduleName,
58+
Path forbiddenPath,
59+
FilesEntitlement.Mode mode
60+
) {
61+
return new IllegalArgumentException(
62+
Strings.format(
63+
"policy for module [%s] in [%s] has an invalid file entitlement. Any path under [%s] is forbidden for mode [%s].",
64+
moduleName,
65+
componentName,
66+
forbiddenPath,
67+
mode
68+
)
69+
);
70+
}
71+
72+
private static void validateReadFilesEntitlements(
73+
String componentName,
74+
String moduleName,
75+
FileAccessTree fileAccessTree,
76+
Set<Path> readForbiddenPaths
77+
) {
78+
79+
for (Path forbiddenPath : readForbiddenPaths) {
80+
if (fileAccessTree.canRead(forbiddenPath)) {
81+
throw buildValidationException(componentName, moduleName, forbiddenPath, READ);
82+
}
83+
}
84+
}
85+
86+
private static void validateWriteFilesEntitlements(
87+
String componentName,
88+
String moduleName,
89+
FileAccessTree fileAccessTree,
90+
Set<Path> writeForbiddenPaths
91+
) {
92+
for (Path forbiddenPath : writeForbiddenPaths) {
93+
if (fileAccessTree.canWrite(forbiddenPath)) {
94+
throw buildValidationException(componentName, moduleName, forbiddenPath, READ_WRITE);
95+
}
96+
}
97+
}
98+
}
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
import static org.hamcrest.Matchers.endsWith;
2828
import static org.hamcrest.Matchers.startsWith;
2929

30-
@ESTestCase.WithoutSecurityManager
31-
public class EntitlementInitializationTests extends ESTestCase {
30+
public class FilesEntitlementsValidationTests extends ESTestCase {
3231

3332
private static PathLookup TEST_PATH_LOOKUP;
3433

@@ -76,7 +75,7 @@ public void testValidationPass() {
7675
)
7776
)
7877
);
79-
EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP);
78+
FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP);
8079
}
8180

8281
public void testValidationFailForRead() {
@@ -95,7 +94,7 @@ public void testValidationFailForRead() {
9594

9695
var ex = expectThrows(
9796
IllegalArgumentException.class,
98-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP)
97+
() -> FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP)
9998
);
10099
assertThat(
101100
ex.getMessage(),
@@ -120,7 +119,7 @@ public void testValidationFailForRead() {
120119

121120
ex = expectThrows(
122121
IllegalArgumentException.class,
123-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin2", policy2), TEST_PATH_LOOKUP)
122+
() -> FilesEntitlementsValidation.validate(Map.of("plugin2", policy2), TEST_PATH_LOOKUP)
124123
);
125124
assertThat(
126125
ex.getMessage(),
@@ -146,7 +145,7 @@ public void testValidationFailForWrite() {
146145

147146
var ex = expectThrows(
148147
IllegalArgumentException.class,
149-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP)
148+
() -> FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP)
150149
);
151150
assertThat(
152151
ex.getMessage(),

0 commit comments

Comments
 (0)