Repository: qpid-jms
Updated Branches:
  refs/heads/master 4b2f03d61 -> 2fde87949


QPIDJMS-65: dont select EXTERNAL when we know there is no local principal 
established for the transport


Project: http://git-wip-us.apache.org/repos/asf/qpid-jms/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-jms/commit/2fde8794
Tree: http://git-wip-us.apache.org/repos/asf/qpid-jms/tree/2fde8794
Diff: http://git-wip-us.apache.org/repos/asf/qpid-jms/diff/2fde8794

Branch: refs/heads/master
Commit: 2fde87949ea1d90f2e51de4a245f3bc36059fa30
Parents: 4b2f03d
Author: Robert Gemmell <[email protected]>
Authored: Wed Jun 3 15:48:14 2015 +0100
Committer: Robert Gemmell <[email protected]>
Committed: Wed Jun 3 15:54:16 2015 +0100

----------------------------------------------------------------------
 .../org/apache/qpid/jms/provider/Provider.java  |  9 +++
 .../qpid/jms/provider/ProviderWrapper.java      | 10 ++-
 .../qpid/jms/provider/amqp/AmqpConnection.java  |  2 +-
 .../qpid/jms/provider/amqp/AmqpProvider.java    | 11 +++
 .../provider/amqp/AmqpSaslAuthenticator.java    | 12 +++-
 .../jms/provider/failover/FailoverProvider.java | 11 +++
 .../qpid/jms/sasl/AnonymousMechanism.java       |  4 +-
 .../apache/qpid/jms/sasl/CramMD5Mechanism.java  |  3 +-
 .../apache/qpid/jms/sasl/ExternalMechanism.java |  6 +-
 .../org/apache/qpid/jms/sasl/Mechanism.java     |  4 +-
 .../apache/qpid/jms/sasl/PlainMechanism.java    |  4 +-
 .../qpid/jms/sasl/SaslMechanismFinder.java      |  7 +-
 .../qpid/jms/transports/SSLTransport.java       | 23 +++++++
 .../jms/transports/netty/NettySslTransport.java | 11 ++-
 .../jms/integration/SaslIntegrationTest.java    | 72 +++++++++++++++++++-
 .../qpid/jms/provider/ProviderWrapperTest.java  | 71 +++++++++++++++++++
 .../provider/failover/FailoverProviderTest.java | 28 ++++++++
 .../qpid/jms/provider/mock/MockProvider.java    | 29 +++++++-
 .../mock/MockProviderConfiguration.java         | 10 +++
 .../qpid/jms/sasl/AnonymousMechanismTest.java   | 30 +++++---
 .../qpid/jms/sasl/CramMD5MechanismTest.java     | 31 ++++++---
 .../qpid/jms/sasl/ExternalMechanismTest.java    | 55 ++++++---------
 .../qpid/jms/sasl/PlainMechanismTest.java       | 31 ++++++---
 .../qpid/jms/test/testpeer/TestAmqpPeer.java    |  7 +-
 .../jms/test/testpeer/TestAmqpPeerRunner.java   |  9 ++-
 25 files changed, 409 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
index e8ce75c..598ed84 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
@@ -18,6 +18,7 @@ package org.apache.qpid.jms.provider;
 
 import java.io.IOException;
 import java.net.URI;
+import java.security.Principal;
 
 import javax.jms.JMSException;
 
@@ -28,6 +29,7 @@ import org.apache.qpid.jms.meta.JmsConsumerId;
 import org.apache.qpid.jms.meta.JmsResource;
 import org.apache.qpid.jms.meta.JmsSessionId;
 import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.transports.SSLTransport;
 
 /**
  * Defines the interface that an Implementation of a Specific wire level 
protocol
@@ -316,4 +318,11 @@ public interface Provider {
      */
     ProviderListener getProviderListener();
 
+    /**
+     * Get the local Principal associated with the {@link SSLTransport}
+     * if the Provider is using one.
+     *
+     * @return the {@link Principal}, or null if there isn't one
+     */
+    Principal getLocalPrincipal();
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
index 4bb9d51..44b4789 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
@@ -18,6 +18,7 @@ package org.apache.qpid.jms.provider;
 
 import java.io.IOException;
 import java.net.URI;
+import java.security.Principal;
 
 import javax.jms.JMSException;
 
@@ -30,8 +31,8 @@ import org.apache.qpid.jms.meta.JmsSessionId;
 import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
 
 /**
- * Allows one AsyncProvider instance to wrap around another and provide some 
additional
- * features beyond the normal AsyncProvider interface.
+ * Allows one {@link Provider} instance to wrap around another and provide 
some additional
+ * features beyond the normal {@link Provider} interface.
  *
  * This wrapper is meant primarily for Providers that are adding some 
additional feature
  * on-top of an existing provider such as a discovery based provider that only 
needs to
@@ -191,4 +192,9 @@ public class ProviderWrapper<E extends Provider> implements 
Provider, ProviderLi
     public Provider getNext() {
         return next;
     }
+
+    @Override
+    public Principal getLocalPrincipal() {
+        return next.getLocalPrincipal();
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
index 17c4bd1..e999515 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
@@ -66,7 +66,7 @@ public class AmqpConnection extends 
AmqpAbstractResource<JmsConnectionInfo, Conn
         this.amqpMessageFactory = new AmqpJmsMessageFactory(this);
 
         if (sasl != null) {
-            this.authenticator = new AmqpSaslAuthenticator(sasl, info);
+            this.authenticator = new AmqpSaslAuthenticator(sasl, info, 
provider.getLocalPrincipal());
         }
 
         this.resource.getConnectionId().setProviderHint(this);

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
index 6a1597d..5c6250b 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
@@ -23,6 +23,7 @@ import io.netty.util.ReferenceCountUtil;
 import java.io.IOException;
 import java.net.URI;
 import java.nio.ByteBuffer;
+import java.security.Principal;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
@@ -55,6 +56,7 @@ import org.apache.qpid.jms.provider.ProviderClosedException;
 import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
 import org.apache.qpid.jms.provider.ProviderFuture;
 import org.apache.qpid.jms.provider.ProviderListener;
+import org.apache.qpid.jms.transports.SSLTransport;
 import org.apache.qpid.jms.transports.TransportFactory;
 import org.apache.qpid.jms.transports.TransportListener;
 import org.apache.qpid.jms.util.IOExceptionSupport;
@@ -1003,4 +1005,13 @@ public class AmqpProvider implements Provider, 
TransportListener {
             }
         }
     }
+
+    @Override
+    public Principal getLocalPrincipal() {
+        if(transport instanceof SSLTransport) {
+            return ((SSLTransport) transport).getLocalPrincipal();
+        }
+
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
index 75ea7cc..cce8546 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.provider.amqp;
 
+import java.security.Principal;
+
 import javax.jms.JMSSecurityException;
 import javax.security.sasl.SaslException;
 
@@ -32,6 +34,7 @@ public class AmqpSaslAuthenticator {
     private final Sasl sasl;
     private final JmsConnectionInfo info;
     private Mechanism mechanism;
+    private Principal localPrincipal;
 
     /**
      * Create the authenticator and initialize it.
@@ -40,10 +43,13 @@ public class AmqpSaslAuthenticator {
      *        The Proton SASL entry point this class will use to manage the 
authentication.
      * @param info
      *        The Connection information used to provide credentials to the 
remote peer.
+     * @param localPrincipal
+     *        The local Principal associated with the transport, or null if 
there is none.
      */
-    public AmqpSaslAuthenticator(Sasl sasl, JmsConnectionInfo info) {
+    public AmqpSaslAuthenticator(Sasl sasl, JmsConnectionInfo info, Principal 
localPrincipal) {
         this.sasl = sasl;
         this.info = info;
+        this.localPrincipal = localPrincipal;
     }
 
     /**
@@ -77,7 +83,7 @@ public class AmqpSaslAuthenticator {
         try {
             String[] remoteMechanisms = sasl.getRemoteMechanisms();
             if (remoteMechanisms != null && remoteMechanisms.length != 0) {
-                mechanism = 
SaslMechanismFinder.findMatchingMechanism(info.getUsername(), 
info.getPassword(), remoteMechanisms);
+                mechanism = 
SaslMechanismFinder.findMatchingMechanism(info.getUsername(), 
info.getPassword(), localPrincipal, remoteMechanisms);
                 if (mechanism != null) {
                     mechanism.setUsername(info.getUsername());
                     mechanism.setPassword(info.getPassword());
@@ -91,7 +97,7 @@ public class AmqpSaslAuthenticator {
                     }
                 } else {
                     // TODO - Better error message.
-                    throw new JMSSecurityException("Could not find a matching 
SASL mechanism for the remote peer.");
+                    throw new JMSSecurityException("Could not find a suitable 
SASL mechanism for the remote peer using the available credentials.");
                 }
             }
         } catch (SaslException se) {

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
index eef6a9a..dbd51f7 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
@@ -19,6 +19,7 @@ package org.apache.qpid.jms.provider.failover;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -1027,4 +1028,14 @@ public class FailoverProvider extends 
DefaultProviderListener implements Provide
             super.onSuccess();
         }
     }
+
+    @Override
+    public Principal getLocalPrincipal() {
+        Provider provider = this.provider;
+        if (provider != null) {
+            return provider.getLocalPrincipal();
+        }
+
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
index 67ec880..6daa5df 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.security.Principal;
+
 /**
  * Implements the Anonymous SASL authentication mechanism.
  */
@@ -42,7 +44,7 @@ public class AnonymousMechanism extends AbstractMechanism {
     }
 
     @Override
-    public boolean isApplicable(String username, String password) {
+    public boolean isApplicable(String username, String password, Principal 
localPrincipal) {
         return true;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
index a920233..208461d 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
@@ -19,6 +19,7 @@ package org.apache.qpid.jms.sasl;
 import java.io.UnsupportedEncodingException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
@@ -85,7 +86,7 @@ public class CramMD5Mechanism extends AbstractMechanism {
     }
 
     @Override
-    public boolean isApplicable(String username, String password) {
+    public boolean isApplicable(String username, String password, Principal 
localPrincipal) {
         return username != null && username.length() > 0 && password != null 
&& password.length() > 0;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/ExternalMechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/ExternalMechanism.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/ExternalMechanism.java
index ebeff08..0bca3b3 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/ExternalMechanism.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/ExternalMechanism.java
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.security.Principal;
+
 /**
  * Implements the External SASL authentication mechanism.
  */
@@ -42,7 +44,7 @@ public class ExternalMechanism extends AbstractMechanism {
     }
 
     @Override
-    public boolean isApplicable(String username, String password) {
-        return true;
+    public boolean isApplicable(String username, String password, Principal 
localPrincipal) {
+        return localPrincipal != null;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
index f8c14a1..b60531e 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.security.Principal;
+
 import javax.security.sasl.SaslException;
 
 /**
@@ -111,6 +113,6 @@ public interface Mechanism extends Comparable<Mechanism> {
      */
     String getPassword();
 
-    boolean isApplicable(String username, String password);
+    boolean isApplicable(String username, String password, Principal 
localPrincipal);
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
index 3ec3aef..50e45bf 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.security.Principal;
+
 /**
  * Implements the SASL PLAIN authentication Mechanism.
  *
@@ -61,7 +63,7 @@ public class PlainMechanism extends AbstractMechanism {
     }
 
     @Override
-    public boolean isApplicable(String username, String password) {
+    public boolean isApplicable(String username, String password, Principal 
localPrincipal) {
         return username != null && username.length() > 0 && password != null 
&& password.length() > 0;
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
index a6a3489..f3318d1 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
@@ -16,6 +16,7 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -51,12 +52,14 @@ public class SaslMechanismFinder {
      *        the username, or null if there is none
      * @param password
      *        the password, or null if there is none
+     * @param localPrincipal
+     *        the Principal associated with the transport, or null if there is 
none
      * @param remoteMechanisms
      *        list of mechanism names that are supported by the remote peer.
      *
      * @return the best matching Mechanism for the supported remote set.
      */
-    public static Mechanism findMatchingMechanism(String username, String 
password, String... remoteMechanisms) {
+    public static Mechanism findMatchingMechanism(String username, String 
password, Principal localPrincipal, String... remoteMechanisms) {
 
         Mechanism match = null;
         List<Mechanism> found = new ArrayList<Mechanism>();
@@ -65,7 +68,7 @@ public class SaslMechanismFinder {
             MechanismFactory factory = findMechanismFactory(remoteMechanism);
             if (factory != null) {
                 Mechanism mech = factory.createMechanism();
-                if(mech.isApplicable(username, password)) {
+                if(mech.isApplicable(username, password, localPrincipal)) {
                     found.add(mech);
                 } else {
                     LOG.debug("Skipping {} mechanism because the available 
credentials are not sufficient", mech);

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SSLTransport.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SSLTransport.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SSLTransport.java
new file mode 100644
index 0000000..dfe5c92
--- /dev/null
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SSLTransport.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.transports;
+
+import java.security.Principal;
+
+public interface SSLTransport extends Transport {
+    Principal getLocalPrincipal();
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/netty/NettySslTransport.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/netty/NettySslTransport.java
 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/netty/NettySslTransport.java
index a190e21..2ea2637 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/netty/NettySslTransport.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/netty/NettySslTransport.java
@@ -22,7 +22,9 @@ import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
 
 import java.net.URI;
+import java.security.Principal;
 
+import org.apache.qpid.jms.transports.SSLTransport;
 import org.apache.qpid.jms.transports.TransportListener;
 import org.apache.qpid.jms.transports.TransportOptions;
 import org.apache.qpid.jms.transports.TransportSslOptions;
@@ -34,7 +36,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Extends the Netty based TCP transport to add SSL support.
  */
-public class NettySslTransport extends NettyTcpTransport {
+public class NettySslTransport extends NettyTcpTransport implements 
SSLTransport {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(NettySslTransport.class);
 
@@ -106,4 +108,11 @@ public class NettySslTransport extends NettyTcpTransport {
     private TransportSslOptions getSslOptions() {
         return (TransportSslOptions) getTransportOptions();
     }
+
+    @Override
+    public Principal getLocalPrincipal() {
+        SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
+
+        return sslHandler.engine().getSession().getLocalPrincipal();
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslIntegrationTest.java
index e19b380..19a6b85 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslIntegrationTest.java
@@ -29,10 +29,13 @@ import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.JMSException;
 import javax.jms.JMSSecurityException;
+import javax.net.ssl.SSLContext;
 
 import org.apache.qpid.jms.JmsConnectionFactory;
 import org.apache.qpid.jms.test.QpidJmsTestCase;
 import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
+import org.apache.qpid.jms.transports.TransportSslOptions;
+import org.apache.qpid.jms.transports.TransportSupport;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.junit.Test;
 
@@ -41,17 +44,37 @@ public class SaslIntegrationTest extends QpidJmsTestCase {
     private static final Symbol ANONYMOUS = Symbol.valueOf("ANONYMOUS");
     private static final Symbol PLAIN = Symbol.valueOf("PLAIN");
     private static final Symbol CRAM_MD5 = Symbol.valueOf("CRAM-MD5");
+    private static final Symbol EXTERNAL = Symbol.valueOf("EXTERNAL");
+
+    private static final String BROKER_JKS_KEYSTORE = 
"src/test/resources/broker-jks.keystore";
+    private static final String BROKER_JKS_TRUSTSTORE = 
"src/test/resources/broker-jks.truststore";
+    private static final String CLIENT_JKS_KEYSTORE = 
"src/test/resources/client-jks.keystore";
+    private static final String CLIENT_JKS_TRUSTSTORE = 
"src/test/resources/client-jks.truststore";
+    private static final String PASSWORD = "password";
 
     @Test(timeout = 5000)
     public void testSaslExternalConnection() throws Exception {
-        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+        TransportSslOptions sslOptions = new TransportSslOptions();
+        sslOptions.setKeyStoreLocation(BROKER_JKS_KEYSTORE);
+        sslOptions.setKeyStorePassword(PASSWORD);
+        sslOptions.setVerifyHost(false);
+        sslOptions.setTrustStoreLocation(BROKER_JKS_TRUSTSTORE);
+        sslOptions.setTrustStorePassword(PASSWORD);
+
+        String connOptions = "?transport.trustStoreLocation=" + 
CLIENT_JKS_TRUSTSTORE + "&" +
+                             "transport.trustStorePassword=" + PASSWORD + "&" +
+                             "transport.keyStoreLocation=" + 
CLIENT_JKS_KEYSTORE + "&" +
+                             "transport.keyStorePassword=" + PASSWORD;
+
+        SSLContext context = TransportSupport.createSslContext(sslOptions);
 
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(context, true);) {
             // Expect an EXTERNAL connection
             testPeer.expectExternalConnect();
             // Each connection creates a session for managing temporary 
destinations etc
             testPeer.expectBegin(true);
 
-            ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort());
+            ConnectionFactory factory = new 
JmsConnectionFactory("amqps://localhost:" + testPeer.getServerPort() + 
connOptions);
             Connection connection = factory.createConnection();
             // Set a clientID to provoke the actual AMQP connection process to 
occur.
             connection.setClientID("clientName");
@@ -143,4 +166,49 @@ public class SaslIntegrationTest extends QpidJmsTestCase {
             testPeer.waitForAllHandlersToComplete(1000);
         }
     }
+
+    @Test(timeout = 5000)
+    public void testExternalSelectedWhenLocalPrincipalPresent() throws 
Exception {
+        doMechanismSelectedExternalTestImpl(true, EXTERNAL, new Symbol[] 
{EXTERNAL, ANONYMOUS});
+    }
+
+    @Test(timeout = 5000)
+    public void testExternalNotSelectedWhenLocalPrincipalMissing() throws 
Exception {
+        doMechanismSelectedExternalTestImpl(false, ANONYMOUS, new Symbol[] 
{EXTERNAL, ANONYMOUS});
+    }
+
+    private void doMechanismSelectedExternalTestImpl(boolean 
requireClientCert, Symbol clientSelectedMech, Symbol[] serverMechs) throws 
Exception {
+        TransportSslOptions sslOptions = new TransportSslOptions();
+        sslOptions.setKeyStoreLocation(BROKER_JKS_KEYSTORE);
+        sslOptions.setKeyStorePassword(PASSWORD);
+        sslOptions.setVerifyHost(false);
+        if (requireClientCert) {
+            sslOptions.setTrustStoreLocation(BROKER_JKS_TRUSTSTORE);
+            sslOptions.setTrustStorePassword(PASSWORD);
+        }
+
+        SSLContext context = TransportSupport.createSslContext(sslOptions);
+
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(context, 
requireClientCert);) {
+            String connOptions = "?transport.trustStoreLocation=" + 
CLIENT_JKS_TRUSTSTORE + "&" +
+                                 "transport.trustStorePassword=" + PASSWORD + 
"&" +
+                                 "jms.clientID=myclientid";
+            if (requireClientCert) {
+                connOptions += "&transport.keyStoreLocation=" + 
CLIENT_JKS_KEYSTORE + "&" +
+                               "transport.keyStorePassword=" + PASSWORD;
+            }
+
+            testPeer.expectFailingSaslConnect(serverMechs, clientSelectedMech);
+
+            JmsConnectionFactory factory = new 
JmsConnectionFactory("amqps://localhost:" + testPeer.getServerPort() + 
connOptions);
+            try {
+                factory.createConnection();
+                fail("Expected exception to be thrown");
+            } catch (JMSException jmse) {
+                // Expected
+            }
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/ProviderWrapperTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/ProviderWrapperTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/ProviderWrapperTest.java
new file mode 100644
index 0000000..42b64c4
--- /dev/null
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/ProviderWrapperTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.provider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.net.URI;
+
+import org.apache.qpid.jms.provider.mock.MockProvider;
+import org.apache.qpid.jms.provider.mock.MockProviderFactory;
+import org.apache.qpid.jms.test.QpidJmsTestCase;
+import org.junit.After;
+import org.junit.Test;
+
+public class ProviderWrapperTest extends QpidJmsTestCase{
+
+    MockProvider mockProvider = null;
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        if (mockProvider != null) {
+            mockProvider.close();
+        }
+        super.tearDown();
+    }
+
+    @Test
+    public void testGetLocalPrincipal() throws Exception {
+        String principalName = "foo";
+
+        MockProviderFactory factory = new MockProviderFactory();
+        mockProvider = factory.createProvider(new 
URI("mock://1.2.3.4:5678?mock.localPrincipal=" + principalName));
+
+        assertNotNull(mockProvider.getLocalPrincipal());
+        assertEquals(principalName, 
mockProvider.getLocalPrincipal().getName());
+
+        ProviderWrapper<MockProvider> wrapper = new 
ProviderWrapper<MockProvider>(mockProvider);
+
+        assertNotNull(wrapper.getLocalPrincipal());
+        assertEquals(principalName, wrapper.getLocalPrincipal().getName());
+    }
+
+    @Test
+    public void testGetLocalPrincipalNull() throws Exception {
+        MockProviderFactory factory = new MockProviderFactory();
+        mockProvider = factory.createProvider(new URI("mock://1.2.3.4:5678"));
+
+        assertNull(mockProvider.getLocalPrincipal());
+
+        ProviderWrapper<MockProvider> wrapper = new 
ProviderWrapper<MockProvider>(mockProvider);
+
+        assertNull(wrapper.getLocalPrincipal());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/failover/FailoverProviderTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/failover/FailoverProviderTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/failover/FailoverProviderTest.java
index 0a57f59..c5f57e5 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/failover/FailoverProviderTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/failover/FailoverProviderTest.java
@@ -140,6 +140,34 @@ public class FailoverProviderTest extends 
FailoverProviderTestSupport {
         }, TimeUnit.SECONDS.toMillis(20), 10));
     }
 
+    @Test(timeout = 15000)
+    public void testGetLocalPrincipal() throws Exception {
+        String principalName = "foo";
+
+        FailoverProviderFactory factory = new FailoverProviderFactory();
+        provider = (FailoverProvider) factory.createProvider(new 
URI("failover:(mock://192.168.2.1:5672?mock.localPrincipal=" + principalName + 
")"));
+        provider.setProviderListener(new DefaultProviderListener());
+
+        provider.connect();
+
+        ProviderFuture request = new ProviderFuture();
+        provider.create(createConnectionInfo(), request);
+
+        request.sync(10, TimeUnit.SECONDS);
+        assertTrue(request.isComplete());
+
+        assertNotNull(provider.getLocalPrincipal());
+        assertEquals(principalName, provider.getLocalPrincipal().getName());
+    }
+
+    @Test(timeout = 15000)
+    public void testGetLocalPrincipalNull() throws Exception {
+        FailoverProviderFactory factory = new FailoverProviderFactory();
+        provider = (FailoverProvider) factory.createProvider(new 
URI("failover:(mock://192.168.2.1:5672)"));
+
+        assertNull(provider.getLocalPrincipal());
+    }
+
     @Test(timeout = 30000)
     public void testToString() throws Exception {
         provider = new FailoverProvider(uris, Collections.<String, 
String>emptyMap());

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProvider.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProvider.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProvider.java
index 46a414f..66521d2 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProvider.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProvider.java
@@ -18,6 +18,7 @@ package org.apache.qpid.jms.provider.mock;
 
 import java.io.IOException;
 import java.net.URI;
+import java.security.Principal;
 import java.util.UUID;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -486,11 +487,37 @@ public class MockProvider implements Provider {
         this.connectTimeout = connectTimeout;
     }
 
+    @Override
+    public Principal getLocalPrincipal() {
+        final String localPrincipal = configuration.getLocalPrincipal();
+
+        if (localPrincipal == null) {
+             return null;
+        } else {
+            return new MockPrincipal(localPrincipal);
+        }
+    }
+
     //----- Implementation details 
-------------------------------------------//
 
+
     private void checkClosed() throws ProviderClosedException {
         if (closed.get()) {
             throw new ProviderClosedException("This Provider is already 
closed");
         }
     }
-}
+
+    private static final class MockPrincipal implements Principal {
+        private final String name;
+
+        private MockPrincipal(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProviderConfiguration.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProviderConfiguration.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProviderConfiguration.java
index 21b1e69..8af3a63 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProviderConfiguration.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/mock/MockProviderConfiguration.java
@@ -24,6 +24,7 @@ public class MockProviderConfiguration {
     private boolean failOnConnect;
     private boolean failOnStart;
     private boolean failOnClose;
+    private String localPrincipal;
 
     public boolean isFailOnConnect() {
         return failOnConnect;
@@ -48,4 +49,13 @@ public class MockProviderConfiguration {
     public void setFailOnClose(boolean value) {
         this.failOnClose = value;
     }
+
+    public String getLocalPrincipal() {
+        return localPrincipal;
+    }
+
+    public void setLocalPrincipal(String localPrincipal) {
+        this.localPrincipal = localPrincipal;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
index e1fa4b5..b87eff6 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.qpid.jms.sasl;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+
+import java.security.Principal;
 
 import org.junit.Test;
 
@@ -26,48 +28,60 @@ public class AnonymousMechanismTest {
     public void testIsApplicableWithNoCredentials() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with no credentials", 
mech.isApplicable(null, null));
+        assertTrue("Should be applicable with no credentials", 
mech.isApplicable(null, null, null));
     }
 
     @Test
     public void testIsNotApplicableWithNoUser() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with no username", 
mech.isApplicable(null, "pass"));
+        assertTrue("Should be applicable with no username", 
mech.isApplicable(null, "pass", null));
     }
 
     @Test
     public void testIsApplicableWithNoPassword() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with no password", 
mech.isApplicable("user", null));
+        assertTrue("Should be applicable with no password", 
mech.isApplicable("user", null, null));
     }
 
     @Test
     public void testIsApplicableWithEmtpyUser() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with empty username", 
mech.isApplicable("", "pass"));
+        assertTrue("Should be applicable with empty username", 
mech.isApplicable("", "pass", null));
     }
 
     @Test
     public void testIsApplicableWithEmtpyPassword() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with empty password", 
mech.isApplicable("user", ""));
+        assertTrue("Should be applicable with empty password", 
mech.isApplicable("user", "", null));
     }
 
     @Test
     public void testIsApplicableWithEmtpyUserAndPassword() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with empty user and password", 
mech.isApplicable("", ""));
+        assertTrue("Should be applicable with empty user and password", 
mech.isApplicable("", "", null));
     }
 
     @Test
     public void testIsApplicableWithUserAndPassword() {
         AnonymousMechanism mech = new AnonymousMechanism();
 
-        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password"));
+        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password", null));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPasswordAndPrincipal() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with user and password and 
principal", mech.isApplicable("user", "password", new Principal() {
+            @Override
+            public String getName() {
+                return "name";
+            }
+        }));
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
index de48830..1a6149f 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
@@ -16,7 +16,10 @@
  */
 package org.apache.qpid.jms.sasl;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.security.Principal;
 
 import org.junit.Test;
 
@@ -26,48 +29,60 @@ public class CramMD5MechanismTest {
     public void testIsNotApplicableWithNoCredentials() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with no credentials", 
mech.isApplicable(null, null));
+        assertFalse("Should not be applicable with no credentials", 
mech.isApplicable(null, null, null));
     }
 
     @Test
     public void testIsNotApplicableWithNoUser() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with no username", 
mech.isApplicable(null, "pass"));
+        assertFalse("Should not be applicable with no username", 
mech.isApplicable(null, "pass", null));
     }
 
     @Test
     public void testIsNotApplicableWithNoPassword() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with no password", 
mech.isApplicable("user", null));
+        assertFalse("Should not be applicable with no password", 
mech.isApplicable("user", null, null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyUser() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with empty username", 
mech.isApplicable("", "pass"));
+        assertFalse("Should not be applicable with empty username", 
mech.isApplicable("", "pass", null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyPassword() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with empty password", 
mech.isApplicable("user", ""));
+        assertFalse("Should not be applicable with empty password", 
mech.isApplicable("user", "", null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyUserAndPassword() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertFalse("Should not be applicable with empty user and password", 
mech.isApplicable("", ""));
+        assertFalse("Should not be applicable with empty user and password", 
mech.isApplicable("", "", null));
     }
 
     @Test
     public void testIsApplicableWithUserAndPassword() {
         CramMD5Mechanism mech = new CramMD5Mechanism();
 
-        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password"));
+        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password", null));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPasswordAndPrincipal() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertTrue("Should be applicable with user and password and 
principal", mech.isApplicable("user", "password", new Principal() {
+            @Override
+            public String getName() {
+                return "name";
+            }
+        }));
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
index 57a0d5f..7bb6341 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
@@ -16,58 +16,43 @@
  */
 package org.apache.qpid.jms.sasl;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.security.Principal;
 
 import org.junit.Test;
 
 public class ExternalMechanismTest {
 
     @Test
-    public void testIsApplicableWithNoCredentials() {
-        ExternalMechanism mech = new ExternalMechanism();
-
-        assertTrue("Should be applicable with no credentials", 
mech.isApplicable(null, null));
-    }
-
-    @Test
-    public void testIsNotApplicableWithNoUser() {
-        ExternalMechanism mech = new ExternalMechanism();
-
-        assertTrue("Should be applicable with no username", 
mech.isApplicable(null, "pass"));
-    }
-
-    @Test
-    public void testIsApplicableWithNoPassword() {
-        ExternalMechanism mech = new ExternalMechanism();
-
-        assertTrue("Should be applicable with no password", 
mech.isApplicable("user", null));
-    }
-
-    @Test
-    public void testIsApplicableWithEmtpyUser() {
-        ExternalMechanism mech = new ExternalMechanism();
-
-        assertTrue("Should be applicable with empty username", 
mech.isApplicable("", "pass"));
-    }
-
-    @Test
-    public void testIsApplicableWithEmtpyPassword() {
+    public void testIsNotApplicableWithUserAndPasswordButNoPrincipal() {
         ExternalMechanism mech = new ExternalMechanism();
 
-        assertTrue("Should be applicable with empty password", 
mech.isApplicable("user", ""));
+        assertFalse("Should not be applicable with user and password but no 
principal", mech.isApplicable("user", "password", null));
     }
 
     @Test
-    public void testIsApplicableWithEmtpyUserAndPassword() {
+    public void testIsApplicableWithUserAndPasswordAndPrincipal() {
         ExternalMechanism mech = new ExternalMechanism();
 
-        assertTrue("Should be applicable with empty user and password", 
mech.isApplicable("", ""));
+        assertTrue("Should be applicable with user and password and 
principal", mech.isApplicable("user", "password", new Principal() {
+            @Override
+            public String getName() {
+                return "name";
+            }
+        }));
     }
 
     @Test
-    public void testIsApplicableWithUserAndPassword() {
+    public void testIsApplicableWithPrincipalOnly() {
         ExternalMechanism mech = new ExternalMechanism();
 
-        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password"));
+        assertTrue("Should be applicable with principal only", 
mech.isApplicable(null, null, new Principal() {
+            @Override
+            public String getName() {
+                return "name";
+            }
+        }));
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
index cc76880..4a251d2 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
@@ -16,7 +16,10 @@
  */
 package org.apache.qpid.jms.sasl;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.security.Principal;
 
 import org.junit.Test;
 
@@ -26,48 +29,60 @@ public class PlainMechanismTest {
     public void testIsNotApplicableWithNoCredentials() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with no credentials", 
mech.isApplicable(null, null));
+        assertFalse("Should not be applicable with no credentials", 
mech.isApplicable(null, null, null));
     }
 
     @Test
     public void testIsNotApplicableWithNoUser() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with no username", 
mech.isApplicable(null, "pass"));
+        assertFalse("Should not be applicable with no username", 
mech.isApplicable(null, "pass", null));
     }
 
     @Test
     public void testIsNotApplicableWithNoPassword() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with no password", 
mech.isApplicable("user", null));
+        assertFalse("Should not be applicable with no password", 
mech.isApplicable("user", null, null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyUser() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with empty username", 
mech.isApplicable("", "pass"));
+        assertFalse("Should not be applicable with empty username", 
mech.isApplicable("", "pass", null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyPassword() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with empty password", 
mech.isApplicable("user", ""));
+        assertFalse("Should not be applicable with empty password", 
mech.isApplicable("user", "", null));
     }
 
     @Test
     public void testIsNotApplicableWithEmtpyUserAndPassword() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertFalse("Should not be applicable with empty user and password", 
mech.isApplicable("", ""));
+        assertFalse("Should not be applicable with empty user and password", 
mech.isApplicable("", "", null));
     }
 
     @Test
     public void testIsApplicableWithUserAndPassword() {
         PlainMechanism mech = new PlainMechanism();
 
-        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password"));
+        assertTrue("Should be applicable with user and password", 
mech.isApplicable("user", "password", null));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPasswordAndPrincipal() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertTrue("Should be applicable with user and password and 
principal", mech.isApplicable("user", "password", new Principal() {
+            @Override
+            public String getName() {
+                return "name";
+            }
+        }));
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
index 219b7e8..d4adeb7 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
@@ -438,11 +438,12 @@ public class TestAmqpPeer implements AutoCloseable
         addHandler(openMatcher);
     }
 
-    /**
-     * NOTE: this is only testing use of the mechanism, there is no SSL here 
yet.
-     */
     public void expectExternalConnect()
     {
+        if(!_driverRunnable.isNeedClientCert()) {
+            throw new IllegalStateException("Need client cert must be 
enabled");
+        }
+
         SaslMechanismsFrame saslMechanismsFrame = new 
SaslMechanismsFrame().setSaslServerMechanisms(Symbol.valueOf("EXTERNAL"));
         addHandler(new HeaderHandlerImpl(AmqpHeader.SASL_HEADER, 
AmqpHeader.SASL_HEADER,
                                             new FrameSender(

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/2fde8794/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
index 085326d..17ec2f6 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
@@ -51,9 +51,12 @@ class TestAmqpPeerRunner implements Runnable
 
     private volatile Throwable _throwable;
 
+    private boolean needClientCert;
+
     public TestAmqpPeerRunner(TestAmqpPeer peer, SSLContext sslContext, 
boolean needClientCert) throws IOException
     {
         int port = useFixedPort ? PORT : 0;
+        this.needClientCert = needClientCert;
 
         if (sslContext == null)
         {
@@ -65,7 +68,7 @@ class TestAmqpPeerRunner implements Runnable
             _serverSocket = socketFactory.createServerSocket(port);
 
             SSLServerSocket sslServerSocket = (SSLServerSocket) _serverSocket;
-            if (needClientCert)
+            if (this.needClientCert)
             {
                 sslServerSocket.setNeedClientAuth(true);
             }
@@ -210,4 +213,8 @@ class TestAmqpPeerRunner implements Runnable
     {
         _suppressReadExceptionOnClose = suppress;
     }
+
+    public boolean isNeedClientCert() {
+        return needClientCert;
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to