QPIDJMS-303: updates to round out GSSAPI/Kerberos authentication handling

-Consolidate around login module config file, simplify options handling.
-Updates to support for passing credentials via URI/ConnectionFactory.
-Only allow the mechanism to be selected if configured to enable it.
-Improve handling of init-failure due to e.g config issues.
-Tests rework, e.g. reuse mini-kdc etc for efficiency, move temp state to 
ensure cleanup, drop unused dep, additional handling in testpeer.


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

Branch: refs/heads/master
Commit: ce833c7b6d72fcff3a5517ede0a22094c86d726a
Parents: 6dff7ac
Author: Robert Gemmell <rob...@apache.org>
Authored: Mon Jul 31 18:22:17 2017 +0100
Committer: Robert Gemmell <rob...@apache.org>
Committed: Mon Jul 31 18:22:17 2017 +0100

----------------------------------------------------------------------
 pom.xml                                         |   7 -
 qpid-jms-client/pom.xml                         |   6 -
 .../qpid/jms/provider/amqp/AmqpProvider.java    |  20 ++-
 .../provider/amqp/AmqpSaslAuthenticator.java    |   2 +-
 .../apache/qpid/jms/sasl/AbstractMechanism.java |  11 ++
 .../apache/qpid/jms/sasl/GssapiMechanism.java   |  86 +++++-----
 .../org/apache/qpid/jms/sasl/Mechanism.java     |  16 ++
 .../qpid/jms/sasl/SaslMechanismFinder.java      |  10 +-
 .../integration/SaslGssApiIntegrationTest.java  | 161 ++++++++++++-------
 .../qpid/jms/sasl/AbstractMechanismTest.java    |   5 +
 .../qpid/jms/sasl/AnonymousMechanismTest.java   |   7 +
 .../qpid/jms/sasl/CramMD5MechanismTest.java     |   7 +
 .../qpid/jms/sasl/ExternalMechanismTest.java    |   7 +
 .../qpid/jms/sasl/GssapiMechanismTest.java      |  39 +++++
 .../qpid/jms/sasl/PlainMechanismTest.java       |   7 +
 .../qpid/jms/sasl/ScramSHA1MechanismTest.java   |  11 ++
 .../qpid/jms/sasl/ScramSHA256MechanismTest.java |  11 ++
 .../qpid/jms/test/testpeer/TestAmqpPeer.java    |  85 ++++++----
 .../jms/test/testpeer/TestAmqpPeerRunner.java   |   2 +-
 .../SaslGssApiIntegrationTest-login.config      |  21 ++-
 20 files changed, 356 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index bace1ac..c912587 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,7 +55,6 @@
     <mockito-version>1.10.19</mockito-version>
     <hamcrest-version>1.3</hamcrest-version>
     <hadoop-minikdc-version>2.8.1</hadoop-minikdc-version>
-    <directory-jdbm2-version>2.0.0-M3</directory-jdbm2-version>
 
     <!-- Maven Plugin Versions for this Project -->
     <maven-javacc-plugin-version>2.6</maven-javacc-plugin-version>
@@ -188,12 +187,6 @@
         <version>${hadoop-minikdc-version}</version>
         <scope>test</scope>
       </dependency>
-      <dependency>
-        <groupId>org.apache.directory.jdbm</groupId>
-        <artifactId>apacheds-jdbm2</artifactId>
-        <version>${directory-jdbm2-version}</version>
-        <scope>test</scope>
-      </dependency>
     </dependencies>
   </dependencyManagement>
 

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-client/pom.xml b/qpid-jms-client/pom.xml
index 7e6e971..b825bb9 100644
--- a/qpid-jms-client/pom.xml
+++ b/qpid-jms-client/pom.xml
@@ -98,12 +98,6 @@
       <artifactId>hadoop-minikdc</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.apache.directory.jdbm</groupId>
-      <artifactId>apacheds-jdbm2</artifactId>
-      <scope>test</scope>
-    </dependency>
-
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 abedabc..16a82a0 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
@@ -19,6 +19,7 @@ package org.apache.qpid.jms.provider.amqp;
 import java.io.IOException;
 import java.net.URI;
 import java.nio.ByteBuffer;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -1383,18 +1384,15 @@ public class AmqpProvider implements Provider, 
TransportListener , AmqpResourceP
             mechanism.setUsername(connectionInfo.getUsername());
             mechanism.setPassword(connectionInfo.getPassword());
 
-            if (GssapiMechanism.NAME.equals(mechanism.getName())) {
-                try {
-                    Map<String, String> props =
-                            
PropertyUtil.filterProperties(PropertyUtil.parseQuery(getRemoteURI()), "sasl.");
-                    if (!props.containsKey("serverName")) {
-                        props.put("serverName", remoteURI.getHost());
-                    }
-                    PropertyUtil.setProperties(mechanism, props);
-                    PropertyUtil.setProperty(mechanism, "options", props);
-                } catch (Exception badConfig) {
-                    throw new RuntimeException("Failed to apply sasl url 
params to mechanism: " + mechanism.getName() + ", reason: " + 
badConfig.toString(), badConfig);
+            try {
+                Map<String, String> saslOptions = 
PropertyUtil.filterProperties(PropertyUtil.parseQuery(getRemoteURI()), 
"sasl.options.");
+                if (!saslOptions.containsKey("serverName")) {
+                    saslOptions.put("serverName", remoteURI.getHost());
                 }
+
+                mechanism.init(Collections.unmodifiableMap(saslOptions));
+            } catch (Exception ex) {
+                throw new RuntimeException("Failed to apply sasl options to 
mechanism: " + mechanism.getName() + ", reason: " + ex.toString(), ex);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 bac8e3e..584dc6d 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
@@ -99,11 +99,11 @@ public class AmqpSaslAuthenticator {
             if (remoteMechanisms != null && remoteMechanisms.length != 0) {
                 mechanism = mechanismFinder.apply(remoteMechanisms);
                 if (mechanism != null) {
-                    sasl.setMechanisms(mechanism.getName());
                     byte[] response = mechanism.getInitialResponse();
                     if (response != null) {
                         sasl.send(response, 0, response.length);
                     }
+                    sasl.setMechanisms(mechanism.getName());
                 } else {
                     recordFailure("Could not find a suitable SASL mechanism 
for the remote peer using the available credentials.", null);
                 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 783029c..098f3e5 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
@@ -16,6 +16,8 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import java.util.Map;
+
 import javax.security.sasl.SaslException;
 
 /**
@@ -30,6 +32,10 @@ public abstract class AbstractMechanism implements Mechanism 
{
     private String password;
 
     @Override
+    public void init(Map<String, String> options) {
+    }
+
+    @Override
     public void verifyCompletion() throws SaslException {
     }
 
@@ -68,4 +74,9 @@ public abstract class AbstractMechanism implements Mechanism {
     public String toString() {
         return "SASL-" + getName();
     }
+
+    @Override
+    public boolean isEnabledByDefault() {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/GssapiMechanism.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/GssapiMechanism.java 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/GssapiMechanism.java
index e2644f8..86627fe 100644
--- 
a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/GssapiMechanism.java
+++ 
b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/GssapiMechanism.java
@@ -19,16 +19,20 @@ package org.apache.qpid.jms.sasl;
 import org.apache.qpid.jms.util.PropertyUtil;
 
 import javax.security.auth.Subject;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.Configuration;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.LoginContext;
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslClient;
 import javax.security.sasl.SaslException;
+
+import java.io.IOException;
 import java.security.Principal;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
-import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -37,12 +41,12 @@ import java.util.Map;
 public class GssapiMechanism extends AbstractMechanism {
 
     public static final String NAME = "GSSAPI";
+
     private Subject subject;
     private SaslClient saslClient;
     private String protocol = "amqp";
     private String serverName = null;
-    private String configScope = null;
-    private Map<String, String> options = new HashMap<String, String>();
+    private String configScope = "amqp-jms-client";
 
     // a gss/sasl service name, x@y, morphs to a krbPrincipal a/y@REALM
 
@@ -57,16 +61,22 @@ public class GssapiMechanism extends AbstractMechanism {
     }
 
     @Override
+    public boolean isEnabledByDefault() {
+        // Only enable if given explicit configuration to do so, as we can't 
discern here
+        // whether the external configuration is appropriately set to actually 
allow its use.
+        return false;
+    }
+
+    @Override
+    public void init(Map<String, String> saslOptions) {
+        PropertyUtil.setProperties(this, saslOptions);
+    }
+
+    @Override
     public byte[] getInitialResponse() throws SaslException {
         try {
-            LoginContext loginContext = null;
-            if (configScope != null) {
-                loginContext = new LoginContext(configScope);
-            } else {
-                // inline keytab config using user as principal
-                loginContext = new LoginContext("", null, null,
-                        kerb5InlineConfig(getUsername(), options));
-            }
+            LoginContext loginContext = new LoginContext(configScope, new 
CredentialCallbackHandler());;
+
             loginContext.login();
             subject = loginContext.getSubject();
 
@@ -109,39 +119,11 @@ public class GssapiMechanism extends AbstractMechanism {
         }
     }
 
-
     @Override
     public boolean isApplicable(String username, String password, Principal 
localPrincipal) {
         return true;
     }
 
-    public static Configuration kerb5InlineConfig(String principal, final 
Map<String, String> userOptions) {
-        final Map<String, String> options = new HashMap<>();
-        options.put("principal", principal);
-        options.put("useKeyTab", "true");
-        options.put("storeKey", "true");
-        String ticketCache = System.getenv("KRB5CCNAME");
-        if (ticketCache != null) {
-            options.put("ticketCache", ticketCache);
-        }
-        options.putAll(PropertyUtil.filterProperties(userOptions, "krb5."));
-        return new Configuration() {
-            @Override
-            public AppConfigurationEntry[] getAppConfigurationEntry(String 
name) {
-                return new AppConfigurationEntry[]{
-                        new AppConfigurationEntry(getKrb5LoginModuleName(),
-                                
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
-                                options)};
-            }
-        };
-    }
-
-    private static final boolean IBM_JAVA =  
System.getProperty("java.vendor").contains("IBM");
-    private static String getKrb5LoginModuleName() {
-        return IBM_JAVA ? "com.ibm.security.auth.module.Krb5LoginModule"
-                : "com.sun.security.auth.module.Krb5LoginModule";
-    }
-
     public String getProtocol() {
         return protocol;
     }
@@ -166,11 +148,23 @@ public class GssapiMechanism extends AbstractMechanism {
         this.configScope = configScope;
     }
 
-    public Map<String, String> getOptions() {
-        return options;
-    }
+    private class CredentialCallbackHandler implements CallbackHandler {
 
-    public void setOptions(Map<String, String> options) {
-        this.options = options;
+        @Override
+        public void handle(Callback[] callbacks) throws IOException, 
UnsupportedCallbackException {
+            for (int i = 0; i < callbacks.length; i++) {
+                Callback cb = callbacks[i];
+                if (cb instanceof NameCallback) {
+                    ((NameCallback) cb).setName(getUsername());
+                } else if (cb instanceof PasswordCallback) {
+                    String pass = getPassword();
+                    if (pass != null) {
+                        ((PasswordCallback) 
cb).setPassword(pass.toCharArray());
+                    }
+                } else {
+                    throw new UnsupportedCallbackException(cb);
+                }
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 ca8225d..53e71f2 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
@@ -17,6 +17,7 @@
 package org.apache.qpid.jms.sasl;
 
 import java.security.Principal;
+import java.util.Map;
 
 import javax.security.sasl.SaslException;
 
@@ -62,6 +63,14 @@ public interface Mechanism extends Comparable<Mechanism> {
     String getName();
 
     /**
+     * Perform any configuration initiation required by the mechanism.
+     *
+     * @param options
+     *        An immutable map of sasl options. Will always be non-null.
+     */
+    void init(Map<String, String> options);
+
+    /**
      * Create an initial response based on selected mechanism.
      *
      * May be null if there is no initial response.
@@ -139,4 +148,11 @@ public interface Mechanism extends Comparable<Mechanism> {
      */
     boolean isApplicable(String username, String password, Principal 
localPrincipal);
 
+    /**
+     * Allows the mechanism to indicate if it is enabled by default, or only 
when explicitly enabled
+     * through configuring the permitted sasl mechanisms.
+     *
+     * @return true if this Mechanism is enabled by default.
+     */
+    boolean isEnabledByDefault();
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 6ca6b9b..ce09489 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
@@ -73,10 +73,16 @@ public class SaslMechanismFinder {
             MechanismFactory factory = findMechanismFactory(remoteMechanism);
             if (factory != null) {
                 Mechanism mech = factory.createMechanism();
-                if(mechRestrictions != null && 
!mechRestrictions.contains(remoteMechanism)) {
+
+                boolean mechConfigured = mechRestrictions != null && 
mechRestrictions.contains(remoteMechanism);
+                if(mechRestrictions != null && !mechConfigured) {
                     LOG.debug("Skipping {} mechanism because it is not in the 
configured mechanisms restriction set", remoteMechanism);
                 } else if(mech.isApplicable(username, password, 
localPrincipal)) {
-                    found.add(mech);
+                    if(mech.isEnabledByDefault() || mechConfigured) {
+                        found.add(mech);
+                    } else {
+                        LOG.debug("Skipping {} mechanism as it must be 
explicitly enabled in the configured sasl mechanisms", 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/ce833c7b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslGssApiIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslGssApiIntegrationTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslGssApiIntegrationTest.java
index 60f8c73..bcbb060 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslGssApiIntegrationTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SaslGssApiIntegrationTest.java
@@ -27,9 +27,10 @@ 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.After;
+import org.junit.AfterClass;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,6 +39,7 @@ import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.JMSSecurityException;
 import java.io.File;
+import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
@@ -49,34 +51,40 @@ public class SaslGssApiIntegrationTest extends 
QpidJmsTestCase {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(SaslGssApiIntegrationTest.class);
 
-    private static final Symbol GSSAPI = Symbol.valueOf("GSSAPI");
-    private static final String serviceName = "amqp/localhost";
-
-    private MiniKdc kdc;
-    private final boolean debug = false;
-
-    @Before
-    public void setUpKerberos() throws Exception {
-
-        // login.config or url overrides necessary for the IBM krb5 login 
module
-        Assume.assumeFalse(System.getProperty("java.vendor").contains("IBM"));
-
-        Path tempDirectory = 
Files.createTempDirectory("junit.SaslGssApiIntegrationTest.");
+    private static final String LOGIN_CONFIG = 
"SaslGssApiIntegrationTest-login.config";
+    private static final String GSSAPI = "GSSAPI";
+    private static final Symbol ANONYMOUS = Symbol.valueOf("ANONYMOUS");
+    private static final Symbol PLAIN = Symbol.valueOf("PLAIN");
+    private static final String KRB5_KEYTAB = 
"target/SaslGssApiIntegrationTest.krb5.keytab";
+    private static final String SERVICE_PRINCIPAL = "amqp/localhost";
+    private static final String CLIENT_PRINCIPAL_LOGIN_CONFIG = 
"clientprincipal";
+    private static final String CLIENT_PRINCIPAL_FACTORY_USERNAME = 
"factoryusername";
+    private static final String CLIENT_PRINCIPAL_URI_USERNAME = "uriusername";
+    private static final String CLIENT_PRINCIPAL_DEFAULT_CONFIG_SCOPE = 
"defaultscopeprincipal";
+
+    private static MiniKdc kdc;
+    private static final boolean DEBUG = false;
+
+    @BeforeClass
+    public static void setUpKerberos() throws Exception {
+        Path targetDir = FileSystems.getDefault().getPath("target");
+        Path tempDirectory = Files.createTempDirectory(targetDir, 
"junit.SaslGssApiIntegrationTest.");
         File root = tempDirectory.toFile();
-        root.deleteOnExit();
+
         kdc = new MiniKdc(MiniKdc.createConf(), new File(root, "kdc"));
         kdc.start();
 
         // hard coded match, default_keytab_name in minikdc-krb5.conf template
-        File userKeyTab = new 
File("target/SaslGssApiIntegrationTest.krb5.keytab");
-        kdc.createPrincipal(userKeyTab, "client", serviceName);
+        File userKeyTab = new File(KRB5_KEYTAB);
+        kdc.createPrincipal(userKeyTab, CLIENT_PRINCIPAL_LOGIN_CONFIG, 
CLIENT_PRINCIPAL_FACTORY_USERNAME,
+                CLIENT_PRINCIPAL_URI_USERNAME, 
CLIENT_PRINCIPAL_DEFAULT_CONFIG_SCOPE, SERVICE_PRINCIPAL);
 
         Keytab kt = Keytab.read(userKeyTab);
         for (KeytabEntry entry : kt.getEntries()) {
             LOG.info("KeyTab Kerb PrincipalNames:" + entry.getPrincipalName());
         }
 
-        if (debug) {
+        if (DEBUG) {
             java.util.logging.Logger logger = 
java.util.logging.Logger.getLogger("javax.security.sasl");
             logger.setLevel(java.util.logging.Level.FINEST);
             logger.addHandler(new java.util.logging.ConsoleHandler());
@@ -86,50 +94,51 @@ public class SaslGssApiIntegrationTest extends 
QpidJmsTestCase {
         }
     }
 
-    @After
-    public void stopKDC() throws Exception {
+    @AfterClass
+    public static void cleanUpKerberos() {
         if (kdc != null) {
             kdc.stop();
         }
     }
 
-    @Test(timeout = 20000)
-    public void testSaslGssApiKrbConnection() throws Exception {
-        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
-
-            testPeer.expectSaslGSSAPI(serviceName);
-            testPeer.expectOpen();
-
-            // Each connection creates a session for managing temporary 
destinations etc
-            testPeer.expectBegin();
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
 
-            String uriOptions = "?amqp.saslMechanisms=" + GSSAPI.toString();
-            ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
-            Connection connection = factory.createConnection("client", null);
-            // Set a clientID to provoke the actual AMQP connection process to 
occur.
-            connection.setClientID("clientName");
+        Assume.assumeFalse(System.getProperty("java.vendor").contains("IBM"));
 
-            testPeer.waitForAllHandlersToComplete(1000);
-            assertNull(testPeer.getThrowable());
+        // NOTE: we may need to isolate this test later if we use login.config 
in others
+        setTestSystemProperty("java.security.auth.login.config",
+                
SaslGssApiIntegrationTest.class.getClassLoader().getResource(LOGIN_CONFIG).getPath());
+    }
 
-            testPeer.expectClose();
-            connection.close();
-        }
+    @Test(timeout = 20000)
+    public void testSaslGssApiKrbConnection() throws Exception {
+        doSaslGssApiKrbConnectionTestImpl("KRB5-CLIENT", 
CLIENT_PRINCIPAL_LOGIN_CONFIG + "@EXAMPLE.COM");
     }
 
     @Test(timeout = 20000)
-    public void testSaslGssApiKrbConnectionJmsUser() throws Exception {
+    public void testSaslGssApiKrbConnectionWithDefaultScope() throws Exception 
{
+        doSaslGssApiKrbConnectionTestImpl(null, 
CLIENT_PRINCIPAL_DEFAULT_CONFIG_SCOPE + "@EXAMPLE.COM");
+    }
+
+    private void doSaslGssApiKrbConnectionTestImpl(String configScope, String 
clientAuthIdAtServer) throws Exception {
         try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
 
-            testPeer.expectSaslGSSAPI(serviceName);
+            testPeer.expectSaslGSSAPI(SERVICE_PRINCIPAL, KRB5_KEYTAB, 
clientAuthIdAtServer);
             testPeer.expectOpen();
 
             // Each connection creates a session for managing temporary 
destinations etc
             testPeer.expectBegin();
 
-            String uriOptions = "?jms.username=client&amqp.saslMechanisms=" + 
GSSAPI.toString();
+            String uriOptions = "?amqp.saslMechanisms=" + GSSAPI;
+            if(configScope != null) {
+                uriOptions += "&sasl.options.configScope=" + configScope;
+            }
+
             ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
-            Connection connection = factory.createConnection();
+            Connection connection = 
factory.createConnection("ignoredusername", null);
             // Set a clientID to provoke the actual AMQP connection process to 
occur.
             connection.setClientID("clientName");
 
@@ -142,18 +151,22 @@ public class SaslGssApiIntegrationTest extends 
QpidJmsTestCase {
     }
 
     @Test(timeout = 20000)
-    public void testSaslGssApiKrb5ConfigOptionOverridePrincipal() throws 
Exception {
+    public void testSaslGssApiKrbConnectionWithPrincipalViaJmsUsernameUri() 
throws Exception {
         try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
 
-            testPeer.expectSaslGSSAPI(serviceName);
+            testPeer.expectSaslGSSAPI(SERVICE_PRINCIPAL, KRB5_KEYTAB, 
CLIENT_PRINCIPAL_URI_USERNAME + "@EXAMPLE.COM");
             testPeer.expectOpen();
 
             // Each connection creates a session for managing temporary 
destinations etc
             testPeer.expectBegin();
 
-            String uriOptions = 
"?jms.username=getsOverridden&sasl.krb5.principal=client&amqp.saslMechanisms=" 
+ GSSAPI.toString();
+            // No password, not needed as using keyTab.
+            String uriOptions = 
"?sasl.options.configScope=KRB5-CLIENT-URI-USERNAME-CALLBACK&jms.username="
+                                + CLIENT_PRINCIPAL_URI_USERNAME 
+"&amqp.saslMechanisms=" + GSSAPI;
             ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
+
             Connection connection = factory.createConnection();
+
             // Set a clientID to provoke the actual AMQP connection process to 
occur.
             connection.setClientID("clientName");
 
@@ -165,23 +178,22 @@ public class SaslGssApiIntegrationTest extends 
QpidJmsTestCase {
         }
     }
 
-
-
     @Test(timeout = 20000)
-    public void testSaslGssApiKrbConfigConnection() throws Exception {
-        setTestSystemProperty("java.security.auth.login.config",
-                
SaslGssApiIntegrationTest.class.getClassLoader().getResource("SaslGssApiIntegrationTest-login.config").getPath());
+    public void 
testSaslGssApiKrbConnectionWithPrincipalViaJmsUsernameConnFactory() throws 
Exception {
         try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
 
-            testPeer.expectSaslGSSAPI(serviceName);
+            testPeer.expectSaslGSSAPI(SERVICE_PRINCIPAL, KRB5_KEYTAB, 
CLIENT_PRINCIPAL_FACTORY_USERNAME + "@EXAMPLE.COM");
             testPeer.expectOpen();
 
             // Each connection creates a session for managing temporary 
destinations etc
             testPeer.expectBegin();
 
-            String uriOptions = 
"?sasl.configScope=KRB5-CLIENT&sasl.protocol=amqp&sasl.server=localhost&amqp.saslMechanisms="
 + GSSAPI.toString();
+            String uriOptions = 
"?sasl.options.configScope=KRB5-CLIENT-FACTORY-USERNAME-CALLBACK" + 
"&amqp.saslMechanisms=" + GSSAPI;
             ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
-            Connection connection = factory.createConnection();
+
+            // No password, not needed as using keyTab.
+            Connection connection = 
factory.createConnection(CLIENT_PRINCIPAL_FACTORY_USERNAME, null);
+
             // Set a clientID to provoke the actual AMQP connection process to 
occur.
             connection.setClientID("clientName");
 
@@ -196,22 +208,49 @@ public class SaslGssApiIntegrationTest extends 
QpidJmsTestCase {
     @Test(timeout = 20000)
     public void testSaslGssApiKrbConfigError() throws Exception {
         final String loginConfigScope = "KRB5-CLIENT-DOES-NOT-EXIST";
-        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
 
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
             testPeer.expectSaslGSSAPIFail();
 
-            String uriOptions = "?sasl.configScope=" + loginConfigScope + 
"&sasl.protocol=amqp&sasl.server=localhost&amqp.saslMechanisms=" + 
GSSAPI.toString();
+            String uriOptions = "?sasl.options.configScope=" + 
loginConfigScope + "&amqp.saslMechanisms=" + GSSAPI;
             ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
-            Connection connection = factory.createConnection();
-            // Set a clientID to provoke the actual AMQP connection process to 
occur.
-            connection.setClientID("clientName");
+            factory.createConnection();
 
-            testPeer.expectClose();
-            connection.close();
             fail("Expect exception on no login config");
         } catch (JMSSecurityException expected) {
             assertTrue(expected.getMessage().contains(loginConfigScope));
         }
     }
 
+    @Test(timeout = 20000)
+    public void testGssapiOnlySelectedWhenPresentIfExplicitlyEnabled() throws 
Exception {
+        doMechanismSelectedTestImpl("username", "password", PLAIN, new 
Symbol[] {Symbol.valueOf(GSSAPI), PLAIN, ANONYMOUS}, false);
+        doMechanismSelectedTestImpl("username", "password", 
Symbol.valueOf(GSSAPI), new Symbol[] {Symbol.valueOf(GSSAPI), PLAIN, 
ANONYMOUS}, true);
+    }
+
+    private void doMechanismSelectedTestImpl(String username, String password, 
Symbol clientSelectedMech, Symbol[] serverMechs, boolean 
enableGssapiExplicitly) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer();) {
+
+            testPeer.expectFailingSaslAuthentication(serverMechs, 
clientSelectedMech);
+
+            String uriOptions = "?jms.clientID=myclientid";
+            if(enableGssapiExplicitly) {
+                uriOptions += "&amqp.saslMechanisms=PLAIN," + GSSAPI;
+            }
+            ConnectionFactory factory = new 
JmsConnectionFactory("amqp://localhost:" + testPeer.getServerPort() + 
uriOptions);
+
+            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.
+
+                LOG.info("Caught expected security exception: {}", 
jmsse.getMessage());
+            }
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AbstractMechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AbstractMechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AbstractMechanismTest.java
index 768cc74..bbacf02 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AbstractMechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/AbstractMechanismTest.java
@@ -68,5 +68,10 @@ public class AbstractMechanismTest {
         public boolean isApplicable(String username, String password, 
Principal localPrincipal) {
             return false;
         }
+
+        @Override
+        public boolean isEnabledByDefault() {
+            return false;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 82b686f..9c9da7c 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
@@ -103,4 +103,11 @@ public class AnonymousMechanismTest {
             }
         }));
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        AnonymousMechanism mech = new AnonymousMechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 1a6149f..3110147 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
@@ -85,4 +85,11 @@ public class CramMD5MechanismTest {
             }
         }));
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        CramMD5Mechanism mech = new CramMD5Mechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 ab613b9..bb9142f 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
@@ -74,4 +74,11 @@ public class ExternalMechanismTest {
             }
         }));
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        ExternalMechanism mech = new ExternalMechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/GssapiMechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/GssapiMechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/GssapiMechanismTest.java
new file mode 100644
index 0000000..713ebd4
--- /dev/null
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/GssapiMechanismTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class GssapiMechanismTest {
+
+    @Test
+    public void testIsApplicableWithoutCredentials() {
+        GssapiMechanism mech = new GssapiMechanism();
+
+        assertTrue("Should be applicable without credentials", 
mech.isApplicable(null, null, null));
+    }
+
+    @Test
+    public void testIsNotEnabledByDefault() {
+        GssapiMechanism mech = new GssapiMechanism();
+
+        assertFalse("Should not be enabled by default", 
mech.isEnabledByDefault());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 ac03286..808c7df 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
@@ -104,4 +104,11 @@ public class PlainMechanismTest {
             }
         }));
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        PlainMechanism mech = new PlainMechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA1MechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA1MechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA1MechanismTest.java
index 094e78b..0011fb8 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA1MechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA1MechanismTest.java
@@ -16,6 +16,10 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
 /**
  * The known good used by these tests is taken from the example in RFC 5802 
section 5.
  */
@@ -46,4 +50,11 @@ public class ScramSHA1MechanismTest extends 
AbstractScramSHAMechanismTestBase {
         mech.setPassword(PASSWORD);
         return mech;
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        ScramSHA1Mechanism mech = new ScramSHA1Mechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA256MechanismTest.java
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA256MechanismTest.java
 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA256MechanismTest.java
index e917e58..945fcd7 100644
--- 
a/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA256MechanismTest.java
+++ 
b/qpid-jms-client/src/test/java/org/apache/qpid/jms/sasl/ScramSHA256MechanismTest.java
@@ -16,6 +16,10 @@
  */
 package org.apache.qpid.jms.sasl;
 
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
 /**
  * The known good used by these tests is taken from the example in RFC 7677 
section 3.
  */
@@ -46,4 +50,11 @@ public class ScramSHA256MechanismTest extends 
AbstractScramSHAMechanismTestBase
         mech.setPassword(PASSWORD);
         return mech;
     }
+
+    @Test
+    public void testIsEnabledByDefault() {
+        ScramSHA256Mechanism mech = new ScramSHA256Mechanism();
+
+        assertTrue("Should be enabled by default", mech.isEnabledByDefault());
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 da1e69a..ffbafa7 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
@@ -21,7 +21,6 @@ package org.apache.qpid.jms.test.testpeer;
 import static 
org.apache.qpid.jms.provider.amqp.AmqpSupport.DYNAMIC_NODE_LIFETIME_POLICY;
 import static org.apache.qpid.jms.provider.amqp.AmqpSupport.GLOBAL;
 import static org.apache.qpid.jms.provider.amqp.AmqpSupport.SHARED;
-import static org.apache.qpid.jms.sasl.GssapiMechanism.kerb5InlineConfig;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.arrayContaining;
 import static org.hamcrest.Matchers.equalTo;
@@ -49,6 +48,8 @@ import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
 import javax.security.auth.login.LoginContext;
 import javax.security.sasl.AuthorizeCallback;
 import javax.security.sasl.Sasl;
@@ -520,12 +521,9 @@ public class TestAmqpPeer implements AutoCloseable
                 new FrameSender(
                         this, FrameType.SASL, 0,
                         saslMechanismsFrame, null)));
-
-        addHandler(new SaslInitMatcher().withMechanism(equalTo(GSSAPI)));
-
     }
 
-    public void expectSaslGSSAPI(String serviceName) throws Exception {
+    public void expectSaslGSSAPI(String serviceName, String keyTab, String 
clientAuthId) throws Exception {
 
         SaslMechanismsFrame saslMechanismsFrame = new 
SaslMechanismsFrame().setSaslServerMechanisms(GSSAPI);
 
@@ -534,18 +532,30 @@ public class TestAmqpPeer implements AutoCloseable
                         this, FrameType.SASL, 0,
                         saslMechanismsFrame, null)));
 
+        // setup server gss context
         final Map<String, String> options = new HashMap<>();
+        options.put("principal", serviceName);
+        options.put("useKeyTab", "true");
+        options.put("keyTab", keyTab);
+        options.put("storeKey", "true");
         options.put("isInitiator", "false");
+        Configuration loginCconfiguration = new Configuration() {
+            @Override
+            public AppConfigurationEntry[] getAppConfigurationEntry(String 
name) {
+                return new AppConfigurationEntry[]{
+                        new 
AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
+                                
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                                options)};
+            }
+        };
 
-        // setup server gss context
-        LoginContext loginContext = new LoginContext("", null, null,
-                kerb5InlineConfig(serviceName, options));
+        LoginContext loginContext = new LoginContext("", null, null, 
loginCconfiguration);
         loginContext.login();
         final Subject serverSubject =loginContext.getSubject();
 
         LOGGER.info("saslServer subject:" + 
serverSubject.getPrivateCredentials());
 
-        Map<String, ?> config = new HashMap();
+        Map<String, ?> config = new HashMap<>();
         final CallbackHandler handler = new CallbackHandler() {
             @Override
             public void handle(Callback[] callbacks) throws IOException, 
UnsupportedCallbackException {
@@ -613,9 +623,8 @@ public class TestAmqpPeer implements AutoCloseable
                     }
                 });
 
-        AtomicBoolean response = new AtomicBoolean(false);
-        SaslResponseMatcher challengeMatcher = new 
SaslResponseMatcher().withResponse(new BaseMatcher<Binary>() {
-
+        AtomicBoolean succeeded = new AtomicBoolean(false);
+        SaslResponseMatcher responseMatcher = new 
SaslResponseMatcher().withResponse(new BaseMatcher<Binary>() {
             @Override
             public void describeTo(Description description) {}
 
@@ -623,8 +632,10 @@ public class TestAmqpPeer implements AutoCloseable
             public boolean matches(Object o) {
                 final Binary binary = (Binary) o;
                 // validate via sasl
+
+                byte[] additionalData = null;
                 try {
-                    Subject.doAs(serverSubject, new 
PrivilegedExceptionAction<byte[]>() {
+                    additionalData = Subject.doAs(serverSubject, new 
PrivilegedExceptionAction<byte[]>() {
                         @Override
                         public byte[] run() throws Exception {
                             LOGGER.info("Evaluate response.. size:" + 
binary.getLength());
@@ -635,32 +646,48 @@ public class TestAmqpPeer implements AutoCloseable
                     e.printStackTrace();
                     throw new RuntimeException("failed to evaluate challenge 
response", e);
                 }
-                LOGGER.info("Complete:" + saslServer.isComplete());
-                return saslServer.isComplete();
+
+                boolean complete = saslServer.isComplete();
+                boolean expectedAuthId = false;
+                if(complete) {
+                    expectedAuthId = 
clientAuthId.equals(saslServer.getAuthorizationID());
+                    LOGGER.info("Authorized ID: " + 
saslServer.getAuthorizationID());
+                }
+
+                LOGGER.info("Complete:" + complete + ", expectedAuthID:" + 
expectedAuthId +", additionalData:" + additionalData);
+
+                if(complete && expectedAuthId && additionalData == null) {
+                    succeeded.set(true);
+                    return true;
+                } else {
+                    return false;
+                }
             }
         }).onCompletion(new AmqpPeerRunnable() {
             @Override
             public void run() {
+                SaslOutcomeFrame saslOutcome = new SaslOutcomeFrame();
+                if (saslServer.isComplete() && succeeded.get()) {
+                    saslOutcome.setCode(SASL_OK);
+                } else {
+                    saslOutcome.setCode(SASL_FAIL_AUTH);
+                }
 
-                if (saslServer.isComplete()) {
-                    LOGGER.info("Authorized ID: " + 
saslServer.getAuthorizationID());
-                    LOGGER.info("Send Outcome");
-                    TestAmqpPeer.this.sendFrame(
-                            FrameType.SASL, 0,
-                            new SaslOutcomeFrame().setCode(SASL_OK),
-                            null,
-                            false, 0);
+                LOGGER.info("Send Outcome");
+                TestAmqpPeer.this.sendFrame(
+                        FrameType.SASL, 0,
+                        saslOutcome,
+                        null,
+                        false, 0);
 
-                    // Now that we processed the SASL layer AMQP header, reset 
the
-                    // peer to expect the non-SASL AMQP header.
-                    _driverRunnable.expectHeader();
-                }
+                // Now that we processed the SASL layer AMQP header, reset the
+                // peer to expect the non-SASL AMQP header.
+                _driverRunnable.expectHeader();
             }
         });
 
         addHandler(saslInitMatcher);
-        addHandler(challengeMatcher);
-
+        addHandler(responseMatcher);
         addHandler(new HeaderHandlerImpl(AmqpHeader.HEADER, 
AmqpHeader.HEADER));
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/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 7b3f24f..393e70a 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
@@ -117,7 +117,7 @@ class TestAmqpPeerRunner implements Runnable
                 {
                     ByteBuffer networkInputByteBuffer = 
ByteBuffer.wrap(networkInputBytes, 0, bytesRead);
 
-                    LOGGER.debug("Read: {}", new Binary(networkInputBytes, 0, 
bytesRead));
+                    LOGGER.debug("Read: {} ({} bytes)", new 
Binary(networkInputBytes, 0, bytesRead), bytesRead);
 
                     try {
                         _testFrameParser.input(networkInputByteBuffer);

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/ce833c7b/qpid-jms-client/src/test/resources/SaslGssApiIntegrationTest-login.config
----------------------------------------------------------------------
diff --git 
a/qpid-jms-client/src/test/resources/SaslGssApiIntegrationTest-login.config 
b/qpid-jms-client/src/test/resources/SaslGssApiIntegrationTest-login.config
index 6aa4123..edd7fc1 100644
--- a/qpid-jms-client/src/test/resources/SaslGssApiIntegrationTest-login.config
+++ b/qpid-jms-client/src/test/resources/SaslGssApiIntegrationTest-login.config
@@ -17,7 +17,26 @@
 
 KRB5-CLIENT {
     com.sun.security.auth.module.Krb5LoginModule required
+    principal="clientprincipal"
+    useKeyTab=true
+    keytab="target/SaslGssApiIntegrationTest.krb5.keytab";
+};
+
+KRB5-CLIENT-URI-USERNAME-CALLBACK {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    keytab="target/SaslGssApiIntegrationTest.krb5.keytab";
+};
+
+KRB5-CLIENT-FACTORY-USERNAME-CALLBACK {
+    com.sun.security.auth.module.Krb5LoginModule required
+    useKeyTab=true
+    keytab="target/SaslGssApiIntegrationTest.krb5.keytab";
+};
+
+amqp-jms-client {
+    com.sun.security.auth.module.Krb5LoginModule required
+    principal="defaultscopeprincipal"
     useKeyTab=true
-    principal="client"
     keytab="target/SaslGssApiIntegrationTest.krb5.keytab";
 };


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

Reply via email to