This is an automated email from the ASF dual-hosted git repository. rotty3000 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/master by this push: new afa3924 [FELIX-6414] Interpolation plugin support multiple secrets directories afa3924 is described below commit afa392414c8939e3f4dd73939621fb22aefbf47c Author: Raymond Augé <rotty3...@apache.org> AuthorDate: Sun May 9 15:41:41 2021 -0400 [FELIX-6414] Interpolation plugin support multiple secrets directories Signed-off-by: Raymond Augé <rotty3...@apache.org> --- configadmin-plugins/interpolation/README.md | 4 +-- .../InterpolationConfigurationPlugin.java | 27 ++++++++++++------ .../InterpolationConfigurationPluginTest.java | 32 +++++++++++++++++----- .../interpolation/src/test/resources/foo.bar | 1 + .../src/test/resources/{ => other}/testfile.txt | 0 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/configadmin-plugins/interpolation/README.md b/configadmin-plugins/interpolation/README.md index 868ea0f..d6605fc 100644 --- a/configadmin-plugins/interpolation/README.md +++ b/configadmin-plugins/interpolation/README.md @@ -109,12 +109,12 @@ In case of the Apache Felix ConfigAdmin implementation, this can be achieved by ### Secrets lookup -In order to look up secrets on the filesystem, the plugin must be provided with the directory +In order to look up secrets on the filesystem, the plugin must be provided with the directories where these can be found. This is done through the following property: -* `org.apache.felix.configadmin.plugin.interpolation.secretsdir`: specify the directory where the files used for the file-based interpolation, such as Kubernetes secrets, are mounted. +* `org.apache.felix.configadmin.plugin.interpolation.secretsdir`: specify a comma-separated (`,`) list of directories where the files used for the file-based interpolation, such as Kubernetes secrets, are mounted. If the property is not present, the plugin will function, but without being able to replace values based on secrets. diff --git a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java index 97656ae..4974848 100644 --- a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java +++ b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java @@ -16,17 +16,22 @@ */ package org.apache.felix.configadmin.plugin.interpolation; +import static java.util.stream.Collectors.toList; + import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -91,17 +96,17 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin { } private final BundleContext context; - private final File directory; + private final List<File> directory; private final Charset encodingCharset; InterpolationConfigurationPlugin(BundleContext bc, String dir, String fileEncoding) { context = bc; if (dir != null) { - directory = new File(dir); + directory = Stream.of(dir.split("\\s*,\\s*")).map(File::new).collect(toList()); getLog().info("Configured directory for secrets: {}", dir); } else { - directory = null; + directory = Collections.emptyList(); } if (fileEncoding == null) { encodingCharset = Charset.defaultCharset(); @@ -188,7 +193,7 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin { } String getVariableFromFile(final String key, final String name, final Object pid) { - if (directory == null) { + if (directory.isEmpty()) { getLog().warn("Cannot replace property value {} for PID {}. No directory configured via framework property " + Activator.DIR_PROPERTY, key, pid); return null; @@ -199,17 +204,21 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin { return null; } - File file = new File(directory, name); - if (!file.isFile()) { - getLog().warn("Cannot replace variable. Configured path is not a regular file: " + file); + List<File> files = directory.stream().map(d -> new File(d, name)).filter(File::exists).collect(toList()); + if (files.stream().noneMatch(File::isFile)) { + getLog().warn("Cannot replace variable. Configured paths are not regular files: " + files); return null; } - if (!file.getAbsolutePath().startsWith(directory.getAbsolutePath())) { + if (files.stream().map(File::getAbsolutePath).noneMatch(s -> directory.stream().anyMatch(dir -> s.startsWith(dir.getAbsolutePath())))) { getLog().error("Illegal secret location: " + name + " Going out the directory structure is not allowed"); return null; } + File file = files.stream().findFirst().orElseThrow( + () -> new IllegalStateException( + "Something went terribly wrong. This should not be possible.")); + byte[] bytes; try { bytes = Files.readAllBytes(file.toPath()); @@ -253,7 +262,7 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin { * the delimiter (avoiding splitting), unless that backslash is preceded by * another backslash, in which case the two backslashes are replaced by a single * one and the value is split after the backslash. - * + * * @param value The value to split * @param delimiter The delimiter * @return The resulting array diff --git a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java index 7a38573..888f0a5 100644 --- a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java +++ b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java @@ -114,9 +114,10 @@ public class InterpolationConfigurationPluginTest { @Test public void testReplacement() throws Exception { - String rf = getClass().getResource("/testfile.txt").getFile(); + String rf = getClass().getResource("/other/testfile.txt").getFile(); + File file = new File(rf); InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(null, - new File(rf).getParent(), null); + file.getParent() + "," + file.getParentFile().getParent(), null); assertEquals("xxla la layy", plugin.replace("akey", "xx$[secret:testfile.txt]yy", "apid")); String doesNotReplace = "xx$[" + rf + "]yy"; @@ -125,9 +126,10 @@ public class InterpolationConfigurationPluginTest { @Test public void testNoReplacement() throws IOException { - String rf = getClass().getResource("/testfile.txt").getFile(); + String rf = getClass().getResource("/other/testfile.txt").getFile(); + File file = new File(rf); InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(null, - new File(rf).getParent(), null); + file.getParent() + "," + file.getParentFile().getParent(), null); assertEquals("foo", plugin.replace("akey", "foo", "apid")); } @@ -187,9 +189,10 @@ public class InterpolationConfigurationPluginTest { public void testMultiplePlaceholders() throws Exception { BundleContext bc = Mockito.mock(BundleContext.class); Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there"); - String rf = getClass().getResource("/testfile.txt").getFile(); - InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, new File(rf).getParent(), - null); + String rf = getClass().getResource("/other/testfile.txt").getFile(); + File file = new File(rf); + InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, + file.getParent() + "," + file.getParentFile().getParent(), null); assertEquals("xxhello thereyyhello therezz", plugin.replace("akey", "xx$[prop:foo.bar]yy$[prop:foo.bar]zz", "apid")); @@ -199,6 +202,21 @@ public class InterpolationConfigurationPluginTest { } @Test + public void testMultipleDirectories() throws Exception { + BundleContext bc = Mockito.mock(BundleContext.class); + String rf = getClass().getResource("/other/testfile.txt").getFile(); + File file = new File(rf); + InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, + file.getParent() + "," + file.getParentFile().getParent(), null); + + assertEquals("xxhello thereyyhello therezz", + plugin.replace("akey", "xx$[secret:foo.bar]yy$[secret:foo.bar]zz", "apid")); + + assertEquals("xxla la layyhello therezz", + plugin.replace("akey", "xx$[secret:testfile.txt]yy$[secret:foo.bar]zz", "apid")); + } + + @Test public void testNestedPlaceholders() throws Exception { BundleContext bc = Mockito.mock(BundleContext.class); Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there"); diff --git a/configadmin-plugins/interpolation/src/test/resources/foo.bar b/configadmin-plugins/interpolation/src/test/resources/foo.bar new file mode 100644 index 0000000..d2aeeec --- /dev/null +++ b/configadmin-plugins/interpolation/src/test/resources/foo.bar @@ -0,0 +1 @@ +hello there \ No newline at end of file diff --git a/configadmin-plugins/interpolation/src/test/resources/testfile.txt b/configadmin-plugins/interpolation/src/test/resources/other/testfile.txt similarity index 100% rename from configadmin-plugins/interpolation/src/test/resources/testfile.txt rename to configadmin-plugins/interpolation/src/test/resources/other/testfile.txt