Skip to content

Commit 0d05ff9

Browse files
authored
Add ignore_url for setting based files entitlement (elastic#123541) (elastic#123546)
File entitlements which read a setting may actually contain urls. This commit adds an optional `ignore_url` property for the entitlement to skip any values which are urls.
1 parent 1a378c0 commit 0d05ff9

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

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

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

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

12+
import org.elasticsearch.core.Booleans;
1213
import org.elasticsearch.entitlement.runtime.policy.ExternalEntitlement;
1314
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
1415
import org.elasticsearch.entitlement.runtime.policy.PolicyValidationException;
@@ -17,6 +18,7 @@
1718
import java.util.ArrayList;
1819
import java.util.HashMap;
1920
import java.util.List;
21+
import java.util.Locale;
2022
import java.util.Map;
2123
import java.util.Objects;
2224
import java.util.stream.Stream;
@@ -85,12 +87,12 @@ static FileData ofRelativePath(Path relativePath, BaseDir baseDir, Mode mode) {
8587
return new RelativePathFileData(relativePath, baseDir, mode, null);
8688
}
8789

88-
static FileData ofPathSetting(String setting, Mode mode) {
89-
return new PathSettingFileData(setting, mode, null);
90+
static FileData ofPathSetting(String setting, Mode mode, boolean ignoreUrl) {
91+
return new PathSettingFileData(setting, mode, ignoreUrl, null);
9092
}
9193

92-
static FileData ofRelativePathSetting(String setting, BaseDir baseDir, Mode mode) {
93-
return new RelativePathSettingFileData(setting, baseDir, mode, null);
94+
static FileData ofRelativePathSetting(String setting, BaseDir baseDir, Mode mode, boolean ignoreUrl) {
95+
return new RelativePathSettingFileData(setting, baseDir, mode, ignoreUrl, null);
9496
}
9597

9698
/**
@@ -207,45 +209,51 @@ public FileData withPlatform(Platform platform) {
207209
}
208210
}
209211

210-
private record PathSettingFileData(String setting, Mode mode, Platform platform) implements FileData {
212+
private record PathSettingFileData(String setting, Mode mode, boolean ignoreUrl, Platform platform) implements FileData {
211213
@Override
212214
public Stream<Path> resolvePaths(PathLookup pathLookup) {
213-
return resolvePathSettings(pathLookup, setting);
215+
return resolvePathSettings(pathLookup, setting, ignoreUrl);
214216
}
215217

216218
@Override
217219
public FileData withPlatform(Platform platform) {
218220
if (platform == platform()) {
219221
return this;
220222
}
221-
return new PathSettingFileData(setting, mode, platform);
223+
return new PathSettingFileData(setting, mode, ignoreUrl, platform);
222224
}
223225
}
224226

225-
private record RelativePathSettingFileData(String setting, BaseDir baseDir, Mode mode, Platform platform)
227+
private record RelativePathSettingFileData(String setting, BaseDir baseDir, Mode mode, boolean ignoreUrl, Platform platform)
226228
implements
227229
FileData,
228230
RelativeFileData {
229231
@Override
230232
public Stream<Path> resolveRelativePaths(PathLookup pathLookup) {
231-
return resolvePathSettings(pathLookup, setting);
233+
return resolvePathSettings(pathLookup, setting, ignoreUrl);
232234
}
233235

234236
@Override
235237
public FileData withPlatform(Platform platform) {
236238
if (platform == platform()) {
237239
return this;
238240
}
239-
return new RelativePathSettingFileData(setting, baseDir, mode, platform);
241+
return new RelativePathSettingFileData(setting, baseDir, mode, ignoreUrl, platform);
240242
}
241243
}
242244

243-
private static Stream<Path> resolvePathSettings(PathLookup pathLookup, String setting) {
245+
private static Stream<Path> resolvePathSettings(PathLookup pathLookup, String setting, boolean ignoreUrl) {
246+
Stream<String> result;
244247
if (setting.contains("*")) {
245-
return pathLookup.settingGlobResolver().apply(setting).map(Path::of);
248+
result = pathLookup.settingGlobResolver().apply(setting);
249+
} else {
250+
String path = pathLookup.settingResolver().apply(setting);
251+
result = path == null ? Stream.of() : Stream.of(path);
252+
}
253+
if (ignoreUrl) {
254+
result = result.filter(s -> s.toLowerCase(Locale.ROOT).startsWith("https://") == false);
246255
}
247-
String path = pathLookup.settingResolver().apply(setting);
248-
return path == null ? Stream.of() : Stream.of(Path.of(path));
256+
return result.map(Path::of);
249257
}
250258

251259
private static Mode parseMode(String mode) {
@@ -298,6 +306,7 @@ public static FilesEntitlement build(List<Object> paths) {
298306
String relativePathSetting = file.remove("relative_path_setting");
299307
String modeAsString = file.remove("mode");
300308
String platformAsString = file.remove("platform");
309+
String ignoreUrlAsString = file.remove("ignore_url");
301310

302311
if (file.isEmpty() == false) {
303312
throw new PolicyValidationException("unknown key(s) [" + file + "] in a listed file for files entitlement");
@@ -324,6 +333,14 @@ public static FilesEntitlement build(List<Object> paths) {
324333
baseDir = parseBaseDir(relativeTo);
325334
}
326335

336+
boolean ignoreUrl = false;
337+
if (ignoreUrlAsString != null) {
338+
if (relativePathAsString != null || pathAsString != null) {
339+
throw new PolicyValidationException("'ignore_url' may only be used with `path_setting` or `relative_path_setting`");
340+
}
341+
ignoreUrl = Booleans.parseBoolean(ignoreUrlAsString);
342+
}
343+
327344
final FileData fileData;
328345
if (relativePathAsString != null) {
329346
if (baseDir == null) {
@@ -342,12 +359,12 @@ public static FilesEntitlement build(List<Object> paths) {
342359
}
343360
fileData = FileData.ofPath(path, mode);
344361
} else if (pathSetting != null) {
345-
fileData = FileData.ofPathSetting(pathSetting, mode);
362+
fileData = FileData.ofPathSetting(pathSetting, mode, ignoreUrl);
346363
} else if (relativePathSetting != null) {
347364
if (baseDir == null) {
348365
throw new PolicyValidationException("files entitlement with a 'relative_path_setting' must specify 'relative_to'");
349366
}
350-
fileData = FileData.ofRelativePathSetting(relativePathSetting, baseDir, mode);
367+
fileData = FileData.ofRelativePathSetting(relativePathSetting, baseDir, mode, ignoreUrl);
351368
} else {
352369
throw new AssertionError("File entry validation error");
353370
}

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

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.Map;
2222

23+
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.BaseDir.CONFIG;
2324
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
2425
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
2526
import static org.hamcrest.Matchers.contains;
@@ -94,22 +95,50 @@ public void testFileDataRelativeWithEmptyDirectory() {
9495
public void testPathSettingResolve() {
9596
var entitlement = FilesEntitlement.build(List.of(Map.of("path_setting", "foo.bar", "mode", "read")));
9697
var filesData = entitlement.filesData();
97-
assertThat(filesData, contains(FileData.ofPathSetting("foo.bar", READ)));
98+
assertThat(filesData, contains(FileData.ofPathSetting("foo.bar", READ, false)));
9899

99-
var fileData = FileData.ofPathSetting("foo.bar", READ);
100+
var fileData = FileData.ofPathSetting("foo.bar", READ, false);
100101
// empty settings
101102
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), empty());
102103

103-
fileData = FileData.ofPathSetting("foo.bar", READ);
104+
fileData = FileData.ofPathSetting("foo.bar", READ, false);
104105
settings = Settings.builder().put("foo.bar", "/setting/path").build();
105106
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), contains(Path.of("/setting/path")));
106107

107-
fileData = FileData.ofPathSetting("foo.*.bar", READ);
108+
fileData = FileData.ofPathSetting("foo.*.bar", READ, false);
108109
settings = Settings.builder().put("foo.baz.bar", "/setting/path").build();
109110
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), contains(Path.of("/setting/path")));
110111

111-
fileData = FileData.ofPathSetting("foo.*.bar", READ);
112+
fileData = FileData.ofPathSetting("foo.*.bar", READ, false);
112113
settings = Settings.builder().put("foo.baz.bar", "/setting/path").put("foo.baz2.bar", "/other/path").build();
113114
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), containsInAnyOrder(Path.of("/setting/path"), Path.of("/other/path")));
114115
}
116+
117+
public void testPathSettingIgnoreUrl() {
118+
var fileData = FileData.ofPathSetting("foo.*.bar", READ, true);
119+
settings = Settings.builder().put("foo.nonurl.bar", "/setting/path").put("foo.url.bar", "https://mysite").build();
120+
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), contains(Path.of("/setting/path")));
121+
}
122+
123+
public void testRelativePathSettingIgnoreUrl() {
124+
var fileData = FileData.ofRelativePathSetting("foo.*.bar", CONFIG, READ, true);
125+
settings = Settings.builder().put("foo.nonurl.bar", "path").put("foo.url.bar", "https://mysite").build();
126+
assertThat(fileData.resolvePaths(TEST_PATH_LOOKUP).toList(), contains(Path.of("/config/path")));
127+
}
128+
129+
public void testIgnoreUrlValidation() {
130+
var e = expectThrows(
131+
PolicyValidationException.class,
132+
() -> FilesEntitlement.build(List.of(Map.of("path", "/foo", "mode", "read", "ignore_url", "true")))
133+
);
134+
assertThat(e.getMessage(), is("'ignore_url' may only be used with `path_setting` or `relative_path_setting`"));
135+
136+
e = expectThrows(
137+
PolicyValidationException.class,
138+
() -> FilesEntitlement.build(
139+
List.of(Map.of("relative_path", "foo", "relative_to", "config", "mode", "read", "ignore_url", "true"))
140+
)
141+
);
142+
assertThat(e.getMessage(), is("'ignore_url' may only be used with `path_setting` or `relative_path_setting`"));
143+
}
115144
}

0 commit comments

Comments
 (0)