This is an automated email from the ASF dual-hosted git repository.

fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git


The following commit(s) were added to refs/heads/main by this push:
     new 23d6bc3ada8 Hashicorp vault early properties parser
23d6bc3ada8 is described below

commit 23d6bc3ada84b3189f42734f523d7f910871d9db
Author: Croway <federico.mariani.1...@gmail.com>
AuthorDate: Wed Oct 9 11:53:08 2024 +0200

    Hashicorp vault early properties parser
---
 .../camel-hashicorp-vault-starter/pom.xml          | 44 ++++++++++++
 .../SpringBootHashicorpVaultPropertiesParser.java  | 80 ++++++++++++++++++++++
 .../src/main/resources/META-INF/spring.factories   |  2 +
 .../springboot/EarlyResolvedPropertiesTest.java    | 75 ++++++++++++++++++++
 .../src/test/resources/application.properties      |  2 +
 5 files changed, 203 insertions(+)

diff --git a/components-starter/camel-hashicorp-vault-starter/pom.xml 
b/components-starter/camel-hashicorp-vault-starter/pom.xml
index 60f7c30ece9..a54bdfebba1 100644
--- a/components-starter/camel-hashicorp-vault-starter/pom.xml
+++ b/components-starter/camel-hashicorp-vault-starter/pom.xml
@@ -38,6 +38,25 @@
       <artifactId>camel-hashicorp-vault</artifactId>
       <version>${camel-version}</version>
     </dependency>
+    <!-- for testing -->
+    <dependency>
+      <groupId>org.awaitility</groupId>
+      <artifactId>awaitility</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+      <version>${spring-boot-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test-infra-hashicorp-vault</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
     <!--START OF GENERATED CODE-->
     <dependency>
       <groupId>org.apache.camel.springboot</groupId>
@@ -45,4 +64,29 @@
     </dependency>
     <!--END OF GENERATED CODE-->
   </dependencies>
+  <profiles>
+    <profile>
+      <id>ppc64le</id>
+      <activation>
+        <os>
+          <arch>ppc64le</arch>
+        </os>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <skipITs>${skipTests}</skipITs>
+              <reuseForks>true</reuseForks>
+              <systemPropertyVariables>
+                
<hashicorp.vault.container>icr.io/ppc64le-oss/vault-ppc64le:v1.13.1</hashicorp.vault.container>
+              </systemPropertyVariables>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>
diff --git 
a/components-starter/camel-hashicorp-vault-starter/src/main/java/org/apache/camel/component/hashicorp/vault/springboot/SpringBootHashicorpVaultPropertiesParser.java
 
b/components-starter/camel-hashicorp-vault-starter/src/main/java/org/apache/camel/component/hashicorp/vault/springboot/SpringBootHashicorpVaultPropertiesParser.java
new file mode 100644
index 00000000000..0b623ddbf8e
--- /dev/null
+++ 
b/components-starter/camel-hashicorp-vault-starter/src/main/java/org/apache/camel/component/hashicorp/vault/springboot/SpringBootHashicorpVaultPropertiesParser.java
@@ -0,0 +1,80 @@
+package org.apache.camel.component.hashicorp.vault.springboot;
+
+import 
org.apache.camel.component.hashicorp.vault.HashicorpVaultPropertiesFunction;
+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 org.springframework.vault.authentication.TokenAuthentication;
+import org.springframework.vault.client.VaultEndpoint;
+import org.springframework.vault.core.VaultTemplate;
+
+import java.util.Objects;
+import java.util.Properties;
+
+public class SpringBootHashicorpVaultPropertiesParser implements 
ApplicationListener<ApplicationEnvironmentPreparedEvent> {
+    private static final Logger LOG = 
LoggerFactory.getLogger(SpringBootHashicorpVaultPropertiesParser.class);
+
+    @Override
+    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
+        ConfigurableEnvironment environment = event.getEnvironment();
+        if 
(Boolean.parseBoolean(environment.getProperty("camel.component.hashicorp-vault.early-resolve-properties")))
 {
+            
Objects.requireNonNull(environment.getProperty("camel.vault.hashicorp.token"), 
"Hashicorp Vault token is required");
+            
Objects.requireNonNull(environment.getProperty("camel.vault.hashicorp.host"), 
"Hashicorp Vault host is required");
+            
Objects.requireNonNull(environment.getProperty("camel.vault.hashicorp.port"), 
"Hashicorp Vault port is required");
+            
Objects.requireNonNull(environment.getProperty("camel.vault.hashicorp.scheme"), 
"Hashicorp Vault scheme is required");
+
+            String token = 
environment.getProperty("camel.vault.hashicorp.token");
+            String host = 
environment.getProperty("camel.vault.hashicorp.host");
+
+            int port = 
Integer.parseInt(environment.getProperty("camel.vault.hashicorp.port"));
+            String scheme = 
environment.getProperty("camel.vault.hashicorp.scheme");
+
+            VaultEndpoint vaultEndpoint = new VaultEndpoint();
+            vaultEndpoint.setHost(host);
+            vaultEndpoint.setPort(port);
+            vaultEndpoint.setScheme(scheme);
+
+            VaultTemplate client = new VaultTemplate(
+                    vaultEndpoint,
+                    new TokenAuthentication(token));
+            HashicorpVaultPropertiesFunction hashicorpVaultPropertiesFunction 
= new HashicorpVaultPropertiesFunction(client);
+
+            final Properties props = new Properties();
+            for (PropertySource mutablePropertySources : 
event.getEnvironment().getPropertySources()) {
+                if (mutablePropertySources instanceof MapPropertySource 
mapPropertySource) {
+                    mapPropertySource.getSource().forEach((key, value) -> {
+                        String stringValue = null;
+                        if ((value instanceof OriginTrackedValue 
originTrackedValue &&
+                                originTrackedValue.getValue() instanceof 
String v)) {
+                            stringValue = v;
+                        } else if (value instanceof String v) {
+                            stringValue = v;
+                        }
+
+                        if (stringValue != null &&
+                                stringValue.startsWith("{{hashicorp:") &&
+                                stringValue.endsWith("}}")) {
+                            LOG.debug("decrypting and overriding property {}", 
key);
+                            try {
+                                props.put(key, 
hashicorpVaultPropertiesFunction.apply(stringValue
+                                        .replace("{{hashicorp:", "")
+                                        .replace("}}", "")));
+                            } catch (Exception e) {
+                                // Log and do nothing
+                                LOG.debug("failed to parse property {}. This 
exception is ignored.", key, e);
+                            }
+                        }
+                    });
+                }
+            }
+
+            environment.getPropertySources().addFirst(new 
PropertiesPropertySource("overridden-camel-hashicorp-vault-properties", props));
+        }
+    }
+}
diff --git 
a/components-starter/camel-hashicorp-vault-starter/src/main/resources/META-INF/spring.factories
 
b/components-starter/camel-hashicorp-vault-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000000..f8813e697fa
--- /dev/null
+++ 
b/components-starter/camel-hashicorp-vault-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.context.ApplicationListener=\
+  
org.apache.camel.component.hashicorp.vault.springboot.SpringBootHashicorpVaultPropertiesParser
\ No newline at end of file
diff --git 
a/components-starter/camel-hashicorp-vault-starter/src/test/java/org/apache/camel/component/hashicorp/vault/springboot/EarlyResolvedPropertiesTest.java
 
b/components-starter/camel-hashicorp-vault-starter/src/test/java/org/apache/camel/component/hashicorp/vault/springboot/EarlyResolvedPropertiesTest.java
new file mode 100644
index 00000000000..adde78049c9
--- /dev/null
+++ 
b/components-starter/camel-hashicorp-vault-starter/src/test/java/org/apache/camel/component/hashicorp/vault/springboot/EarlyResolvedPropertiesTest.java
@@ -0,0 +1,75 @@
+package org.apache.camel.component.hashicorp.vault.springboot;
+
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import 
org.apache.camel.test.infra.hashicorp.vault.services.HashicorpServiceFactory;
+import 
org.apache.camel.test.infra.hashicorp.vault.services.HashicorpVaultService;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.vault.authentication.TokenAuthentication;
+import org.springframework.vault.client.VaultEndpoint;
+import org.springframework.vault.core.VaultKeyValueOperations;
+import org.springframework.vault.core.VaultKeyValueOperationsSupport;
+import org.springframework.vault.core.VaultTemplate;
+
+import java.util.Map;
+
+@CamelSpringBootTest
+@DirtiesContext
+@SpringBootApplication
+@SpringBootTest(
+        classes = { EarlyResolvedPropertiesTest.TestConfiguration.class },
+        properties = {
+                
"camel.component.hashicorp-vault.early-resolve-properties=true",
+                
"early.resolved.property.simple={{hashicorp:secret:simple#string}}"
+        })
+public class EarlyResolvedPropertiesTest {
+
+    @RegisterExtension
+    public static HashicorpVaultService service = 
HashicorpServiceFactory.createService();
+
+    @BeforeAll
+    public static void setup() {
+        System.setProperty("camel.vault.hashicorp.host", service.host());
+        System.setProperty("camel.vault.hashicorp.port", 
String.valueOf(service.port()));
+        System.setProperty("camel.vault.hashicorp.scheme", "http");
+        System.setProperty("camel.vault.hashicorp.token", service.token());
+
+        VaultEndpoint vaultEndpoint = new VaultEndpoint();
+        vaultEndpoint.setHost(service.host());
+        vaultEndpoint.setPort(service.port());
+        vaultEndpoint.setScheme("http");
+
+        VaultTemplate client = new VaultTemplate(
+                vaultEndpoint,
+                new TokenAuthentication(service.token()));
+        VaultKeyValueOperations vaultKeyValueOperations = 
client.opsForKeyValue("secret", 
VaultKeyValueOperationsSupport.KeyValueBackend.versioned());
+        vaultKeyValueOperations.put("simple", Map.of("string", "test"));
+        vaultKeyValueOperations.put("database/password", Map.of("string", 
"pazzword"));
+    }
+
+    @Value("${early.resolved.property}")
+    private String earlyResolvedProperty;
+
+    @Value("${early.resolved.property.simple}")
+    private String earlyResolvedPropertySimple;
+
+    @Test
+    public void testEarlyResolvedProperties() {
+        Assertions.assertThat(earlyResolvedProperty).isEqualTo("pazzword");
+        Assertions.assertThat(earlyResolvedPropertySimple).isEqualTo("test");
+    }
+
+    @Configuration
+    @AutoConfigureBefore(CamelAutoConfiguration.class)
+    public static class TestConfiguration {
+    }
+}
\ No newline at end of file
diff --git 
a/components-starter/camel-hashicorp-vault-starter/src/test/resources/application.properties
 
b/components-starter/camel-hashicorp-vault-starter/src/test/resources/application.properties
new file mode 100644
index 00000000000..e3be01d4e06
--- /dev/null
+++ 
b/components-starter/camel-hashicorp-vault-starter/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+# Needed by EarlyResolvedPropertiesTest
+early.resolved.property = {{hashicorp:secret:database/password#string}}
\ No newline at end of file

Reply via email to