From de00e1c807d77bc869dcacdf0aaa2057819b4e56 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Fri, 28 Aug 2026 09:53:54 +0200 Subject: [PATCH] CAMEL-24503: camel-spring-boot - see camel properties supplied as environment variables extractCamelProperties filtered on the property name exactly as its source reports it. The systemEnvironment source reports environment variables in their native CAMEL_COMPONENT_FOO_BAR form, which never matches the "camel." prefix, so any Camel option configured through the environment was invisible to the camel.security policy check added in CAMEL-23250 - even though Spring's relaxed binding applies it to the component regardless. That is the usual way to configure a containerised application, so the check was blind to a large part of real deployments. Names are now canonicalized with ConfigurationPropertyName.adapt before the prefix test, and the canonical name is used for the lookup so relaxed binding resolves it back to the variable. SecurityUtils.getSecurityOption already lowercases and strips dashes, so the canonical name matches the same option. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Andrea Cosentino (cherry picked from commit 27fb340edbd0d3936262736073bc6287debc5107) --- .../CamelSecurityPolicyAutoConfiguration.java | 31 ++++++++++++++-- ...elSecurityPolicyAutoConfigurationTest.java | 37 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) 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(); + }); + } + }