Repository: camel Updated Branches: refs/heads/master ca660ed24 -> 9218c6637
CAMEL-10045: camel-spring-boot - Allow to load sensitive options from external file Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/9218c663 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/9218c663 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/9218c663 Branch: refs/heads/master Commit: 9218c6637063c69e7985f23e5d1e4400693f04b0 Parents: ca660ed Author: Claus Ibsen <davscl...@apache.org> Authored: Fri Jul 1 10:57:26 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Fri Jul 1 14:22:06 2016 +0200 ---------------------------------------------------------------------- .../spring/boot/CamelAutoConfiguration.java | 20 +++++ .../boot/CamelConfigurationProperties.java | 20 +++++ .../camel/spring/boot/FilePropertySource.java | 81 ++++++++++++++++++++ .../boot/CamelConfigurationLocationsTest.java | 61 +++++++++++++++ .../src/test/secret/do-not-tell.properties | 18 +++++ 5 files changed, 200 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/9218c663/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java index a293b6e..a2a760e 100644 --- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java @@ -27,18 +27,26 @@ import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.component.properties.PropertiesParser; import org.apache.camel.spring.CamelBeanPostProcessor; import org.apache.camel.spring.SpringCamelContext; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MutablePropertySources; @Configuration @EnableConfigurationProperties(CamelConfigurationProperties.class) @Import(TypeConversionConfiguration.class) public class CamelAutoConfiguration { + private static final Logger LOG = LoggerFactory.getLogger(CamelAutoConfiguration.class); + /** * Spring-aware Camel context for the application. Auto-detects and loads all routes available in the Spring context. */ @@ -47,6 +55,18 @@ public class CamelAutoConfiguration { CamelContext camelContext(ApplicationContext applicationContext, CamelConfigurationProperties config) { + if (ObjectHelper.isNotEmpty(config.getFileConfigurations())) { + Environment env = applicationContext.getEnvironment(); + if (env instanceof ConfigurableEnvironment) { + MutablePropertySources sources = ((ConfigurableEnvironment) env).getPropertySources(); + if (sources != null) { + if (!sources.contains("camel-file-configuration")) { + sources.addFirst(new FilePropertySource("camel-file-configuration", applicationContext, config.getFileConfigurations())); + } + } + } + } + CamelContext camelContext = new SpringCamelContext(applicationContext); SpringCamelContext.setNoStart(true); http://git-wip-us.apache.org/repos/asf/camel/blob/9218c663/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java index 8f65c9d..e88b6e3 100644 --- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java @@ -62,6 +62,18 @@ public class CamelConfigurationProperties { private String xmlRests = "classpath:camel-rest/*.xml"; /** + * Directory to load additional configuration files that contains + * configuration values that takes precedence over any other configuration. + * This can be used to refer to files that may have secret configuration that + * has been mounted on the file system for containers. + * <p/> + * You must use either <tt>file:</tt> or <tt>classpath:</tt> as prefix to load + * from file system or classpath. Then you can specify a pattern to load + * from sub directories and a name pattern such as <tt>file:/var/app/secret/*.properties</tt> + */ + private String fileConfigurations; + + /** * Whether to use the main run controller to ensure the Spring-Boot application * keeps running until being stopped or the JVM terminated. * You typically only need this if you run Spring-Boot standalone. @@ -322,4 +334,12 @@ public class CamelConfigurationProperties { public void setJmxCreateConnector(boolean jmxCreateConnector) { this.jmxCreateConnector = jmxCreateConnector; } + + public String getFileConfigurations() { + return fileConfigurations; + } + + public void setFileConfigurations(String fileConfigurations) { + this.fileConfigurations = fileConfigurations; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/9218c663/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/FilePropertySource.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/FilePropertySource.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/FilePropertySource.java new file mode 100644 index 0000000..e2aa295 --- /dev/null +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/FilePropertySource.java @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.spring.boot; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.Resource; + +/** + * To load properties from files, such as a secret mounted to the container. + */ +public class FilePropertySource extends PropertySource { + + private static final Logger LOG = LoggerFactory.getLogger(FilePropertySource.class); + + // properties for all the loaded files + private final Properties properties; + + public FilePropertySource(String name, ApplicationContext applicationContext, String directory) { + super(name); + ObjectHelper.notEmpty(directory, "directory"); + + Properties loaded = new Properties(); + try { + Resource[] files = applicationContext.getResources(directory); + for (Resource file : files) { + if (file.exists()) { + try (FileInputStream fis = new FileInputStream(file.getFile())) { + LOG.debug("Loading properties from file: {}", file); + Properties extra = new Properties(); + extra.load(fis); + if (!extra.isEmpty()) { + loaded.putAll(extra); + } + } catch (IOException e) { + // ignore + } + } + } + } catch (IOException e) { + // ignore + } + + // if we loaded any files then store as properties + if (loaded.isEmpty()) { + properties = null; + LOG.warn("No properties found while loading from: {}", directory); + } else { + properties = loaded; + LOG.info("Loaded {} properties from: {}", properties.size(), directory); + } + } + + @Override + public Object getProperty(String name) { + Object answer = properties != null ? properties.getProperty(name) : null; + LOG.trace("getProperty {} -> {}", name, answer); + return answer; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/9218c663/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelConfigurationLocationsTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelConfigurationLocationsTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelConfigurationLocationsTest.java new file mode 100644 index 0000000..2d8691a --- /dev/null +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/CamelConfigurationLocationsTest.java @@ -0,0 +1,61 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.spring.boot; + +import org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@EnableAutoConfiguration +@SpringApplicationConfiguration(classes = CamelConfigurationLocationsTest.class) +@IntegrationTest("camel.springboot.file-configurations=file:src/test/secret/*.properties") +public class CamelConfigurationLocationsTest extends Assert { + + @Autowired + CamelContext camelContext; + + @Autowired + ProducerTemplate producerTemplate; + + @Bean + RouteBuilder routeBuilder() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:foo") + .to("stub:foo?password={{mypassword}}"); + } + }; + } + + @Test + public void shouldSecret() throws InterruptedException { + Object endpoint = camelContext.hasEndpoint("stub:foo?password=1234"); + assertNotNull(endpoint); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/9218c663/components/camel-spring-boot/src/test/secret/do-not-tell.properties ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/test/secret/do-not-tell.properties b/components/camel-spring-boot/src/test/secret/do-not-tell.properties new file mode 100644 index 0000000..277c8c0 --- /dev/null +++ b/components/camel-spring-boot/src/test/secret/do-not-tell.properties @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +mypassword=1234 \ No newline at end of file