You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2015/06/02 16:51:56 UTC

qpid-jms git commit: QPIDJMS-65: dont use CRAM-MD5 or PLAIN if either a username and password have not actually been supplied

Repository: qpid-jms
Updated Branches:
  refs/heads/master 5c21506fc -> 7e831696c


QPIDJMS-65: dont use CRAM-MD5 or PLAIN if either a username and password have not actually been supplied


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

Branch: refs/heads/master
Commit: 7e831696cd9be6758642eb0d366dc59073e4b158
Parents: 5c21506
Author: Robert Gemmell <ro...@apache.org>
Authored: Tue Jun 2 15:44:44 2015 +0100
Committer: Robert Gemmell <ro...@apache.org>
Committed: Tue Jun 2 15:44:44 2015 +0100

----------------------------------------------------------------------
 .../provider/amqp/AmqpSaslAuthenticator.java    |  2 +-
 .../apache/qpid/jms/sasl/AbstractMechanism.java | 11 ---
 .../qpid/jms/sasl/AnonymousMechanism.java       |  5 ++
 .../apache/qpid/jms/sasl/CramMD5Mechanism.java  |  5 ++
 .../apache/qpid/jms/sasl/ExternalMechanism.java |  5 ++
 .../org/apache/qpid/jms/sasl/Mechanism.java     | 15 +---
 .../apache/qpid/jms/sasl/PlainMechanism.java    |  5 ++
 .../qpid/jms/sasl/SaslMechanismFinder.java      | 13 +++-
 .../jms/integration/SaslIntegrationTest.java    | 44 ++++++++++++
 .../qpid/jms/sasl/AnonymousMechanismTest.java   | 73 ++++++++++++++++++++
 .../qpid/jms/sasl/CramMD5MechanismTest.java     | 73 ++++++++++++++++++++
 .../qpid/jms/sasl/ExternalMechanismTest.java    | 73 ++++++++++++++++++++
 .../qpid/jms/sasl/PlainMechanismTest.java       | 73 ++++++++++++++++++++
 .../qpid/jms/test/testpeer/TestAmqpPeer.java    | 25 +++++++
 14 files changed, 394 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 49da083..75ea7cc 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
@@ -77,7 +77,7 @@ public class AmqpSaslAuthenticator {
         try {
             String[] remoteMechanisms = sasl.getRemoteMechanisms();
             if (remoteMechanisms != null && remoteMechanisms.length != 0) {
-                mechanism = SaslMechanismFinder.findMatchingMechanism(remoteMechanisms);
+                mechanism = SaslMechanismFinder.findMatchingMechanism(info.getUsername(), info.getPassword(), remoteMechanisms);
                 if (mechanism != null) {
                     mechanism.setUsername(info.getUsername());
                     mechanism.setPassword(info.getPassword());

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
index 91c3140..318cc2a 100644
--- a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
@@ -29,7 +29,6 @@ public abstract class AbstractMechanism implements Mechanism {
 
     private String username;
     private String password;
-    private Map<String, Object> properties = new HashMap<String, Object>();
 
     @Override
     public int compareTo(Mechanism other) {
@@ -64,16 +63,6 @@ public abstract class AbstractMechanism implements Mechanism {
     }
 
     @Override
-    public void setProperties(Map<String, Object> properties) {
-        this.properties = properties;
-    }
-
-    @Override
-    public Map<String, Object> getProperties() {
-        return this.properties;
-    }
-
-    @Override
     public String toString() {
         return "SASL-" + getName();
     }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 903a5fe..67ec880 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
@@ -40,4 +40,9 @@ public class AnonymousMechanism extends AbstractMechanism {
     public String getName() {
         return "ANONYMOUS";
     }
+
+    @Override
+    public boolean isApplicable(String username, String password) {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 448e01e..a920233 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
@@ -83,4 +83,9 @@ public class CramMD5Mechanism extends AbstractMechanism {
             return EMPTY;
         }
     }
+
+    @Override
+    public boolean isApplicable(String username, String password) {
+        return username != null && username.length() > 0 && password != null && password.length() > 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 5cca955..ebeff08 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
@@ -40,4 +40,9 @@ public class ExternalMechanism extends AbstractMechanism {
     public String getName() {
         return "EXTERNAL";
     }
+
+    @Override
+    public boolean isApplicable(String username, String password) {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 07dc495..fcd567f 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
@@ -113,19 +113,6 @@ public interface Mechanism extends Comparable<Mechanism> {
      */
     String getPassword();
 
-    /**
-     * Sets any additional Mechanism specific properties using a {@code Map<String, Object>}
-     *
-     * @param options
-     *        the map of additional properties that this Mechanism should utilize.
-     */
-    void setProperties(Map<String, Object> options);
-
-    /**
-     * The currently set Properties for this Mechanism.
-     *
-     * @return the current set of configuration Properties for this Mechanism.
-     */
-    Map<String, Object> getProperties();
+    boolean isApplicable(String username, String password);
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 11d3ec2..3ec3aef 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
@@ -59,4 +59,9 @@ public class PlainMechanism extends AbstractMechanism {
     public byte[] getChallengeResponse(byte[] challenge) {
         return EMPTY;
     }
+
+    @Override
+    public boolean isApplicable(String username, String password) {
+        return username != null && username.length() > 0 && password != null && password.length() > 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 ef2a64e..a6a3489 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
@@ -47,12 +47,16 @@ public class SaslMechanismFinder {
      * mechanisms from a remote peer.  Can return null if no matching Mechanisms are
      * found.
      *
+     * @param username
+     *        the username, or null if there is none
+     * @param password
+     *        the password, 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...remoteMechanisms) {
+    public static Mechanism findMatchingMechanism(String username, String password, String... remoteMechanisms) {
 
         Mechanism match = null;
         List<Mechanism> found = new ArrayList<Mechanism>();
@@ -60,7 +64,12 @@ public class SaslMechanismFinder {
         for (String remoteMechanism : remoteMechanisms) {
             MechanismFactory factory = findMechanismFactory(remoteMechanism);
             if (factory != null) {
-                found.add(factory.createMechanism());
+                Mechanism mech = factory.createMechanism();
+                if(mech.isApplicable(username, password)) {
+                    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/7e831696/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 03cc6b6..e19b380 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
@@ -21,17 +21,27 @@
 package org.apache.qpid.jms.integration;
 
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
 
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
 
 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.proton.amqp.Symbol;
 import org.junit.Test;
 
 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");
+
     @Test(timeout = 5000)
     public void testSaslExternalConnection() throws Exception {
         try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
@@ -99,4 +109,38 @@ public class SaslIntegrationTest extends QpidJmsTestCase {
             connection.close();
         }
     }
+
+    @Test(timeout = 5000)
+    public void testAnonymousSelectedWhenNoCredentialsWereSupplied() throws Exception {
+        doMechanismSelectedTestImpl(null, null, ANONYMOUS, new Symbol[] {CRAM_MD5, PLAIN, ANONYMOUS});
+    }
+
+    @Test(timeout = 5000)
+    public void testAnonymousSelectedWhenNoPasswordWasSupplied() throws Exception {
+        doMechanismSelectedTestImpl("username", null, ANONYMOUS, new Symbol[] {CRAM_MD5, PLAIN, ANONYMOUS});
+    }
+
+    @Test(timeout = 5000)
+    public void testCramMd5SelectedWhenCredentialsPresent() throws Exception {
+        doMechanismSelectedTestImpl("username", "password", CRAM_MD5, new Symbol[] {CRAM_MD5, PLAIN, ANONYMOUS});
+    }
+
+    private void doMechanismSelectedTestImpl(String username, String password, Symbol clientSelectedMech, Symbol[] serverMechs) throws JMSException, InterruptedException, Exception, IOException {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+
+            testPeer.expectFailingSaslConnect(serverMechs, clientSelectedMech);
+
+            ConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + "?jms.clientID=myclientid");
+            try {
+                factory.createConnection(username, password);
+                fail("Excepted exception to be thrown");
+            }catch (JMSSecurityException jmsse) {
+                // Expected, we deliberately failed the SASL process,
+                // we only wanted to verify the correct mechanism
+                // was selected, other tests verify the remainder.
+            }
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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
new file mode 100644
index 0000000..e1fa4b5
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AnonymousMechanismTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sasl;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class AnonymousMechanismTest {
+
+    @Test
+    public void testIsApplicableWithNoCredentials() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with no credentials", mech.isApplicable(null, null));
+    }
+
+    @Test
+    public void testIsNotApplicableWithNoUser() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with no username", mech.isApplicable(null, "pass"));
+    }
+
+    @Test
+    public void testIsApplicableWithNoPassword() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with no password", mech.isApplicable("user", null));
+    }
+
+    @Test
+    public void testIsApplicableWithEmtpyUser() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with empty username", mech.isApplicable("", "pass"));
+    }
+
+    @Test
+    public void testIsApplicableWithEmtpyPassword() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with empty password", mech.isApplicable("user", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithEmtpyUserAndPassword() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with empty user and password", mech.isApplicable("", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPassword() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be applicable with user and password", mech.isApplicable("user", "password"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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
new file mode 100644
index 0000000..de48830
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/CramMD5MechanismTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sasl;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class CramMD5MechanismTest {
+
+    @Test
+    public void testIsNotApplicableWithNoCredentials() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with no credentials", mech.isApplicable(null, null));
+    }
+
+    @Test
+    public void testIsNotApplicableWithNoUser() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with no username", mech.isApplicable(null, "pass"));
+    }
+
+    @Test
+    public void testIsNotApplicableWithNoPassword() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with no password", mech.isApplicable("user", null));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyUser() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with empty username", mech.isApplicable("", "pass"));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyPassword() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with empty password", mech.isApplicable("user", ""));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyUserAndPassword() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertFalse("Should not be applicable with empty user and password", mech.isApplicable("", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPassword() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertTrue("Should be applicable with user and password", mech.isApplicable("user", "password"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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
new file mode 100644
index 0000000..57a0d5f
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ExternalMechanismTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sasl;
+
+import static org.junit.Assert.*;
+
+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() {
+        ExternalMechanism mech = new ExternalMechanism();
+
+        assertTrue("Should be applicable with empty password", mech.isApplicable("user", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithEmtpyUserAndPassword() {
+        ExternalMechanism mech = new ExternalMechanism();
+
+        assertTrue("Should be applicable with empty user and password", mech.isApplicable("", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPassword() {
+        ExternalMechanism mech = new ExternalMechanism();
+
+        assertTrue("Should be applicable with user and password", mech.isApplicable("user", "password"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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
new file mode 100644
index 0000000..cc76880
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/PlainMechanismTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sasl;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class PlainMechanismTest {
+
+    @Test
+    public void testIsNotApplicableWithNoCredentials() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with no credentials", mech.isApplicable(null, null));
+    }
+
+    @Test
+    public void testIsNotApplicableWithNoUser() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with no username", mech.isApplicable(null, "pass"));
+    }
+
+    @Test
+    public void testIsNotApplicableWithNoPassword() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with no password", mech.isApplicable("user", null));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyUser() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with empty username", mech.isApplicable("", "pass"));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyPassword() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with empty password", mech.isApplicable("user", ""));
+    }
+
+    @Test
+    public void testIsNotApplicableWithEmtpyUserAndPassword() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertFalse("Should not be applicable with empty user and password", mech.isApplicable("", ""));
+    }
+
+    @Test
+    public void testIsApplicableWithUserAndPassword() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertTrue("Should be applicable with user and password", mech.isApplicable("user", "password"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/7e831696/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 186f4b3..219b7e8 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
@@ -364,6 +364,31 @@ public class TestAmqpPeer implements AutoCloseable
         return openFrame;
     }
 
+    public void expectFailingSaslConnect(Symbol[] serverMechs, Symbol clientSelectedMech)
+    {
+        SaslMechanismsFrame saslMechanismsFrame = new SaslMechanismsFrame().setSaslServerMechanisms(serverMechs);
+        addHandler(new HeaderHandlerImpl(AmqpHeader.SASL_HEADER, AmqpHeader.SASL_HEADER,
+                                            new FrameSender(
+                                                    this, FrameType.SASL, 0,
+                                                    saslMechanismsFrame, null)));
+
+        SaslInitMatcher saslInitMatcher = new SaslInitMatcher().withMechanism(equalTo(clientSelectedMech));
+        saslInitMatcher.onSuccess(new AmqpPeerRunnable()
+        {
+            @Override
+            public void run()
+            {
+                TestAmqpPeer.this.sendFrame(
+                        FrameType.SASL, 0,
+                        new SaslOutcomeFrame().setCode(UnsignedByte.valueOf((byte)1)),
+                        null,
+                        false);
+                _driverRunnable.expectHeader();
+            }
+        });
+        addHandler(saslInitMatcher);
+    }
+
     public void expectAnonymousConnect(boolean authorize)
     {
         expectAnonymousConnect(authorize, null);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org