diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java index b68caf15775cf..b60e3b46378e6 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java @@ -33,6 +33,7 @@ import java.io.Serializable; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.apache.pulsar.client.util.Secret; /** * This is a simple holder of the client configuration values. @@ -51,9 +52,9 @@ public class ClientConfigurationData implements Serializable, Cloneable { private Authentication authentication = AuthenticationDisabled.INSTANCE; private String authPluginClassName; - @JsonIgnore + @Secret private String authParams; - @JsonIgnore + @Secret private Map authParamMap; private long operationTimeoutMs = 30000; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/util/Secret.java b/pulsar-client/src/main/java/org/apache/pulsar/client/util/Secret.java new file mode 100644 index 0000000000000..380800adea6bc --- /dev/null +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/util/Secret.java @@ -0,0 +1,34 @@ +/** + * 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.pulsar.client.util; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@JsonSerialize(using = SecretsSerializer.class) +public @interface Secret { + +} diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/util/SecretsSerializer.java b/pulsar-client/src/main/java/org/apache/pulsar/client/util/SecretsSerializer.java new file mode 100644 index 0000000000000..35e4150886444 --- /dev/null +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/util/SecretsSerializer.java @@ -0,0 +1,38 @@ +/** + * 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.pulsar.client.util; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; + +public class SecretsSerializer extends JsonSerializer { + + @Override + public void serialize(final Object value, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) + throws IOException { + if (value == null) { + serializerProvider.defaultSerializeNull(jsonGenerator); + return; + } + + jsonGenerator.writeObject("*****"); + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/conf/ConfigurationDataUtilsTest.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/conf/ConfigurationDataUtilsTest.java index a1bafbdefb4ec..3659ce8463ba3 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/conf/ConfigurationDataUtilsTest.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/conf/ConfigurationDataUtilsTest.java @@ -18,6 +18,10 @@ */ package org.apache.pulsar.client.impl.conf; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -47,14 +51,24 @@ public void testLoadClientConfigurationData() { confData.setMaxLookupRedirects(10); confData.setNumIoThreads(33); Map config = new HashMap<>(); + Map authParamMap = new HashMap<>(); + authParamMap.put("k1", "v1"); + authParamMap.put("k2", "v2"); + config.put("serviceUrl", "pulsar://localhost:6650"); config.put("maxLookupRequest", 70000); config.put("maxLookupRedirects", 50); + config.put("authParams", "testAuthParams"); + config.put("authParamMap", authParamMap); + confData = ConfigurationDataUtils.loadData(config, confData, ClientConfigurationData.class); assertEquals("pulsar://localhost:6650", confData.getServiceUrl()); assertEquals(70000, confData.getMaxLookupRequest()); assertEquals(50, confData.getMaxLookupRedirects()); assertEquals(33, confData.getNumIoThreads()); + assertEquals("testAuthParams", confData.getAuthParams()); + assertEquals("v1", confData.getAuthParamMap().get("k1")); + assertEquals("v2", confData.getAuthParamMap().get("k2")); } @Test @@ -136,6 +150,40 @@ public void testConfigBuilder() throws PulsarClientException { assertEquals(pulsarClient.getConfiguration().getServiceUrl(), "pulsar://unknown:6650"); assertEquals(pulsarClient.getConfiguration().getNumListenerThreads(), 1, "builder default not set properly"); assertEquals(pulsarClient.getConfiguration().getStatsIntervalSeconds(), 80, - "builder default should overrite if set explicitly"); + "builder default should override if set explicitly"); + } + + @Test + public void testLoadSecretParams() { + ClientConfigurationData confData = new ClientConfigurationData(); + Map authParamMap = new HashMap<>(); + authParamMap.put("k1", "v1"); + + confData.setServiceUrl("pulsar://unknown:6650"); + confData.setAuthParams(""); + confData.setAuthParamMap(authParamMap); + + authParamMap.put("k2", "v2"); + Map config = new HashMap<>(); + config.put("serviceUrl", "pulsar://localhost:6650"); + config.put("authParams", "testAuthParams"); + config.put("authParamMap", authParamMap); + + confData = ConfigurationDataUtils.loadData(config, confData, ClientConfigurationData.class); + assertEquals("pulsar://localhost:6650", confData.getServiceUrl()); + assertEquals("testAuthParams", confData.getAuthParams()); + assertEquals("v1", confData.getAuthParamMap().get("k1")); + assertEquals("v2", confData.getAuthParamMap().get("k2")); + + final String secretStr = "*****"; + try { + String confDataJson = new ObjectMapper().writeValueAsString(confData); + Map confDataMap = new ObjectMapper().readValue(confDataJson, Map.class); + assertEquals("pulsar://localhost:6650", confDataMap.get("serviceUrl")); + assertEquals(secretStr, confDataMap.get("authParams")); + assertEquals(secretStr, confDataMap.get("authParamMap")); + } catch (Exception e) { + Assert.fail(); + } } }