Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -111,10 +113,11 @@ private static Map<String, Object> 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);
}
}
}
Expand All @@ -125,6 +128,28 @@ private static Map<String, Object> extractCamelProperties(Environment environmen
return properties;
}

/**
* Canonicalizes a property name as its source reports it, returning <tt>null</tt> when it is not a Camel
* property.
* <p/>
* Property sources report names in their own form: an option set in application.properties arrives as
* <tt>camel.component.foo.bar</tt>, while the same option set as an environment variable arrives as
* <tt>CAMEL_COMPONENT_FOO_BAR</tt>. 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
});
}

}