Skip to content

Commit f90b015

Browse files
authored
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 64568ee commit f90b015

File tree

3 files changed

+104
-77
lines changed

3 files changed

+104
-77
lines changed

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

+1-72
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@
1010
package org.elasticsearch.entitlement.initialization;
1111

1212
import org.elasticsearch.core.Booleans;
13-
import org.elasticsearch.core.Strings;
1413
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
1514
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
1615
import org.elasticsearch.entitlement.runtime.api.ElasticsearchEntitlementChecker;
17-
import org.elasticsearch.entitlement.runtime.policy.FileAccessTree;
1816
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
1917
import org.elasticsearch.entitlement.runtime.policy.Policy;
2018
import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
@@ -39,7 +37,6 @@
3937
import java.nio.file.Path;
4038
import java.util.ArrayList;
4139
import java.util.Collections;
42-
import java.util.HashSet;
4340
import java.util.List;
4441
import java.util.Map;
4542
import java.util.Set;
@@ -248,7 +245,7 @@ private static PolicyManager createPolicyManager() {
248245
)
249246
);
250247

251-
validateFilesEntitlements(pluginPolicies, pathLookup);
248+
FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
252249

253250
return new PolicyManager(
254251
serverPolicy,
@@ -262,74 +259,6 @@ private static PolicyManager createPolicyManager() {
262259
);
263260
}
264261

265-
// package visible for tests
266-
static void validateFilesEntitlements(Map<String, Policy> pluginPolicies, PathLookup pathLookup) {
267-
Set<Path> readAccessForbidden = new HashSet<>();
268-
pathLookup.getBaseDirPaths(PLUGINS).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
269-
pathLookup.getBaseDirPaths(MODULES).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
270-
pathLookup.getBaseDirPaths(LIB).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
271-
Set<Path> writeAccessForbidden = new HashSet<>();
272-
pathLookup.getBaseDirPaths(CONFIG).forEach(p -> writeAccessForbidden.add(p.toAbsolutePath().normalize()));
273-
for (var pluginPolicy : pluginPolicies.entrySet()) {
274-
for (var scope : pluginPolicy.getValue().scopes()) {
275-
var filesEntitlement = scope.entitlements()
276-
.stream()
277-
.filter(x -> x instanceof FilesEntitlement)
278-
.map(x -> ((FilesEntitlement) x))
279-
.findFirst();
280-
if (filesEntitlement.isPresent()) {
281-
var fileAccessTree = FileAccessTree.withoutExclusivePaths(filesEntitlement.get(), pathLookup, null);
282-
validateReadFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, readAccessForbidden);
283-
validateWriteFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, writeAccessForbidden);
284-
}
285-
}
286-
}
287-
}
288-
289-
private static IllegalArgumentException buildValidationException(
290-
String componentName,
291-
String moduleName,
292-
Path forbiddenPath,
293-
FilesEntitlement.Mode mode
294-
) {
295-
return new IllegalArgumentException(
296-
Strings.format(
297-
"policy for module [%s] in [%s] has an invalid file entitlement. Any path under [%s] is forbidden for mode [%s].",
298-
moduleName,
299-
componentName,
300-
forbiddenPath,
301-
mode
302-
)
303-
);
304-
}
305-
306-
private static void validateReadFilesEntitlements(
307-
String componentName,
308-
String moduleName,
309-
FileAccessTree fileAccessTree,
310-
Set<Path> readForbiddenPaths
311-
) {
312-
313-
for (Path forbiddenPath : readForbiddenPaths) {
314-
if (fileAccessTree.canRead(forbiddenPath)) {
315-
throw buildValidationException(componentName, moduleName, forbiddenPath, READ);
316-
}
317-
}
318-
}
319-
320-
private static void validateWriteFilesEntitlements(
321-
String componentName,
322-
String moduleName,
323-
FileAccessTree fileAccessTree,
324-
Set<Path> writeForbiddenPaths
325-
) {
326-
for (Path forbiddenPath : writeForbiddenPaths) {
327-
if (fileAccessTree.canWrite(forbiddenPath)) {
328-
throw buildValidationException(componentName, moduleName, forbiddenPath, READ_WRITE);
329-
}
330-
}
331-
}
332-
333262
/**
334263
* If bytecode verification is enabled, ensure these classes get loaded before transforming/retransforming them.
335264
* For these classes, the order in which we transform and verify them matters. Verification during class transformation is at least an
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+
}
+5-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import static org.hamcrest.Matchers.endsWith;
2828
import static org.hamcrest.Matchers.startsWith;
2929

30-
public class EntitlementInitializationTests extends ESTestCase {
30+
public class FilesEntitlementsValidationTests extends ESTestCase {
3131

3232
private static PathLookup TEST_PATH_LOOKUP;
3333

@@ -75,7 +75,7 @@ public void testValidationPass() {
7575
)
7676
)
7777
);
78-
EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP);
78+
FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP);
7979
}
8080

8181
public void testValidationFailForRead() {
@@ -94,7 +94,7 @@ public void testValidationFailForRead() {
9494

9595
var ex = expectThrows(
9696
IllegalArgumentException.class,
97-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP)
97+
() -> FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP)
9898
);
9999
assertThat(
100100
ex.getMessage(),
@@ -119,7 +119,7 @@ public void testValidationFailForRead() {
119119

120120
ex = expectThrows(
121121
IllegalArgumentException.class,
122-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin2", policy2), TEST_PATH_LOOKUP)
122+
() -> FilesEntitlementsValidation.validate(Map.of("plugin2", policy2), TEST_PATH_LOOKUP)
123123
);
124124
assertThat(
125125
ex.getMessage(),
@@ -145,7 +145,7 @@ public void testValidationFailForWrite() {
145145

146146
var ex = expectThrows(
147147
IllegalArgumentException.class,
148-
() -> EntitlementInitialization.validateFilesEntitlements(Map.of("plugin", policy), TEST_PATH_LOOKUP)
148+
() -> FilesEntitlementsValidation.validate(Map.of("plugin", policy), TEST_PATH_LOOKUP)
149149
);
150150
assertThat(
151151
ex.getMessage(),

0 commit comments

Comments
 (0)