You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2016/12/02 15:47:52 UTC

svn commit: r1772364 [4/4] - in /qpid/java/trunk: broker-core/src/main/java/org/apache/qpid/server/model/ broker-core/src/main/java/org/apache/qpid/server/security/ broker-core/src/main/java/org/apache/qpid/server/security/auth/database/ broker-core/sr...

Added: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/scram/ScramNegotiatorTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/scram/ScramNegotiatorTest.java?rev=1772364&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/scram/ScramNegotiatorTest.java (added)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/scram/ScramNegotiatorTest.java Fri Dec  2 15:47:52 2016
@@ -0,0 +1,442 @@
+/*
+ * 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.server.security.auth.sasl.scram;
+
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.sasl.SaslException;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectFactory;
+import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.ScramSHA1AuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.ScramSHA256AuthenticationManager;
+import org.apache.qpid.server.security.auth.sasl.PasswordSource;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.util.Strings;
+
+public class ScramNegotiatorTest extends QpidTestCase
+{
+    private static final String VALID_USER_NAME = "testUser";
+    private static final String VALID_USER_PASSWORD = "testPassword";
+    private static final String INVALID_USER_PASSWORD = VALID_USER_PASSWORD + "1";
+    private static final String INVALID_USER_NAME = VALID_USER_NAME + "1";
+    private static final String GS2_HEADER = "n,,";
+    private static final Charset ASCII = Charset.forName("ASCII");
+    private static final int ITERATION_COUNT = 4096;
+
+    private String _clientFirstMessageBare;
+    private String _clientNonce;
+    private byte[] _serverSignature;
+    private PasswordSource _passwordSource;
+    private AuthenticationProvider<?> _authenticationProvider;
+    private Broker<?> _broker;
+
+    @Override
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        _clientNonce = UUID.randomUUID().toString();
+        _passwordSource = mock(PasswordSource.class);
+        when(_passwordSource.getPassword(eq(VALID_USER_NAME))).thenReturn(VALID_USER_PASSWORD.toCharArray());
+        _authenticationProvider = mock(AuthenticationProvider.class);
+        _broker = BrokerTestHelper.createBrokerMock();
+    }
+
+    @Override
+    public void tearDown() throws Exception
+    {
+        try
+        {
+            super.tearDown();
+        }
+        finally
+        {
+            _authenticationProvider.close();
+        }
+    }
+
+    public void testHandleResponseForScramSha256ValidCredentialsAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA256AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA256AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestValidCredentials(ScramSHA256AuthenticationManager.MECHANISM,
+                                              _authenticationProvider,
+                                              scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha1ValidCredentialsAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA1AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA1AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestValidCredentials(ScramSHA1AuthenticationManager.MECHANISM,
+                                              _authenticationProvider,
+                                              scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha256InvalidPasswordAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA256AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA256AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestInvalidCredentials(VALID_USER_NAME,
+                                                INVALID_USER_PASSWORD,
+                                                ScramSHA256AuthenticationManager.MECHANISM,
+                                                _authenticationProvider,
+                                                scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha1InvalidPasswordAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA1AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA1AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestInvalidCredentials(VALID_USER_NAME,
+                                                INVALID_USER_PASSWORD,
+                                                ScramSHA1AuthenticationManager.MECHANISM,
+                                                _authenticationProvider,
+                                                scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha256InvalidUsernameAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA256AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA256AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestInvalidCredentials(INVALID_USER_NAME,
+                                                VALID_USER_PASSWORD,
+                                                ScramSHA256AuthenticationManager.MECHANISM,
+                                                _authenticationProvider,
+                                                scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha1InvalidUsernameAdapterSource() throws Exception
+    {
+        final ScramSaslServerSource scramSaslServerSource =
+                new ScramSaslServerSourceAdapter(ITERATION_COUNT,
+                                                 ScramSHA1AuthenticationManager.HMAC_NAME,
+                                                 ScramSHA1AuthenticationManager.DIGEST_NAME,
+                                                 _passwordSource);
+        doSaslNegotiationTestInvalidCredentials(INVALID_USER_NAME,
+                                                VALID_USER_PASSWORD,
+                                                ScramSHA1AuthenticationManager.MECHANISM,
+                                                _authenticationProvider,
+                                                scramSaslServerSource);
+    }
+
+    public void testHandleResponseForScramSha256ValidCredentialsAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA256AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestValidCredentials(ScramSHA256AuthenticationManager.MECHANISM, _authenticationProvider,
+                                              (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    public void testHandleResponseForScramSha1ValidCredentialsAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA1AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestValidCredentials(ScramSHA1AuthenticationManager.MECHANISM, _authenticationProvider,
+                                              (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    public void testHandleResponseForScramSha256InvalidPasswordAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA256AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestInvalidCredentials(VALID_USER_NAME,
+                                                INVALID_USER_PASSWORD,
+                                                "SCRAM-SHA-256",
+                                                _authenticationProvider,
+                                                (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    public void testHandleResponseForScramSha1InvalidPasswordAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA1AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestInvalidCredentials(VALID_USER_NAME,
+                                                INVALID_USER_PASSWORD,
+                                                "SCRAM-SHA-1",
+                                                _authenticationProvider,
+                                                (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    public void testHandleResponseForScramSha256InvalidUsernameAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA256AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestInvalidCredentials(INVALID_USER_NAME,
+                                                VALID_USER_PASSWORD,
+                                                "SCRAM-SHA-256",
+                                                _authenticationProvider,
+                                                (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    public void testHandleResponseForScramSha1InvalidUsernameAuthenticationProvider() throws Exception
+    {
+        _authenticationProvider = createTestAuthenticationManager(ScramSHA1AuthenticationManager.PROVIDER_TYPE);
+        doSaslNegotiationTestInvalidCredentials(INVALID_USER_NAME,
+                                                VALID_USER_PASSWORD,
+                                                "SCRAM-SHA-1",
+                                                _authenticationProvider,
+                                                (ScramSaslServerSource) _authenticationProvider);
+    }
+
+    private void doSaslNegotiationTestValidCredentials(final String mechanism,
+                                                       final AuthenticationProvider<?> authenticationProvider,
+                                                       final ScramSaslServerSource scramSaslServerSource)
+            throws Exception
+    {
+        ScramNegotiator scramNegotiator = new ScramNegotiator(authenticationProvider,
+                                                              scramSaslServerSource,
+                                                              mechanism);
+
+        byte[] initialResponse = createInitialResponse(VALID_USER_NAME);
+
+        AuthenticationResult firstResult = scramNegotiator.handleResponse(initialResponse);
+        assertEquals("Unexpected first result status",
+                     AuthenticationResult.AuthenticationStatus.CONTINUE,
+                     firstResult.getStatus());
+        assertNotNull("Unexpected first result challenge", firstResult.getChallenge());
+
+        byte[] response = calculateClientProof(firstResult.getChallenge(),
+                                               scramSaslServerSource.getHmacName(),
+                                               scramSaslServerSource.getDigestName(),
+                                               VALID_USER_PASSWORD);
+        AuthenticationResult secondResult = scramNegotiator.handleResponse(response);
+        assertEquals("Unexpected second result status",
+                     AuthenticationResult.AuthenticationStatus.SUCCESS,
+                     secondResult.getStatus());
+        assertNotNull("Unexpected second result challenge", secondResult.getChallenge());
+        assertEquals("Unexpected second result principal", VALID_USER_NAME, secondResult.getMainPrincipal().getName());
+
+        String serverFinalMessage = new String(secondResult.getChallenge(), ASCII);
+        String[] parts = serverFinalMessage.split(",");
+        if (!parts[0].startsWith("v="))
+        {
+            fail("Server final message did not contain verifier");
+        }
+        byte[] serverSignature = Strings.decodeBase64(parts[0].substring(2));
+        if (!Arrays.equals(_serverSignature, serverSignature))
+        {
+            fail("Server signature did not match");
+        }
+
+        AuthenticationResult thirdResult = scramNegotiator.handleResponse(initialResponse);
+        assertEquals("Unexpected result status after completion of negotiation",
+                     AuthenticationResult.AuthenticationStatus.ERROR,
+                     thirdResult.getStatus());
+        assertNull("Unexpected principal after completion of negotiation", thirdResult.getMainPrincipal());
+    }
+
+    private void doSaslNegotiationTestInvalidCredentials(final String userName,
+                                                         final String userPassword,
+                                                         final String mechanism,
+                                                         final AuthenticationProvider<?> authenticationProvider,
+                                                         final ScramSaslServerSource scramSaslServerSource)
+            throws Exception
+    {
+        ScramNegotiator scramNegotiator = new ScramNegotiator(authenticationProvider,
+                                                              scramSaslServerSource,
+                                                              mechanism);
+
+        byte[] initialResponse = createInitialResponse(userName);
+        AuthenticationResult firstResult = scramNegotiator.handleResponse(initialResponse);
+        assertEquals("Unexpected first result status",
+                     AuthenticationResult.AuthenticationStatus.CONTINUE,
+                     firstResult.getStatus());
+        assertNotNull("Unexpected first result challenge", firstResult.getChallenge());
+
+        byte[] response = calculateClientProof(firstResult.getChallenge(),
+                                               scramSaslServerSource.getHmacName(),
+                                               scramSaslServerSource.getDigestName(),
+                                               userPassword);
+        AuthenticationResult secondResult = scramNegotiator.handleResponse(response);
+        assertEquals("Unexpected second result status",
+                     AuthenticationResult.AuthenticationStatus.ERROR,
+                     secondResult.getStatus());
+        assertNull("Unexpected second result challenge", secondResult.getChallenge());
+        assertNull("Unexpected second result principal", secondResult.getMainPrincipal());
+    }
+
+
+    private byte[] calculateClientProof(final byte[] challenge,
+                                        String hmacName,
+                                        String digestName,
+                                        String userPassword) throws Exception
+    {
+
+        String serverFirstMessage = new String(challenge, ASCII);
+        String[] parts = serverFirstMessage.split(",");
+        if (parts.length < 3)
+        {
+            fail("Server challenge '" + serverFirstMessage + "' cannot be parsed");
+        }
+        else if (parts[0].startsWith("m="))
+        {
+            fail("Server requires mandatory extension which is not supported: " + parts[0]);
+        }
+        else if (!parts[0].startsWith("r="))
+        {
+            fail("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find nonce");
+        }
+        String nonce = parts[0].substring(2);
+        if (!nonce.startsWith(_clientNonce))
+        {
+            fail("Server challenge did not use correct client nonce");
+        }
+        if (!parts[1].startsWith("s="))
+        {
+            fail("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find salt");
+        }
+        byte[] salt = Strings.decodeBase64(parts[1].substring(2));
+        if (!parts[2].startsWith("i="))
+        {
+            fail("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find iteration count");
+        }
+        int _iterationCount = Integer.parseInt(parts[2].substring(2));
+        if (_iterationCount <= 0)
+        {
+            fail("Iteration count " + _iterationCount + " is not a positive integer");
+        }
+        byte[] passwordBytes = saslPrep(userPassword).getBytes("UTF-8");
+        byte[] saltedPassword = generateSaltedPassword(passwordBytes, hmacName, _iterationCount, salt);
+
+        String clientFinalMessageWithoutProof =
+                "c=" + DatatypeConverter.printBase64Binary(GS2_HEADER.getBytes(ASCII))
+                + ",r=" + nonce;
+
+        String authMessage = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
+        byte[] clientKey = computeHmac(saltedPassword, "Client Key", hmacName);
+        byte[] storedKey = MessageDigest.getInstance(digestName).digest(clientKey);
+        byte[] clientSignature = computeHmac(storedKey, authMessage, hmacName);
+        byte[] clientProof = clientKey.clone();
+        for (int i = 0; i < clientProof.length; i++)
+        {
+            clientProof[i] ^= clientSignature[i];
+        }
+        byte[] serverKey = computeHmac(saltedPassword, "Server Key", hmacName);
+        _serverSignature = computeHmac(serverKey, authMessage, hmacName);
+        String finalMessageWithProof = clientFinalMessageWithoutProof
+                                       + ",p=" + DatatypeConverter.printBase64Binary(clientProof);
+        return finalMessageWithProof.getBytes();
+    }
+
+    private byte[] computeHmac(final byte[] key, final String string, String hmacName)
+            throws Exception
+    {
+        Mac mac = createHmac(key, hmacName);
+        mac.update(string.getBytes(ASCII));
+        return mac.doFinal();
+    }
+
+    private byte[] generateSaltedPassword(final byte[] passwordBytes,
+                                          String hmacName,
+                                          final int iterationCount,
+                                          final byte[] salt) throws Exception
+    {
+        Mac mac = createHmac(passwordBytes, hmacName);
+        mac.update(salt);
+        mac.update(new byte[]{0, 0, 0, 1});
+        byte[] result = mac.doFinal();
+
+        byte[] previous = null;
+        for (int i = 1; i < iterationCount; i++)
+        {
+            mac.update(previous != null ? previous : result);
+            previous = mac.doFinal();
+            for (int x = 0; x < result.length; x++)
+            {
+                result[x] ^= previous[x];
+            }
+        }
+
+        return result;
+    }
+
+    private Mac createHmac(final byte[] keyBytes, String hmacName) throws Exception
+    {
+        SecretKeySpec key = new SecretKeySpec(keyBytes, hmacName);
+        Mac mac = Mac.getInstance(hmacName);
+        mac.init(key);
+        return mac;
+    }
+
+    private String saslPrep(String name) throws SaslException
+    {
+        name = name.replace("=", "=3D");
+        name = name.replace(",", "=2C");
+        return name;
+    }
+
+    private byte[] createInitialResponse(final String userName) throws SaslException
+    {
+        _clientFirstMessageBare = "n=" + saslPrep(userName) + ",r=" + _clientNonce;
+        return (GS2_HEADER + _clientFirstMessageBare).getBytes(ASCII);
+    }
+
+    private AuthenticationProvider createTestAuthenticationManager(String type)
+    {
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(ConfiguredObject.NAME, getTestName());
+        attributes.put(ConfiguredObject.ID, UUID.randomUUID());
+        attributes.put(ConfiguredObject.TYPE, type);
+        ConfiguredObjectFactory objectFactory = _broker.getObjectFactory();
+        @SuppressWarnings("unchecked")
+        AuthenticationProvider<?> configuredObject =
+                objectFactory.create(AuthenticationProvider.class, attributes, _broker);
+        assertEquals("Unexpected state", State.ACTIVE, configuredObject.getState());
+
+        PasswordCredentialManagingAuthenticationProvider<?> authenticationProvider =
+                (PasswordCredentialManagingAuthenticationProvider<?>) configuredObject;
+        authenticationProvider.createUser(VALID_USER_NAME,
+                                          VALID_USER_PASSWORD,
+                                          Collections.<String, String>emptyMap());
+        return configuredObject;
+    }
+}
\ No newline at end of file

Modified: qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/AMQPConnection_0_10.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/AMQPConnection_0_10.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/AMQPConnection_0_10.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/AMQPConnection_0_10.java Fri Dec  2 15:47:52 2016
@@ -20,8 +20,6 @@
  */
 package org.apache.qpid.server.protocol.v0_10;
 
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Collection;
@@ -84,15 +82,9 @@ public class AMQPConnection_0_10 extends
         super(broker, network, port, transport, Protocol.AMQP_0_10, id, aggregateTicker);
 
         _connection = new ServerConnection(id, broker, port, transport, this);
-        SocketAddress address = network.getLocalAddress();
-        String fqdn = null;
 
-        if (address instanceof InetSocketAddress)
-        {
-            fqdn = ((InetSocketAddress) address).getHostName();
-        }
         SubjectCreator subjectCreator = port.getAuthenticationProvider().getSubjectCreator(transport.isSecure());
-        ConnectionDelegate connDelegate = new ServerConnectionDelegate(broker, fqdn, subjectCreator);
+        ConnectionDelegate connDelegate = new ServerConnectionDelegate(broker, subjectCreator);
 
         _connection.setConnectionDelegate(connDelegate);
         _connection.setRemoteAddress(network.getRemoteAddress());

Modified: qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java Fri Dec  2 15:47:52 2016
@@ -30,6 +30,8 @@ import java.security.PrivilegedAction;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Queue;
 import java.util.Set;
@@ -37,6 +39,7 @@ import java.util.concurrent.ConcurrentLi
 import java.util.concurrent.atomic.AtomicLong;
 
 import javax.security.auth.Subject;
+import javax.security.sasl.SaslServer;
 
 import org.apache.qpid.protocol.ErrorCodes;
 import org.apache.qpid.server.logging.EventLogger;
@@ -610,4 +613,44 @@ public class ServerConnection extends Co
     {
         return super.isConnectionLost();
     }
+
+    @Override
+    protected void setLocale(String locale)
+    {
+        super.setLocale(locale);
+    }
+
+    @Override
+    protected void sendConnectionSecure(byte[] challenge, Option ... options)
+    {
+        super.sendConnectionSecure(challenge, options);
+    }
+
+    @Override
+    protected void sendConnectionTune(int channelMax, int maxFrameSize, int heartbeatMin, int heartbeatMax, Option ... options)
+    {
+        super.sendConnectionTune(channelMax, maxFrameSize, heartbeatMin, heartbeatMax, options);
+    }
+
+    @Override
+    protected void setChannelMax(int max)
+    {
+        super.setChannelMax(max);
+    }
+
+    @Override
+    protected void map(Session ssn, int channel)
+    {
+        super.map(ssn, channel);
+    }
+
+    @Override
+    protected void sendConnectionStart(final Map<String, Object> clientProperties,
+                                       final List<Object> mechanisms,
+                                       final List<Object> locales,
+                                       final Option... options)
+    {
+        super.sendConnectionStart(clientProperties, mechanisms, locales, options);
+    }
+
 }

Modified: qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java Fri Dec  2 15:47:52 2016
@@ -32,9 +32,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,23 +44,45 @@ import org.apache.qpid.server.model.port
 import org.apache.qpid.server.security.SubjectCreator;
 import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
 import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
 import org.apache.qpid.server.virtualhost.VirtualHostUnavailableException;
-import org.apache.qpid.transport.*;
+import org.apache.qpid.transport.Binary;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionClose;
+import org.apache.qpid.transport.ConnectionCloseCode;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.transport.ConnectionOpen;
+import org.apache.qpid.transport.ConnectionOpenOk;
+import org.apache.qpid.transport.ConnectionRedirect;
+import org.apache.qpid.transport.ConnectionSecureOk;
+import org.apache.qpid.transport.ConnectionStartOk;
+import org.apache.qpid.transport.ConnectionTuneOk;
+import org.apache.qpid.transport.Constant;
+import org.apache.qpid.transport.ProtocolHeader;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionAttach;
+import org.apache.qpid.transport.SessionDelegate;
+import org.apache.qpid.transport.SessionDetach;
+import org.apache.qpid.transport.SessionDetachCode;
+import org.apache.qpid.transport.SessionDetached;
 
-public class ServerConnectionDelegate extends ServerDelegate
+public class ServerConnectionDelegate extends ConnectionDelegate
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(ServerConnectionDelegate.class);
 
+    private List<Object> _locales;
+    private List<Object> _mechanisms;
+
     private final Broker _broker;
-    private final String _localFQDN;
     private int _maxNoOfChannels;
     private Map<String,Object> _clientProperties;
     private final SubjectCreator _subjectCreator;
     private int _maximumFrameSize;
 
     private boolean _compressionSupported;
+    private volatile SaslNegotiator _saslNegotiator;
 
     enum ConnectionState
     {
@@ -79,21 +98,21 @@ public class ServerConnectionDelegate ex
     private volatile SubjectAuthenticationResult _successfulAuthenticationResult;
 
 
-    public ServerConnectionDelegate(Broker<?> broker, String localFQDN, SubjectCreator subjectCreator)
+    public ServerConnectionDelegate(Broker<?> broker, SubjectCreator subjectCreator)
     {
-        this(createConnectionProperties(broker), Collections.singletonList((Object)"en_US"), broker, localFQDN, subjectCreator);
+        this(createConnectionProperties(broker), Collections.singletonList((Object)"en_US"), broker, subjectCreator);
     }
 
     private ServerConnectionDelegate(Map<String, Object> properties,
                                      List<Object> locales,
                                      Broker<?> broker,
-                                     String localFQDN,
                                      SubjectCreator subjectCreator)
     {
-        super(properties, (List) subjectCreator.getMechanisms(), locales);
+        _clientProperties = properties;
+        _mechanisms = (List) subjectCreator.getMechanisms();
+        _locales = locales;
 
         _broker = broker;
-        _localFQDN = localFQDN;
         _maxNoOfChannels = broker.getConnection_sessionCountLimit();
         _subjectCreator = subjectCreator;
         _maximumFrameSize = Math.min(0xffff, broker.getNetworkBufferSize());
@@ -120,8 +139,10 @@ public class ServerConnectionDelegate ex
     @Override
     public void init(final Connection conn, final ProtocolHeader hdr)
     {
-        assertState((ServerConnection)conn, ConnectionState.INIT);
-        super.init(conn, hdr);
+        ServerConnection serverConnection = (ServerConnection) conn;
+        assertState(serverConnection, ConnectionState.INIT);
+        serverConnection.send(new ProtocolHeader(1, 0, 10));
+        serverConnection.sendConnectionStart(_clientProperties, _mechanisms, _locales);
         _state = ConnectionState.AWAIT_START_OK;
     }
 
@@ -168,27 +189,21 @@ public class ServerConnectionDelegate ex
         return ssn;
     }
 
-    protected SaslServer createSaslServer(Connection conn, String mechanism) throws SaslException
-    {
-        return _subjectCreator.createSaslServer(mechanism, _localFQDN, ((ServerConnection) conn).getPeerPrincipal());
-
-    }
-
     @Override
     public void connectionSecureOk(final Connection conn, final ConnectionSecureOk ok)
     {
-        assertState((ServerConnection)conn, ConnectionState.AWAIT_SECURE_OK);
-        super.connectionSecureOk(conn, ok);
+        ServerConnection serverConnection = (ServerConnection) conn;
+        assertState(serverConnection, ConnectionState.AWAIT_SECURE_OK);
+        secure(serverConnection, ok.getResponse());
     }
 
-    protected void secure(final SaslServer ss, final Connection conn, final byte[] response)
+    protected void secure(final ServerConnection sconn, final byte[] response)
     {
-        final ServerConnection sconn = (ServerConnection) conn;
         SubjectAuthenticationResult authResult = _successfulAuthenticationResult;
         byte[] challenge = null;
         if (authResult == null)
         {
-            authResult = _subjectCreator.authenticate(ss, response);
+            authResult = _subjectCreator.authenticate(_saslNegotiator, response);
             challenge = authResult.getChallenge();
         }
 
@@ -197,19 +212,20 @@ public class ServerConnectionDelegate ex
             _successfulAuthenticationResult = authResult;
             if (challenge == null || challenge.length == 0)
             {
-                tuneAuthorizedConnection(sconn);
+                sconn.sendConnectionTune(getChannelMax(), getFrameMax(), 0, getHeartbeatMax());
                 sconn.setAuthorizedSubject(authResult.getSubject());
                 _state = ConnectionState.AWAIT_TUNE_OK;
+                disposeSaslNegotiator();
             }
             else
             {
-                connectionAuthContinue(sconn, authResult.getChallenge());
+                sconn.sendConnectionSecure(authResult.getChallenge());
                 _state = ConnectionState.AWAIT_SECURE_OK;
             }
         }
         else if (AuthenticationStatus.CONTINUE.equals(authResult.getStatus()))
         {
-            connectionAuthContinue(sconn, authResult.getChallenge());
+            sconn.sendConnectionSecure(authResult.getChallenge());
             _state = ConnectionState.AWAIT_SECURE_OK;
         }
         else
@@ -348,24 +364,19 @@ public class ServerConnectionDelegate ex
             sconn.getAmqpConnection().initialiseHeartbeating(writerIdle, readerIdle);
         }
 
-        setConnectionTuneOkChannelMax(sconn, okChannelMax);
-        conn.setMaxFrameSize(okMaxFrameSize);
+        //0 means no implied limit, except available server resources
+        //(or that forced by protocol limitations [0xFFFF])
+        sconn.setChannelMax(okChannelMax == 0 ? getChannelMax() : okChannelMax);
+        sconn.setMaxFrameSize(okMaxFrameSize);
         _state = ConnectionState.AWAIT_OPEN;
     }
 
-    @Override
-    public int getChannelMax()
+    private int getChannelMax()
     {
         return _maxNoOfChannels;
     }
 
-    protected void setChannelMax(int channelMax)
-    {
-        _maxNoOfChannels = channelMax;
-    }
-
-    @Override
-    protected int getFrameMax()
+    private int getFrameMax()
     {
         return _maximumFrameSize;
     }
@@ -395,17 +406,21 @@ public class ServerConnectionDelegate ex
     @Override
     public void sessionAttach(final Connection conn, final SessionAttach atc)
     {
-        assertState((ServerConnection)conn, ConnectionState.OPEN);
+        ServerConnection serverConnection = (ServerConnection) conn;
+        assertState(serverConnection, ConnectionState.OPEN);
 
-        final Session ssn;
+        final ServerSession ssn = getSession(conn, atc);
 
         if(isSessionNameUnique(atc.getName(), conn))
         {
-            super.sessionAttach(conn, atc);
+
+            serverConnection.map(ssn, atc.getChannel());
+            serverConnection.registerSession(ssn);
+            ssn.sendSessionAttached(atc.getName());
+            ssn.setState(Session.State.OPEN);
         }
         else
         {
-            ssn = getSession(conn, atc);
             ssn.invoke(new SessionDetached(atc.getName(), SessionDetachCode.SESSION_BUSY));
             ssn.closed();
         }
@@ -437,7 +452,8 @@ public class ServerConnectionDelegate ex
     @Override
     public void connectionStartOk(Connection conn, ConnectionStartOk ok)
     {
-        assertState((ServerConnection)conn, ConnectionState.AWAIT_START_OK);
+        ServerConnection serverConnection = (ServerConnection)conn;
+        assertState(serverConnection, ConnectionState.AWAIT_START_OK);
         _clientProperties = ok.getClientProperties();
         if(_clientProperties != null)
         {
@@ -448,13 +464,34 @@ public class ServerConnectionDelegate ex
                 _compressionSupported = Boolean.parseBoolean(String.valueOf(compressionSupported));
 
             }
-            final AMQPConnection_0_10 protocolEngine = ((ServerConnection) conn).getAmqpConnection();
+            final AMQPConnection_0_10 protocolEngine = serverConnection.getAmqpConnection();
             protocolEngine.setClientId(getStringClientProperty(ConnectionStartProperties.CLIENT_ID_0_10));
             protocolEngine.setClientProduct(getStringClientProperty(ConnectionStartProperties.PRODUCT));
             protocolEngine.setClientVersion(getStringClientProperty(ConnectionStartProperties.VERSION_0_10));
             protocolEngine.setRemoteProcessPid(getStringClientProperty(ConnectionStartProperties.PID));
         }
-        super.connectionStartOk(conn, ok);
+
+
+        serverConnection.setLocale(ok.getLocale());
+        String mechanism = ok.getMechanism();
+
+        if (mechanism == null || mechanism.length() == 0)
+        {
+            serverConnection.sendConnectionClose(ConnectionCloseCode.CONNECTION_FORCED,
+                                                 "No Sasl mechanism was specified");
+            return;
+        }
+
+        _saslNegotiator = _subjectCreator.createSaslNegotiator(mechanism, serverConnection.getAmqpConnection());
+        if (_saslNegotiator == null)
+        {
+            serverConnection.sendConnectionClose(ConnectionCloseCode.CONNECTION_FORCED,
+                                                 "No SaslServer could be created for mechanism: " + mechanism);
+        }
+        else
+        {
+            secure(serverConnection, ok.getResponse());
+        }
     }
 
     private String getStringClientProperty(final String name)
@@ -487,15 +524,31 @@ public class ServerConnectionDelegate ex
         return (_clientProperties == null || _clientProperties.get(ConnectionStartProperties.PID) == null) ? null : String.valueOf(_clientProperties.get(ConnectionStartProperties.PID));
     }
 
-    @Override
     protected int getHeartbeatMax()
     {
         int delay = (Integer)_broker.getAttribute(Broker.CONNECTION_HEART_BEAT_DELAY);
-        return delay == 0 ? super.getHeartbeatMax() : delay;
+        return delay == 0 ? 0xFFFF : delay;
     }
 
     public boolean isCompressionSupported()
     {
         return _compressionSupported && _broker.isMessageCompressionEnabled();
     }
+
+    private void connectionAuthFailed(final Connection conn, Exception e)
+    {
+        ServerConnection serverConnection = (ServerConnection)conn;
+        if (e != null)
+        {
+            serverConnection.exception(e);
+        }
+        serverConnection.sendConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, e == null ? "Authentication failed" : e.getMessage());
+        disposeSaslNegotiator();
+    }
+
+    private void disposeSaslNegotiator()
+    {
+        _saslNegotiator.dispose();
+        _saslNegotiator = null;
+    }
 }

Modified: qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java Fri Dec  2 15:47:52 2016
@@ -107,6 +107,7 @@ import org.apache.qpid.transport.Message
 import org.apache.qpid.transport.MessageStop;
 import org.apache.qpid.transport.MessageTransfer;
 import org.apache.qpid.transport.Method;
+import org.apache.qpid.transport.Option;
 import org.apache.qpid.transport.Range;
 import org.apache.qpid.transport.RangeSet;
 import org.apache.qpid.transport.RangeSetFactory;
@@ -1257,6 +1258,12 @@ public class ServerSession extends Sessi
         return getId().compareTo(o.getId());
     }
 
+    @Override
+    protected void sendSessionAttached(final byte[] name, final Option... options)
+    {
+        super.sendSessionAttached(name, options);
+    }
+
     private class CheckCapacityAction implements Action<MessageInstance>
     {
         @Override

Modified: qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java Fri Dec  2 15:47:52 2016
@@ -24,11 +24,8 @@ import java.io.IOException;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
 import java.security.AccessControlException;
 import java.security.AccessController;
-import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.util.Collection;
 import java.util.Collections;
@@ -44,9 +41,6 @@ import java.util.concurrent.atomic.Atomi
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
 
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,6 +67,7 @@ import org.apache.qpid.server.protocol.A
 import org.apache.qpid.server.protocol.ConnectionClosingTicker;
 import org.apache.qpid.server.security.SubjectCreator;
 import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.store.StoreException;
 import org.apache.qpid.server.transport.AbstractAMQPConnection;
 import org.apache.qpid.server.transport.AggregateTicker;
@@ -122,7 +117,7 @@ public class AMQPConnection_0_8Impl
 
     private final ServerDecoder _decoder;
 
-    private volatile SaslServer _saslServer;
+    private volatile SaslNegotiator _saslNegotiator;
 
     private volatile long _maxNoOfChannels;
 
@@ -583,29 +578,6 @@ public class AMQPConnection_0_8Impl
         getNetwork().close();
     }
 
-    private String getLocalFQDN()
-    {
-        SocketAddress address = getNetwork().getLocalAddress();
-        if (address instanceof InetSocketAddress)
-        {
-            return ((InetSocketAddress) address).getHostName();
-        }
-        else
-        {
-            throw new IllegalArgumentException("Unsupported socket address class: " + address);
-        }
-    }
-
-    private SaslServer getSaslServer()
-    {
-        return _saslServer;
-    }
-
-    private void setSaslServer(SaslServer saslServer)
-    {
-        _saslServer = saslServer;
-    }
-
     public boolean isSendQueueDeleteOkRegardless()
     {
         return _sendQueueDeleteOkRegardless;
@@ -691,11 +663,6 @@ public class AMQPConnection_0_8Impl
         return _protocolOutputConverter;
     }
 
-    public Principal getPeerPrincipal()
-    {
-        return getNetwork().getPeerPrincipal();
-    }
-
     public MethodRegistry getMethodRegistry()
     {
         return _methodRegistry;
@@ -1080,33 +1047,14 @@ public class AMQPConnection_0_8Impl
 
         assertState(ConnectionState.AWAIT_SECURE_OK);
 
-        SubjectCreator subjectCreator = getSubjectCreator();
-
-        SaslServer ss = getSaslServer();
-        if (ss == null)
-        {
-            sendConnectionClose(ErrorCodes.INTERNAL_ERROR, "No SASL context set up in connection", 0);
-        }
-
-        processSaslResponse(response, subjectCreator, ss);
+        processSaslResponse(response, getSubjectCreator());
     }
 
 
-    private void disposeSaslServer()
+    private void disposeSaslNegotiator()
     {
-        SaslServer ss = getSaslServer();
-        if (ss != null)
-        {
-            setSaslServer(null);
-            try
-            {
-                ss.dispose();
-            }
-            catch (SaslException e)
-            {
-                _logger.error("Error disposing of Sasl server: " + e);
-            }
-        }
+        _saslNegotiator.dispose();
+        _saslNegotiator = null;
     }
 
     @Override
@@ -1132,46 +1080,33 @@ public class AMQPConnection_0_8Impl
 
         _logger.debug("SASL Mechanism selected: {} Locale : {}", mechanism, locale);
 
-        SubjectCreator subjectCreator = getSubjectCreator();
-        SaslServer ss;
-        try
+        if (mechanism == null || mechanism.length() == 0)
         {
-            ss = subjectCreator.createSaslServer(String.valueOf(mechanism),
-                                                 getLocalFQDN(),
-                                                 getPeerPrincipal());
-
-            if (ss == null)
-            {
-                sendConnectionClose(ErrorCodes.RESOURCE_ERROR, "Unable to create SASL Server:" + mechanism, 0);
-
-            }
-            else
-            {
-                //save clientProperties
-                setClientProperties(clientProperties);
-
-                setSaslServer(ss);
+            sendConnectionClose(ErrorCodes.CONNECTION_FORCED, "No Sasl mechanism was specified", 0);
+            return;
+        }
 
-                processSaslResponse(response, subjectCreator, ss);
-            }
+        SubjectCreator subjectCreator = getSubjectCreator();
+        _saslNegotiator = subjectCreator.createSaslNegotiator(String.valueOf(mechanism), this);
+        if (_saslNegotiator == null)
+        {
+            sendConnectionClose(ErrorCodes.CONNECTION_FORCED, "No SaslServer could be created for mechanism: " + mechanism, 0);
         }
-        catch (SaslException e)
+        else
         {
-            disposeSaslServer();
-            sendConnectionClose(ErrorCodes.INTERNAL_ERROR, "SASL error: " + e, 0);
+            setClientProperties(clientProperties);
+            processSaslResponse(response, subjectCreator);
         }
     }
 
-    private void processSaslResponse(final byte[] response,
-                                     final SubjectCreator subjectCreator,
-                                     final SaslServer ss)
+    private void processSaslResponse(final byte[] response, final SubjectCreator subjectCreator)
     {
         MethodRegistry methodRegistry = getMethodRegistry();
         SubjectAuthenticationResult authResult = _successfulAuthenticationResult;
         byte[] challenge = null;
         if (authResult == null)
         {
-            authResult = subjectCreator.authenticate(ss, response);
+            authResult = subjectCreator.authenticate(_saslNegotiator, response);
             challenge = authResult.getChallenge();
         }
 
@@ -1184,7 +1119,7 @@ public class AMQPConnection_0_8Impl
 
                 sendConnectionClose(ErrorCodes.NOT_ALLOWED, "Authentication failed", 0);
 
-                disposeSaslServer();
+                disposeSaslNegotiator();
                 break;
 
             case SUCCESS:
@@ -1209,7 +1144,7 @@ public class AMQPConnection_0_8Impl
                                                                     broker.getConnection_heartBeatDelay());
                     writeFrame(tuneBody.generateFrame(0));
                     _state = ConnectionState.AWAIT_TUNE_OK;
-                    disposeSaslServer();
+                    disposeSaslNegotiator();
                 }
                 else
                 {

Modified: qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Test.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Test.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Test.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Test.java Fri Dec  2 15:47:52 2016
@@ -29,7 +29,6 @@ import java.net.InetSocketAddress;
 import java.util.Collections;
 
 import javax.security.auth.Subject;
-import javax.security.sasl.SaslServer;
 
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
@@ -56,6 +55,8 @@ import org.apache.qpid.server.security.a
 import org.apache.qpid.server.security.auth.AuthenticationResult;
 import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
 import org.apache.qpid.server.security.auth.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
+import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.transport.AggregateTicker;
 import org.apache.qpid.server.transport.ServerNetworkConnection;
@@ -131,11 +132,10 @@ public class AMQPConnection_0_8Test exte
         SubjectCreator subjectCreator = mock(SubjectCreator.class);
 
         when(subjectCreator.getMechanisms()).thenReturn(Collections.singletonList(SASL_MECH.toString()));
-        SaslServer saslServer = mock(SaslServer.class);
-        when(subjectCreator.createSaslServer(SASL_MECH.toString(),
-                                             "localhost",
-                                             null)).thenReturn(saslServer);
-        when(subjectCreator.authenticate(saslServer, SASL_RESPONSE)).thenReturn(new SubjectAuthenticationResult(
+
+        SaslNegotiator saslNegotiator = mock(SaslNegotiator.class);
+        when(subjectCreator.createSaslNegotiator(eq(SASL_MECH.toString()), any(SaslSettings.class))).thenReturn(saslNegotiator);
+        when(subjectCreator.authenticate(saslNegotiator, SASL_RESPONSE)).thenReturn(new SubjectAuthenticationResult(
                 new AuthenticationResult(new AuthenticatedPrincipal(new UsernamePrincipal("username", null))), new Subject()));
 
         AuthenticationProvider authenticationProvider = mock(AuthenticationProvider.class);

Modified: qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/AMQPConnection_1_0.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/AMQPConnection_1_0.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/AMQPConnection_1_0.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/AMQPConnection_1_0.java Fri Dec  2 15:47:52 2016
@@ -103,6 +103,7 @@ import org.apache.qpid.server.security.a
 import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
 import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
 import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManagerImpl;
+import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
 import org.apache.qpid.server.store.StoreException;
 import org.apache.qpid.server.transport.AbstractAMQPConnection;
 import org.apache.qpid.server.transport.AggregateTicker;
@@ -211,10 +212,9 @@ public class AMQPConnection_1_0 extends
 
 
     private Map _properties;
-    private SaslServerProvider _saslServerProvider;
     private boolean _saslComplete;
 
-    private SaslServer _saslServer;
+    private SaslNegotiator _saslNegotiator;
     private String _localHostname;
     private long _desiredIdleTimeout;
 
@@ -244,14 +244,12 @@ public class AMQPConnection_1_0 extends
                        AmqpPort<?> port,
                        Transport transport,
                        long id,
-                       final AggregateTicker aggregateTicker,
-                       final boolean useSASL)
+                       final AggregateTicker aggregateTicker)
     {
         super(broker, network, port, transport, Protocol.AMQP_1_0, id, aggregateTicker);
 
         _subjectCreator = port.getAuthenticationProvider().getSubjectCreator(transport.isSecure());
 
-        _saslServerProvider = useSASL ? asSaslServerProvider(_subjectCreator, network) : null;
         _port = port;
 
         Map<Symbol, Object> serverProperties = new LinkedHashMap<>();
@@ -322,11 +320,18 @@ public class AMQPConnection_1_0 extends
     private void closeSaslWithFailure()
     {
         _saslComplete = true;
+        disposeSaslNegotiator();
         _frameReceivingState = FrameReceivingState.CLOSED;
         setClosedForInput(true);
         addCloseTicker();
     }
 
+    private void disposeSaslNegotiator()
+    {
+        _saslNegotiator.dispose();
+        _saslNegotiator = null;
+    }
+
     public void receiveSaslChallenge(final SaslChallenge saslChallenge)
     {
         LOGGER.info("{} : Unexpected frame sasl-challenge", getLogSubject());
@@ -905,16 +910,8 @@ public class AMQPConnection_1_0 extends
         final Binary initialResponse = saslInit.getInitialResponse();
         byte[] response = initialResponse == null ? new byte[0] : initialResponse.getArray();
 
-
-        try
-        {
-            _saslServer = _saslServerProvider.getSaslServer(mechanism, "localhost");
-            processSaslResponse(response);
-        }
-        catch (SaslException e)
-        {
-            handleSaslError();
-        }
+        _saslNegotiator = _subjectCreator.createSaslNegotiator(mechanism, this);
+        processSaslResponse(response);
     }
 
     private void processSaslResponse(final byte[] response)
@@ -923,7 +920,7 @@ public class AMQPConnection_1_0 extends
         SubjectAuthenticationResult authenticationResult = _successfulAuthenticationResult;
         if (authenticationResult == null)
         {
-            authenticationResult = _subjectCreator.authenticate(_saslServer, response != null ? response : new byte[0]);
+            authenticationResult = _subjectCreator.authenticate(_saslNegotiator, response != null ? response : new byte[0]);
             challenge = authenticationResult.getChallenge();
         }
 
@@ -938,6 +935,7 @@ public class AMQPConnection_1_0 extends
                 send(new SASLFrame(outcome), null);
                 _saslComplete = true;
                 _frameReceivingState = FrameReceivingState.AMQP_HEADER;
+                disposeSaslNegotiator();
             }
             else
             {
@@ -1110,19 +1108,6 @@ public class AMQPConnection_1_0 extends
     {
     }
 
-    private static SaslServerProvider asSaslServerProvider(final SubjectCreator subjectCreator,
-                                                           final ServerNetworkConnection network)
-    {
-        return new SaslServerProvider()
-        {
-            @Override
-            public SaslServer getSaslServer(String mechanism, String fqdn) throws SaslException
-            {
-                return subjectCreator.createSaslServer(mechanism, fqdn, network.getPeerPrincipal());
-            }
-        };
-    }
-
     public String getAddress()
     {
         return getNetwork().getRemoteAddress().toString();

Modified: qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0.java Fri Dec  2 15:47:52 2016
@@ -90,7 +90,7 @@ public class ProtocolEngineCreator_1_0_0
                 || (supportedMechanisms.contains(ExternalAuthenticationManagerImpl.MECHANISM_NAME) && network.getPeerPrincipal() != null))
         {
             final AMQPConnection_1_0 amqpConnection_1_0 =
-                    new AMQPConnection_1_0(broker, network, port, transport, id, aggregateTicker, false);
+                    new AMQPConnection_1_0(broker, network, port, transport, id, aggregateTicker);
             amqpConnection_1_0.create();
             return amqpConnection_1_0;
         }

Modified: qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0_SASL.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0_SASL.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0_SASL.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngineCreator_1_0_0_SASL.java Fri Dec  2 15:47:52 2016
@@ -66,7 +66,7 @@ public class ProtocolEngineCreator_1_0_0
                                             long id, final AggregateTicker aggregateTicker)
     {
         final AMQPConnection_1_0 amqpConnection_1_0 =
-                new AMQPConnection_1_0(broker, network, port, transport, id, aggregateTicker, true);
+                new AMQPConnection_1_0(broker, network, port, transport, id, aggregateTicker);
         amqpConnection_1_0.create();
         return amqpConnection_1_0;
     }

Modified: qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/test/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngine_1_0_0Test.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/test/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngine_1_0_0Test.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/test/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngine_1_0_0Test.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-1-0-protocol/src/test/java/org/apache/qpid/server/protocol/v1_0/ProtocolEngine_1_0_0Test.java Fri Dec  2 15:47:52 2016
@@ -29,6 +29,8 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.security.Principal;
 import java.util.ArrayList;
@@ -94,6 +96,7 @@ public class ProtocolEngine_1_0_0Test ex
     {
         super.setUp();
         _networkConnection = mock(ServerNetworkConnection.class);
+        when(_networkConnection.getLocalAddress()).thenReturn(new InetSocketAddress(0));
         _broker = mock(Broker.class);
         when(_broker.getModel()).thenReturn(BrokerModel.getInstance());
         final TaskExecutor taskExecutor = new TaskExecutorImpl();
@@ -199,9 +202,8 @@ public class ProtocolEngine_1_0_0Test ex
                 (new AnonymousAuthenticationManagerFactory()).create(null, attrs, _broker);
         when(_port.getAuthenticationProvider()).thenReturn(anonymousAuthenticationManager);
         allowMechanisms(AnonymousAuthenticationManager.MECHANISM_NAME);
-        final boolean useSASL = false;
 
-        createEngine(useSASL, Transport.TCP);
+        createEngine(Transport.TCP);
 
         _protocolEngine_1_0_0.received(QpidByteBuffer.wrap(ProtocolEngineCreator_1_0_0.getInstance()
                                                                    .getHeaderIdentifier()));
@@ -219,9 +221,8 @@ public class ProtocolEngine_1_0_0Test ex
     public void testProtocolEngineWithNoSaslNonTLSandNoAnon() throws Exception
     {
         allowMechanisms("foo");
-        final boolean useSASL = false;
 
-        createEngine(useSASL, Transport.TCP);
+        createEngine(Transport.TCP);
 
         _protocolEngine_1_0_0.received(QpidByteBuffer.wrap(ProtocolEngineCreator_1_0_0.getInstance().getHeaderIdentifier()));
 
@@ -246,9 +247,8 @@ public class ProtocolEngine_1_0_0Test ex
         when(_networkConnection.getPeerPrincipal()).thenReturn(principal);
 
         allowMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME);
-        final boolean useSASL = false;
 
-        createEngine(useSASL, Transport.SSL);
+        createEngine(Transport.SSL);
         _protocolEngine_1_0_0.received(QpidByteBuffer.wrap(ProtocolEngineCreator_1_0_0.getInstance().getHeaderIdentifier()));
 
         Open open = new Open();
@@ -267,9 +267,8 @@ public class ProtocolEngine_1_0_0Test ex
                 (new AnonymousAuthenticationManagerFactory()).create(null, attrs, _broker);
         when(_port.getAuthenticationProvider()).thenReturn(anonymousAuthenticationManager);
         allowMechanisms(AnonymousAuthenticationManager.MECHANISM_NAME);
-        final boolean useSASL = true;
 
-        createEngine(useSASL, Transport.TCP);
+        createEngine(Transport.TCP);
 
         _protocolEngine_1_0_0.received(QpidByteBuffer.wrap(ProtocolEngineCreator_1_0_0_SASL.getInstance()
                                                                    .getHeaderIdentifier()));
@@ -291,43 +290,14 @@ public class ProtocolEngine_1_0_0Test ex
     }
 
 
-    private void createEngine(final boolean useSASL, Transport transport)
+    private void createEngine(Transport transport)
     {
-        _protocolEngine_1_0_0 = new AMQPConnection_1_0(_broker, _networkConnection,
-                                                         _port, transport, 1, new AggregateTicker(),
-                                                         useSASL);
+        _protocolEngine_1_0_0 =
+                new AMQPConnection_1_0(_broker, _networkConnection, _port, transport, 1, new AggregateTicker());
     }
 
     private void allowMechanisms(String... mechanisms)
     {
         when(_subjectCreator.getMechanisms()).thenReturn(Arrays.asList(mechanisms));
     }
-
-    private final ByteBufferSender _sender = new ByteBufferSender()
-    {
-
-        @Override
-        public boolean isDirectBufferPreferred()
-        {
-            return false;
-        }
-
-        @Override
-        public void send(final QpidByteBuffer msg)
-        {
-            _protocolEngine_1_0_0.received(msg);
-        }
-
-        @Override
-        public void flush()
-        {
-
-        }
-
-        @Override
-        public void close()
-        {
-
-        }
-    };
 }

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java Fri Dec  2 15:47:52 2016
@@ -29,7 +29,6 @@ import java.util.Map;
 import java.util.Random;
 
 import javax.security.auth.Subject;
-import javax.security.sasl.SaslServer;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -46,6 +45,8 @@ import org.apache.qpid.server.security.S
 import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
 import org.apache.qpid.server.security.auth.AuthenticationResult;
 import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
+import org.apache.qpid.server.security.auth.sasl.SaslSettings;
 import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
 import org.apache.qpid.util.Strings;
 
@@ -58,7 +59,7 @@ public class SaslServlet extends Abstrac
     private static final SecureRandom SECURE_RANDOM = new SecureRandom();
     private static final String ATTR_RANDOM = "SaslServlet.Random";
     private static final String ATTR_ID = "SaslServlet.ID";
-    private static final String ATTR_SASL_SERVER = "SaslServlet.SaslServer";
+    private static final String ATTR_SASL_NEGOTIATOR = "SaslServlet.SaslNegotiator";
     private static final String ATTR_EXPIRY = "SaslServlet.Expiry";
     private static final long SASL_EXCHANGE_EXPIRY = 3000L;
 
@@ -132,16 +133,26 @@ public class SaslServlet extends Abstrac
                 {
                     LOGGER.debug("Creating SaslServer for mechanism: {}", mechanism);
 
-                    SaslServer saslServer = subjectCreator.createSaslServer(mechanism, request.getServerName(), null/*TODO*/);
-                    evaluateSaslResponse(request, response, session, saslResponse, saslServer, subjectCreator);
+                    SaslNegotiator saslNegotiator = subjectCreator.createSaslNegotiator(mechanism, new SaslSettings()
+                    {
+                        @Override
+                        public String getLocalFQDN()
+                        {
+                            return request.getServerName();
+                        }
+
+                        @Override
+                        public Principal getExternalPrincipal()
+                        {
+                            return null/*TODO*/;
+                        }
+                    });
+                    evaluateSaslResponse(request, response, session, saslResponse, saslNegotiator, subjectCreator);
                 }
                 else
                 {
+                    cleanup(request, session);
                     response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER,
-                                                                                               request));
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request));
                 }
             }
             else
@@ -152,28 +163,22 @@ public class SaslServlet extends Abstrac
                                                                                                          request))) && System.currentTimeMillis() < (Long) session.getAttribute(
                             HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request)))
                     {
-                        SaslServer saslServer = (SaslServer) session.getAttribute(HttpManagementUtil.getRequestSpecificAttributeName(
-                                ATTR_SASL_SERVER,
-                                request));
-                        evaluateSaslResponse(request, response, session, saslResponse, saslServer, subjectCreator);
+                        SaslNegotiator saslNegotiator =
+                                (SaslNegotiator) session.getAttribute(HttpManagementUtil.getRequestSpecificAttributeName(
+                                        ATTR_SASL_NEGOTIATOR,
+                                        request));
+                        evaluateSaslResponse(request, response, session, saslResponse, saslNegotiator, subjectCreator);
                     }
                     else
                     {
+                        cleanup(request, session);
                         response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
-                        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
-                        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER,
-                                                                                                   request));
-                        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY,
-                                                                                                   request));
                     }
                 }
                 else
                 {
+                    cleanup(request, session);
                     response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER,
-                                                                                               request));
-                    session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request));
                 }
             }
         }
@@ -186,6 +191,19 @@ public class SaslServlet extends Abstrac
         }
     }
 
+    private void cleanup(final HttpServletRequest request, final HttpSession session)
+    {
+        final SaslNegotiator negotiator =
+                (SaslNegotiator) session.getAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_NEGOTIATOR, request));
+        if (negotiator != null)
+        {
+            negotiator.dispose();
+        }
+        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
+        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_NEGOTIATOR, request));
+        session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request));
+    }
+
     private void checkSaslAuthEnabled(HttpServletRequest request)
     {
         boolean saslAuthEnabled = false;
@@ -206,15 +224,18 @@ public class SaslServlet extends Abstrac
 
     private void evaluateSaslResponse(final HttpServletRequest request,
                                       final HttpServletResponse response,
-                                      final HttpSession session, final String saslResponse, final SaslServer saslServer, SubjectCreator subjectCreator) throws IOException
+                                      final HttpSession session,
+                                      final String saslResponse,
+                                      final SaslNegotiator saslNegotiator,
+                                      SubjectCreator subjectCreator) throws IOException
     {
         byte[] saslResponseBytes = saslResponse == null
                 ? new byte[0]
                 : Strings.decodeBase64(saslResponse);
-        SubjectAuthenticationResult authenticationResult = subjectCreator.authenticate(saslServer, saslResponseBytes);
+        SubjectAuthenticationResult authenticationResult = subjectCreator.authenticate(saslNegotiator, saslResponseBytes);
         byte[] challenge = authenticationResult.getChallenge();
         Map<String, Object> outputObject = new LinkedHashMap<>();
-        int responseStatus;
+        int responseStatus = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
 
         if (authenticationResult.getStatus() == AuthenticationResult.AuthenticationStatus.SUCCESS)
         {
@@ -226,9 +247,6 @@ public class SaslServlet extends Abstrac
                 Subject subject = HttpManagementUtil.createServletConnectionSubject(request, original);
 
                 HttpManagementUtil.saveAuthorisedSubject(request, subject);
-                session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
-                session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER, request));
-                session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request));
                 if(challenge != null && challenge.length != 0)
                 {
                     outputObject.put("challenge", DatatypeConverter.printBase64Binary(challenge));
@@ -239,13 +257,17 @@ public class SaslServlet extends Abstrac
             {
                 responseStatus = HttpServletResponse.SC_FORBIDDEN;
             }
+            finally
+            {
+                cleanup(request, session);
+            }
         }
         else if (authenticationResult.getStatus() == AuthenticationResult.AuthenticationStatus.CONTINUE)
         {
             Random rand = getRandom(request);
             String id = String.valueOf(rand.nextLong());
             session.setAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request), id);
-            session.setAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER, request), saslServer);
+            session.setAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_NEGOTIATOR, request), saslNegotiator);
             session.setAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request), System.currentTimeMillis() + SASL_EXCHANGE_EXPIRY);
 
             outputObject.put("id", id);
@@ -254,10 +276,8 @@ public class SaslServlet extends Abstrac
         }
         else
         {
-            session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_ID, request));
-            session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_SASL_SERVER, request));
-            session.removeAttribute(HttpManagementUtil.getRequestSpecificAttributeName(ATTR_EXPIRY, request));
             responseStatus = HttpServletResponse.SC_UNAUTHORIZED;
+            cleanup(request, session);
         }
 
         sendJsonResponse(outputObject, request, response, responseStatus, false);

Modified: qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Connection.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Connection.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Connection.java (original)
+++ qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Connection.java Fri Dec  2 15:47:52 2016
@@ -166,7 +166,7 @@ public class Connection extends Connecti
         }
     }
 
-    void setLocale(String locale)
+    protected void setLocale(String locale)
     {
         this.locale = locale;
     }
@@ -466,7 +466,7 @@ public class Connection extends Connecti
         return channelMax;
     }
 
-    void setChannelMax(int max)
+    protected void setChannelMax(int max)
     {
         channelMax = max;
     }
@@ -489,7 +489,7 @@ public class Connection extends Connecti
         }
     }
 
-    void map(Session ssn, int channel)
+    protected void map(Session ssn, int channel)
     {
         synchronized (lock)
         {
@@ -875,4 +875,21 @@ public class Connection extends Connecti
         }
     }
 
+    protected void sendConnectionSecure(byte[] challenge, Option ... options)
+    {
+        super.connectionSecure(challenge, options);
+    }
+
+    protected void sendConnectionTune(int channelMax, int maxFrameSize, int heartbeatMin, int heartbeatMax, Option ... options)
+    {
+        super.connectionTune(channelMax, maxFrameSize, heartbeatMin, heartbeatMax, options);
+    }
+
+    protected void sendConnectionStart(final Map<String, Object> clientProperties,
+                                       final List<Object> mechanisms,
+                                       final List<Object> locales, final Option... options)
+    {
+        super.connectionStart(clientProperties, mechanisms, locales, options);
+    }
+
 }

Modified: qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Session.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Session.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Session.java (original)
+++ qpid/java/trunk/common/src/main/java/org/apache/qpid/transport/Session.java Fri Dec  2 15:47:52 2016
@@ -1198,4 +1198,9 @@ public class Session extends SessionInvo
     {
         return flowControl && credit.availablePermits() == 0;
     }
+
+    protected void sendSessionAttached(final byte[] name, final Option... options)
+    {
+        super.sessionAttached(name, options);
+    }
 }

Modified: qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java?rev=1772364&r1=1772363&r2=1772364&view=diff
==============================================================================
--- qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java (original)
+++ qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java Fri Dec  2 15:47:52 2016
@@ -21,6 +21,7 @@
 package org.apache.qpid.systest.rest;
 
 import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5ClientResponse;
+import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5HashedClientResponse;
 import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5HexClientResponse;
 import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generatePlainClientResponse;
 
@@ -291,6 +292,45 @@ public class SaslRestTest extends QpidRe
         assertEquals("Unexpected response", HttpServletResponse.SC_EXPECTATION_FAILED, responseCode);
     }
 
+    public void testCramMD5HashedSaslAuthenticationForValidCredentials() throws Exception
+    {
+        configureBase64MD5FilePrincipalDatabase();
+        startBrokerNow();
+
+        // request the challenge for CRAM-MD5-HASHED
+        HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HASHED");
+        List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+        // authenticate user with correct credentials
+        int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5-HASHED");
+        assertEquals("Unexpected response code", 200, code);
+
+        // request authenticated user details
+        connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET");
+        applyCookiesToConnection(cookies, connection);
+        Map<String, Object> response2 = getRestTestHelper().readJsonResponseAsMap(connection);
+        assertEquals("Unexpected user", "admin", response2.get("user"));
+    }
+
+    public void testCramMD5HashedSaslAuthenticationForInvalidPassword() throws Exception
+    {
+        configureBase64MD5FilePrincipalDatabase();
+        startBrokerNow();
+
+        HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HASHED");
+        List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+        // try to authenticate user with incorrect passowrd
+        int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5-HASHED");
+        assertEquals("Unexpected response code", 401, code);
+
+        // request authenticated user details
+        connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET");
+        applyCookiesToConnection(cookies, connection);
+        Map<String, Object> response2 = getRestTestHelper().readJsonResponseAsMap(connection);
+        assertNull("Unexpected user", response2.get("user"));
+    }
+
     private HttpURLConnection requestSasServerChallenge(String mechanism) throws IOException
     {
         HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST");
@@ -339,6 +379,10 @@ public class SaslRestTest extends QpidRe
         {
             responseBytes = generateCramMD5ClientResponse(userName, userPassword, challengeBytes);
         }
+        else if ("CRAM-MD5-HASHED".equalsIgnoreCase(mechanism))
+        {
+            responseBytes = generateCramMD5HashedClientResponse(userName, userPassword, challengeBytes);
+        }
         else
         {
             throw new RuntimeException("Not implemented test mechanism " + mechanism);



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