You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@edgent.apache.org by dl...@apache.org on 2016/03/30 18:02:27 UTC

[1/3] incubator-quarks git commit: [QUARKS-61] mqtt-ssl / client-auth support

Repository: incubator-quarks
Updated Branches:
  refs/heads/master 9e13ad781 -> a3c2770e7


http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/mosquitto.org.crt
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/mosquitto.org.crt b/connectors/mqtt/src/test/keystores/mosquitto.org.crt
new file mode 100644
index 0000000..b8535e8
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/mosquitto.org.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8DCCAlmgAwIBAgIJAOD63PlXjJi8MA0GCSqGSIb3DQEBBQUAMIGQMQswCQYD
+VQQGEwJHQjEXMBUGA1UECAwOVW5pdGVkIEtpbmdkb20xDjAMBgNVBAcMBURlcmJ5
+MRIwEAYDVQQKDAlNb3NxdWl0dG8xCzAJBgNVBAsMAkNBMRYwFAYDVQQDDA1tb3Nx
+dWl0dG8ub3JnMR8wHQYJKoZIhvcNAQkBFhByb2dlckBhdGNob28ub3JnMB4XDTEy
+MDYyOTIyMTE1OVoXDTIyMDYyNzIyMTE1OVowgZAxCzAJBgNVBAYTAkdCMRcwFQYD
+VQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwGA1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1v
+c3F1aXR0bzELMAkGA1UECwwCQ0ExFjAUBgNVBAMMDW1vc3F1aXR0by5vcmcxHzAd
+BgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hvby5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBAMYkLmX7SqOT/jJCZoQ1NWdCrr/pq47m3xxyXcI+FLEmwbE3R9vM
+rE6sRbP2S89pfrCt7iuITXPKycpUcIU0mtcT1OqxGBV2lb6RaOT2gC5pxyGaFJ+h
+A+GIbdYKO3JprPxSBoRponZJvDGEZuM3N7p3S/lRoi7G5wG5mvUmaE5RAgMBAAGj
+UDBOMB0GA1UdDgQWBBTad2QneVztIPQzRRGj6ZHKqJTv5jAfBgNVHSMEGDAWgBTa
+d2QneVztIPQzRRGj6ZHKqJTv5jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA
+A4GBAAqw1rK4NlRUCUBLhEFUQasjP7xfFqlVbE2cRy0Rs4o3KS0JwzQVBwG85xge
+REyPOFdGdhBY2P1FNRy0MDr6xr+D2ZOwxs63dG1nnAnWZg7qwoLgpZ4fESPD3PkA
+1ZgKJc2zbSQ9fCPxt2W3mdVav66c6fsb7els2W2Iz7gERJSX
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/server.crt
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/server.crt b/connectors/mqtt/src/test/keystores/server.crt
new file mode 100644
index 0000000..f0dcbc4
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/server.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnwCCQDb5n2CQihT/DANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk1BMRIwEAYDVQQHEwlMaXR0bGV0b24xDDAKBgNVBAoTA0lC
+TTEPMA0GA1UECxMGUXVhcmtzMR0wGwYDVQQDExRNeSBUZXN0IE1vc3F1aXR0byBD
+QTEbMBkGCSqGSIb3DQEJARYMZm9vQHRlc3Qub3JnMB4XDTE2MDMzMDEzNDY0OFoX
+DTM2MDMyNTEzNDY0OFowgY0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTESMBAG
+A1UEBxMJTGl0dGxldG9uMQwwCgYDVQQKEwNJQk0xDzANBgNVBAsTBlF1YXJrczEh
+MB8GA1UEAxMYTXkgVGVzdCBNb3NxdWl0dG8gU2VydmVyMRswGQYJKoZIhvcNAQkB
+Fgxmb29AdGVzdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD9
+FX0nXD8Ut9DJEJLS8aqIyGx3wIaVqo9VXgcmlIHTDC+z7scBY7PGriAqwY5o8WE4
+6q84NxIQY9SiLjH4ED4clwpsYOLMm1+cXQ9IqQnf3ocaiUxHmuQxkVEQ3o83TMrd
+osg9O6Tf4NCStTbzPvfX6lS6sX5vf/EkHc/WHN7qFPsNlUfyghv76Lwo9qCduo56
+k++gZy3PM0kih9pArBRoUuiBOFIuTpuExeZd1tu8w7YFNiTbjMZwiQKALgzMtXHs
+/i9ipt+/SB170NehNA8qpdRTdfrXAn/++7WZCk7pQ8a3EFQ50tDRQCC8dZSr1NXL
+SF+iP1Oz7Uk6oNC8AL9LAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEABUYMekPyB36W
+KpnGm7J+R2nOFizSofVSo/Xa4lzIOShtqlumok+94zH9zicpRuOzraBHEJwQR5Lm
+LdsS7yM6vb1+FggpKTMAqoA0HIZEjEQ7finJF5XGk5XhbBTiPfyNlsnVWjpqgGUp
+1OCkuoJuuKB99bRDlZgm1/evFIA/ZPw=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/server.csr
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/server.csr b/connectors/mqtt/src/test/keystores/server.csr
new file mode 100644
index 0000000..ea5b7e4
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/server.csr
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIC0zCCAbsCAQAwgY0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTESMBAGA1UE
+BxMJTGl0dGxldG9uMQwwCgYDVQQKEwNJQk0xDzANBgNVBAsTBlF1YXJrczEhMB8G
+A1UEAxMYTXkgVGVzdCBNb3NxdWl0dG8gU2VydmVyMRswGQYJKoZIhvcNAQkBFgxm
+b29AdGVzdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD9FX0n
+XD8Ut9DJEJLS8aqIyGx3wIaVqo9VXgcmlIHTDC+z7scBY7PGriAqwY5o8WE46q84
+NxIQY9SiLjH4ED4clwpsYOLMm1+cXQ9IqQnf3ocaiUxHmuQxkVEQ3o83TMrdosg9
+O6Tf4NCStTbzPvfX6lS6sX5vf/EkHc/WHN7qFPsNlUfyghv76Lwo9qCduo56k++g
+Zy3PM0kih9pArBRoUuiBOFIuTpuExeZd1tu8w7YFNiTbjMZwiQKALgzMtXHs/i9i
+pt+/SB170NehNA8qpdRTdfrXAn/++7WZCk7pQ8a3EFQ50tDRQCC8dZSr1NXLSF+i
+P1Oz7Uk6oNC8AL9LAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEANOKdPIhduq0A
+3W2THd/3+eXdU0W6v0M173cOrUvGZswNW2xvWYknvNhFGIGb6xeYd0F9XtAii4qo
+4OXzL7rUGobOkoO7lCDbESskRy7D64zy8RSt7wFKOJzPojnSH0orbLVdbfWTp5Lb
+6mRXZ6GYQqDA0N9CmOfaH2G1ATLxEibTSGQUaAutg2r3QAPD4Hb+VATGAwpnh3xl
+DTMOV8pnWGms3bKT5tYv7EJyRW92McBes5OyxpdhlcrKDnjOzNBPpIpD0+QfkLGo
+Fl6ye4mAI7m+t7jj14rYwB4gpgKIIhubh1ox7AmjWnnjzNMCfR0gDmtlDlAg94Mb
+N40pxE2oeQ==
+-----END CERTIFICATE REQUEST-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/server.key
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/server.key b/connectors/mqtt/src/test/keystores/server.key
new file mode 100644
index 0000000..2bc339e
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA/RV9J1w/FLfQyRCS0vGqiMhsd8CGlaqPVV4HJpSB0wwvs+7H
+AWOzxq4gKsGOaPFhOOqvODcSEGPUoi4x+BA+HJcKbGDizJtfnF0PSKkJ396HGolM
+R5rkMZFREN6PN0zK3aLIPTuk3+DQkrU28z731+pUurF+b3/xJB3P1hze6hT7DZVH
+8oIb++i8KPagnbqOepPvoGctzzNJIofaQKwUaFLogThSLk6bhMXmXdbbvMO2BTYk
+24zGcIkCgC4MzLVx7P4vYqbfv0gde9DXoTQPKqXUU3X61wJ//vu1mQpO6UPGtxBU
+OdLQ0UAgvHWUq9TVy0hfoj9Ts+1JOqDQvAC/SwIDAQABAoIBABCi3Ps9YRgnjR3q
+bPxYznD3W8nzaeVktM9TwvySPoZ1Ap29UG+S8jpZL9wfpRDY7R8krifv1swlA9E1
+YCuCRdLzSsgdBkuU2xAYPez0z6Vbp13jMJR0ZhOsDbwiJR/peFxhWvBLf2cIDC3Y
+o6gRt5EF4lPzXvBNZLiPDR5x/2U7ol5NihEwhoYma29FGYbOgbD4ZiBTAaahIRNB
+2RgL6WnIno7nJ/YHuzoAH++0LmRD9qqus8S4MfBO0IdCHk9h4wIWxw5ONn3BHC8z
+xHna+QQOPilZwdEpzny2MBbE0eQgue1zz4KGk6wAqoY1yFPK7KbTLag5qYWDOEXD
+JMzlGIECgYEA/y7nfX2FmR33lRf2OK37GpLQAK3C4HRRTsuIQCAd+zLP2JdjIC1/
+TTWGoFyJ3KrT/+86Tr7DKyLhPV6vpxyU5XPx4hz7dltxxFlsmCGjidVKSqrmi8XY
+2xO5/hZ/yH9mkzofWcNMBWqltdoVAukfQhbaZN8hdw4vxzFkuimXHBECgYEA/eTd
+Tu4O1LaqdltefJ8qn+kRPRt1W8HgzpSgQ7r/oYvpuiIQr+mIopbVJTaJuOw9gHJd
+3BbY5iXqRo19HZOXfjZi/krS0nRDGSzaZxjpfJirgo063PKFp2JNjdsl8Juf/aOV
+K4cKlgDZQdRVuOMUoSZL9c5UMNdf/KEocdhrsZsCgYBUvTusJXmu7g+gWBOwoL3J
+BkXCY/FZ3eZ+NwJo4QFzwFza/PKy5cjnV8X8DJ7PQ38g900yhxCCi5OmcIH+CXS8
+eXMydhNfK2CtJlD0d/85rzV7dCMY+TtZDMTvxoLqjrv+Wge9JChjiBW9PM1LaSSz
+KqmdY6dWRMTC7fkYBOWkMQKBgQCf6M7OkLd8mBQi+Yc4XJNfJk86OpofEayC0C9k
+mVm6KMIr/pqeASuSpAdZKdFyTDCsPtwI68bupcC5cRH1V+kZkC2nVf8UmC9OouZn
++tPMKugTENqbIJC3jP2ls/pgYdRRzv777FDpi11Kze6zxSpQGSvMhIiYPn5xQhuU
+IKgrswKBgQCxmf7FzXAxRGvXKE6YLLTOE4UpNpu6Gz44Cmah6DnCZQlpU+xt9Cwi
+HkwSTzCeSjuAw303a+PkqjZF432OP5Dlr6etr2OBoZMMgIDQCtc+XAOMDZKkzN4e
+RcrNtUybYzGSk0TAWmdKUOSmBfqPMOy8VrGaorV7Eyrly0sbxCKG2g==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/KeystorePath.java
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/KeystorePath.java b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/KeystorePath.java
deleted file mode 100644
index 5aaa0a8..0000000
--- a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/KeystorePath.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-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 quarks.tests.connectors.wsclient.javax.websocket;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-public class KeystorePath {
-    
-    public static String getStorePath(String storeLeaf) {
-        String pathStr = System.getProperty("user.dir");
-        // Under eclipse/junit: path to project in repo: <repo>/connectors
-        // Under ant/junit: <repo>/connectors/<project>/unittests/testrunxxxxxxx
-        // Get the path to the <repo>/connectors
-        Path path = new File(pathStr).toPath();
-        do {
-            if (path.endsWith("connectors"))
-                break;
-            path = path.getParent();
-        } while (path != null);
-        path = path.resolve(Paths.get("wsclient-javax.websocket",
-                            "src", "test", "keystores", storeLeaf));
-        if (!path.toFile().exists())
-            throw new IllegalArgumentException("File does not exist: "+path);
-        return path.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
index d241691..04ca101 100644
--- a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
+++ b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
@@ -40,6 +40,7 @@ import com.google.gson.JsonObject;
 import quarks.connectors.wsclient.WebSocketClient;
 import quarks.connectors.wsclient.javax.websocket.Jsr356WebSocketClient;
 import quarks.test.connectors.common.ConnectorTestBase;
+import quarks.test.connectors.common.KeystorePath;
 import quarks.topology.TSink;
 import quarks.topology.TStream;
 import quarks.topology.Topology;
@@ -121,7 +122,7 @@ public class WebSocketClientTest extends ConnectorTestBase {
     }
     
     private String getStorePath(String storeLeaf) {
-        return KeystorePath.getStorePath(storeLeaf);
+        return KeystorePath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
index 36199ef..ea8eb47 100644
--- a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
+++ b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
@@ -46,6 +46,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
 
+import quarks.test.connectors.common.KeystorePath;
+
 /**
  * Simple WebSocket server program to echo received messages.
  * <p>
@@ -143,7 +145,7 @@ public class WebSocketServerEcho {
     }
     
     private String getStorePath(String storeLeaf) {
-        return KeystorePath.getStorePath(storeLeaf);
+        return KeystorePath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
     }
     
     public int getPort() {

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/wsclient-javax.websocket/src/test/keystores/README
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/keystores/README b/connectors/wsclient-javax.websocket/src/test/keystores/README
index bb1a8bd..4419c23 100644
--- a/connectors/wsclient-javax.websocket/src/test/keystores/README
+++ b/connectors/wsclient-javax.websocket/src/test/keystores/README
@@ -9,7 +9,7 @@
 set -x
 
 # ############################################
-echo ==============  server key&cert setup
+echo ==============  server key and cert setup
 
 # create server key&certificate and serverKeyStore.jks
 keytool -genkey -validity 7300 -alias default -keyalg RSA \
@@ -33,7 +33,7 @@ yes
 xxEOFxx
 
 # ############################################
-echo ==============  client "default" key&cert setup
+echo ==============  client "default" key and cert setup
 
 # create client certificate and clientKeyStore.jks
 keytool -genkey -validity 7300 -alias default -keyalg RSA \
@@ -60,7 +60,7 @@ xxEOFxx
 # --------------------------------------------
 # create 2nd client certificate with different alias (for cert selection testing)
 # don't add to server's trust store
-echo ==============  client "my2ndcert" key&cert setup
+echo ==============  client "my2ndcert" key and cert setup
 keytool -genkey -validity 7300 -alias my2ndcert -keyalg RSA \
      -keypass passw0rd -storepass passw0rd -keystore clientKeyStore.jks <<xxEOFxx
 Test Client my2ndcert
@@ -75,7 +75,7 @@ xxEOFxx
 
 # --------------------------------------------
 # create 3rd client certificate with different alias (for cert selection testing)
-echo ==============  client "my3rdcert" key&cert setup
+echo ==============  client "my3rdcert" key and cert setup
 keytool -genkey -validity 7300 -alias my3rdcert -keyalg RSA \
      -keypass passw0rd -storepass passw0rd -keystore clientKeyStore.jks <<xxEOFxx
 Test Client my3rdcert

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/Runner.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/Runner.java b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/Runner.java
index f3243dd..725cf40 100644
--- a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/Runner.java
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/Runner.java
@@ -24,10 +24,14 @@ import static quarks.samples.connectors.mqtt.MqttClient.OPT_CLIENT_ID;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_CN_TIMEOUT_SEC;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_IDLE_RECONNECT_INTERVAL_SEC;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_IDLE_TIMEOUT_SEC;
+import static quarks.samples.connectors.mqtt.MqttClient.OPT_KEY_STORE;
+import static quarks.samples.connectors.mqtt.MqttClient.OPT_KEY_STORE_PASSWORD;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_PASSWORD;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_PUB;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_SERVER_URI;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_TOPIC;
+import static quarks.samples.connectors.mqtt.MqttClient.OPT_TRUST_STORE;
+import static quarks.samples.connectors.mqtt.MqttClient.OPT_TRUST_STORE_PASSWORD;
 import static quarks.samples.connectors.mqtt.MqttClient.OPT_USER_ID;
 
 import quarks.connectors.mqtt.MqttConfig;
@@ -61,6 +65,8 @@ public class Runner {
             SubscriberApp subscriber = new SubscriberApp(tp, options);
             top = subscriber.buildAppTopology();
         }
+
+        // System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
         
         // Submit the app/topology; send or receive the messages.
         System.out.println(
@@ -96,15 +102,14 @@ public class Runner {
             config.setUserName(options.get(OPT_USER_ID));
         if (options.get(OPT_PASSWORD) != null)
             config.setPassword(((String)options.get(OPT_PASSWORD)).toCharArray());
-        // TODO
-//        if (options.get(OPT_TRUST_STORE) != null)
-//            config.setTrustStore(options.get(OPT_TRUST_STORE));
-//        if (options.get(OPT_TRUST_STORE_PASSWORD) != null)
-//            config.setTrustStore(options.get(OPT_TRUST_STORE_PASSWORD));
-//        if (options.get(OPT_KEY_STORE) != null)
-//            config.setKeyStore(options.get(OPT_KEY_STORE));
-//        if (options.get(OPT_KEY_STORE_PASSWORD) != null)
-//            config.setTrustStore(options.get(OPT_KEY_STORE_PASSWORD));
+        if (options.get(OPT_TRUST_STORE) != null)
+            config.setTrustStore(options.get(OPT_TRUST_STORE));
+        if (options.get(OPT_TRUST_STORE_PASSWORD) != null)
+            config.setTrustStore(options.get(OPT_TRUST_STORE_PASSWORD));
+        if (options.get(OPT_KEY_STORE) != null)
+            config.setKeyStore(options.get(OPT_KEY_STORE));
+        if (options.get(OPT_KEY_STORE_PASSWORD) != null)
+            config.setTrustStore(options.get(OPT_KEY_STORE_PASSWORD));
         return config;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimplePublisherApp.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimplePublisherApp.java b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimplePublisherApp.java
index c80f923..d272442 100644
--- a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimplePublisherApp.java
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimplePublisherApp.java
@@ -52,17 +52,11 @@ public class SimplePublisherApp {
     SimplePublisherApp(String mqttPropsPath) throws Exception {
         props = new Properties();
         props.load(Files.newBufferedReader(new File(mqttPropsPath).toPath()));
-        topic = props.getProperty("topic");
+        topic = props.getProperty("mqtt.topic");
     }
     
     private MqttConfig createMqttConfig() {
-        MqttConfig mqttConfig = new MqttConfig(props.getProperty("serverURI"),
-                                                null);
-        // used if broker requires username/pw authentication
-        mqttConfig.setUserName(props.getProperty("userID",
-                                System.getProperty("user.name")));
-        mqttConfig.setPassword(props.getProperty("password",
-                                "myMosquittoPw").toCharArray());
+        MqttConfig mqttConfig = MqttConfig.fromProperties(props);
         return mqttConfig;
     }
     
@@ -75,6 +69,8 @@ public class SimplePublisherApp {
         // build the application/topology
         
         Topology t = tp.newTopology("mqttSamplePublisher");
+        
+        // System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
 
         // Create the MQTT broker connector
         MqttConfig mqttConfig = createMqttConfig();

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimpleSubscriberApp.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimpleSubscriberApp.java b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimpleSubscriberApp.java
index 0f77afb..edcf64d 100644
--- a/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimpleSubscriberApp.java
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/mqtt/SimpleSubscriberApp.java
@@ -50,17 +50,11 @@ public class SimpleSubscriberApp {
     SimpleSubscriberApp(String mqttPropsPath) throws Exception {
         props = new Properties();
         props.load(Files.newBufferedReader(new File(mqttPropsPath).toPath()));
-        topic = props.getProperty("topic");
+        topic = props.getProperty("mqtt.topic");
     }
     
     private MqttConfig createMqttConfig() {
-        MqttConfig mqttConfig = new MqttConfig(props.getProperty("serverURI"),
-                                                null);
-        // used if broker requires username/pw authentication
-        mqttConfig.setUserName(props.getProperty("userID",
-                                System.getProperty("user.name")));
-        mqttConfig.setPassword(props.getProperty("password",
-                                "myMosquittoPw").toCharArray());
+        MqttConfig mqttConfig = MqttConfig.fromProperties(props);
         return mqttConfig;
     }
     
@@ -74,6 +68,8 @@ public class SimpleSubscriberApp {
         
         Topology t = tp.newTopology("mqttSampleSubscriber");
         
+        // System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
+
         // Create the MQTT broker connector
         MqttConfig mqttConfig = createMqttConfig();
         MqttStreams mqtt = new MqttStreams(t, () -> mqttConfig);

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/scripts/connectors/mqtt/mqtt.properties
----------------------------------------------------------------------
diff --git a/scripts/connectors/mqtt/mqtt.properties b/scripts/connectors/mqtt/mqtt.properties
index 8370cb5..3d400c7 100644
--- a/scripts/connectors/mqtt/mqtt.properties
+++ b/scripts/connectors/mqtt/mqtt.properties
@@ -1,8 +1,8 @@
-serverURI=tcp://localhost:1883
-topic=mqttSampleTopic
-#userID=
-#password=
-#trustStore=
-#trustStorePassword=
-#keyStore=
-#keyStorePassword=
+mqtt.serverURLs=tcp://localhost:1883
+mqtt.topic=mqttSampleTopic
+#mqtt.userName=
+#mqtt.password=
+#mqtt.trustStore=
+#mqtt.trustStorePassword=
+#mqtt.keyStore=
+#mqtt.keyStorePassword=


[2/3] incubator-quarks git commit: [QUARKS-61] mqtt-ssl / client-auth support

Posted by dl...@apache.org.
[QUARKS-61] mqtt-ssl / client-auth support

- enhance MqttConfig
  - until there's a demonstrated need, omit the ability
    to specify a keyCertificateAlias or separate key password
    since the paho's convenient MqttConfigOptions SSL properties
    doesn't expose such support.
- add tests
- relocate test KeystorePath to sharable location
- expose in mqtt samples


Project: http://git-wip-us.apache.org/repos/asf/incubator-quarks/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quarks/commit/ecbd4279
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quarks/tree/ecbd4279
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quarks/diff/ecbd4279

Branch: refs/heads/master
Commit: ecbd4279bde6543b0222fad10119541b93532150
Parents: 9e13ad7
Author: Dale LaBossiere <dl...@us.ibm.com>
Authored: Wed Mar 30 10:55:18 2016 -0400
Committer: Dale LaBossiere <dl...@us.ibm.com>
Committed: Wed Mar 30 11:18:30 2016 -0400

----------------------------------------------------------------------
 .../test/connectors/common/KeystorePath.java    |  69 ++
 .../java/quarks/connectors/mqtt/MqttConfig.java | 170 +++-
 .../test/connectors/mqtt/MqttOpenTest.java      |  14 +-
 .../connectors/mqtt/MqttStreamsTestManual.java  | 281 ++++--
 connectors/mqtt/src/test/keystores/README       |  37 +
 connectors/mqtt/src/test/keystores/ca.crt       |  21 +
 connectors/mqtt/src/test/keystores/ca.key       |  18 +
 connectors/mqtt/src/test/keystores/ca.srl       |   1 +
 connectors/mqtt/src/test/keystores/client.crt   |  19 +
 connectors/mqtt/src/test/keystores/client.csr   |  18 +
 connectors/mqtt/src/test/keystores/client.key   |  27 +
 connectors/mqtt/src/test/keystores/client.p12   | Bin 0 -> 3341 bytes
 .../mqtt/src/test/keystores/clientKeyStore.jks  | Bin 0 -> 3055 bytes
 .../src/test/keystores/clientTrustStore.jks     | Bin 0 -> 1770 bytes
 .../mqtt/src/test/keystores/create-all.sh       | 128 +++
 .../test/keystores/mosquitto-SSL.conf.template  | 849 +++++++++++++++++++
 .../mqtt/src/test/keystores/mosquitto.org.crt   |  18 +
 connectors/mqtt/src/test/keystores/server.crt   |  19 +
 connectors/mqtt/src/test/keystores/server.csr   |  18 +
 connectors/mqtt/src/test/keystores/server.key   |  27 +
 .../wsclient/javax/websocket/KeystorePath.java  |  45 -
 .../javax/websocket/WebSocketClientTest.java    |   3 +-
 .../javax/websocket/WebSocketServerEcho.java    |   4 +-
 .../src/test/keystores/README                   |   8 +-
 .../quarks/samples/connectors/mqtt/Runner.java  |  23 +-
 .../connectors/mqtt/SimplePublisherApp.java     |  12 +-
 .../connectors/mqtt/SimpleSubscriberApp.java    |  12 +-
 scripts/connectors/mqtt/mqtt.properties         |  16 +-
 28 files changed, 1714 insertions(+), 143 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
----------------------------------------------------------------------
diff --git a/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java b/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
new file mode 100644
index 0000000..32e374d
--- /dev/null
+++ b/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
@@ -0,0 +1,69 @@
+/*
+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 quarks.test.connectors.common;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class KeystorePath {
+
+    /**
+     * 
+     * @param connectorsRelPathComponent
+     * @param more additional path components
+     * @return absolute path to the keystore
+     */
+    public static String getStorePath(String connectorsRelPathComponent, String... more) {
+        String pathStr = System.getProperty("user.dir");
+        // Under eclipse/junit: path to project in repo: <repo>/connectors
+        // Under ant/junit: <repo>/connectors/<project>/unittests/testrunxxxxxxx
+        // Get the path to the <repo>/connectors
+        Path path = new File(pathStr).toPath();
+        do {
+            if (path.endsWith("connectors"))
+                break;
+            path = path.getParent();
+        } while (path != null);
+        path = path.resolve(Paths.get(connectorsRelPathComponent, more));
+        if (!path.toFile().exists())
+            throw new IllegalArgumentException("File does not exist: "+path);
+        return path.toString();
+    }
+
+    public static String getPath(String repoRelPathComponent, String... more) {
+        String pathStr = System.getProperty("user.dir");
+        // Under eclipse/junit: path to project in repo: <repo>/connectors
+        // Under ant/junit: <repo>/connectors/<project>/unittests/testrunxxxxxxx
+        // Get the path to the <repo>/connectors
+        Path path = new File(pathStr).toPath();
+        do {
+            if (path.endsWith(repoRelPathComponent)) {
+                path = path.getParent();
+                break;
+            }
+            path = path.getParent();
+        } while (path != null);
+        path = path.resolve(Paths.get(repoRelPathComponent, more));
+        if (!path.toFile().exists())
+            throw new IllegalArgumentException("File does not exist: "+path);
+        return path.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/main/java/quarks/connectors/mqtt/MqttConfig.java
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/main/java/quarks/connectors/mqtt/MqttConfig.java b/connectors/mqtt/src/main/java/quarks/connectors/mqtt/MqttConfig.java
index 023aa31..4eb7ebc 100644
--- a/connectors/mqtt/src/main/java/quarks/connectors/mqtt/MqttConfig.java
+++ b/connectors/mqtt/src/main/java/quarks/connectors/mqtt/MqttConfig.java
@@ -60,12 +60,27 @@ public class MqttConfig {
      * <li>mqtt.connectionTimeoutSec</li>
      * <li>mqtt.idleTimeoutSec</li>
      * <li>mqtt.keepAliveSec</li>
+     * <li>mqtt.keyStore - optional. Only used with "ssl:" serverURL when the
+     *     server is configured for client auth.
+     *     Path to key store file in JKS format.
+     *     The first key in the store is used.  The key must have the same
+     *     password as the store if any.
+     *     If not set, the standard JRE and javax.net.ssl system properties
+     *     control the SSL behavior.</li>
+     * <li>mqtt.keyStorePassword - required if mqtt.keyStore is set.</li>
      * <li>mqtt.password</li>
      * <li>mqtt.persistence</li>
      * <li>mqtt.serverURLs - csv list of MQTT URLs of the form: 
-     *                          {@code tcp://<host>:<port>}
+     *                          {@code tcp://<host>:<port>} or
+     *                          {@code ssl://<host>:<port>}
      *    </li>
      * <li>mqtt.subscriberIdleReconnectIntervalSec</li>
+     * <li>mqtt.trustStore - optional. Only used with "ssl:" serverURL.
+     *     Path to trust store file in JKS format.
+     *     If not set, the standard JRE and javax.net.ssl system properties
+     *     control the SSL behavior.
+     *     Generally not required if server has a CA-signed certificate.</li>
+     * <li>mqtt.trustStorePassword - required if mqtt.trustStore is set</li>
      * <li>mqtt.userName</li>
      * <li>mqtt.will - JSON for with the following properties:
      *     <ul>
@@ -96,6 +111,15 @@ public class MqttConfig {
                 val -> config.setIdleTimeout(Integer.valueOf(val)));
         setConfig(p, "mqtt.keepAliveSec", 
                 val -> config.setKeepAliveInterval(Integer.valueOf(val)));
+        setConfig(p, "mqtt.keyStore", 
+                val -> config.setKeyStore(val));
+        setConfig(p, "mqtt.keyStorePassword", 
+                val -> config.setKeyStorePassword(val.toCharArray()));
+// paho MqttConnectOptions.setSslProperties() doesn't support this control
+//        setConfig(p, "mqtt.keyPassword", 
+//                val -> config.setKeyPassword(val.toCharArray()));
+//        setConfig(p, "mqtt.keyCertificateAlias", 
+//                val -> config.setKeyCertificateAlias(val));
         setConfig(p, "mqtt.password", 
                 val -> config.setPassword(val.toCharArray()));
         setConfig(p, "mqtt.persistence", 
@@ -104,6 +128,10 @@ public class MqttConfig {
                 val -> config.setServerURLs(val.split(",")));
         setConfig(p, "mqtt.subscriberIdleReconnectIntervalSec", 
                 val -> config.setSubscriberIdleReconnectInterval(Integer.valueOf(val)));
+        setConfig(p, "mqtt.trustStore", 
+                val -> config.setTrustStore(val));
+        setConfig(p, "mqtt.trustStorePassword", 
+                val -> config.setTrustStorePassword(val.toCharArray()));
         setConfig(p, "mqtt.userName", 
                 val -> config.setUserName(val));
         setConfig(p, "mqtt.will", val -> {
@@ -409,6 +437,146 @@ public class MqttConfig {
     }
 
     /**
+     * @param name option name
+     * @param value option value. null to unset.
+     */
+    private void setSslOption(String name, String value) {
+        Properties props = options.getSSLProperties();
+        if (props == null)
+            props = new Properties();
+        if (value == null)
+            props.remove(name);
+        else
+            props.setProperty(name, value);
+        options.setSSLProperties(props);
+    }
+
+    /**
+     * @param name option name
+     * @return option's value. null if not set.
+     */
+    private String getSslOption(String name) {
+        Properties props = options.getSSLProperties(); 
+        return props == null ? null : props.getProperty(name);
+    }
+
+    /**
+     * Set the SSL trust store path.
+     * <p>
+     * Only used with "ssl:" serverURL.
+     * Path to trust store file in JKS format.
+     * If not set, the standard JRE and javax.net.ssl system properties
+     * control the SSL behavior.
+     * Generally not required if server has a CA-signed certificate.
+     * @param path the path. null to unset.
+     */
+    public void setTrustStore(String path) {
+        setSslOption("com.ibm.ssl.trustStore", path);
+    }
+
+    /**
+     * Get the SSL trust store path.
+     * @return the path. null if not set.
+     */
+    public String getTrustStore() {
+        return getSslOption("com.ibm.ssl.trustStore");
+    }
+    
+    /**
+     * Set the SSL trust store password.
+     * <p>
+     * Required if the trust store path is set.
+     * 
+     * @param password the password
+     */
+    public void setTrustStorePassword(char[] password) {
+        setSslOption("com.ibm.ssl.trustStorePassword", new String(password));
+    }
+
+    /**
+     * Get the SSL trust store path password.
+     * @return the password. null if not set.
+     */
+    public char[] getTrustStorePassword() {
+        String s = getSslOption("com.ibm.ssl.trustStorePassword");
+        return s == null ? null : s.toCharArray();
+    }
+    
+    /**
+     * Set the SSL key store path.
+     * <p>
+     * Only used with "ssl:" serverURL when the server is configured for
+     * client auth.
+     * Path to trust store file in JKS format.
+     * If not set, the standard JRE and javax.net.ssl system properties
+     * control the SSL behavior.
+     * @param path the path. null to unset.
+     */
+    public void setKeyStore(String path) {
+        setSslOption("com.ibm.ssl.keyStore", path);
+    }
+
+    /**
+     * Get the SSL trust store path.
+     * @return the path. null if not set.
+     */
+    public String getKeyStore() {
+        return getSslOption("com.ibm.ssl.keyStore");
+    }
+    
+    /**
+     * Set the SSL key store password.
+     * <p>
+     * Required if the key store path is set.
+     * 
+     * @param password the password. null to unset.
+     */
+    public void setKeyStorePassword(char[] password) {
+        setSslOption("com.ibm.ssl.keyStorePassword", new String(password));
+    }
+
+    /**
+     * Get the SSL key store path password.
+     * @return the password. null if not set.
+     */
+    public char[] getKeyStorePassword() {
+        String s = getSslOption("com.ibm.ssl.keyStorePassword");
+        return s == null ? null : s.toCharArray();
+    }
+
+// paho MqttConnectOptions.setSslProperties() doesn't support this control
+//    /**
+//     * Set the SSL key password.
+//     * <p>
+//     * Defaults to using the key store password if not set.
+//     * 
+//     * @param password the password. null to unset.
+//     */
+//    public void setKeyPassword(char[] password) {
+//        setSslOption("com.ibm.ssl.XXXX-NO-SUCH-KEY-XXXX.keyPassword", new String(password));
+//    }
+//    
+//    public char[] getKeyPassword() {
+//        String s = getSslOption("com.ibm.ssl.XXXX-NO-SUCH-KEY-XXXX.keyPassword");
+//        return s == null ? null : s.toCharArray();
+//    }
+
+ // paho MqttConnectOptions.setSslProperties() doesn't support this control
+//    /**
+//     * Set the SSL key certificate alias.
+//     * <p>
+//     * Defaults to using "default" if not set.
+//     * @param alias the alias. null to unset.
+//     */
+//    public void setKeyCertificateAlias(String alias) {
+//        setSslOption("com.ibm.ssl.XXXX-NO-SUCH-KEY-XXXX.keyCertificateAlias", alias);
+//    }
+//
+//    public String getKeyCertificateAlias() {
+//        return getSslOption("com.ibm.ssl.XXXX-NO-SUCH-KEY-XXXX.keyCertificateAlias");
+//    }
+
+    /**
      * INTERNAL USE ONLY.
      * @return object
      */

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttOpenTest.java
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttOpenTest.java b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttOpenTest.java
index d8dc43b..ef900f4 100644
--- a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttOpenTest.java
+++ b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttOpenTest.java
@@ -40,7 +40,7 @@ public class MqttOpenTest extends MqttStreamsTestManual {
     
     @Before
     public void setupAuthInfo() {
-        this.authInfo.clear();
+        this.authInfo.clear();  // mosquitto.org server isn't happy w/username&pw
         // Skip tests if the MQTT server can't be contacted.
         try {
             URI uri = new URI(getServerURI());
@@ -48,7 +48,7 @@ public class MqttOpenTest extends MqttStreamsTestManual {
             s.close();
         } catch (Exception e) {
             System.err.println("Unable to connect to MQTT broker "+getServerURI()+" : "+e.getMessage());
-            e.printStackTrace();
+            // e.printStackTrace();
             assumeTrue(false);
         }
     }
@@ -65,6 +65,14 @@ public class MqttOpenTest extends MqttStreamsTestManual {
         return "tcp://test.mosquitto.org:1883";
     }
     
+    protected String getSslServerURI() {
+        return "ssl://test.mosquitto.org:8883";
+    }
+    
+    protected String getSslClientAuthServerURI() {
+        return "ssl://test.mosquitto.org:8884";
+    }
+    
     protected String newClientId(String name) {
         return uniqueid + "_" + name;
     }
@@ -73,4 +81,6 @@ public class MqttOpenTest extends MqttStreamsTestManual {
     public void testIdleSubscribe() {}  // intermittent (timing related?) failures
     @Ignore
     public void testIdlePublish() {}  // intermittent (timing related?) failures
+    @Ignore
+    public void testSslClientAuth() {} // we don't have a mosquitto.org generated client cert
 }

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
index a938b55..82b71a6 100644
--- a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
+++ b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
@@ -34,7 +34,9 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
@@ -43,12 +45,15 @@ import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.gson.JsonObject;
+
 import quarks.connectors.mqtt.MqttConfig;
 import quarks.connectors.mqtt.MqttStreams;
 import quarks.function.BiFunction;
 import quarks.function.Function;
 import quarks.function.Supplier;
 import quarks.test.connectors.common.ConnectorTestBase;
+import quarks.test.connectors.common.KeystorePath;
 import quarks.topology.TSink;
 import quarks.topology.TStream;
 import quarks.topology.Topology;
@@ -64,33 +69,9 @@ import quarks.topology.tester.Condition;
  * <li>if the server is configured for authentication requiring
  * a username/pw, it is configured for userName="testUserName" and password="testUserNamePw"</li>
  * </ul>
- * 
- * The expected configuration can be overriden via the following
- * system properties:
- * <ul>
- * <li>{@code quarks.test.connectors.mqtt.serverURI} the
- *      MQTT broker serverURI. Defaults to "tcp:://localhost:1883"
- *      or "ssl:://localhost:8883" if sslAuthMode starts with ssl.</li>
- * <li>{@code quarks.test.connectors.mqtt.sslAuthMode} the
- *      authentication mode: null, "ssl", "sslClientAuth".
- *      Default is null - not ssl.</li>
- * <li>{@code quarks.test.connectors.mqtt.userID}
- *      Default is "testUserName"</li>
- * <li>{@code quarks.test.connectors.mqtt.password}
- *      Default is "testUserNamePw"</li>
- * <li>{@code quarks.test.connectors.mqtt.trustStore}
- *      trustStore pathname for sslAuthMode=ssl,sslClientAuth.</li>
- * <li>{@code quarks.test.connectors.mqtt.trustStorePassword}
- *      trustStore password for sslAuthMode=ssl,sslClientAuth.</li>
- * <li>{@code quarks.test.connectors.mqtt.keyStore}
- *      keyStore pathname for sslAuthMode=sslClientAuth.</li>
- * <li>{@code quarks.test.connectors.mqtt.keyStorePassword}
- *      keyStore password for sslAuthMode=sslClientAuth.</li>
- * </ul>
  */
 public class MqttStreamsTestManual extends ConnectorTestBase {
 
-    protected static final String PROP_PREFIX = "quarks.test.connectors.mqtt.";
     private static final int SEC_TIMEOUT = 15;
     private static final int PUB_DELAY_MSEC = 2*1000;
     private final String BASE_CLIENT_ID = "mqttStreamsTestClientId";
@@ -101,41 +82,47 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
     
     @Before
     public void setupAuthInfo() {
-        System.setProperty(PROP_PREFIX+"userID", TEST_USERNAME);
-        System.setProperty(PROP_PREFIX+"password", TEST_PASSWORD);
-        initAuthInfo("userID");
-        initAuthInfo("password");
-        initAuthInfo("trustStore");
-        initAuthInfo("trustStorePassword");
-        initAuthInfo("keyStore");
-        initAuthInfo("keyStorePassword");
+        authInfo.clear();
+        authInfo.put("userID", TEST_USERNAME);
+        authInfo.put("password", TEST_PASSWORD);
     }
-
-    private void initAuthInfo(String item) {
-        String val = System.getProperty(PROP_PREFIX + item);
-        if (val != null) {
-            authInfo.put(item, val);
-            if (item.toLowerCase().contains("password"))
-                val = "*****";
-            System.out.println("Using "+item+"="+val);
+    
+    protected void setSslAuthInfo(String sslAuthMode) {
+        String trustStore = getKeystorePath("clientTrustStore.jks");
+        authInfo.put("trustStore", trustStore);
+        authInfo.put("trustStorePassword", "passw0rd");
+        
+        if (sslAuthMode.equals("sslClientAuth")) {
+            String keyStore = getKeystorePath("clientKeyStore.jks");
+            authInfo.put("keyStore", keyStore);
+            authInfo.put("keyStorePassword", "passw0rd");
+            // authInfo.put("keyPassword", value);
+            // authInfo.put("keyCertificateAlias", value);
         }
     }
     
+    protected String getKeystorePath(String storeLeaf) {
+        return KeystorePath.getPath("connectors", "mqtt", "src", "test", "keystores", storeLeaf);
+    }
+    
     private MqttConfig newConfig(String serverURL, String clientId) {
         MqttConfig config = new MqttConfig(serverURL, clientId);
         if (authInfo.get("userID") != null)
             config.setUserName(authInfo.get("userID"));
         if (authInfo.get("password") != null)
             config.setPassword(authInfo.get("password").toCharArray());
-        // TODO
-//        if (authInfo.get("trustStore") != null)
-//            ...;
-//        if (authInfo.get("trustStorePassword") != null)
-//            ...;
-//        if (authInfo.get("keyStore") != null)
-//            ...;
-//        if (authInfo.get("keyStorePassword") != null)
-//            ...;
+        if (authInfo.get("trustStore") != null)
+            config.setTrustStore(authInfo.get("trustStore"));
+        if (authInfo.get("trustStorePassword") != null)
+            config.setTrustStorePassword(authInfo.get("trustStorePassword").toCharArray());
+        if (authInfo.get("keyStore") != null)
+            config.setKeyStore(authInfo.get("keyStore"));
+        if (authInfo.get("keyStorePassword") != null)
+            config.setKeyStorePassword(authInfo.get("keyStorePassword").toCharArray());
+//        if (authInfo.get("keyPassword") != null)
+//            config.setKeyPassword(authInfo.get("keyPassword").toCharArray());
+//        if (authInfo.get("keyCertificateAlias") != null)
+//            config.setKeyCertificateAlias(authInfo.get("keyCertificateAlias"));
         return config;
     }
        
@@ -176,18 +163,21 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
     }
     
     protected String[] getMqttTopics() {
-        String csvTopics = System.getProperty(PROP_PREFIX+"csvTopics", "testTopic1,testTopic2");
+        String csvTopics = "testTopic1,testTopic2";
         String[] topics = csvTopics.split(",");
         return topics;
     }
     
     protected String getServerURI() {
-        String authMode = System.getProperty(PROP_PREFIX+"sslAuthMode", "");
-        String serverURI = System.getProperty(PROP_PREFIX+"serverURI",
-                authMode.startsWith("ssl")
-                    ? "ssl:://localhost:8883"
-                    : "tcp://localhost:1883");
-        return serverURI;
+        return "tcp://localhost:1883";
+    }
+    
+    protected String getSslServerURI() {
+        return "ssl://localhost:8883";
+    }
+    
+    protected String getSslClientAuthServerURI() {
+        return "ssl://localhost:8884";
     }
     
     @Test
@@ -659,6 +649,16 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
             assertEquals(12, config.getKeepAliveInterval());
         }
         {
+            assertEquals(null, config.getKeyStore());
+            config.setKeyStore("some/path");
+            assertEquals("some/path", config.getKeyStore());
+        }
+        {
+            assertArrayEquals(null, config.getKeyStorePassword());
+            config.setKeyStorePassword("xyzzy".toCharArray());
+            assertArrayEquals("xyzzy".toCharArray(), config.getKeyStorePassword());
+        }
+        {
             assertEquals(0, config.getIdleTimeout());
             config.setIdleTimeout(13);
             assertEquals(13, config.getIdleTimeout());
@@ -687,6 +687,16 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
             assertEquals(p, config.getPersistence());
         }
         {
+            assertEquals(null, config.getTrustStore());
+            config.setTrustStore("some/path");
+            assertEquals("some/path", config.getTrustStore());
+        }
+        {
+            assertArrayEquals(null, config.getTrustStorePassword());
+            config.setTrustStorePassword("xyzzy".toCharArray());
+            assertArrayEquals("xyzzy".toCharArray(), config.getTrustStorePassword());
+        }
+        {
             assertArrayEquals(new String[]{getServerURI()}, config.getServerURLs());
             String[] urls = new String[]{"tcp://localhost:30000","tcp://localhost:30001"};
             config.setServerURLs(urls);
@@ -711,6 +721,101 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
         }
     }
     
+    private static class PropertyTester {
+        private final Properties props;
+        private List<Checker> checkers = new ArrayList<>();
+
+        private static class Checker {
+            String name;
+            String value;
+            Supplier<String> getterFn;
+            public Checker(String name, String value, Supplier<String> getterFn) {
+                this.name = name;
+                this.value = value;
+                this.getterFn = getterFn;
+            }
+        }
+        
+        public PropertyTester(Properties props) {
+            this.props = props;
+        }
+        
+        public void add(String name, String value, Supplier<String> getterFn) {
+            props.setProperty(name, value);
+            checkers.add(new Checker(name, value, getterFn));
+        }
+        
+        public void checkAll() throws Exception {
+            for (Checker checker : checkers) {
+                String val = checker.getterFn.get();
+                //System.out.println("checking name="+checker.name+" exp="+checker.value+" act="+val);
+                assertEquals(checker.name, checker.value, val);
+            }
+        }
+    }
+    
+    @Test
+    public void testConfigFromProperties() throws Exception {
+        
+        Properties props = new Properties();
+        AtomicReference<MqttConfig> configRef = new AtomicReference<>();
+        
+        PropertyTester propTester = new PropertyTester(props);
+        
+        propTester.add("mqtt.actionTimeToWaitMillis", "10", 
+                () -> ((Long)configRef.get().getActionTimeToWaitMillis()).toString());
+        propTester.add("mqtt.cleanSession", "false",
+                () -> ((Boolean)configRef.get().isCleanSession()).toString());
+        propTester.add("mqtt.clientId", "xyzzy-clientId",
+                () -> configRef.get().getClientId());
+        propTester.add("mqtt.connectionTimeoutSec", "11", 
+                () -> ((Integer)configRef.get().getConnectionTimeout()).toString());
+        propTester.add("mqtt.idleTimeoutSec", "12", 
+                () -> ((Integer)configRef.get().getIdleTimeout()).toString());
+        propTester.add("mqtt.keepAliveSec", "13", 
+                () -> ((Integer)configRef.get().getKeepAliveInterval()).toString());
+        propTester.add("mqtt.keyStore", "some/path/keystore",
+                () -> configRef.get().getKeyStore());
+        propTester.add("mqtt.keyStorePassword", "some-keystore-password",
+                () -> new String(configRef.get().getKeyStorePassword()));
+//        propTester.add("mqtt.keyPassword", "some-key-password",
+//                () -> new String(configRef.get().getKeyPassword()));
+//        propTester.add("mqtt.keyCertificateAlias", "someKeyCertificateAlias",
+//                () -> configRef.get().getKeyCertificateAlias());
+        propTester.add("mqtt.password", "some-password",
+                () -> new String(configRef.get().getPassword()));
+//        propTester.add("mqtt.persistence", "some.persistence.classname",
+//                () -> configRef.get().getPersistence());
+        propTester.add("mqtt.serverURLs", "tcp://somehost:1234,ssl://somehost:5678",
+                () -> String.join(",", configRef.get().getServerURLs()));
+        propTester.add("mqtt.subscriberIdleReconnectIntervalSec", "14", 
+                () -> ((Integer)configRef.get().getSubscriberIdleReconnectInterval()).toString());
+        propTester.add("mqtt.trustStore", "some/path/truststore",
+                () -> configRef.get().getTrustStore());
+        propTester.add("mqtt.trustStorePassword", "some-truststore-password",
+                () -> new String(configRef.get().getTrustStorePassword()));
+        propTester.add("mqtt.userName", "xyzzy-username",
+                () -> configRef.get().getUserName());
+        
+        JsonObject will = new JsonObject();
+        will.addProperty("topic", "someWillTopic");
+        will.addProperty("payload", "someWillPayload");
+        will.addProperty("qos", 1);
+        will.addProperty("retained", true);
+        propTester.add("mqtt.will", will.toString(),
+                () -> {
+                        JsonObject actWill = new JsonObject();
+                        actWill.addProperty("topic", configRef.get().getWillDestination());
+                        actWill.addProperty("payload", new String(configRef.get().getWillPayload()));
+                        actWill.addProperty("qos", configRef.get().getWillQOS());
+                        actWill.addProperty("retained", configRef.get().getWillRetained());
+                        return actWill.toString();
+                      });
+
+        configRef.set(MqttConfig.fromProperties(props));
+        propTester.checkAll();
+    }
+    
     @Test
     public void testMultipleServerURL() throws Exception {
         Topology top = newTopology("testMultipleServerURL");
@@ -1029,5 +1134,69 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
 
         completeAndValidate(clientId, top, rcvd, mgen, SEC_TIMEOUT, expectMsgs.toArray(new String[0]));
     }
+    
+    /* 
+     * See mqtt/src/test/keystores/README for info about SSL/TLS and mosquitto
+     */
+    
+    @Test
+    public void testSsl() throws Exception {
+        Topology top = newTopology("testSsl");
+        MsgGenerator mgen = new MsgGenerator(top.getName());
+        int qos = 0;
+        boolean retain = false;
+        String clientId = newClientId(top.getName());
+        String topic = getMqttTopics()[0];
+        List<String> msgs = createMsgs(mgen, topic);
+        
+        TStream<String> s = PlumbingStreams.blockingOneShotDelay(
+                top.collection(msgs), PUB_DELAY_MSEC, TimeUnit.MILLISECONDS);
+        
+        // Test publish(TStream<String>, topic, qos)
+        // Test TStream<String> subscribe(topic, qos)
+
+        // System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
+        
+        setSslAuthInfo("ssl");
+        MqttConfig config = newConfig(getSslServerURI(), clientId);
+        MqttStreams mqtt = new MqttStreams(top, () -> config);
+
+        TSink<String> sink = mqtt.publish(s, topic, qos, retain);
+        TStream<String> rcvd = mqtt.subscribe(topic, qos);
+
+        completeAndValidate(clientId, top, rcvd, mgen, SEC_TIMEOUT, msgs.toArray(new String[0]));
+        
+        assertNotNull(sink);
+    }
+    
+    @Test
+    public void testSslClientAuth() throws Exception {
+        Topology top = newTopology("testSslClientAuth");
+        MsgGenerator mgen = new MsgGenerator(top.getName());
+        int qos = 0;
+        boolean retain = false;
+        String clientId = newClientId(top.getName());
+        String topic = getMqttTopics()[0];
+        List<String> msgs = createMsgs(mgen, topic);
+        
+        TStream<String> s = PlumbingStreams.blockingOneShotDelay(
+                top.collection(msgs), PUB_DELAY_MSEC, TimeUnit.MILLISECONDS);
+        
+        // Test publish(TStream<String>, topic, qos)
+        // Test TStream<String> subscribe(topic, qos)
+        
+        // System.setProperty("javax.net.debug", "ssl"); // or "all"; "help" for full list
+        
+        setSslAuthInfo("sslClientAuth");
+        MqttConfig config = newConfig(getSslClientAuthServerURI(), clientId);
+        MqttStreams mqtt = new MqttStreams(top, () -> config);
+
+        TSink<String> sink = mqtt.publish(s, topic, qos, retain);
+        TStream<String> rcvd = mqtt.subscribe(topic, qos);
+
+        completeAndValidate(clientId, top, rcvd, mgen, SEC_TIMEOUT, msgs.toArray(new String[0]));
+        
+        assertNotNull(sink);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/README
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/README b/connectors/mqtt/src/test/keystores/README
new file mode 100644
index 0000000..70b4a73
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/README
@@ -0,0 +1,37 @@
+Configuring mosquitto for SSL/TLS and client-auth.
+
+mosquitto deals in terms of PEM format certificates and key files.
+The files can optionally be passphrase encrypted.  If they are
+encrypted, the server prompts for passphrases when starting up.
+
+mosquitto, written in C/C++, is ignorant of Java specific notions
+such as JKS encoded keystores.  
+
+mosquitto SSL client-auth follows a model where clients are issued
+certificates signed by a CA known to the mosquitto server and,
+unlike a typical java SSL/client-auth server configuration, the
+client certificates themselves are not "registered" with the mosquitto server.
+i.e., the server makes authentication decisions purely based on
+receiving a client certificate signed by its know CA.
+
+It was easiest to follow mosquitto's:
+    https://mosquitto.org/man/mosquitto-tls-7.html
+for generating the needed info for mosquitto and then create JKS stores
+from that info for use by java clients.  The create-all.sh script does
+just that should you need to regenerate the files.
+
+mosquitto-SSL.conf.template file is a template mosquitto configuration
+file supporting non-SSL clients on port 1883, SSL on 8883,
+and SSL-client-auth on 8884.  To generate a conf file that works
+with these files in the quarks repository:
+
+    cd <this-keystores-directory>
+    cat mosquitto-SSL.conf.template | 
+       sed -e "s,TEST-KEYSTORES-DIR,`pwd`," >/usr/local/etc/mosquitto/mosquitto-SSL.conf
+
+start your mosquitto server as:
+
+    /usr/local/sbin/mosquitto -c /usr/local/etc/mosquitto/mosquitto-SSL.conf
+
+
+Other helpful info: https://docs.oracle.com/cd/E35976_01/server.740/es_admin/src/tadm_ssl_convert_pem_to_jks.html

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/ca.crt
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/ca.crt b/connectors/mqtt/src/test/keystores/ca.crt
new file mode 100644
index 0000000..dc99384
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/ca.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAu2gAwIBAgIJAKwMA+ikp6R5MA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTUExEjAQBgNVBAcTCUxpdHRsZXRvbjEMMAoGA1UE
+ChMDSUJNMQ8wDQYDVQQLEwZRdWFya3MxHTAbBgNVBAMTFE15IFRlc3QgTW9zcXVp
+dHRvIENBMRswGQYJKoZIhvcNAQkBFgxmb29AdGVzdC5vcmcwHhcNMTYwMzMwMTM0
+NjQ4WhcNMzYwMzI1MTM0NjQ4WjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1B
+MRIwEAYDVQQHEwlMaXR0bGV0b24xDDAKBgNVBAoTA0lCTTEPMA0GA1UECxMGUXVh
+cmtzMR0wGwYDVQQDExRNeSBUZXN0IE1vc3F1aXR0byBDQTEbMBkGCSqGSIb3DQEJ
+ARYMZm9vQHRlc3Qub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCt3lOj
+XM+XmVx2li74Q4dhApXluGUbKjavzmk1Ey8SBvNlgH80xbnCivzPRotGlVpt/fmN
+JmoEHD/WzFolk+X+ndu2N20gzpFTMz2sGEFtQxd/FYZYDWOqQEep78AmiZtdt812
+44q+LdhmsrlbnGTjIssEHuecGw7/w/cgy3FfdQIDAQABo4HxMIHuMB0GA1UdDgQW
+BBS2a9/QOq0l2y94L8PeUj5AV/4aBTCBvgYDVR0jBIG2MIGzgBS2a9/QOq0l2y94
+L8PeUj5AV/4aBaGBj6SBjDCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMRIw
+EAYDVQQHEwlMaXR0bGV0b24xDDAKBgNVBAoTA0lCTTEPMA0GA1UECxMGUXVhcmtz
+MR0wGwYDVQQDExRNeSBUZXN0IE1vc3F1aXR0byBDQTEbMBkGCSqGSIb3DQEJARYM
+Zm9vQHRlc3Qub3JnggkArAwD6KSnpHkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
+AQUFAAOBgQBNQBL58gz5s4josyR9DXgHF0Q6e38CwQiybVRPwDFaFP2+YdP9g4Aw
+hPvMSaZVf4wyNICx3fdjsYqQqbR52KXsFD+YRGxLI03AAhbKvc8WaIxo5q7UKDmb
+twBjRhCClYrU8+cmZInhus71CT5w3RMsZRkyuzr4WigYbR06ajbSVw==
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/ca.key
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/ca.key b/connectors/mqtt/src/test/keystores/ca.key
new file mode 100644
index 0000000..be8771c
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/ca.key
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,0D51548BC81A38B1
+
+HvHGWYU495R/hI8rc6ieQoQBO1eIbxexzJuJnFGR26wW8ZU4NmiiA7soGzPdDBB2
+lyA/h6T/rCFOvKb02eBJn8XqHh83OQYCOGmLM3IVw5RtOjuWztucOqNI9lvVG1ay
+D2W+LXNoJmri7TPJLLUv8Yk+toxe2DETiCiW3u8p+krUoxYNjY2U2aNEXEaRTCbh
+v+xobYcp/h/GLzlKUUhRsf+EKqLcSeSqh/52MPVL27cSvnSIVgoT7ynZfPzWgAMb
+RdoX5ZzTSHZEvC3P1KjZm8xGhwlHZFw8fgckM+qxq4WAuqh1vhux6WDm6IQqifZ5
+kKgS7l6oGS/6bSuST6FGlc5ciCUnUv758+FlxeHSCkNV9u/Wos+NyurjdTNGHIcF
+Amk2gYk7dL0lBWX2uHCcZCCXFh3MPYMCGAaWcfthInw/wmbVizkpJCZCme3F+n7T
+w2JnX/fiX/TD/OnnGXf1XBAtl8wQS5HExBFYRIo/crzWBybMoFST3dXJPnyLw/70
+KC1ukS+nBt6K6kM99y1aiptUE5OCH0dDfqVLh3SNBIP65ihyPXu2QLIQhNTRQmz3
+/i71bBErLhq/1tXyYAPwfGQVZjpHpjExx+XQO1/x8QpHJQvr+RlMDMJ8repmRmwj
+xBnc7DKSxf/Uj1e4x4peCeUQjnBh4evJzbe1WyUwQNJM+pZbmXDJfZ+o8UJZWPzx
+60PoCI9LJ/osN2igHVYslKR8ZtUGnoUcvILaoOjLfBjvIF2uj1e4VBEz+KrzZfK/
+mphyHis5aEYXlRJtqDzsvkG8017Y9WvCRF7KWiZlXCz7A3Hp1T/2nw==
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/ca.srl
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/ca.srl b/connectors/mqtt/src/test/keystores/ca.srl
new file mode 100644
index 0000000..ca2584d
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/ca.srl
@@ -0,0 +1 @@
+DBE67D82422853FD

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/client.crt
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/client.crt b/connectors/mqtt/src/test/keystores/client.crt
new file mode 100644
index 0000000..2c5bc79
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/client.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnwCCQDb5n2CQihT/TANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk1BMRIwEAYDVQQHEwlMaXR0bGV0b24xDDAKBgNVBAoTA0lC
+TTEPMA0GA1UECxMGUXVhcmtzMR0wGwYDVQQDExRNeSBUZXN0IE1vc3F1aXR0byBD
+QTEbMBkGCSqGSIb3DQEJARYMZm9vQHRlc3Qub3JnMB4XDTE2MDMzMDEzNDY0OFoX
+DTM2MDMyNTEzNDY0OFowgY0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTESMBAG
+A1UEBxMJTGl0dGxldG9uMQwwCgYDVQQKEwNJQk0xDzANBgNVBAsTBlF1YXJrczEh
+MB8GA1UEAxMYTXkgVGVzdCBNb3NxdWl0dG8gQ2xpZW50MRswGQYJKoZIhvcNAQkB
+Fgxmb29AdGVzdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy
+YrpdU1YmmJlzas5FTZmylTgBu5iIH0nc3dvymNxpBmVxKEuBfvH8+EckHe/W6MWO
+7DBlcHSKTFaofO9Bu1OX+g07JBshKn/y2LNzVS9z4mL7/+IDiTlTg0x/kbOJZkyw
+1luSc56eOQvvwOgMRPQf0wY+JJcMoqcABO3+x83e7RdcSyJENWAeAWANAXWuTx6c
+QS2ml4E2fJFZIC8+gjt4gXmtIlKaQQ1E2HnwjcEZ6krOquPCYK9gAA8bKSXp/il6
+n9AcShF8iqRs+IO63Ifqdyx+Tq0q/HNrE4sKjM6T8xRhHdy+vacrel2Xtd1y1iPI
+ZFyw5GCOIjjCJVbiTaFJAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAY2M2lbiB0zDA
+iPclJWtirxZ5zgAfpDPAAINqERbcujZ5Upe29TgT8qp8/kAnqMgG6hJH/5kT9g/w
+w0UkvPmOeRkOnnGp0vanDWKDg/Ey/v9aLSECsdwZqIlOvgxLMjIyBKJZhwOps7IY
+A36HMdzTtQwLVKCPacH/6Zz91VZcGp0=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/client.csr
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/client.csr b/connectors/mqtt/src/test/keystores/client.csr
new file mode 100644
index 0000000..0e202ef
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/client.csr
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIC0zCCAbsCAQAwgY0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTESMBAGA1UE
+BxMJTGl0dGxldG9uMQwwCgYDVQQKEwNJQk0xDzANBgNVBAsTBlF1YXJrczEhMB8G
+A1UEAxMYTXkgVGVzdCBNb3NxdWl0dG8gQ2xpZW50MRswGQYJKoZIhvcNAQkBFgxm
+b29AdGVzdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyYrpd
+U1YmmJlzas5FTZmylTgBu5iIH0nc3dvymNxpBmVxKEuBfvH8+EckHe/W6MWO7DBl
+cHSKTFaofO9Bu1OX+g07JBshKn/y2LNzVS9z4mL7/+IDiTlTg0x/kbOJZkyw1luS
+c56eOQvvwOgMRPQf0wY+JJcMoqcABO3+x83e7RdcSyJENWAeAWANAXWuTx6cQS2m
+l4E2fJFZIC8+gjt4gXmtIlKaQQ1E2HnwjcEZ6krOquPCYK9gAA8bKSXp/il6n9Ac
+ShF8iqRs+IO63Ifqdyx+Tq0q/HNrE4sKjM6T8xRhHdy+vacrel2Xtd1y1iPIZFyw
+5GCOIjjCJVbiTaFJAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAk/BmnFWayIIa
+lqXNf7/Dc1uDHHegHkx00FbcPTndqR9kPnHgaH5CotfYdvE1iZpU8gRh6A+YhR0S
+BLqYqozBO7zv7jB/fcJ/hpB/s70tnhIOLLCPaCg8QxiczXw6sHfflOKeUB3IZ04+
+btiwHmwJgKkpaqhjzZ+72JOsCXWvKnnvUUmjHntod0LR8Hy/3++UkBA3oKsLbNdb
+SGam0lcrgeXiiN1Xr7OArGztSBz4LAZETKscqJ3c06iYn6EXlSxHF8KUT1zS1z22
+9OR8PDKuhLPbwyyF2KlN+7e4gVjDart6mb1hDHgTfpuLmgJbd5uikxnCQFSF63eB
+SvkeYeMLqA==
+-----END CERTIFICATE REQUEST-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/client.key
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/client.key b/connectors/mqtt/src/test/keystores/client.key
new file mode 100644
index 0000000..5968801
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAsmK6XVNWJpiZc2rORU2ZspU4AbuYiB9J3N3b8pjcaQZlcShL
+gX7x/PhHJB3v1ujFjuwwZXB0ikxWqHzvQbtTl/oNOyQbISp/8tizc1Uvc+Ji+//i
+A4k5U4NMf5GziWZMsNZbknOenjkL78DoDET0H9MGPiSXDKKnAATt/sfN3u0XXEsi
+RDVgHgFgDQF1rk8enEEtppeBNnyRWSAvPoI7eIF5rSJSmkENRNh58I3BGepKzqrj
+wmCvYAAPGykl6f4pep/QHEoRfIqkbPiDutyH6ncsfk6tKvxzaxOLCozOk/MUYR3c
+vr2nK3pdl7XdctYjyGRcsORgjiI4wiVW4k2hSQIDAQABAoIBAQCI6XWYQ2oP3XeJ
+OiRu1IxuoFCII++CKmGKf01c+S3R/fLF0uOA1GnuerA/bCq0i5t1gpnygUkxDD5G
+uvz3OkuCjYyyI5ge8Huba+7vSiZNjyfhuhdCF4REMLX6A14Eytt5rkxCLzNCxQ4A
+SdLP9+xWsKRN9c9pBz2dqirwLXI48f+abbdQyxQ4zimTCnKwbZ4SasGrIKptKBNa
+CAVtpymz1U7JwckR3NXW+7zgn8Hg2UqjM/cvGNJmGZGmGHwD967qlb1L5HSUKijc
+/Vk1wiaHhJRujAIAI+j9D13dpxjcmN4574tJUmL2gIIOSrGruytMqEz8jQ1g282I
+5FUV0O2xAoGBANwjKtKr7LJwI+PxB6UjkX+pBLC5V42YYHqMWjuKHwRCh4vIK1zc
+z8wWb+DBftug0GfEM3m5GYJpnQmauzPynZ+qKg9ry412UTY6S65eN4sKIqI4Q9vY
++++Mw0wZzkWR33lleZ3sJr4qqFHYNTg3lm/S7PeNhbSroAAxzuIAsGBvAoGBAM9y
+TgFjOBobDXTGOnuS8YAWY9wR3JjvORiutTh3BqbbwVygIcIS1XpTopQIDJ+5VZld
+ARpCMtSdZx1c37GxvAMIpPFbVBEz7yOxSisIQ7I3Lm40XpEsBl9Xa6cq3G2Wb5Fc
+G8KYNwsovrP90GhelfbQnua7XxwGx8WEn1kU94XHAoGBAK8bXj30OjT6VOJFYUJw
+F5XHuY5l8AoW8m+o40HHLcLytOVw1WVp0/VQx6+t2x4TPpO8EwI5Rdxh7GOubEj3
+LYDLF+fqZCFjw1fyaS8LjP0Rk9kcDoZ7hHPZsaQARv85+NyU5nfDWFIeloN8C2Fr
+fkP3MT39miTL/FsLQ7isuaALAoGAdupPTPxTbKOVUxtO6weQ6JvtInoaupBnan67
+42JXrc7LSQ2CTH3/YeAPkkwK8ISNTRzDRQotmTOhqHNUx8favuJ1quVvi2z56Lv4
+iDJ0m/SF6SacDxvtiznRvEIVmbxiuDDUuPgIlZ0FtKgKj8morZNpg1plaut4GQGt
+VqNuQIECgYEAmolO3TnJZ1X2g01f1Ltr3XoXfs1Hrc7QeyFmfe6LK2P/5AXYw4Bm
+lHrOpLD69Q+EvS3bJN/Y1tjZ5m3ViSNy4XrDl9ofEcpnE0iGOoTOmKUTs67QqbYV
+KDd3tEsMNmPNUcgHZxmxIkpVkGXLDJqO/65OdRztNoYH62aHNqrTZ0U=
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/client.p12
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/client.p12 b/connectors/mqtt/src/test/keystores/client.p12
new file mode 100644
index 0000000..86fe084
Binary files /dev/null and b/connectors/mqtt/src/test/keystores/client.p12 differ

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/clientKeyStore.jks
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/clientKeyStore.jks b/connectors/mqtt/src/test/keystores/clientKeyStore.jks
new file mode 100644
index 0000000..63a6ee4
Binary files /dev/null and b/connectors/mqtt/src/test/keystores/clientKeyStore.jks differ

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/clientTrustStore.jks
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/clientTrustStore.jks b/connectors/mqtt/src/test/keystores/clientTrustStore.jks
new file mode 100644
index 0000000..38a8817
Binary files /dev/null and b/connectors/mqtt/src/test/keystores/clientTrustStore.jks differ

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/create-all.sh
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/create-all.sh b/connectors/mqtt/src/test/keystores/create-all.sh
new file mode 100644
index 0000000..53418f5
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/create-all.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+
+USAGE=`basename $0`
+
+# Generate the PEM format keys and certificates for the CA, server and client
+# and JKS trust store and key stores for java clients.
+#
+# Consistent with the test's expectations,
+# "passw0rd" is used in all cases where a pass phrase is used.
+
+# hints:
+# - to see the textual contents of a PEM certificate file:
+#   openssl x509 -text -in server.crt
+#
+# - to see the textual contents of a PEM RSA key file:
+#   openssl rsa -text -in server.key  # will prompt for a pass phrase if encrypted
+#
+
+set -e
+set -x
+
+# ================================================================
+# Generating CA, server, and client keys/certificates for use with mosquitto
+# https://mosquitto.org/man/mosquitto-tls-7.html
+#
+# Pay heed to: "It is important to use different certificate subject parameters for your CA, server and clients"
+
+echo;echo =====  Generating CA, server, and client keys/certificates
+
+echo;echo =====  Generate encrypted RSA CA key and certificate
+openssl req -new -x509 -days 7300 -passout pass:passw0rd -extensions v3_ca \
+    -keyout ca.key -out ca.crt <<xxEOFxx
+US
+MA
+Littleton
+IBM
+Quarks
+My Test Mosquitto CA
+foo@test.org
+xxEOFxx
+
+echo;echo =====  Generate unencrypted RSA Server key
+openssl genrsa -out server.key 2048
+
+echo;echo =====  Generate an encrypted server certificate signing request to send to the CA.
+openssl req -new -passout pass:passw0rd -out server.csr -key server.key <<xxEOFxx
+US
+MA
+Littleton
+IBM
+Quarks
+My Test Mosquitto Server
+foo@test.org
+
+
+xxEOFxx
+
+echo;echo =====  Generate the Server cert by signing the certificate request with the CA key
+openssl x509 -req -passin pass:passw0rd -in server.csr -out server.crt \
+    -days 7300 -CA ca.crt -CAkey ca.key -CAcreateserial
+
+echo;echo =====  Generate an unencrypted RSA Client key
+openssl genrsa -out client.key 2048
+
+echo;echo =====  Generate an encrypted client certificate signing request to send to the CA.
+openssl req -new -passout pass:passw0rd -out client.csr -key client.key <<xxEOFxx
+US
+MA
+Littleton
+IBM
+Quarks
+My Test Mosquitto Client
+foo@test.org
+
+
+xxEOFxx
+
+echo;echo =====  Generate the Client cert by signing the certificate request with the CA key.
+openssl x509 -req -passin pass:passw0rd -in client.csr -out client.crt \
+    -days 7300 -CA ca.crt -CAkey ca.key -CAcreateserial 
+
+# ================================================================
+# Create the JKS stores for java clients
+# https://docs.oracle.com/cd/E35976_01/server.740/es_admin/src/tadm_ssl_convert_pem_to_jks.html
+
+echo;echo =====  Create JKS stores for MqttStreams '(paho client)'  
+
+# Create an empty clientTrustStore.jks
+echo;echo =====  Create clientTrustStore.jks  
+echo;echo =====  Create an empty clientTrustStore.jks  
+keytool -genkey -keyalg RSA -alias xyzzy \
+    -dname 'CN=foo.example.com,L=Melbourne,ST=Victoria,C=AU' \
+    -keypass passw0rd -keystore clientTrustStore.jks -storepass passw0rd 
+keytool -delete -alias xyzzy \
+    -keystore clientTrustStore.jks -storepass passw0rd 
+
+echo;echo =====  Add the CA cert to the clientTrustStore.jks  
+keytool -import -v -trustcacerts -alias my-mosquitto-ca -file ca.crt \
+    -keystore clientTrustStore.jks -storepass passw0rd <<xxEOFxx
+yes
+xxEOFxx
+
+echo;echo =====  Add the mosquitto.org cert to clientTrustStore.jks
+keytool -import -v -trustcacerts -alias mosquitto.org -file mosquitto.org.crt \
+    -keystore clientTrustStore.jks -storepass passw0rd <<xxEOFxx
+yes
+xxEOFxx
+
+echo;echo =====  Create clientKeyStore.jks  
+echo;echo =====  Create an empty clientKeyStore.jks  
+keytool -genkey -keyalg RSA -alias xyzzy \
+    -dname 'CN=foo.example.com,L=Melbourne,ST=Victoria,C=AU' \
+    -keypass passw0rd -keystore clientKeyStore.jks -storepass passw0rd 
+keytool -delete -alias xyzzy \
+    -keystore clientKeyStore.jks -storepass passw0rd 
+
+echo;echo  =====  Add the client key to clientKeyStore.jks '(PEM => pkcs12 => jks)'
+openssl pkcs12 -export -out client.p12 -passout pass:passw0rd \
+    -passin pass:passw0rd -inkey client.key -in client.crt -certfile ca.crt
+keytool -v -importkeystore \
+    -srckeystore client.p12 -srcstorepass passw0rd -srcstoretype PKCS12 \
+    -destkeystore clientKeyStore.jks -deststorepass passw0rd -deststoretype JKS
+
+# show store contents
+echo;echo =====  clientTrustStore
+keytool -list -storepass passw0rd -keystore clientTrustStore.jks
+echo;echo =====  clientKeyStore
+keytool -list -storepass passw0rd -keystore clientKeyStore.jks

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/ecbd4279/connectors/mqtt/src/test/keystores/mosquitto-SSL.conf.template
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/keystores/mosquitto-SSL.conf.template b/connectors/mqtt/src/test/keystores/mosquitto-SSL.conf.template
new file mode 100644
index 0000000..f3993a8
--- /dev/null
+++ b/connectors/mqtt/src/test/keystores/mosquitto-SSL.conf.template
@@ -0,0 +1,849 @@
+# Config file for mosquitto
+#
+# See mosquitto.conf(5) for more information.
+#
+# Default values are shown, uncomment to change.
+#
+# Use the # character to indicate a comment, but only if it is the 
+# very first character on the line.
+
+# =================================================================
+# General configuration
+# =================================================================
+
+# Time in seconds to wait before resending an outgoing QoS=1 or 
+# QoS=2 message.
+#retry_interval 20
+
+# Time in seconds between updates of the $SYS tree.
+# Set to 0 to disable the publishing of the $SYS tree.
+#sys_interval 10
+
+# Time in seconds between cleaning the internal message store of 
+# unreferenced messages. Lower values will result in lower memory 
+# usage but more processor time, higher values will have the 
+# opposite effect.
+# Setting a value of 0 means the unreferenced messages will be 
+# disposed of as quickly as possible.
+#store_clean_interval 10
+
+# Write process id to a file. Default is a blank string which means 
+# a pid file shouldn't be written.
+# This should be set to /var/run/mosquitto.pid if mosquitto is
+# being run automatically on boot with an init script and 
+# start-stop-daemon or similar.
+#pid_file
+
+# When run as root, drop privileges to this user and its primary 
+# group.
+# Leave blank to stay as root, but this is not recommended.
+# If run as a non-root user, this setting has no effect.
+# Note that on Windows this has no effect and so mosquitto should 
+# be started by the user you wish it to run as.
+#user mosquitto
+
+# The maximum number of QoS 1 and 2 messages currently inflight per 
+# client.
+# This includes messages that are partway through handshakes and 
+# those that are being retried. Defaults to 20. Set to 0 for no 
+# maximum. Setting to 1 will guarantee in-order delivery of QoS 1 
+# and 2 messages.
+#max_inflight_messages 20
+
+# The maximum number of QoS 1 and 2 messages to hold in a queue 
+# above those that are currently in-flight.  Defaults to 100. Set 
+# to 0 for no maximum (not recommended).
+# See also queue_qos0_messages.
+#max_queued_messages 100
+
+# Set to true to queue messages with QoS 0 when a persistent client is
+# disconnected. These messages are included in the limit imposed by
+# max_queued_messages.
+# Defaults to false.
+# This is a non-standard option for the MQTT v3.1 spec but is allowed in
+# v3.1.1.
+#queue_qos0_messages false
+
+# This option sets the maximum publish payload size that the broker will allow.
+# Received messages that exceed this size will not be accepted by the broker.
+# The default value is 0, which means that all valid MQTT messages are
+# accepted. MQTT imposes a maximum payload size of 268435455 bytes. 
+#message_size_limit 0
+
+# This option controls whether a client is allowed to connect with a zero
+# length client id or not. This option only affects clients using MQTT v3.1.1
+# and later. If set to false, clients connecting with a zero length client id
+# are disconnected. If set to true, clients will be allocated a client id by
+# the broker. This means it is only useful for clients with clean session set
+# to true.
+#allow_zero_length_clientid true
+
+# If allow_zero_length_clientid is true, this option allows you to set a prefix
+# to automatically generated client ids to aid visibility in logs.
+#auto_id_prefix
+
+# This option allows persistent clients (those with clean session set to false)
+# to be removed if they do not reconnect within a certain time frame.
+#
+# This is a non-standard option in MQTT V3.1 but allowed in MQTT v3.1.1.
+#
+# Badly designed clients may set clean session to false whilst using a randomly
+# generated client id. This leads to persistent clients that will never
+# reconnect. This option allows these clients to be removed.
+#
+# The expiration period should be an integer followed by one of h d w m y for
+# hour, day, week, month and year respectively. For example
+#
+# persistent_client_expiration 2m
+# persistent_client_expiration 14d
+# persistent_client_expiration 1y
+#
+# The default if not set is to never expire persistent clients.
+#persistent_client_expiration
+
+# If a client is subscribed to multiple subscriptions that overlap, e.g. foo/#
+# and foo/+/baz , then MQTT expects that when the broker receives a message on
+# a topic that matches both subscriptions, such as foo/bar/baz, then the client
+# should only receive the message once.
+# Mosquitto keeps track of which clients a message has been sent to in order to
+# meet this requirement. The allow_duplicate_messages option allows this
+# behaviour to be disabled, which may be useful if you have a large number of
+# clients subscribed to the same set of topics and are very concerned about
+# minimising memory usage.
+# It can be safely set to true if you know in advance that your clients will
+# never have overlapping subscriptions, otherwise your clients must be able to
+# correctly deal with duplicate messages even when then have QoS=2.
+#allow_duplicate_messages false
+
+# The MQTT specification requires that the QoS of a message delivered to a
+# subscriber is never upgraded to match the QoS of the subscription. Enabling
+# this option changes this behaviour. If upgrade_outgoing_qos is set true,
+# messages sent to a subscriber will always match the QoS of its subscription.
+# This is a non-standard option explicitly disallowed by the spec.
+#upgrade_outgoing_qos false
+
+# =================================================================
+# Default listener
+# =================================================================
+
+# IP address/hostname to bind the default listener to. If not
+# given, the default listener will not be bound to a specific 
+# address and so will be accessible to all network interfaces.
+# bind_address ip-address/host name
+#bind_address
+
+# Port to use for the default listener.
+#port 1883
+# need to uncomment when also defining an "extra" (SSL) listener below
+# so the server handles both ports
+port 1883
+
+# The maximum number of client connections to allow. This is 
+# a per listener setting.
+# Default is -1, which means unlimited connections.
+# Note that other process limits mean that unlimited connections 
+# are not really possible. Typically the default maximum number of 
+# connections possible is around 1024.
+#max_connections -1
+
+# Choose the protocol to use when listening.
+# This can be either mqtt or websockets.
+# Websockets support is currently disabled by default at compile time.
+# Certificate based TLS may be used with websockets, except that
+# only the cafile, certfile, keyfile and ciphers options are supported.
+#protocol mqtt
+
+# When a listener is using the websockets protocol, it is possible to serve
+# http data as well. Set http_dir to a directory which contains the files you
+# wish to serve. If this option is not specified, then no normal http
+# connections will be possible.
+#http_dir
+
+# Set use_username_as_clientid to true to replace the clientid that a client
+# connected with with its username. This allows authentication to be tied to
+# the clientid, which means that it is possible to prevent one client
+# disconnecting another by using the same clientid.
+# If a client connects with no username it will be disconnected as not
+# authorised when this option is set to true.
+# Do not use in conjunction with clientid_prefixes.
+# See also use_identity_as_username.
+#use_username_as_clientid
+
+# -----------------------------------------------------------------
+# Certificate based SSL/TLS support
+# -----------------------------------------------------------------
+# The following options can be used to enable SSL/TLS support for 
+# this listener. Note that the recommended port for MQTT over TLS
+# is 8883, but this must be set manually.
+#
+# See also the mosquitto-tls man page.
+
+# At least one of cafile or capath must be defined. They both 
+# define methods of accessing the PEM encoded Certificate 
+# Authority certificates that have signed your server certificate 
+# and that you wish to trust.
+# cafile defines the path to a file containing the CA certificates.
+# capath defines a directory that will be searched for files
+# containing the CA certificates. For capath to work correctly, the
+# certificate files must have ".crt" as the file ending and you must run
+# "c_rehash <path to capath>" each time you add/remove a certificate.
+#cafile
+#capath
+
+# Path to the PEM encoded server certificate.
+#certfile
+
+# Path to the PEM encoded keyfile.
+#keyfile
+
+# This option defines the version of the TLS protocol to use for this listener.
+# The default value allows v1.2, v1.1 and v1.0, if they are all supported by
+# the version of openssl that the broker was compiled against. For openssl >=
+# 1.0.1 the valid values are tlsv1.2 tlsv1.1 and tlsv1. For openssl < 1.0.1 the
+# valid values are tlsv1.
+#tls_version
+
+# By default a TLS enabled listener will operate in a similar fashion to a
+# https enabled web server, in that the server has a certificate signed by a CA
+# and the client will verify that it is a trusted certificate. The overall aim
+# is encryption of the network traffic. By setting require_certificate to true,
+# the client must provide a valid certificate in order for the network
+# connection to proceed. This allows access to the broker to be controlled
+# outside of the mechanisms provided by MQTT.
+#require_certificate false
+
+# If require_certificate is true, you may set use_identity_as_username to true
+# to use the CN value from the client certificate as a username. If this is
+# true, the password_file option will not be used for this listener.
+#use_identity_as_username false
+
+# If you have require_certificate set to true, you can create a certificate
+# revocation list file to revoke access to particular client certificates. If
+# you have done this, use crlfile to point to the PEM encoded revocation file.
+#crlfile
+
+# If you wish to control which encryption ciphers are used, use the ciphers
+# option. The list of available ciphers can be optained using the "openssl
+# ciphers" command and should be provided in the same format as the output of
+# that command.
+# If unset defaults to DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH
+#ciphers DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH
+
+# -----------------------------------------------------------------
+# Pre-shared-key based SSL/TLS support
+# -----------------------------------------------------------------
+# The following options can be used to enable PSK based SSL/TLS support for
+# this listener. Note that the recommended port for MQTT over TLS is 8883, but
+# this must be set manually.
+#
+# See also the mosquitto-tls man page and the "Certificate based SSL/TLS
+# support" section. Only one of certificate or PSK encryption support can be
+# enabled for any listener.
+
+# The psk_hint option enables pre-shared-key support for this listener and also
+# acts as an identifier for this listener. The hint is sent to clients and may
+# be used locally to aid authentication. The hint is a free form string that
+# doesn't have much meaning in itself, so feel free to be creative.
+# If this option is provided, see psk_file to define the pre-shared keys to be
+# used or create a security plugin to handle them.
+#psk_hint
+
+# Set use_identity_as_username to have the psk identity sent by the client used
+# as its username. Authentication will be carried out using the PSK rather than
+# the MQTT username/password and so password_file will not be used for this
+# listener.
+#use_identity_as_username false
+
+# When using PSK, the encryption ciphers used will be chosen from the list of
+# available PSK ciphers. If you want to control which ciphers are available,
+# use the "ciphers" option.  The list of available ciphers can be optained
+# using the "openssl ciphers" command and should be provided in the same format
+# as the output of that command.
+#ciphers
+
+# =================================================================
+# Extra listeners
+# =================================================================
+
+# Listen on a port/ip address combination. By using this variable 
+# multiple times, mosquitto can listen on more than one port. If 
+# this variable is used and neither bind_address nor port given, 
+# then the default listener will not be started.
+# The port number to listen on must be given. Optionally, an ip 
+# address or host name may be supplied as a second argument. In 
+# this case, mosquitto will attempt to bind the listener to that 
+# address and so restrict access to the associated network and 
+# interface. By default, mosquitto will listen on all interfaces.
+# listener port-number [ip address/host name]
+#listener
+listener 8883
+
+# The maximum number of client connections to allow. This is 
+# a per listener setting.
+# Default is -1, which means unlimited connections.
+# Note that other process limits mean that unlimited connections 
+# are not really possible. Typically the default maximum number of 
+# connections possible is around 1024.
+#max_connections -1
+
+# The listener can be restricted to operating within a topic hierarchy using
+# the mount_point option. This is achieved be prefixing the mount_point string
+# to all topics for any clients connected to this listener. This prefixing only
+# happens internally to the broker; the client will not see the prefix.
+#mount_point
+
+# Choose the protocol to use when listening.
+# This can be either mqtt or websockets.
+# Certificate based TLS may be used with websockets, except that only the
+# cafile, certfile, keyfile and ciphers options are supported.
+#protocol mqtt
+
+# When a listener is using the websockets protocol, it is possible to serve
+# http data as well. Set http_dir to a directory which contains the files you
+# wish to serve. If this option is not specified, then no normal http
+# connections will be possible.
+#http_dir
+
+# Set use_username_as_clientid to true to replace the clientid that a client
+# connected with with its username. This allows authentication to be tied to
+# the clientid, which means that it is possible to prevent one client
+# disconnecting another by using the same clientid.
+# If a client connects with no username it will be disconnected as not
+# authorised when this option is set to true.
+# Do not use in conjunction with clientid_prefixes.
+# See also use_identity_as_username.
+#use_username_as_clientid
+
+# -----------------------------------------------------------------
+# Certificate based SSL/TLS support
+# -----------------------------------------------------------------
+# The following options can be used to enable certificate based SSL/TLS support
+# for this listener. Note that the recommended port for MQTT over TLS is 8883,
+# but this must be set manually.
+#
+# See also the mosquitto-tls man page and the "Pre-shared-key based SSL/TLS
+# support" section. Only one of certificate or PSK encryption support can be
+# enabled for any listener.
+
+# At least one of cafile or capath must be defined to enable certificate based
+# TLS encryption. They both define methods of accessing the PEM encoded
+# Certificate Authority certificates that have signed your server certificate
+# and that you wish to trust.
+# cafile defines the path to a file containing the CA certificates.
+# capath defines a directory that will be searched for files
+# containing the CA certificates. For capath to work correctly, the
+# certificate files must have ".crt" as the file ending and you must run
+# "c_rehash <path to capath>" each time you add/remove a certificate.
+#cafile
+#capath
+cafile TEST-KEYSTORES-DIR/ca.crt
+
+# Path to the PEM encoded server certificate.
+#certfile
+certfile TEST-KEYSTORES-DIR/server.crt
+
+# Path to the PEM encoded keyfile.
+#keyfile
+keyfile TEST-KEYSTORES-DIR/server.key
+
+# By default an TLS enabled listener will operate in a similar fashion to a
+# https enabled web server, in that the server has a certificate signed by a CA
+# and the client will verify that it is a trusted certificate. The overall aim
+# is encryption of the network traffic. By setting require_certificate to true,
+# the client must provide a valid certificate in order for the network
+# connection to proceed. This allows access to the broker to be controlled
+# outside of the mechanisms provided by MQTT.
+#require_certificate false
+
+# If require_certificate is true, you may set use_identity_as_username to true
+# to use the CN value from the client certificate as a username. If this is
+# true, the password_file option will not be used for this listener.
+#use_identity_as_username false
+
+# If you have require_certificate set to true, you can create a certificate
+# revocation list file to revoke access to particular client certificates. If
+# you have done this, use crlfile to point to the PEM encoded revocation file.
+#crlfile
+
+# If you wish to control which encryption ciphers are used, use the ciphers
+# option. The list of available ciphers can be optained using the "openssl
+# ciphers" command and should be provided in the same format as the output of
+# that command.
+#ciphers
+
+# -----------------------------------------------------------------
+# Pre-shared-key based SSL/TLS support
+# -----------------------------------------------------------------
+# The following options can be used to enable PSK based SSL/TLS support for
+# this listener. Note that the recommended port for MQTT over TLS is 8883, but
+# this must be set manually.
+#
+# See also the mosquitto-tls man page and the "Certificate based SSL/TLS
+# support" section. Only one of certificate or PSK encryption support can be
+# enabled for any listener.
+
+# The psk_hint option enables pre-shared-key support for this listener and also
+# acts as an identifier for this listener. The hint is sent to clients and may
+# be used locally to aid authentication. The hint is a free form string that
+# doesn't have much meaning in itself, so feel free to be creative.
+# If this option is provided, see psk_file to define the pre-shared keys to be
+# used or create a security plugin to handle them.
+#psk_hint
+
+# Set use_identity_as_username to have the psk identity sent by the client used
+# as its username. Authentication will be carried out using the PSK rather than
+# the MQTT username/password and so password_file will not be used for this
+# listener.
+#use_identity_as_username false
+
+# When using PSK, the encryption ciphers used will be chosen from the list of
+# available PSK ciphers. If you want to control which ciphers are available,
+# use the "ciphers" option.  The list of available ciphers can be optained
+# using the "openssl ciphers" command and should be provided in the same format
+# as the output of that command.
+#ciphers
+
+# =============================================
+# extra listener 2  on 8884 - SSL with require client-auth
+# =============================================
+listener 8884
+require_certificate true
+
+# At least one of cafile or capath must be defined to enable certificate based
+# TLS encryption. They both define methods of accessing the PEM encoded
+# Certificate Authority certificates that have signed your server certificate
+# and that you wish to trust.
+# cafile defines the path to a file containing the CA certificates.
+# capath defines a directory that will be searched for files
+# containing the CA certificates. For capath to work correctly, the
+# certificate files must have ".crt" as the file ending and you must run
+# "c_rehash <path to capath>" each time you add/remove a certificate.
+#cafile
+cafile TEST-KEYSTORES-DIR/ca.crt
+#capath
+
+certfile TEST-KEYSTORES-DIR/server.crt
+keyfile TEST-KEYSTORES-DIR/server.key
+
+
+# =================================================================
+# Persistence
+# =================================================================
+
+# If persistence is enabled, save the in-memory database to disk 
+# every autosave_interval seconds. If set to 0, the persistence 
+# database will only be written when mosquitto exits. See also
+# autosave_on_changes.
+# Note that writing of the persistence database can be forced by 
+# sending mosquitto a SIGUSR1 signal.
+#autosave_interval 1800
+
+# If true, mosquitto will count the number of subscription changes, retained
+# messages received and queued messages and if the total exceeds
+# autosave_interval then the in-memory database will be saved to disk.
+# If false, mosquitto will save the in-memory database to disk by treating
+# autosave_interval as a time in seconds.
+#autosave_on_changes false
+
+# Save persistent message data to disk (true/false).
+# This saves information about all messages, including 
+# subscriptions, currently in-flight messages and retained 
+# messages.
+# retained_persistence is a synonym for this option.
+#persistence false
+
+# The filename to use for the persistent database, not including 
+# the path.
+#persistence_file mosquitto.db
+
+# Location for persistent database. Must include trailing /
+# Default is an empty string (current directory).
+# Set to e.g. /var/lib/mosquitto/ if running as a proper service on Linux or
+# similar.
+#persistence_location
+
+# =================================================================
+# Logging
+# =================================================================
+
+# Places to log to. Use multiple log_dest lines for multiple 
+# logging destinations.
+# Possible destinations are: stdout stderr syslog topic file
+#
+# stdout and stderr log to the console on the named output.
+#
+# syslog uses the userspace syslog facility which usually ends up 
+# in /var/log/messages or similar.
+#
+# topic logs to the broker topic '$SYS/broker/log/<severity>', 
+# where severity is one of D, E, W, N, I, M which are debug, error, 
+# warning, notice, information and message. Message type severity is used by
+# the subscribe/unsubscribe log_types and publishes log messages to
+# $SYS/broker/log/M/susbcribe or $SYS/broker/log/M/unsubscribe.
+#
+# The file destination requires an additional parameter which is the file to be
+# logged to, e.g. "log_dest file /var/log/mosquitto.log". The file will be
+# closed and reopened when the broker receives a HUP signal. Only a single file
+# destination may be configured.
+#
+# Note that if the broker is running as a Windows service it will default to
+# "log_dest none" and neither stdout nor stderr logging is available.
+# Use "log_dest none" if you wish to disable logging.
+#log_dest stderr
+
+# If using syslog logging (not on Windows), messages will be logged to the
+# "daemon" facility by default. Use the log_facility option to choose which of
+# local0 to local7 to log to instead. The option value should be an integer
+# value, e.g. "log_facility 5" to use local5.
+#log_facility
+
+# Types of messages to log. Use multiple log_type lines for logging
+# multiple types of messages.
+# Possible types are: debug, error, warning, notice, information, 
+# none, subscribe, unsubscribe, websockets, all.
+# Note that debug type messages are for decoding the incoming/outgoing
+# network packets. They are not logged in "topics".
+#log_type error
+#log_type warning
+#log_type notice
+#log_type information
+
+# Change the websockets logging level. This is a global option, it is not
+# possible to set per listener. This is an integer that is interpreted by
+# libwebsockets as a bit mask for its lws_log_levels enum. See the
+# libwebsockets documentation for more details. "log_type websockets" must also
+# be enabled.
+#websockets_log_level 0
+
+# If set to true, client connection and disconnection messages will be included
+# in the log.
+#connection_messages true
+
+# If set to true, add a timestamp value to each log message.
+#log_timestamp true
+
+# =================================================================
+# Security
+# =================================================================
+
+# If set, only clients that have a matching prefix on their 
+# clientid will be allowed to connect to the broker. By default, 
+# all clients may connect.
+# For example, setting "secure-" here would mean a client "secure-
+# client" could connect but another with clientid "mqtt" couldn't.
+#clientid_prefixes
+
+# Boolean value that determines whether clients that connect 
+# without providing a username are allowed to connect. If set to 
+# false then a password file should be created (see the 
+# password_file option) to control authenticated client access. 
+# Defaults to true.
+#allow_anonymous true
+
+# In addition to the clientid_prefixes, allow_anonymous and TLS 
+# authentication options, username based authentication is also 
+# possible. The default support is described in "Default 
+# authentication and topic access control" below. The auth_plugin 
+# allows another authentication method to be used.
+# Specify the path to the loadable plugin and see the 
+# "Authentication and topic access plugin options" section below.
+#auth_plugin
+
+# -----------------------------------------------------------------
+# Default authentication and topic access control
+# -----------------------------------------------------------------
+
+# Control access to the broker using a password file. This file can be
+# generated using the mosquitto_passwd utility. If TLS support is not compiled
+# into mosquitto (it is recommended that TLS support should be included) then
+# plain text passwords are used, in which case the file should be a text file
+# with lines in the format:
+# username:password
+# The password (and colon) may be omitted if desired, although this 
+# offers very little in the way of security.
+# 
+# See the TLS client require_certificate and use_identity_as_username options
+# for alternative authentication options.
+#password_file
+
+# Access may also be controlled using a pre-shared-key file. This requires
+# TLS-PSK support and a listener configured to use it. The file should be text
+# lines in the format:
+# identity:key
+# The key should be in hexadecimal format without a leading "0x".
+#psk_file
+
+# Control access to topics on the broker using an access control list
+# file. If this parameter is defined then only the topics listed will
+# have access.
+# If the first character of a line of the ACL file is a # it is treated as a
+# comment.
+# Topic access is added with lines of the format:
+#
+# topic [read|write|readwrite] <topic>
+# 
+# The access type is controlled using "read", "write" or "readwrite". This
+# parameter is optional (unless <topic> contains a space character) - if not
+# given then the access is read/write.  <topic> can contain the + or #
+# wildcards as in subscriptions.
+# 
+# The first set of topics are applied to anonymous clients, assuming
+# allow_anonymous is true. User specific topic ACLs are added after a 
+# user line as follows:
+#
+# user <username>
+#
+# The username referred to here is the same as in password_file. It is
+# not the clientid.
+#
+#
+# If is also possible to define ACLs based on pattern substitution within the
+# topic. The patterns available for substition are:
+#
+# %c to match the client id of the client
+# %u to match the username of the client
+#
+# The substitution pattern must be the only text for that level of hierarchy.
+#
+# The form is the same as for the topic keyword, but using pattern as the
+# keyword.
+# Pattern ACLs apply to all users even if the "user" keyword has previously
+# been given.
+#
+# If using bridges with usernames and ACLs, connection messages can be allowed
+# with the following pattern:
+# pattern write $SYS/broker/connection/%c/state
+#
+# pattern [read|write|readwrite] <topic>
+#
+# Example:
+#
+# pattern write sensor/%u/data
+#
+#acl_file
+
+# -----------------------------------------------------------------
+# Authentication and topic access plugin options
+# -----------------------------------------------------------------
+
+# If the auth_plugin option above is used, define options to pass to the
+# plugin here as described by the plugin instructions. All options named
+# using the format auth_opt_* will be passed to the plugin, for example:
+#
+# auth_opt_db_host
+# auth_opt_db_port 
+# auth_opt_db_username
+# auth_opt_db_password
+
+
+# =================================================================
+# Bridges
+# =================================================================
+
+# A bridge is a way of connecting multiple MQTT brokers together.
+# Create a new bridge using the "connection" option as described below. Set
+# options for the bridges using the remaining parameters. You must specify the
+# address and at least one topic to subscribe to.
+# Each connection must have a unique name.
+# The address line may have multiple host address and ports specified. See
+# below in the round_robin description for more details on bridge behaviour if
+# multiple addresses are used.
+# The direction that the topic will be shared can be chosen by 
+# specifying out, in or both, where the default value is out. 
+# The QoS level of the bridged communication can be specified with the next
+# topic option. The default QoS level is 0, to change the QoS the topic
+# direction must also be given.
+# The local and remote prefix options allow a topic to be remapped when it is
+# bridged to/from the remote broker. This provides the ability to place a topic
+# tree in an appropriate location. 
+# For more details see the mosquitto.conf man page.
+# Multiple topics can be specified per connection, but be careful 
+# not to create any loops.
+# If you are using bridges with cleansession set to false (the default), then
+# you may get unexpected behaviour from incoming topics if you change what
+# topics you are subscribing to. This is because the remote broker keeps the
+# subscription for the old topic. If you have this problem, connect your bridge
+# with cleansession set to true, then reconnect with cleansession set to false
+# as normal.
+#connection <name>
+#address <host>[:<port>] [<host>[:<port>]]
+#topic <topic> [[[out | in | both] qos-level] local-prefix remote-prefix]
+
+# Set the version of the MQTT protocol to use with for this bridge. Can be one
+# of mqttv31 or mqttv311. Defaults to mqttv31.
+#bridge_protocol_version mqttv31
+
+# If a bridge has topics that have "out" direction, the default behaviour is to
+# send an unsubscribe request to the remote broker on that topic. This means
+# that changing a topic direction from "in" to "out" will not keep receiving
+# incoming messages. Sending these unsubscribe requests is not always
+# desirable, setting bridge_attempt_unsubscribe to false will disable sending
+# the unsubscribe request.
+#bridge_attempt_unsubscribe true
+
+# If the bridge has more than one address given in the address/addresses
+# configuration, the round_robin option defines the behaviour of the bridge on
+# a failure of the bridge connection. If round_robin is false, the default
+# value, then the first address is treated as the main bridge connection. If
+# the connection fails, the other secondary addresses will be attempted in
+# turn. Whilst connected to a secondary bridge, the bridge will periodically
+# attempt to reconnect to the main bridge until successful.
+# If round_robin is true, then all addresses are treated as equals. If a
+# connection fails, the next address will be tried and if successful will
+# remain connected until it fails
+#round_robin false
+
+# Set the client id to use on the remote end of this bridge connection. If not
+# defined, this defaults to 'name.hostname' where name is the connection name
+# and hostname is the hostname of this computer.
+# This replaces the old "clientid" option to avoid confusion. "clientid"
+# remains valid for the time being.
+#remote_clientid
+
+# Set the clientid to use on the local broker. If not defined, this defaults to
+# 'local.<clientid>'. If you are bridging a broker to itself, it is important
+# that local_clientid and clientid do not match.
+#local_clientid
+
+# Set the clean session variable for this bridge.
+# When set to true, when the bridge disconnects for any reason, all 
+# messages and subscriptions will be cleaned up on the remote 
+# broker. Note that with cleansession set to true, there may be a 
+# significant amount of retained messages sent when the bridge 
+# reconnects after losing its connection.
+# When set to false, the subscriptions and messages are kept on the 
+# remote broker, and delivered when the bridge reconnects.
+#cleansession false
+
+# If set to true, publish notification messages to the local and remote brokers
+# giving information about the state of the bridge connection. Retained
+# messages are published to the topic $SYS/broker/connection/<clientid>/state
+# unless the notification_topic option is used.
+# If the message is 1 then the connection is active, or 0 if the connection has
+# failed.
+#notifications true
+
+# Choose the topic on which notification messages for this bridge are
+# published. If not set, messages are published on the topic
+# $SYS/broker/connection/<clientid>/state
+#notification_topic 
+
+# Set the keepalive interval for this bridge connection, in 
+# seconds.
+#keepalive_interval 60
+
+# Set the start type of the bridge. This controls how the bridge starts and
+# can be one of three types: automatic, lazy and once. Note that RSMB provides
+# a fourth start type "manual" which isn't currently supported by mosquitto.
+#
+# "automatic" is the default start type and means that the bridge connection
+# will be started automatically when the broker starts and also restarted
+# after a short delay (30 seconds) if the connection fails.
+#
+# Bridges using the "lazy" start type will be started automatically when the
+# number of queued messages exceeds the number set with the "threshold"
+# parameter. It will be stopped automatically after the time set by the
+# "idle_timeout" parameter. Use this start type if you wish the connection to
+# only be active when it is needed.
+#
+# A bridge using the "once" start type will be started automatically when the
+# broker starts but will not be restarted if the connection fails.
+#start_type automatic
+
+# Set the amount of time a bridge using the automatic start type will wait
+# until attempting to reconnect.  Defaults to 30 seconds.
+#restart_timeout 30
+
+# Set the amount of time a bridge using the lazy start type must be idle before
+# it will be stopped. Defaults to 60 seconds.
+#idle_timeout 60
+
+# Set the number of messages that need to be queued for a bridge with lazy
+# start type to be restarted. Defaults to 10 messages.
+# Must be less than max_queued_messages.
+#threshold 10
+
+# If try_private is set to true, the bridge will attempt to indicate to the
+# remote broker that it is a bridge not an ordinary client. If successful, this
+# means that loop detection will be more effective and that retained messages
+# will be propagated correctly. Not all brokers support this feature so it may
+# be necessary to set try_private to false if your bridge does not connect
+# properly.
+#try_private true
+
+# Set the username to use when connecting to a broker that requires
+# authentication.
+# This replaces the old "username" option to avoid confusion. "username"
+# remains valid for the time being.
+#remote_username
+
+# Set the password to use when connecting to a broker that requires
+# authentication. This option is only used if remote_username is also set.
+# This replaces the old "password" option to avoid confusion. "password"
+# remains valid for the time being.
+#remote_password
+
+# -----------------------------------------------------------------
+# Certificate based SSL/TLS support
+# -----------------------------------------------------------------
+# Either bridge_cafile or bridge_capath must be defined to enable TLS support
+# for this bridge.
+# bridge_cafile defines the path to a file containing the
+# Certificate Authority certificates that have signed the remote broker
+# certificate.
+# bridge_capath defines a directory that will be searched for files containing
+# the CA certificates. For bridge_capath to work correctly, the certificate
+# files must have ".crt" as the file ending and you must run "c_rehash <path to
+# capath>" each time you add/remove a certificate.
+#bridge_cafile
+#bridge_capath
+
+# Path to the PEM encoded client certificate, if required by the remote broker.
+#bridge_certfile
+
+# Path to the PEM encoded client private key, if required by the remote broker.
+#bridge_keyfile
+
+# When using certificate based encryption, bridge_insecure disables
+# verification of the server hostname in the server certificate. This can be
+# useful when testing initial server configurations, but makes it possible for
+# a malicious third party to impersonate your server through DNS spoofing, for
+# example. Use this option in testing only. If you need to resort to using this
+# option in a production environment, your setup is at fault and there is no
+# point using encryption.
+#bridge_insecure false
+
+# -----------------------------------------------------------------
+# PSK based SSL/TLS support
+# -----------------------------------------------------------------
+# Pre-shared-key encryption provides an alternative to certificate based
+# encryption. A bridge can be configured to use PSK with the bridge_identity
+# and bridge_psk options. These are the client PSK identity, and pre-shared-key
+# in hexadecimal format with no "0x". Only one of certificate and PSK based
+# encryption can be used on one
+# bridge at once.
+#bridge_identity
+#bridge_psk
+
+
+# =================================================================
+# External config files
+# =================================================================
+
+# External configuration files may be included by using the 
+# include_dir option. This defines a directory that will be searched
+# for config files. All files that end in '.conf' will be loaded as
+# a configuration file. It is best to have this as the last option
+# in the main file. This option will only be processed from the main
+# configuration file. The directory specified must not contain the 
+# main configuration file.
+#include_dir
+
+# =================================================================
+# rsmb options - unlikely to ever be supported
+# =================================================================
+
+#ffdc_output
+#max_log_entries
+#trace_level
+#trace_output



[3/3] incubator-quarks git commit: rebase and resolve issues

Posted by dl...@apache.org.
rebase and resolve issues

Project: http://git-wip-us.apache.org/repos/asf/incubator-quarks/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quarks/commit/a3c2770e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quarks/tree/a3c2770e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quarks/diff/a3c2770e

Branch: refs/heads/master
Commit: a3c2770e7091ad8d49b63573daaed570d4acff6b
Parents: ecbd427
Author: Dale LaBossiere <dl...@us.ibm.com>
Authored: Wed Mar 30 11:33:46 2016 -0400
Committer: Dale LaBossiere <dl...@us.ibm.com>
Committed: Wed Mar 30 11:33:46 2016 -0400

----------------------------------------------------------------------
 .../test/connectors/common/KeystorePath.java    | 69 --------------------
 .../test/connectors/common/TestRepoPath.java    | 61 +++++++++++++++++
 .../connectors/mqtt/MqttStreamsTestManual.java  |  4 +-
 .../javax/websocket/WebSocketClientTest.java    |  4 +-
 .../javax/websocket/WebSocketServerEcho.java    |  4 +-
 5 files changed, 67 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/a3c2770e/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
----------------------------------------------------------------------
diff --git a/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java b/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
deleted file mode 100644
index 32e374d..0000000
--- a/connectors/common/src/test/java/quarks/test/connectors/common/KeystorePath.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-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 quarks.test.connectors.common;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-public class KeystorePath {
-
-    /**
-     * 
-     * @param connectorsRelPathComponent
-     * @param more additional path components
-     * @return absolute path to the keystore
-     */
-    public static String getStorePath(String connectorsRelPathComponent, String... more) {
-        String pathStr = System.getProperty("user.dir");
-        // Under eclipse/junit: path to project in repo: <repo>/connectors
-        // Under ant/junit: <repo>/connectors/<project>/unittests/testrunxxxxxxx
-        // Get the path to the <repo>/connectors
-        Path path = new File(pathStr).toPath();
-        do {
-            if (path.endsWith("connectors"))
-                break;
-            path = path.getParent();
-        } while (path != null);
-        path = path.resolve(Paths.get(connectorsRelPathComponent, more));
-        if (!path.toFile().exists())
-            throw new IllegalArgumentException("File does not exist: "+path);
-        return path.toString();
-    }
-
-    public static String getPath(String repoRelPathComponent, String... more) {
-        String pathStr = System.getProperty("user.dir");
-        // Under eclipse/junit: path to project in repo: <repo>/connectors
-        // Under ant/junit: <repo>/connectors/<project>/unittests/testrunxxxxxxx
-        // Get the path to the <repo>/connectors
-        Path path = new File(pathStr).toPath();
-        do {
-            if (path.endsWith(repoRelPathComponent)) {
-                path = path.getParent();
-                break;
-            }
-            path = path.getParent();
-        } while (path != null);
-        path = path.resolve(Paths.get(repoRelPathComponent, more));
-        if (!path.toFile().exists())
-            throw new IllegalArgumentException("File does not exist: "+path);
-        return path.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/a3c2770e/connectors/common/src/test/java/quarks/test/connectors/common/TestRepoPath.java
----------------------------------------------------------------------
diff --git a/connectors/common/src/test/java/quarks/test/connectors/common/TestRepoPath.java b/connectors/common/src/test/java/quarks/test/connectors/common/TestRepoPath.java
new file mode 100644
index 0000000..6132d13
--- /dev/null
+++ b/connectors/common/src/test/java/quarks/test/connectors/common/TestRepoPath.java
@@ -0,0 +1,61 @@
+/*
+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 quarks.test.connectors.common;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Utility for tests to get the path to something in the local git repository.
+ */
+public class TestRepoPath {
+
+    /**
+     * Get an absolute path to something in the local git repository.
+     * <p>
+     * Deals with implications of the different execution contexts:
+     * eclipse/junit and ant/junit.
+     * 
+     * @param testProject the project (e.g., "connectors") that the
+     *        test belongs to.
+     * @param more more components
+     * @return absolute path in the repository
+     */
+    public static String getPath(String testProject, String... more) {
+        String pathStr = System.getProperty("user.dir");
+        // Under eclipse/junit: path to project in repo: <repo>/<testProject>
+        // Under ant/junit: <repo>/<testProject>/<project>/unittests/testrunxxxxxxx
+        // Get the path to the <repo>
+        Path path = new File(pathStr).toPath();
+        do {
+            if (path.endsWith(testProject)) {
+                path = path.getParent();
+                break;
+            }
+            path = path.getParent();
+        } while (path != null);
+        // add the components to the repo-path
+        path = path.resolve(Paths.get(testProject, more));
+        if (!path.toFile().exists())
+            throw new IllegalArgumentException("File does not exist: "+path);
+        return path.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/a3c2770e/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
----------------------------------------------------------------------
diff --git a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
index 82b71a6..b747c37 100644
--- a/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
+++ b/connectors/mqtt/src/test/java/quarks/test/connectors/mqtt/MqttStreamsTestManual.java
@@ -53,7 +53,7 @@ import quarks.function.BiFunction;
 import quarks.function.Function;
 import quarks.function.Supplier;
 import quarks.test.connectors.common.ConnectorTestBase;
-import quarks.test.connectors.common.KeystorePath;
+import quarks.test.connectors.common.TestRepoPath;
 import quarks.topology.TSink;
 import quarks.topology.TStream;
 import quarks.topology.Topology;
@@ -102,7 +102,7 @@ public class MqttStreamsTestManual extends ConnectorTestBase {
     }
     
     protected String getKeystorePath(String storeLeaf) {
-        return KeystorePath.getPath("connectors", "mqtt", "src", "test", "keystores", storeLeaf);
+        return TestRepoPath.getPath("connectors", "mqtt", "src", "test", "keystores", storeLeaf);
     }
     
     private MqttConfig newConfig(String serverURL, String clientId) {

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/a3c2770e/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
index 04ca101..a1e72e2 100644
--- a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
+++ b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketClientTest.java
@@ -40,7 +40,7 @@ import com.google.gson.JsonObject;
 import quarks.connectors.wsclient.WebSocketClient;
 import quarks.connectors.wsclient.javax.websocket.Jsr356WebSocketClient;
 import quarks.test.connectors.common.ConnectorTestBase;
-import quarks.test.connectors.common.KeystorePath;
+import quarks.test.connectors.common.TestRepoPath;
 import quarks.topology.TSink;
 import quarks.topology.TStream;
 import quarks.topology.Topology;
@@ -122,7 +122,7 @@ public class WebSocketClientTest extends ConnectorTestBase {
     }
     
     private String getStorePath(String storeLeaf) {
-        return KeystorePath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
+        return TestRepoPath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/a3c2770e/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
----------------------------------------------------------------------
diff --git a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
index ea8eb47..a63a471 100644
--- a/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
+++ b/connectors/wsclient-javax.websocket/src/test/java/quarks/tests/connectors/wsclient/javax/websocket/WebSocketServerEcho.java
@@ -46,7 +46,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
 
-import quarks.test.connectors.common.KeystorePath;
+import quarks.test.connectors.common.TestRepoPath;
 
 /**
  * Simple WebSocket server program to echo received messages.
@@ -145,7 +145,7 @@ public class WebSocketServerEcho {
     }
     
     private String getStorePath(String storeLeaf) {
-        return KeystorePath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
+        return TestRepoPath.getPath("connectors", "wsclient-javax.websocket", "src", "test", "keystores", storeLeaf);
     }
     
     public int getPort() {