This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 0bf86e2ee231 Do not print credentials in configuration toString()
(#29705)
0bf86e2ee231 is described below
commit 0bf86e2ee2316c39fa975f62804d0ebed7a6db3d
Author: dhairya05 <[email protected]>
AuthorDate: Thu Nov 12 19:54:48 2026 +0530
Do not print credentials in configuration toString() (#29705)
* Do not print credentials in configuration toString()
Four classes write secrets into their toString() in clear:
camel-zendesk ZendeskConfiguration - password, token, oauthToken
camel-kubernetes KubernetesConfiguration - password, oauthToken,
caCertData, clientCertData, clientKeyData,
clientKeyPassphrase
camel-smpp SmppConfiguration - password, httpProxyPassword
camel-huaweicloud-dms CreateInstanceRequestBody - password,
kafkaManagerPassword
Each component's own catalog marks those options secret = true, and
clientKeyData is a private key. A configuration's toString() reaches a log
file, a JMX attribute or an exception message without anyone meaning to
publish it, so marking an option secret has to hold there too.
The credential material is masked with xxxxxx, the mask URISupport already
uses when it sanitizes a URI, and only when the value is non-null, so a line
still says whether a credential was configured. What points at the material
-
masterUrl, serverUrl, username, systemId, caCertFile, clientKeyFile - stays
readable, so the output is still useful for diagnosis.
camel-netty-http's HttpPrincipal ("do not display the password") and
camel-snmp's SnmpEndpoint ("only show address to avoid user and password
details to be shown") already do this.
* Regen
---------
Co-authored-by: Guillaume Nodet <[email protected]>
---
.../dms/models/CreateInstanceRequestBody.java | 12 ++++-
.../kubernetes/KubernetesConfiguration.java | 19 ++++++--
.../kubernetes/KubernetesConfigurationTest.java | 56 +++++++++++++++++++++
.../camel/component/smpp/SmppConfiguration.java | 12 ++++-
.../component/smpp/SmppConfigurationTest.java | 17 +++++++
.../component/zendesk/ZendeskConfiguration.java | 10 +++-
.../zendesk/ZendeskConfigurationTest.java | 57 ++++++++++++++++++++++
7 files changed, 174 insertions(+), 9 deletions(-)
diff --git
a/components/camel-huawei/camel-huaweicloud-dms/src/main/java/org/apache/camel/component/huaweicloud/dms/models/CreateInstanceRequestBody.java
b/components/camel-huawei/camel-huaweicloud-dms/src/main/java/org/apache/camel/component/huaweicloud/dms/models/CreateInstanceRequestBody.java
index b094b0c4248e..b1daf9b0e550 100644
---
a/components/camel-huawei/camel-huaweicloud-dms/src/main/java/org/apache/camel/component/huaweicloud/dms/models/CreateInstanceRequestBody.java
+++
b/components/camel-huawei/camel-huaweicloud-dms/src/main/java/org/apache/camel/component/huaweicloud/dms/models/CreateInstanceRequestBody.java
@@ -505,14 +505,14 @@ public class CreateInstanceRequestBody {
", storageSpace=" + storageSpace +
", partitionNum=" + partitionNum +
", accessUser='" + accessUser + '\'' +
- ", password='" + password + '\'' +
+ ", password='" + mask(password) + '\'' +
", vpcId='" + vpcId + '\'' +
", securityGroupId='" + securityGroupId + '\'' +
", subnetId='" + subnetId + '\'' +
", availableZones=" + availableZones +
", productId='" + productId + '\'' +
", kafkaManagerUser='" + kafkaManagerUser + '\'' +
- ", kafkaManagerPassword='" + kafkaManagerPassword + '\'' +
+ ", kafkaManagerPassword='" + mask(kafkaManagerPassword) + '\'' +
", maintainBegin='" + maintainBegin + '\'' +
", maintainEnd='" + maintainEnd + '\'' +
", enablePublicip=" + enablePublicip +
@@ -526,4 +526,12 @@ public class CreateInstanceRequestBody {
", enterpriseProjectId='" + enterpriseProjectId + '\'' +
'}';
}
+
+ /**
+ * Masks a credential so that logging this request body cannot leak it.
{@code xxxxxx} is the mask Camel uses when
+ * it sanitizes a URI, and whether the value was set at all is still
visible.
+ */
+ private static String mask(Object secret) {
+ return secret != null ? "xxxxxx" : "null";
+ }
}
diff --git
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConfiguration.java
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConfiguration.java
index 3b533831f889..678c7caf5c26 100644
---
a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConfiguration.java
+++
b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConfiguration.java
@@ -499,15 +499,26 @@ public class KubernetesConfiguration implements Cloneable
{
public String toString() {
return "KubernetesConfiguration [masterUrl=" + masterUrl + ",
category=" + category + ", kubernetesClient="
+ kubernetesClient + ", username=" + username + ", password="
- + password + ", operation=" + operation + ", apiVersion=" +
apiVersion + ", caCertData=" + caCertData
+ + mask(password) + ", operation=" + operation + ", apiVersion="
+ apiVersion + ", caCertData="
+ + mask(caCertData)
+ ", caCertFile=" + caCertFile + ", clientCertData="
- + clientCertData + ", clientCertFile=" + clientCertFile + ",
clientKeyAlgo=" + clientKeyAlgo + ", clientKeyData="
- + clientKeyData + ", clientKeyFile="
- + clientKeyFile + ", clientKeyPassphrase=" +
clientKeyPassphrase + ", oauthToken=" + oauthToken + ", trustCerts="
+ + mask(clientCertData) + ", clientCertFile=" + clientCertFile +
", clientKeyAlgo=" + clientKeyAlgo
+ + ", clientKeyData="
+ + mask(clientKeyData) + ", clientKeyFile="
+ + clientKeyFile + ", clientKeyPassphrase=" +
mask(clientKeyPassphrase) + ", oauthToken="
+ + mask(oauthToken) + ", trustCerts="
+ trustCerts + ", namespace=" + namespace
+ ", labelKey=" + labelKey + ", labelValue=" + labelValue + ",
resourceName=" + resourceName + ", portName="
+ portName + ", dnsDomain=" + dnsDomain + ", poolSize="
+ poolSize + ", connectionTimeout=" + connectionTimeout + "]";
}
+ /**
+ * Masks a credential so that logging or a JMX attribute of this
configuration cannot leak it. {@code xxxxxx} is the
+ * mask Camel uses when it sanitizes a URI, and whether the value was set
at all is still visible.
+ */
+ private static String mask(Object secret) {
+ return secret != null ? "xxxxxx" : "null";
+ }
+
}
diff --git
a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/KubernetesConfigurationTest.java
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/KubernetesConfigurationTest.java
new file mode 100644
index 000000000000..7003a68f95c7
--- /dev/null
+++
b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/KubernetesConfigurationTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.kubernetes;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class KubernetesConfigurationTest {
+
+ @Test
+ public void toStringShouldNotLeakCredentials() {
+ KubernetesConfiguration configuration = new KubernetesConfiguration();
+ configuration.setMasterUrl("https://localhost:6443");
+ configuration.setUsername("someone");
+ configuration.setPassword("s3cret");
+ configuration.setOauthToken("0authT0ken");
+ configuration.setCaCertData("caCertD4ta");
+ configuration.setClientCertData("clientCertD4ta");
+ configuration.setClientKeyData("clientKeyD4ta");
+ configuration.setClientKeyPassphrase("passphr4se");
+ configuration.setClientKeyFile("/etc/kubernetes/client.key");
+
+ String actual = configuration.toString();
+
+ assertFalse(actual.contains("s3cret"), actual);
+ assertFalse(actual.contains("0authT0ken"), actual);
+ assertFalse(actual.contains("caCertD4ta"), actual);
+ assertFalse(actual.contains("clientCertD4ta"), actual);
+ assertFalse(actual.contains("clientKeyD4ta"), actual);
+ assertFalse(actual.contains("passphr4se"), actual);
+
+ assertTrue(actual.contains("password=xxxxxx"), actual);
+ assertTrue(actual.contains("oauthToken=xxxxxx"), actual);
+ assertTrue(actual.contains("clientKeyData=xxxxxx"), actual);
+ // the paths that point at the material, and the cluster being talked
to, stay readable
+
assertTrue(actual.contains("clientKeyFile=/etc/kubernetes/client.key"), actual);
+ assertTrue(actual.contains("masterUrl=https://localhost:6443"),
actual);
+ }
+
+}
diff --git
a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConfiguration.java
b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConfiguration.java
index 271f683b70ce..79d3a0e46e01 100644
---
a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConfiguration.java
+++
b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConfiguration.java
@@ -774,7 +774,7 @@ public class SmppConfiguration implements Cloneable {
+ ", hostnameVerification=" + hostnameVerification
+ ", enquireLinkTimer=" + enquireLinkTimer
+ ", host=" + host
- + ", password=" + password
+ + ", password=" + mask(password)
+ ", port=" + port
+ ", systemId=" + systemId
+ ", systemType=" + systemType
@@ -807,10 +807,18 @@ public class SmppConfiguration implements Cloneable {
+ ", httpProxyHost=" + httpProxyHost
+ ", httpProxyPort=" + httpProxyPort
+ ", httpProxyUsername=" + httpProxyUsername
- + ", httpProxyPassword=" + httpProxyPassword
+ + ", httpProxyPassword=" + mask(httpProxyPassword)
+ ", splittingPolicy=" + splittingPolicy
+ ", proxyHeaders=" + proxyHeaders
+ ", interfaceVersion=" + interfaceVersion
+ "]";
}
+
+ /**
+ * Masks a credential so that logging or a JMX attribute of this
configuration cannot leak it. {@code xxxxxx} is the
+ * mask Camel uses when it sanitizes a URI, and whether the value was set
at all is still visible.
+ */
+ private static String mask(Object secret) {
+ return secret != null ? "xxxxxx" : "null";
+ }
}
diff --git
a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConfigurationTest.java
b/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConfigurationTest.java
index 46677b40e258..c7461b0ce228 100644
---
a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConfigurationTest.java
+++
b/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConfigurationTest.java
@@ -31,8 +31,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* JUnit test class for
<code>org.apache.camel.component.smpp.SmppConfiguration</code>
@@ -240,6 +242,21 @@ public class SmppConfigurationTest {
assertEquals(expected, configuration.toString());
}
+ @Test
+ public void toStringShouldNotLeakCredentials() {
+ configuration.setPassword("s3cret");
+ configuration.setHttpProxyPassword("proxyS3cret");
+
+ String actual = configuration.toString();
+
+ assertFalse(actual.contains("s3cret"), actual);
+ assertFalse(actual.contains("proxyS3cret"), actual);
+ assertTrue(actual.contains("password=xxxxxx"), actual);
+ assertTrue(actual.contains("httpProxyPassword=xxxxxx"), actual);
+ // the systemId is not a credential, and stays readable
+ assertTrue(actual.contains("systemId=smppclient"), actual);
+ }
+
private void setNoneDefaultValues(SmppConfiguration config) {
config.setDestAddr("1919");
config.setDestAddrNpi(NumberingPlanIndicator.NATIONAL.value());
diff --git
a/components/camel-zendesk/src/main/java/org/apache/camel/component/zendesk/ZendeskConfiguration.java
b/components/camel-zendesk/src/main/java/org/apache/camel/component/zendesk/ZendeskConfiguration.java
index d664e7281742..29f49523f0ec 100644
---
a/components/camel-zendesk/src/main/java/org/apache/camel/component/zendesk/ZendeskConfiguration.java
+++
b/components/camel-zendesk/src/main/java/org/apache/camel/component/zendesk/ZendeskConfiguration.java
@@ -147,7 +147,15 @@ public class ZendeskConfiguration {
public String toString() {
return String.format(
"ZendeskConfiguration:[methodName=%s, serverUrl=%s,
username=%s, password=%s, token=%s, oauthToken=%s]",
- methodName, serverUrl, username, password, token, oauthToken);
+ methodName, serverUrl, username, mask(password), mask(token),
mask(oauthToken));
+ }
+
+ /**
+ * Masks a credential so that logging or a JMX attribute of this
configuration cannot leak it. {@code xxxxxx} is the
+ * mask Camel uses when it sanitizes a URI, and whether the value was set
at all is still visible.
+ */
+ private static String mask(Object secret) {
+ return secret != null ? "xxxxxx" : "null";
}
@Override
diff --git
a/components/camel-zendesk/src/test/java/org/apache/camel/component/zendesk/ZendeskConfigurationTest.java
b/components/camel-zendesk/src/test/java/org/apache/camel/component/zendesk/ZendeskConfigurationTest.java
new file mode 100644
index 000000000000..965df030c221
--- /dev/null
+++
b/components/camel-zendesk/src/test/java/org/apache/camel/component/zendesk/ZendeskConfigurationTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.zendesk;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ZendeskConfigurationTest {
+
+ @Test
+ public void toStringShouldNotLeakCredentials() {
+ ZendeskConfiguration configuration = new ZendeskConfiguration();
+ configuration.setServerUrl("https://example.zendesk.com");
+ configuration.setUsername("[email protected]");
+ configuration.setPassword("s3cret");
+ configuration.setToken("t0ken");
+ configuration.setOauthToken("0authT0ken");
+
+ String actual = configuration.toString();
+
+ assertFalse(actual.contains("s3cret"), actual);
+ assertFalse(actual.contains("t0ken"), actual);
+ assertFalse(actual.contains("0authT0ken"), actual);
+ assertTrue(actual.contains("password=xxxxxx"), actual);
+ assertTrue(actual.contains("token=xxxxxx"), actual);
+ assertTrue(actual.contains("oauthToken=xxxxxx"), actual);
+ // what the configuration points at stays readable, so the line is
still useful
+ assertTrue(actual.contains("serverUrl=https://example.zendesk.com"),
actual);
+ }
+
+ @Test
+ public void toStringShouldStillShowThatACredentialIsUnset() {
+ ZendeskConfiguration configuration = new ZendeskConfiguration();
+
+ String actual = configuration.toString();
+
+ assertTrue(actual.contains("password=null"), actual);
+ assertTrue(actual.contains("token=null"), actual);
+ }
+
+}