diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java index 93d2dcbd6dcc..77a0f118d5eb 100644 --- a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; import org.springframework.context.annotation.Bean; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; @@ -45,6 +46,7 @@ public class CamelSecurityPolicyAutoConfiguration { private static final Logger LOG = LoggerFactory.getLogger(CamelSecurityPolicyAutoConfiguration.class); + private static final String CAMEL_PREFIX = "camel."; @Bean SecurityPolicyResult camelSecurityPolicyResult(CamelContext camelContext, @@ -111,10 +113,11 @@ private static Map extractCamelProperties(Environment environmen ce.getPropertySources().forEach(ps -> { if (ps instanceof EnumerablePropertySource eps) { for (String name : eps.getPropertyNames()) { - if (name != null && name.startsWith("camel.") && !name.startsWith("camel.security.")) { - Object value = environment.getProperty(name); + String canonical = canonicalCamelName(name); + if (canonical != null && !canonical.startsWith("camel.security.")) { + Object value = environment.getProperty(canonical); if (value != null) { - properties.putIfAbsent(name, value); + properties.putIfAbsent(canonical, value); } } } @@ -125,6 +128,28 @@ private static Map extractCamelProperties(Environment environmen return properties; } + /** + * Canonicalizes a property name as its source reports it, returning null when it is not a Camel + * property. + *

+ * Property sources report names in their own form: an option set in application.properties arrives as + * camel.component.foo.bar, while the same option set as an environment variable arrives as + * CAMEL_COMPONENT_FOO_BAR. Spring's relaxed binding applies both to the same option, so both have to + * be recognised here - otherwise every option configured through the environment, which is the usual way to + * configure a containerised application, is invisible to the policy check. + */ + private static String canonicalCamelName(String name) { + if (name == null) { + return null; + } + if (name.startsWith(CAMEL_PREFIX)) { + return name; + } + ConfigurationPropertyName adapted = ConfigurationPropertyName.adapt(name, '_'); + String canonical = adapted.toString(); + return canonical.startsWith(CAMEL_PREFIX) ? canonical : null; + } + private static boolean containsSensitive(CamelContext camelContext, String key, Object value) { boolean answer = CamelContextHelper.containsSensitive(camelContext, key); if (!answer && value != null) { diff --git a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfigurationTest.java b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfigurationTest.java index b7b7cf20a8fb..6d50f9f4012c 100644 --- a/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfigurationTest.java +++ b/core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/security/CamelSecurityPolicyAutoConfigurationTest.java @@ -22,6 +22,9 @@ import org.apache.camel.main.SecurityPolicyResult; import org.apache.camel.spring.boot.CamelAutoConfiguration; import org.junit.jupiter.api.Test; +import org.springframework.core.env.SystemEnvironmentPropertySource; + +import java.util.Map; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -132,4 +135,38 @@ public void insecureSerializationPolicyOverride() { }); } + + /** + * The same option configured as an environment variable arrives as CAMEL_COMPONENT_HTTP_TRUSTALLCERTIFICATES, + * which never matched the "camel." prefix - so every option set through the environment, the usual way to + * configure a containerised application, escaped the policy check entirely. + */ + @Test + public void policyShouldSeeInsecureOptionsSetThroughTheEnvironment() { + runner.withPropertyValues("camel.security.policy=warn") + .withInitializer(ctx -> ctx.getEnvironment().getPropertySources() + .addFirst(new SystemEnvironmentPropertySource("testSystemEnvironment", + Map.of("CAMEL_COMPONENT_HTTP_TRUSTALLCERTIFICATES", "true")))) + .run(context -> { + assertThat(context).hasNotFailed(); + SecurityPolicyResult result = context.getBean(SecurityPolicyResult.class); + assertThat(result.hasViolations()).isTrue(); + assertThat(result.getViolations()) + .anySatisfy(v -> assertThat(v.propertyKey()).endsWith("trustallcertificates")); + }); + } + + @Test + public void environmentVariablesUnrelatedToCamelAreIgnored() { + runner.withPropertyValues("camel.security.policy=warn") + .withInitializer(ctx -> ctx.getEnvironment().getPropertySources() + .addFirst(new SystemEnvironmentPropertySource("testSystemEnvironment", + Map.of("SOME_OTHER_TRUSTALLCERTIFICATES", "true")))) + .run(context -> { + assertThat(context).hasNotFailed(); + SecurityPolicyResult result = context.getBean(SecurityPolicyResult.class); + assertThat(result.hasViolations()).isFalse(); + }); + } + }