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

davsclaus pushed a commit to branch sk
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6c524fa102900e2456936e77ea556f730b4ecfba
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Aug 25 13:51:41 2025 +0200

    CAMEL-22365: Make it possible to configure extra keywords that are 
sensitive and should be masked by Camel
---
 .../main/camel-main-configuration-metadata.json    |  1 +
 .../org/apache/camel/ExtendedCamelContext.java     | 16 ++++++++++
 .../impl/engine/DefaultCamelContextExtension.java  | 14 +++++++++
 .../camel/impl/ExtendedCamelContextConfigurer.java |  6 ++++
 .../MainConfigurationPropertiesConfigurer.java     |  7 +++++
 .../camel-main-configuration-metadata.json         |  1 +
 core/camel-main/src/main/docs/main.adoc            |  3 +-
 .../camel/main/DefaultConfigurationConfigurer.java |  3 ++
 .../camel/main/DefaultConfigurationProperties.java | 22 +++++++++++++
 .../management/mbean/ManagedCamelContextMBean.java |  3 ++
 .../management/mbean/ManagedCamelContext.java      |  5 +++
 .../java/org/apache/camel/util/URISupport.java     | 36 +++++++++++++++++++---
 .../java/org/apache/camel/util/URISupportTest.java | 12 ++++++++
 13 files changed, 124 insertions(+), 5 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 19aea07fcea..d4e27b859ea 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -27,6 +27,7 @@
     { "name": "camel.lra", "description": "Camel Saga EIP (Long Running 
Actions) configurations", "sourceType": 
"org.apache.camel.main.LraConfigurationProperties" }
   ],
   "properties": [
+    { "name": "camel.main.additionalSensitiveKeywords", "required": false, 
"description": "Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add additional custom keywords to 
be masked as well. Multiple keywords can be separated by comma.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.main.allowUseOriginalMessage", "required": false, 
"description": "Sets whether to allow access to the original message from 
Camel's error handler, or from 
org.apache.camel.spi.UnitOfWork.getOriginalInMessage(). Turning this off can 
optimize performance, as defensive copy of the original message is not needed. 
Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false", "se [...]
     { "name": "camel.main.autoConfigurationEnabled", "required": false, 
"description": "Whether auto configuration of components, dataformats, 
languages is enabled or not. When enabled the configuration parameters are 
loaded from the properties component. You can prefix the parameters in the 
properties file with: - camel.component.name.option1=value1 - 
camel.component.name.option2=value2 - camel.dataformat.name.option1=value1 - 
camel.dataformat.name.option2=value2 - camel.language.name.o [...]
     { "name": "camel.main.autoConfigurationEnvironmentVariablesEnabled", 
"required": false, "description": "Whether auto configuration should include OS 
environment variables as well. When enabled this allows to overrule any 
configuration using an OS environment variable. For example to set a shutdown 
timeout of 5 seconds: CAMEL_MAIN_SHUTDOWNTIMEOUT=5. This option is default 
enabled.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", 
"type": "boolean", "javaType": "bool [...]
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java 
b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
index fe5dbaaf226..7e8b4819c11 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
@@ -521,6 +521,22 @@ public interface ExtendedCamelContext {
      */
     void setBasePackageScan(String basePackageScan);
 
+    /**
+     * Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add
+     * additional custom keywords to be masked as well. Multiple keywords can 
be separated by comma.
+     *
+     * @see org.apache.camel.util.SensitiveUtils
+     */
+    String getAdditionalSensitiveKeywords();
+
+    /**
+     * Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add
+     * additional custom keywords to be masked as well. Multiple keywords can 
be separated by comma.
+     *
+     * @see org.apache.camel.util.SensitiveUtils
+     */
+    void setAdditionalSensitiveKeywords(String additionalSensitiveKeywords);
+
     /**
      * The {@link CamelContext} have additional phases that are not defined in 
{@link ServiceStatus} and this method
      * provides the phase ordinal value.
diff --git 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
index 2ece8945036..28cd9a87dfc 100644
--- 
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
+++ 
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
@@ -85,6 +85,7 @@ import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.startup.DefaultStartupStepRecorder;
 import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.URISupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -143,6 +144,7 @@ class DefaultCamelContextExtension implements 
ExtendedCamelContext {
     @Deprecated(since = "3.17.0")
     private ErrorHandlerFactory errorHandlerFactory;
     private String basePackageScan;
+    private String additionalSensitiveKeywords;
 
     private final Lock lock = new ReentrantLock();
 
@@ -572,6 +574,18 @@ class DefaultCamelContextExtension implements 
ExtendedCamelContext {
         this.basePackageScan = basePackageScan;
     }
 
+    @Override
+    public String getAdditionalSensitiveKeywords() {
+        return additionalSensitiveKeywords;
+    }
+
+    @Override
+    public void setAdditionalSensitiveKeywords(String 
additionalSensitiveKeywords) {
+        this.additionalSensitiveKeywords = additionalSensitiveKeywords;
+        // re-configure sensitive keywords asap so they take effect immediately
+        URISupport.addSanitizeKeywords(additionalSensitiveKeywords);
+    }
+
     @Override
     public HeadersMapFactory getHeadersMapFactory() {
         return headersMapFactory;
diff --git 
a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
 
b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
index b665fc149dc..433ff9038a8 100644
--- 
a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
+++ 
b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
@@ -23,6 +23,8 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
     public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
         org.apache.camel.ExtendedCamelContext target = 
(org.apache.camel.ExtendedCamelContext) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": 
target.setAdditionalSensitiveKeywords(property(camelContext, 
java.lang.String.class, value)); return true;
         case "basepackagescan":
         case "basePackageScan": 
target.setBasePackageScan(property(camelContext, java.lang.String.class, 
value)); return true;
         case "bootstrapfactoryfinder":
@@ -60,6 +62,8 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": return java.lang.String.class;
         case "basepackagescan":
         case "basePackageScan": return java.lang.String.class;
         case "bootstrapfactoryfinder":
@@ -98,6 +102,8 @@ public class ExtendedCamelContextConfigurer extends 
org.apache.camel.support.com
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         org.apache.camel.ExtendedCamelContext target = 
(org.apache.camel.ExtendedCamelContext) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": return 
target.getAdditionalSensitiveKeywords();
         case "basepackagescan":
         case "basePackageScan": return target.getBasePackageScan();
         case "bootstrapfactoryfinder":
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
index 1f2ff8d5d57..2d401446988 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java
@@ -22,6 +22,7 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
     private static final Map<String, Object> ALL_OPTIONS;
     static {
         Map<String, Object> map = new CaseInsensitiveMap();
+        map.put("AdditionalSensitiveKeywords", java.lang.String.class);
         map.put("AllowUseOriginalMessage", boolean.class);
         map.put("AutoConfigurationEnabled", boolean.class);
         map.put("AutoConfigurationEnvironmentVariablesEnabled", boolean.class);
@@ -153,6 +154,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
     public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
         org.apache.camel.main.MainConfigurationProperties target = 
(org.apache.camel.main.MainConfigurationProperties) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": 
target.setAdditionalSensitiveKeywords(property(camelContext, 
java.lang.String.class, value)); return true;
         case "allowuseoriginalmessage":
         case "allowUseOriginalMessage": 
target.setAllowUseOriginalMessage(property(camelContext, boolean.class, 
value)); return true;
         case "autoconfigurationenabled":
@@ -407,6 +410,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": return java.lang.String.class;
         case "allowuseoriginalmessage":
         case "allowUseOriginalMessage": return boolean.class;
         case "autoconfigurationenabled":
@@ -657,6 +662,8 @@ public class MainConfigurationPropertiesConfigurer extends 
org.apache.camel.supp
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         org.apache.camel.main.MainConfigurationProperties target = 
(org.apache.camel.main.MainConfigurationProperties) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "additionalsensitivekeywords":
+        case "additionalSensitiveKeywords": return 
target.getAdditionalSensitiveKeywords();
         case "allowuseoriginalmessage":
         case "allowUseOriginalMessage": return 
target.isAllowUseOriginalMessage();
         case "autoconfigurationenabled":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 19aea07fcea..d4e27b859ea 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -27,6 +27,7 @@
     { "name": "camel.lra", "description": "Camel Saga EIP (Long Running 
Actions) configurations", "sourceType": 
"org.apache.camel.main.LraConfigurationProperties" }
   ],
   "properties": [
+    { "name": "camel.main.additionalSensitiveKeywords", "required": false, 
"description": "Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add additional custom keywords to 
be masked as well. Multiple keywords can be separated by comma.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.main.allowUseOriginalMessage", "required": false, 
"description": "Sets whether to allow access to the original message from 
Camel's error handler, or from 
org.apache.camel.spi.UnitOfWork.getOriginalInMessage(). Turning this off can 
optimize performance, as defensive copy of the original message is not needed. 
Default is false.", "sourceType": 
"org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", 
"javaType": "boolean", "defaultValue": "false", "se [...]
     { "name": "camel.main.autoConfigurationEnabled", "required": false, 
"description": "Whether auto configuration of components, dataformats, 
languages is enabled or not. When enabled the configuration parameters are 
loaded from the properties component. You can prefix the parameters in the 
properties file with: - camel.component.name.option1=value1 - 
camel.component.name.option2=value2 - camel.dataformat.name.option1=value1 - 
camel.dataformat.name.option2=value2 - camel.language.name.o [...]
     { "name": "camel.main.autoConfigurationEnvironmentVariablesEnabled", 
"required": false, "description": "Whether auto configuration should include OS 
environment variables as well. When enabled this allows to overrule any 
configuration using an OS environment variable. For example to set a shutdown 
timeout of 5 seconds: CAMEL_MAIN_SHUTDOWNTIMEOUT=5. This option is default 
enabled.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", 
"type": "boolean", "javaType": "bool [...]
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 8233a665d9c..32663a06d22 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -19,11 +19,12 @@ The following tables lists all the options:
 
 // main options: START
 === Camel Main configurations
-The camel.main supports 124 options, which are listed below.
+The camel.main supports 125 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
+| *camel.main.additionalSensitive{zwsp}Keywords* | Camel comes with a default 
set of sensitive keywords which are automatically masked. This option allows to 
add additional custom keywords to be masked as well. Multiple keywords can be 
separated by comma. |  | String
 | *camel.main.allowUseOriginal{zwsp}Message* | Sets whether to allow access to 
the original message from Camel's error handler, or from 
org.apache.camel.spi.UnitOfWork.getOriginalInMessage(). Turning this off can 
optimize performance, as defensive copy of the original message is not needed. 
Default is false. | false | boolean
 | *camel.main.autoConfiguration{zwsp}Enabled* | Whether auto configuration of 
components, dataformats, languages is enabled or not. When enabled the 
configuration parameters are loaded from the properties component. You can 
prefix the parameters in the properties file with: - 
camel.component.name.option1=value1 - camel.component.name.option2=value2 - 
camel.dataformat.name.option1=value1 - camel.dataformat.name.option2=value2 - 
camel.language.name.option1=value1 - camel.language.name.opti [...]
 | *camel.main.autoConfiguration{zwsp}EnvironmentVariablesEnabled* | Whether 
auto configuration should include OS environment variables as well. When 
enabled this allows to overrule any configuration using an OS environment 
variable. For example to set a shutdown timeout of 5 seconds: 
CAMEL_MAIN_SHUTDOWNTIMEOUT=5. This option is default enabled. | true | boolean
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
index dd459d3a4af..92420d4d765 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java
@@ -129,6 +129,9 @@ public final class DefaultConfigurationConfigurer {
     public static void configure(CamelContext camelContext, 
DefaultConfigurationProperties<?> config) throws Exception {
         ExtendedCamelContext ecc = camelContext.getCamelContextExtension();
 
+        if (config.getAdditionalSensitiveKeywords() != null) {
+            
ecc.setAdditionalSensitiveKeywords(config.getAdditionalSensitiveKeywords());
+        }
         if (config.getStartupRecorder() != null) {
             if ("false".equals(config.getStartupRecorder())) {
                 ecc.getStartupStepRecorder().setEnabled(false);
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index c10fb6838e0..259ff1cfc96 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -84,6 +84,7 @@ public abstract class DefaultConfigurationProperties<T> {
     private boolean logExhaustedMessageBody;
     private String logName;
     private String logLanguage;
+    private String additionalSensitiveKeywords;
     private boolean autoStartup = true;
     private String autoStartupExcludePattern;
     private boolean allowUseOriginalMessage;
@@ -789,6 +790,18 @@ public abstract class DefaultConfigurationProperties<T> {
         this.logLanguage = logLanguage;
     }
 
+    public String getAdditionalSensitiveKeywords() {
+        return additionalSensitiveKeywords;
+    }
+
+    /**
+     * Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add
+     * additional custom keywords to be masked as well. Multiple keywords can 
be separated by comma.
+     */
+    public void setAdditionalSensitiveKeywords(String 
additionalSensitiveKeywords) {
+        this.additionalSensitiveKeywords = additionalSensitiveKeywords;
+    }
+
     public boolean isAutoStartup() {
         return autoStartup;
     }
@@ -2130,6 +2143,15 @@ public abstract class DefaultConfigurationProperties<T> {
         return (T) this;
     }
 
+    /**
+     * Camel comes with a default set of sensitive keywords which are 
automatically masked. This option allows to add
+     * additional custom keywords to be masked as well. Multiple keywords can 
be separated by comma.
+     */
+    public T withAdditionalSensitiveKeywords(String 
additionalSensitiveKeywords) {
+        this.additionalSensitiveKeywords = additionalSensitiveKeywords;
+        return (T) this;
+    }
+
     /**
      * Sets whether the object should automatically start when Camel starts. 
Important: Currently only routes can be
      * disabled, as CamelContext's are always started. Note: When setting auto 
startup false on CamelContext then that
diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java
index b716a80ef26..d7670630d20 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedCamelContextMBean.java
@@ -73,6 +73,9 @@ public interface ManagedCamelContextMBean extends 
ManagedPerformanceCounterMBean
     @ManagedAttribute(description = "HeadersMapFactory class name")
     String getHeadersMapFactoryClassName();
 
+    @ManagedAttribute(description = "Additional sensitive keywords (such as 
passwords) that should be masked when logging")
+    String getAdditionalSensitiveKeywords();
+
     /**
      * Gets the value of a CamelContext global option
      *
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
index 14b8eff71fd..ceae33189a5 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
@@ -263,6 +263,11 @@ public class ManagedCamelContext extends 
ManagedPerformanceCounter implements Ti
         return 
context.getCamelContextExtension().getHeadersMapFactory().getClass().getName();
     }
 
+    @Override
+    public String getAdditionalSensitiveKeywords() {
+        return 
context.getCamelContextExtension().getAdditionalSensitiveKeywords();
+    }
+
     @Override
     public Map<String, String> getGlobalOptions() {
         if (context.getGlobalOptions().isEmpty()) {
diff --git 
a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java 
b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
index a6fbc27fd68..b2a3db90658 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
@@ -28,8 +28,10 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringJoiner;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -49,13 +51,15 @@ public final class URISupport {
     public static final char[] RAW_TOKEN_START = { '(', '{' };
     public static final char[] RAW_TOKEN_END = { ')', '}' };
 
+    @SuppressWarnings("RegExpUnnecessaryNonCapturingGroup")
+    private static final String PRE_SECRETS_FORMAT = 
"([?&][^=]*(?:%s)[^=]*)=(RAW(([{][^}]*[}])|([(][^)]*[)]))|[^&]*)";
+
     // Match any key-value pair in the URI query string whose key contains
     // "passphrase" or "password" or secret key (case-insensitive).
     // First capture group is the key, second is the value.
-    @SuppressWarnings("RegExpUnnecessaryNonCapturingGroup")
-    private static final Pattern ALL_SECRETS = Pattern.compile(
-            "([?&][^=]*(?:" + SensitiveUtils.getSensitivePattern() + 
")[^=]*)=(RAW(([{][^}]*[}])|([(][^)]*[)]))|[^&]*)",
-            Pattern.CASE_INSENSITIVE);
+    private static final Pattern ALL_SECRETS
+            = 
Pattern.compile(PRE_SECRETS_FORMAT.formatted(SensitiveUtils.getSensitivePattern()),
+                    Pattern.CASE_INSENSITIVE);
 
     // Match the user password in the URI as second capture group
     // (applies to URI with authority component and userinfo token in the form
@@ -71,10 +75,31 @@ public final class URISupport {
 
     private static final String EMPTY_QUERY_STRING = "";
 
+    private static Pattern EXTRA_SECRETS;
+
     private URISupport() {
         // Helper class
     }
 
+    /**
+     * Adds custom keywords for sanitizing sensitive information (such as 
passwords) from URIs. Notice that when a key
+     * has been added it cannot be removed.
+     *
+     * @param keywords keywords separated by comma
+     */
+    public static synchronized void addSanitizeKeywords(String keywords) {
+        StringJoiner pattern = new StringJoiner("|");
+        for (String key : keywords.split(",")) {
+            // skip existing keys
+            key = key.toLowerCase(Locale.ROOT).trim();
+            if (!SensitiveUtils.containsSensitive(key)) {
+                pattern.add("\\Q" + key.toLowerCase(Locale.ROOT) + "\\E");
+            }
+        }
+        EXTRA_SECRETS = Pattern.compile(PRE_SECRETS_FORMAT.formatted(pattern),
+                Pattern.CASE_INSENSITIVE);
+    }
+
     /**
      * Removes detected sensitive information (such as passwords) from the URI 
and returns the result.
      *
@@ -88,6 +113,9 @@ public final class URISupport {
         String sanitized = uri;
         if (uri != null) {
             sanitized = ALL_SECRETS.matcher(sanitized).replaceAll("$1=xxxxxx");
+            if (EXTRA_SECRETS != null) {
+                sanitized = 
EXTRA_SECRETS.matcher(sanitized).replaceFirst("$1=xxxxxx");
+            }
             sanitized = 
USERINFO_PASSWORD.matcher(sanitized).replaceFirst("$1xxxxxx$3");
         }
         return sanitized;
diff --git 
a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java 
b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
index cb71f254434..83cb36d0cf1 100644
--- a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
+++ b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
@@ -637,6 +637,18 @@ public class URISupportTest {
 
         dec = URISupport.getDecodeQuery(enc);
         assertEquals(out, dec);
+    }
+
+    @Test
+    public void testSanitizeCustomKeys() {
+        String uri1 = 
"http://foo?username=me&password=secret&domain=foobar&database=customers";;
+        String expected = 
"http://foo?username=xxxxxx&password=xxxxxx&domain=foobar&database=customers";;
+        assertEquals(expected, URISupport.sanitizeUri(uri1));
 
+        URISupport.addSanitizeKeywords("domain,system,cheese");
+        assertNotEquals(expected, URISupport.sanitizeUri(uri1));
+        expected = 
"http://foo?username=xxxxxx&password=xxxxxx&domain=xxxxxx&database=customers";;
+        assertEquals(expected, URISupport.sanitizeUri(uri1));
     }
+
 }

Reply via email to