Decrypt properties earlier in the SB lifecycle
diff --git a/components-starter/camel-jasypt-starter/src/main/docs/jasypt.json b/components-starter/camel-jasypt-starter/src/main/docs/jasypt.json
index 120b69c..d08601a 100644
--- a/components-starter/camel-jasypt-starter/src/main/docs/jasypt.json
+++ b/components-starter/camel-jasypt-starter/src/main/docs/jasypt.json
@@ -15,6 +15,13 @@
"defaultValue": "PBEWithMD5AndDES"
},
{
+ "name": "camel.component.jasypt.early-decryption-enabled",
+ "type": "java.lang.Boolean",
+ "description": "Enable the early properties decryption during Spring Start Up",
+ "sourceType": "org.apache.camel.component.jasypt.springboot.JasyptEncryptedPropertiesConfiguration",
+ "defaultValue": false
+ },
+ {
"name": "camel.component.jasypt.enabled",
"type": "java.lang.Boolean",
"description": "Enable the component",
diff --git a/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/JasyptEncryptedPropertiesConfiguration.java b/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/JasyptEncryptedPropertiesConfiguration.java
index ccfa179..e721dfad 100644
--- a/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/JasyptEncryptedPropertiesConfiguration.java
+++ b/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/JasyptEncryptedPropertiesConfiguration.java
@@ -29,6 +29,14 @@
private boolean enabled;
/**
+ * Enable the early properties decryption during Spring Start Up.
+ * Enabling this feature, encrypted properties can be decrypted before the Spring Boot AutoConfiguration
+ * kicks in, for example, server.port=ENC(oBpQDDUvFY0c4WNAG0o4LIS5bWqmlxYlUUDTW2iXJIAZFYvM+3vOredaMcVfL4xW)
+ * will be decrypted to 8082, and the application will start using that port.
+ */
+ private boolean earlyDecryptionEnabled;
+
+ /**
* The algorithm to be used for decryption. Default: PBEWithMD5AndDES
*/
private String algorithm = "PBEWithMD5AndDES";
@@ -73,6 +81,14 @@
this.enabled = enabled;
}
+ public boolean isEarlyDecryptionEnabled() {
+ return earlyDecryptionEnabled;
+ }
+
+ public void setEarlyDecryptionEnabled(boolean earlyDecryptionEnabled) {
+ this.earlyDecryptionEnabled = earlyDecryptionEnabled;
+ }
+
public String getAlgorithm() {
return algorithm;
}
diff --git a/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/SpringBootJasyptPropertiesParser.java b/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/SpringBootJasyptPropertiesParser.java
new file mode 100644
index 0000000..d4d5b95
--- /dev/null
+++ b/components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/SpringBootJasyptPropertiesParser.java
@@ -0,0 +1,78 @@
+package org.apache.camel.component.jasypt.springboot;
+
+import org.apache.camel.component.jasypt.JasyptPropertiesParser;
+import org.apache.camel.component.properties.PropertiesParser;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.jasypt.encryption.StringEncryptor;
+import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
+import org.springframework.boot.origin.OriginTrackedValue;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+
+import java.util.Properties;
+
+public class SpringBootJasyptPropertiesParser implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
+ private static final Logger LOG = LoggerFactory.getLogger(SpringBootJasyptPropertiesParser.class);
+
+ public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
+ ConfigurableEnvironment environment = event.getEnvironment();
+
+ // Manual Autoconfigure jasypt component
+ JasyptEncryptedPropertiesAutoconfiguration jasyptEncryptedPropertiesAutoconfiguration = new JasyptEncryptedPropertiesAutoconfiguration();
+ JasyptEncryptedPropertiesConfiguration jasyptEncryptedPropertiesConfiguration =
+ jasyptEncryptedPropertiesAutoconfiguration.JasyptEncryptedPropertiesAutoconfiguration(event.getEnvironment());
+
+ if (jasyptEncryptedPropertiesConfiguration != null && jasyptEncryptedPropertiesConfiguration.isEarlyDecryptionEnabled()) {
+ // Too early in the lifecycle, the property has to be resolved manually
+ String password = jasyptEncryptedPropertiesConfiguration.getPassword();
+ if (password.startsWith("sysenv:")) {
+ password = System.getenv(StringHelper.after(password, "sysenv:"));
+ }
+ if (ObjectHelper.isNotEmpty(password) && password.startsWith("sys:")) {
+ password = System.getProperty(StringHelper.after(password, "sys:"));
+ }
+ jasyptEncryptedPropertiesConfiguration.setPassword(password);
+
+ EnvironmentStringPBEConfig environmentStringPBEConfig =
+ jasyptEncryptedPropertiesAutoconfiguration.environmentVariablesConfiguration(jasyptEncryptedPropertiesConfiguration);
+ StringEncryptor stringEncryptor =
+ jasyptEncryptedPropertiesAutoconfiguration.stringEncryptor(environmentStringPBEConfig);
+ EncryptablePropertySourcesPlaceholderConfigurer encryptablePropertySourcesPlaceholderConfigurer =
+ jasyptEncryptedPropertiesAutoconfiguration.propertyConfigurer(stringEncryptor);
+ PropertiesParser propertiesParser = jasyptEncryptedPropertiesAutoconfiguration.encryptedPropertiesParser(environment,
+ stringEncryptor,
+ environment);
+
+ final Properties props = new Properties();
+ for (PropertySource mutablePropertySources : event.getEnvironment().getPropertySources()) {
+ if (mutablePropertySources instanceof MapPropertySource mapPropertySource) {
+ mapPropertySource.getSource().forEach((key, value) -> {
+ if (value instanceof OriginTrackedValue originTrackedValue &&
+ originTrackedValue.getValue() instanceof String stringValue &&
+ stringValue.startsWith(JasyptPropertiesParser.JASYPT_PREFIX_TOKEN) &&
+ stringValue.endsWith(JasyptPropertiesParser.JASYPT_SUFFIX_TOKEN)) {
+
+ LOG.debug("decrypting and overriding property {}", key);
+ try {
+ props.put(key, propertiesParser.parseProperty(key.toString(), stringValue, null));
+ } catch (Exception e) {
+ // Log and do nothing
+ LOG.debug("failed to parse property {}", key, e);
+ }
+ }
+ });
+ }
+ }
+
+ environment.getPropertySources().addFirst(new PropertiesPropertySource("overridden-camel-jasypt-properties", props));
+ }
+ }
+}
+
diff --git a/components-starter/camel-jasypt-starter/src/main/resources/META-INF/spring.factories b/components-starter/camel-jasypt-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..300e703
--- /dev/null
+++ b/components-starter/camel-jasypt-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.context.ApplicationListener=\
+ org.apache.camel.component.jasypt.springboot.SpringBootJasyptPropertiesParser
\ No newline at end of file
diff --git a/components-starter/camel-jasypt-starter/src/test/java/org/apache/camel/component/jasypt/springboot/EarlyEncryptedPropertiesTest.java b/components-starter/camel-jasypt-starter/src/test/java/org/apache/camel/component/jasypt/springboot/EarlyEncryptedPropertiesTest.java
new file mode 100644
index 0000000..be072ad
--- /dev/null
+++ b/components-starter/camel-jasypt-starter/src/test/java/org/apache/camel/component/jasypt/springboot/EarlyEncryptedPropertiesTest.java
@@ -0,0 +1,15 @@
+package org.apache.camel.component.jasypt.springboot;
+
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+
+@CamelSpringBootTest
+@DirtiesContext
+@SpringBootApplication
+@SpringBootTest(
+ classes = { EncryptedPropertiesTest.TestConfiguration.class },
+ properties = { "camel.component.jasypt.early-decryption-enabled=true" })
+public class EarlyEncryptedPropertiesTest extends EncryptedPropertiesTest {
+}