QPID-8135: Mask connection URL password options
diff --git a/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
index a2cd52a..5a19791 100644
--- a/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
+++ b/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java
@@ -20,6 +20,8 @@
  */
 package org.apache.qpid.client;
 
+import static org.apache.qpid.client.BrokerDetails.PASSWORD_YIELDING_OPTIONS;
+
 import org.apache.qpid.client.url.URLParser;
 import org.apache.qpid.jms.ConnectionURL;
 import org.apache.qpid.url.URLHelper;
@@ -351,17 +353,18 @@
 
     private String optionsToString()
     {
-        StringBuffer sb = new StringBuffer("?");
+        StringBuilder sb = new StringBuilder();
         
         if (!_options.isEmpty())
         {
-            for (Map.Entry<String, String> option : _options.entrySet())
-            {
-                sb.append(option.getKey()).append("='").append(option.getValue()).append("'");
-                sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
-            }
+            sb.append(URLHelper.printOptions(_options, PASSWORD_YIELDING_OPTIONS));
+            sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
         }
-        
+        else
+        {
+            sb.append("?");
+        }
+
         sb.append(OPTIONS_BROKERLIST).append("='");
         for (BrokerDetails service : _brokers)
         {
diff --git a/client/src/main/java/org/apache/qpid/client/BrokerDetails.java b/client/src/main/java/org/apache/qpid/client/BrokerDetails.java
index 5b99285..609dd59 100644
--- a/client/src/main/java/org/apache/qpid/client/BrokerDetails.java
+++ b/client/src/main/java/org/apache/qpid/client/BrokerDetails.java
@@ -69,7 +69,7 @@
     public static final String OPTIONS_ENCRYPTION_KEY_STORE = "encryption_key_store";
     public static final String OPTIONS_ENCRYPTION_KEY_STORE_PASSWORD = "encryption_key_store_password";
 
-    private static final Set<String> PASSWORD_YIELDING_OPTIONS =
+    static final Set<String> PASSWORD_YIELDING_OPTIONS =
             Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
                     OPTIONS_TRUST_STORE_PASSWORD,
                     OPTIONS_KEY_STORE_PASSWORD,
@@ -424,38 +424,7 @@
 
     private String printOptionsURL()
     {
-        StringBuffer optionsURL = new StringBuffer();
-
-        optionsURL.append('?');
-
-        if (!(_options.isEmpty()))
-        {
-
-            for (String key : _options.keySet())
-            {
-                optionsURL.append(key);
-
-                optionsURL.append("='");
-
-                if (PASSWORD_YIELDING_OPTIONS.contains(key))
-                {
-                    optionsURL.append("********");
-                }
-                else
-                {
-                    optionsURL.append(_options.get(key));
-                }
-
-                optionsURL.append("'");
-
-                optionsURL.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
-            }
-        }
-
-        //removeKey the extra DEFAULT_OPTION_SEPERATOR or the '?' if there are no options
-        optionsURL.deleteCharAt(optionsURL.length() - 1);
-
-        return optionsURL.toString();
+        return URLHelper.printOptions(_options, PASSWORD_YIELDING_OPTIONS);
     }
 
     public static String checkTransport(String broker)
diff --git a/client/src/main/java/org/apache/qpid/url/URLHelper.java b/client/src/main/java/org/apache/qpid/url/URLHelper.java
index c7fea15..219cccd 100644
--- a/client/src/main/java/org/apache/qpid/url/URLHelper.java
+++ b/client/src/main/java/org/apache/qpid/url/URLHelper.java
@@ -20,7 +20,9 @@
  */
 package org.apache.qpid.url;
 
+import java.util.Collections;
 import java.util.Map;
+import java.util.Set;
 
 public class URLHelper
 {
@@ -145,6 +147,11 @@
 
     public static String printOptions(Map<String, String> options)
     {
+        return printOptions(options, Collections.<String>emptySet());
+    }
+
+    public static String printOptions(Map<String, String> options, Set<String> optionNamesToMask)
+    {
         if (options.isEmpty())
         {
             return "";
@@ -159,7 +166,14 @@
 
                 sb.append("='");
 
-                sb.append(entry.getValue());
+                if (optionNamesToMask.contains(entry.getKey()))
+                {
+                    sb.append("********");
+                }
+                else
+                {
+                    sb.append(entry.getValue());
+                }
 
                 sb.append("'");
                 sb.append(DEFAULT_OPTION_SEPERATOR);
diff --git a/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index c31eb4d..fb7b058 100644
--- a/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -285,6 +285,38 @@
         assertEquals("Unexpected toString form", expectedToString, actualToString);
     }
 
+    public void testToStringMasksConnectionOptionForEncryptionTrustStorePassword() throws Exception
+    {
+        ConnectionURL url = new AMQConnectionURL("amqp://user:pass@temp/test?encryption_trust_store_password='password'&brokerlist='tcp://localhost:5672'");
+
+        String expectedToString = "amqp://user:********@temp/test?encryption_trust_store_password='********'&brokerlist='tcp://localhost:5672'";
+        assertEquals("Unexpected toString", expectedToString, url.toString());
+    }
+
+    public void testToStringMasksConnectionOptionForEncryptionKeyStorePassword() throws Exception
+    {
+        ConnectionURL url = new AMQConnectionURL("amqp://user:pass@temp/test?encryption_key_store_password='password'&brokerlist='tcp://localhost:5672'");
+
+        String expectedToString = "amqp://user:********@temp/test?encryption_key_store_password='********'&brokerlist='tcp://localhost:5672'";
+        assertEquals("Unexpected toString", expectedToString, url.toString());
+    }
+
+    public void testToStringMasksConnectionOptionForTrustStorePassword() throws Exception
+    {
+        ConnectionURL url = new AMQConnectionURL("amqp://user:pass@temp/test?trust_store_password='password'&brokerlist='tcp://localhost:5672'");
+
+        String expectedToString = "amqp://user:********@temp/test?trust_store_password='********'&brokerlist='tcp://localhost:5672'";
+        assertEquals("Unexpected toString", expectedToString, url.toString());
+    }
+
+    public void testToStringMasksConnectionOptionForKeyStorePassword() throws Exception
+    {
+        ConnectionURL url = new AMQConnectionURL("amqp://user:pass@temp/test?key_store_password='password'&brokerlist='tcp://localhost:5672'");
+
+        String expectedToString = "amqp://user:********@temp/test?key_store_password='********'&brokerlist='tcp://localhost:5672'";
+        assertEquals("Unexpected toString", expectedToString, url.toString());
+    }
+
     /**
      * Test for QPID-3662 to ensure the {@code toString()} representation is correct.
      */