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

acosentino 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 35488e9e5e5 CAMEL-21834 - Camel-Spring-Boot: Create 
ApplicationEnvironmentPreparedEvent for Vault IBM Secrets Manager (#1389)
35488e9e5e5 is described below

commit 35488e9e5e5b43057b0ea241f23ecdd159581b9c
Author: Andrea Cosentino <anco...@gmail.com>
AuthorDate: Thu Mar 6 14:59:39 2025 +0100

    CAMEL-21834 - Camel-Spring-Boot: Create ApplicationEnvironmentPreparedEvent 
for Vault IBM Secrets Manager (#1389)
    
    * CAMEL-21834 - Camel-Spring-Boot: Create 
ApplicationEnvironmentPreparedEvent for Vault IBM Secrets Manager
    
    Signed-off-by: Andrea Cosentino <anco...@gmail.com>
    
    * Fixed Camel-Jira-starter tests
    
    Signed-off-by: Andrea Cosentino <anco...@gmail.com>
    
    ---------
    
    Signed-off-by: Andrea Cosentino <anco...@gmail.com>
---
 .../camel-ibm-secrets-manager-starter/pom.xml      |  12 ++
 .../IBMSecretsManagerVaultPropertiesParser.java    |  74 ++++++++++++
 .../src/main/resources/META-INF/spring.factories   |   2 +
 .../src/test/java/EarlyResolvedPropertiesTest.java | 126 +++++++++++++++++++++
 .../src/test/resources/application.properties      |   2 +
 .../component/jira/springboot/test/Utils.java      |  14 +--
 6 files changed, 223 insertions(+), 7 deletions(-)

diff --git a/components-starter/camel-ibm-secrets-manager-starter/pom.xml 
b/components-starter/camel-ibm-secrets-manager-starter/pom.xml
index 39d3174d7c1..50c85d550e5 100644
--- a/components-starter/camel-ibm-secrets-manager-starter/pom.xml
+++ b/components-starter/camel-ibm-secrets-manager-starter/pom.xml
@@ -38,6 +38,18 @@
       <artifactId>camel-ibm-secrets-manager</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>
     <!--START OF GENERATED CODE-->
     <dependency>
       <groupId>org.apache.camel.springboot</groupId>
diff --git 
a/components-starter/camel-ibm-secrets-manager-starter/src/main/java/org/apache/camel/component/ibm/secrets/manager/springboot/IBMSecretsManagerVaultPropertiesParser.java
 
b/components-starter/camel-ibm-secrets-manager-starter/src/main/java/org/apache/camel/component/ibm/secrets/manager/springboot/IBMSecretsManagerVaultPropertiesParser.java
new file mode 100644
index 00000000000..82f42dcbcec
--- /dev/null
+++ 
b/components-starter/camel-ibm-secrets-manager-starter/src/main/java/org/apache/camel/component/ibm/secrets/manager/springboot/IBMSecretsManagerVaultPropertiesParser.java
@@ -0,0 +1,74 @@
+package org.apache.camel.component.ibm.secrets.manager.springboot;
+
+import com.ibm.cloud.sdk.core.security.IamAuthenticator;
+import com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.SecretsManager;
+import org.apache.camel.RuntimeCamelException;
+import 
org.apache.camel.component.ibm.secrets.manager.IBMSecretsManagerPropertiesFunction;
+import org.apache.camel.util.ObjectHelper;
+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 IBMSecretsManagerVaultPropertiesParser implements 
ApplicationListener<ApplicationEnvironmentPreparedEvent> {
+    private static final Logger LOG = 
LoggerFactory.getLogger(IBMSecretsManagerVaultPropertiesParser.class);
+
+    @Override
+    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
+        SecretsManager client;
+        ConfigurableEnvironment environment = event.getEnvironment();
+        String token;
+        String serviceUrl;
+        if 
(Boolean.parseBoolean(environment.getProperty("camel.component.ibm-secrets-manager.early-resolve-properties")))
 {
+            token = environment.getProperty("camel.vault.ibm.token");
+            serviceUrl = environment.getProperty("camel.vault.ibm.serviceUrl");
+            if (ObjectHelper.isNotEmpty(token) && 
ObjectHelper.isNotEmpty(serviceUrl)) {
+                IamAuthenticator iamAuthenticator = new 
IamAuthenticator.Builder()
+                        .apikey(token)
+                        .build();
+                client = new SecretsManager("Camel Secrets Manager Service for 
Properties", iamAuthenticator);
+                client.setServiceUrl(serviceUrl);
+            } else {
+                throw new RuntimeCamelException(
+                        "Using the IBM Secrets Manager Properties Function 
requires setting IBM Credentials and service url as application properties or 
environment variables");
+            }
+            IBMSecretsManagerPropertiesFunction 
secretsManagerPropertiesFunction = new 
IBMSecretsManagerPropertiesFunction(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("{{ibm:") &&
+                                stringValue.endsWith("}}")) {
+                            LOG.debug("decrypting and overriding property {}", 
key);
+                            try {
+                                String element = 
secretsManagerPropertiesFunction.apply(stringValue
+                                        .replace("{{ibm:", "")
+                                        .replace("}}", ""));
+                                props.put(key, element);
+                            } 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-ibm-secrets-manager-properties", props));
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/components-starter/camel-ibm-secrets-manager-starter/src/main/resources/META-INF/spring.factories
 
b/components-starter/camel-ibm-secrets-manager-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000000..0cd64be49cc
--- /dev/null
+++ 
b/components-starter/camel-ibm-secrets-manager-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.context.ApplicationListener=\
+ 
org.apache.camel.component.ibm.secrets.manager.springboot.IBMSecretsManagerVaultPropertiesParser
\ No newline at end of file
diff --git 
a/components-starter/camel-ibm-secrets-manager-starter/src/test/java/EarlyResolvedPropertiesTest.java
 
b/components-starter/camel-ibm-secrets-manager-starter/src/test/java/EarlyResolvedPropertiesTest.java
new file mode 100644
index 00000000000..9c30283ac5e
--- /dev/null
+++ 
b/components-starter/camel-ibm-secrets-manager-starter/src/test/java/EarlyResolvedPropertiesTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ibm.secrets.manager.springboot;
+
+import com.ibm.cloud.sdk.core.http.Response;
+import com.ibm.cloud.sdk.core.security.IamAuthenticator;
+import com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.SecretsManager;
+import 
com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.model.CreateSecretOptions;
+import 
com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.model.DeleteSecretOptions;
+import 
com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.model.KVSecretPrototype;
+import com.ibm.cloud.secrets_manager_sdk.secrets_manager.v2.model.Secret;
+import 
org.apache.camel.component.ibm.secrets.manager.IBMSecretsManagerConstants;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.apache.camel.util.ObjectHelper;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariables;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+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 java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+@CamelSpringBootTest
+@DirtiesContext
+@SpringBootApplication
+@SpringBootTest(
+        classes = { EarlyResolvedPropertiesTest.TestConfiguration.class },
+        properties = {
+                
"camel.component.ibm-secrets-manager.early-resolve-properties=true",
+                
"early.resolved.property.simple={{ibm:default:databaseTestPassword#username}}"
+        })
+
+// Must be manually tested. Provide your own accessKey and secretKey using 
-Dsecrets-manager and -Dcamel.ibm.sm.serviceurl
+@EnabledIfSystemProperties({
+        @EnabledIfSystemProperty(named = "camel.ibm.test.sm.token", matches = 
".*",
+                disabledReason = "Secrets Manager Token not provided"),
+        @EnabledIfSystemProperty(named = "camel.ibm.test.sm.serviceurl", 
matches = ".*",
+                disabledReason = "Secrets Manager Service URL not provided")
+})
+public class EarlyResolvedPropertiesTest {
+
+    static SecretsManager client;
+
+    static String secretId = "";
+    @BeforeAll
+    public static void setup() throws IOException {
+        String token = System.getProperty("camel.ibm.test.sm.token");
+        String serviceUrl = System.getProperty("camel.ibm.test.sm.serviceurl");
+        System.setProperty("camel.vault.ibm.token", token);
+        System.setProperty("camel.vault.ibm.serviceUrl", serviceUrl);
+
+        IamAuthenticator iamAuthenticator = new IamAuthenticator.Builder()
+                .apikey(token)
+                .build();
+        client = new SecretsManager("Camel Secrets Manager Service for 
Properties", iamAuthenticator);
+        client.setServiceUrl(serviceUrl);
+
+        KVSecretPrototype.Builder kvSecretResourceBuilder = new 
KVSecretPrototype.Builder();
+        kvSecretResourceBuilder
+                    .name("databaseTestPassword");
+        Map<String, Object> payload = new HashMap<>();
+        payload.put("username", "admin");
+        payload.put("password", "password");
+        kvSecretResourceBuilder.data(payload);
+        kvSecretResourceBuilder.secretType(KVSecretPrototype.SecretType.KV);
+        KVSecretPrototype kvSecretResource = kvSecretResourceBuilder.build();
+
+        CreateSecretOptions createSecretOptions = new 
CreateSecretOptions.Builder()
+                .secretPrototype(kvSecretResource)
+                .build();
+        Response<Secret> createResp = 
client.createSecret(createSecretOptions).execute();
+
+        secretId = createResp.getResult().getId();
+    }
+
+    @AfterAll
+    public static void teardown() throws IOException {
+
+        DeleteSecretOptions.Builder deleteSecretOptionsBuilder = new 
DeleteSecretOptions.Builder();
+        deleteSecretOptionsBuilder.id(secretId);
+        client.deleteSecret(deleteSecretOptionsBuilder.build());
+    }
+
+    @Value("${early.resolved.property}")
+    private String earlyResolvedProperty;
+
+    @Value("${early.resolved.property.simple}")
+    private String earlyResolvedPropertySimple;
+
+    @Test
+    public void testEarlyResolvedProperties() {
+        Assertions.assertThat(earlyResolvedProperty).isEqualTo("admin");
+        Assertions.assertThat(earlyResolvedPropertySimple).isEqualTo("admin");
+    }
+
+    @Configuration
+    @AutoConfigureBefore(CamelAutoConfiguration.class)
+    public static class TestConfiguration {
+    }
+}
diff --git 
a/components-starter/camel-ibm-secrets-manager-starter/src/test/resources/application.properties
 
b/components-starter/camel-ibm-secrets-manager-starter/src/test/resources/application.properties
new file mode 100644
index 00000000000..d36a9066a6d
--- /dev/null
+++ 
b/components-starter/camel-ibm-secrets-manager-starter/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+# Needed by EarlyResolvedPropertiesTest
+early.resolved.property = {{ibm:default:databaseTestPassword#username}}
\ No newline at end of file
diff --git 
a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java
 
b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java
index 9d72882e084..136d12a6c0a 100644
--- 
a/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java
+++ 
b/components-starter/camel-jira-starter/src/test/java/org/apache/camel/component/jira/springboot/test/Utils.java
@@ -71,21 +71,21 @@ public final class Utils {
         URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + 
id);
         return new Issue(summary, selfUri, KEY + "-" + id, id, null, 
issueType, null, description, priority, null, null,
                 null, assignee, null, null, null, null, null, components, 
null, null, null, null, null, null, null,
-                watchers, null, null, null, null, null, null);
+                watchers, null, null, null, null, null);
     }
 
     public static Issue transitionIssueDone(Issue issue, Status status, 
Resolution resolution) {
         return new Issue(issue.getSummary(), issue.getSelf(), issue.getKey(), 
issue.getId(), null, issue.getIssueType(),
                 status, issue.getDescription(), issue.getPriority(), 
resolution, null, null, issue.getAssignee(), null,
                 null, null, null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null,
-                null, null);
+                null);
     }
 
     public static Issue setPriority(Issue issue, Priority p) {
         return new Issue(issue.getSummary(), issue.getSelf(), issue.getKey(), 
issue.getId(), null, issue.getIssueType(),
                 issue.getStatus(), issue.getDescription(), p, 
issue.getResolution(), null, null, issue.getAssignee(),
                 null, null, null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null,
-                null, null, null);
+                null, null);
     }
 
     public static Issue transitionIssueDone(Issue issue) {
@@ -102,7 +102,7 @@ public final class Utils {
         URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + 
id);
         return new Issue(summary, selfUri, KEY + "-" + id, id, null, 
issueType, null, description, priority, null,
                 attachments, null, assignee, null, null, null, null, null, 
null, null, null, null, null, null, null,
-                null, null, null, null, null, null, null, null);
+                null, null, null, null, null, null, null);
     }
 
     public static Issue createIssueWithComments(long id, int numComments) {
@@ -120,21 +120,21 @@ public final class Utils {
         URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + 
id);
         return new Issue("jira summary test " + id, selfUri, KEY + "-" + id, 
id, null, issueType, null,
                 "Description " + id, null, null, null, null, userAssignee, 
null, null, null, null, null, null, null,
-                null, comments, null, null, null, null, null, null, null, 
null, null, null, null);
+                null, comments, null, null, null, null, null, null, null, 
null, null, null);
     }
 
     public static Issue createIssueWithLinks(long id, Collection<IssueLink> 
issueLinks) {
         URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + 
id);
         return new Issue("jira summary test " + id, selfUri, KEY + "-" + id, 
id, null, issueType, null,
                 "Description " + id, null, null, null, null, userAssignee, 
null, null, null, null, null, null, null,
-                null, null, null, issueLinks, null, null, null, null, null, 
null, null, null, null);
+                null, null, null, issueLinks, null, null, null, null, null, 
null, null, null);
     }
 
     public static Issue createIssueWithWorkLogs(long id, Collection<Worklog> 
worklogs) {
         URI selfUri = URI.create(TEST_JIRA_URL + "/rest/api/latest/issue/" + 
id);
         return new Issue("jira summary test " + id, selfUri, KEY + "-" + id, 
id, null, issueType, null,
                 "Description " + id, null, null, null, null, userAssignee, 
null, null, null, null, null, null, null,
-                null, null, null, null, null, worklogs, null, null, null, 
null, null, null, null);
+                null, null, null, null, null, worklogs, null, null, null, 
null, null, null);
     }
 
     public static Comment newComment(long issueId, int newCommentId, String 
comment) {

Reply via email to