Skip to content

Commit 27c4054

Browse files
gnodetclaude
andcommitted
CAMEL-23250: Add Spring Boot auto-configuration for security policy properties
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 32ca855 commit 27c4054

4 files changed

Lines changed: 434 additions & 0 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.spring.boot.security;
18+
19+
import java.util.ArrayList;
20+
import java.util.LinkedHashMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
import java.util.Set;
24+
25+
import org.apache.camel.CamelContext;
26+
import org.apache.camel.RuntimeCamelException;
27+
import org.apache.camel.main.SecurityConfigurationProperties;
28+
import org.apache.camel.main.SecurityPolicyResult;
29+
import org.apache.camel.spring.boot.CamelAutoConfiguration;
30+
import org.apache.camel.support.CamelContextHelper;
31+
import org.apache.camel.util.SecurityUtils;
32+
import org.apache.camel.util.SecurityViolation;
33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
35+
import org.springframework.boot.autoconfigure.AutoConfiguration;
36+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
37+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
38+
import org.springframework.context.annotation.Bean;
39+
import org.springframework.core.env.ConfigurableEnvironment;
40+
import org.springframework.core.env.EnumerablePropertySource;
41+
import org.springframework.core.env.Environment;
42+
43+
@AutoConfiguration(after = CamelAutoConfiguration.class)
44+
@ConditionalOnBean(CamelAutoConfiguration.class)
45+
@EnableConfigurationProperties(CamelSecurityPolicyConfigurationProperties.class)
46+
public class CamelSecurityPolicyAutoConfiguration {
47+
48+
private static final Logger LOG = LoggerFactory.getLogger(CamelSecurityPolicyAutoConfiguration.class);
49+
50+
@Bean
51+
SecurityPolicyResult camelSecurityPolicyResult(
52+
CamelContext camelContext,
53+
CamelSecurityPolicyConfigurationProperties config,
54+
Environment environment) {
55+
56+
SecurityConfigurationProperties securityConfig = applySecurityProperties(camelContext, config);
57+
58+
Map<String, Object> camelProperties = extractCamelProperties(environment);
59+
60+
List<SecurityViolation> violations = SecurityUtils.detectViolations(
61+
camelProperties,
62+
(k, v) -> containsSensitive(camelContext, k, v),
63+
securityConfig::resolvePolicy,
64+
securityConfig.getAllowedPropertySet());
65+
66+
SecurityPolicyResult result = new SecurityPolicyResult(violations);
67+
camelContext.getCamelContextExtension().addContextPlugin(SecurityPolicyResult.class, result);
68+
69+
enforceViolations(violations);
70+
71+
return result;
72+
}
73+
74+
private SecurityConfigurationProperties applySecurityProperties(
75+
CamelContext camelContext,
76+
CamelSecurityPolicyConfigurationProperties config) {
77+
78+
// get the security config from camel-main's MainConfigurationProperties
79+
// which is already bound by CamelAutoConfiguration via CamelConfigurationProperties
80+
SecurityConfigurationProperties securityConfig
81+
= new SecurityConfigurationProperties(null);
82+
83+
securityConfig.setPolicy(config.getPolicy());
84+
if (config.getSecretPolicy() != null) {
85+
securityConfig.setSecretPolicy(config.getSecretPolicy());
86+
}
87+
if (config.getInsecureSslPolicy() != null) {
88+
securityConfig.setInsecureSslPolicy(config.getInsecureSslPolicy());
89+
}
90+
if (config.getInsecureSerializationPolicy() != null) {
91+
securityConfig.setInsecureSerializationPolicy(config.getInsecureSerializationPolicy());
92+
}
93+
if (config.getInsecureDevPolicy() != null) {
94+
securityConfig.setInsecureDevPolicy(config.getInsecureDevPolicy());
95+
}
96+
if (config.getAllowedProperties() != null) {
97+
securityConfig.setAllowedProperties(config.getAllowedProperties());
98+
}
99+
100+
return securityConfig;
101+
}
102+
103+
private static Map<String, Object> extractCamelProperties(Environment environment) {
104+
Map<String, Object> properties = new LinkedHashMap<>();
105+
106+
if (environment instanceof ConfigurableEnvironment ce) {
107+
ce.getPropertySources().forEach(ps -> {
108+
if (ps instanceof EnumerablePropertySource<?> eps) {
109+
for (String name : eps.getPropertyNames()) {
110+
if (name.startsWith("camel.") && !name.startsWith("camel.security.")) {
111+
Object value = environment.getProperty(name);
112+
if (value != null) {
113+
properties.putIfAbsent(name, value);
114+
}
115+
}
116+
}
117+
}
118+
});
119+
}
120+
121+
return properties;
122+
}
123+
124+
private static boolean containsSensitive(CamelContext camelContext, String key, Object value) {
125+
boolean answer = CamelContextHelper.containsSensitive(camelContext, key);
126+
if (!answer && value != null) {
127+
String v = value.toString();
128+
answer = v.startsWith("RAW(");
129+
}
130+
return answer;
131+
}
132+
133+
private static void enforceViolations(List<SecurityViolation> violations) {
134+
List<String> failures = new ArrayList<>();
135+
for (SecurityViolation v : violations) {
136+
if ("fail".equals(v.policy())) {
137+
failures.add(v.toString());
138+
} else {
139+
LOG.warn("SECURITY WARNING: {}", v);
140+
}
141+
}
142+
143+
if (!failures.isEmpty()) {
144+
throw new RuntimeCamelException(
145+
"Security policy violations detected (policy=fail):\n - " + String.join("\n - ", failures)
146+
+ "\nTo allow specific properties, add them to camel.security.allowed-properties"
147+
+ " or change the policy to 'warn' or 'allow'.");
148+
}
149+
}
150+
151+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.spring.boot.security;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Security policy configuration for Camel Spring Boot applications.
23+
* <p>
24+
* Controls how Camel reacts to insecure configuration at startup. Policies can be set globally or per security
25+
* category:
26+
* <ul>
27+
* <li>{@code allow} — no warnings, allow the configuration</li>
28+
* <li>{@code warn} — log a warning at startup (default)</li>
29+
* <li>{@code fail} — throw an exception and prevent startup</li>
30+
* </ul>
31+
*/
32+
@ConfigurationProperties(prefix = "camel.security")
33+
public class CamelSecurityPolicyConfigurationProperties {
34+
35+
/**
36+
* Global security policy applied to all categories unless overridden. Controls how Camel reacts when insecure
37+
* configuration is detected at startup.
38+
*/
39+
private String policy = "warn";
40+
41+
/**
42+
* Security policy for plain-text secrets. When set, overrides the global policy for properties that contain
43+
* sensitive values configured as plain text.
44+
*/
45+
private String secretPolicy;
46+
47+
/**
48+
* Security policy for insecure SSL/TLS configuration. When set, overrides the global policy for options that
49+
* disable certificate validation or hostname verification.
50+
*/
51+
private String insecureSslPolicy;
52+
53+
/**
54+
* Security policy for insecure deserialization configuration. When set, overrides the global policy for options that
55+
* enable dangerous deserialization of untrusted data.
56+
*/
57+
private String insecureSerializationPolicy;
58+
59+
/**
60+
* Security policy for development-only features. When set, overrides the global policy for options intended only for
61+
* development environments.
62+
*/
63+
private String insecureDevPolicy;
64+
65+
/**
66+
* Comma-separated list of property keys to exclude from security policy checks. Use full property paths (e.g.,
67+
* camel.component.aws2-s3.trustAllCertificates) to allow specific properties regardless of the configured policy.
68+
*/
69+
private String allowedProperties;
70+
71+
public String getPolicy() {
72+
return policy;
73+
}
74+
75+
public void setPolicy(String policy) {
76+
this.policy = policy;
77+
}
78+
79+
public String getSecretPolicy() {
80+
return secretPolicy;
81+
}
82+
83+
public void setSecretPolicy(String secretPolicy) {
84+
this.secretPolicy = secretPolicy;
85+
}
86+
87+
public String getInsecureSslPolicy() {
88+
return insecureSslPolicy;
89+
}
90+
91+
public void setInsecureSslPolicy(String insecureSslPolicy) {
92+
this.insecureSslPolicy = insecureSslPolicy;
93+
}
94+
95+
public String getInsecureSerializationPolicy() {
96+
return insecureSerializationPolicy;
97+
}
98+
99+
public void setInsecureSerializationPolicy(String insecureSerializationPolicy) {
100+
this.insecureSerializationPolicy = insecureSerializationPolicy;
101+
}
102+
103+
public String getInsecureDevPolicy() {
104+
return insecureDevPolicy;
105+
}
106+
107+
public void setInsecureDevPolicy(String insecureDevPolicy) {
108+
this.insecureDevPolicy = insecureDevPolicy;
109+
}
110+
111+
public String getAllowedProperties() {
112+
return allowedProperties;
113+
}
114+
115+
public void setAllowedProperties(String allowedProperties) {
116+
this.allowedProperties = allowedProperties;
117+
}
118+
119+
}

core/camel-spring-boot/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ org.apache.camel.spring.boot.actuate.health.CamelAvailabilityCheckAutoConfigurat
2525
org.apache.camel.spring.boot.actuate.info.CamelInfoAutoConfiguration
2626
org.apache.camel.spring.boot.cluster.ClusteredRouteControllerAutoConfiguration
2727
org.apache.camel.spring.boot.routecontroller.SupervisingRouteControllerAutoConfiguration
28+
org.apache.camel.spring.boot.security.CamelSecurityPolicyAutoConfiguration
2829
org.apache.camel.spring.boot.security.CamelSSLAutoConfiguration
2930
org.apache.camel.spring.boot.threadpool.CamelThreadPoolAutoConfiguration
3031
org.apache.camel.spring.boot.trace.CamelTraceAutoConfiguration

0 commit comments

Comments
 (0)