You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kw...@apache.org on 2018/01/07 18:04:43 UTC
[2/2] qpid-broker-j git commit: QPID-8038: [Broker-J] [AMQP 0-x] Add
connection protocol tests related to SASL.
QPID-8038: [Broker-J] [AMQP 0-x] Add connection protocol tests related to SASL.
Project: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/commit/cd13129a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/tree/cd13129a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/diff/cd13129a
Branch: refs/heads/master
Commit: cd13129adff47932b2e26e4a33a9bcba27c661ce
Parents: a9a275d
Author: Keith Wall <kw...@apache.org>
Authored: Sat Jan 6 22:34:15 2018 +0000
Committer: Keith Wall <kw...@apache.org>
Committed: Sun Jan 7 18:04:16 2018 +0000
----------------------------------------------------------------------
.../protocol/v0_8/ConnectionInteraction.java | 7 +
.../tests/protocol/v0_8/ConnectionTest.java | 204 ++++++++++++++++++-
.../v1_0/transport/security/sasl/SaslTest.java | 19 +-
.../apache/qpid/tests/protocol/SaslUtils.java | 41 ++++
4 files changed, 244 insertions(+), 27 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/cd13129a/systests/protocol-tests-amqp-0-8/src/main/java/org/apache/qpid/tests/protocol/v0_8/ConnectionInteraction.java
----------------------------------------------------------------------
diff --git a/systests/protocol-tests-amqp-0-8/src/main/java/org/apache/qpid/tests/protocol/v0_8/ConnectionInteraction.java b/systests/protocol-tests-amqp-0-8/src/main/java/org/apache/qpid/tests/protocol/v0_8/ConnectionInteraction.java
index 3c4943e..d7b661f 100644
--- a/systests/protocol-tests-amqp-0-8/src/main/java/org/apache/qpid/tests/protocol/v0_8/ConnectionInteraction.java
+++ b/systests/protocol-tests-amqp-0-8/src/main/java/org/apache/qpid/tests/protocol/v0_8/ConnectionInteraction.java
@@ -29,6 +29,7 @@ import org.apache.qpid.server.protocol.v0_8.AMQShortString;
import org.apache.qpid.server.protocol.v0_8.FieldTable;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionCloseBody;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionOpenBody;
+import org.apache.qpid.server.protocol.v0_8.transport.ConnectionSecureOkBody;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionStartOkBody;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionTuneOkBody;
@@ -40,6 +41,7 @@ public class ConnectionInteraction
private String _startOkMechanism;
private byte[] _startOkResponse;
private String _startOkLocale;
+
private int _tuneOkChannelMax;
private long _tuneOkFrameMax;
private int _tuneOkHeartbeat;
@@ -76,6 +78,11 @@ public class ConnectionInteraction
AMQShortString.valueOf(_startOkLocale)));
}
+ public Interaction secureOk(final byte[] secureOkResponse) throws Exception
+ {
+ return _interaction.sendPerformative(new ConnectionSecureOkBody(secureOkResponse));
+ }
+
public ConnectionInteraction tuneOkChannelMax(final int channelMax)
{
_tuneOkChannelMax = channelMax;
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/cd13129a/systests/protocol-tests-amqp-0-8/src/test/java/org/apache/qpid/tests/protocol/v0_8/ConnectionTest.java
----------------------------------------------------------------------
diff --git a/systests/protocol-tests-amqp-0-8/src/test/java/org/apache/qpid/tests/protocol/v0_8/ConnectionTest.java b/systests/protocol-tests-amqp-0-8/src/test/java/org/apache/qpid/tests/protocol/v0_8/ConnectionTest.java
index 81dbb85..5526c0f 100644
--- a/systests/protocol-tests-amqp-0-8/src/test/java/org/apache/qpid/tests/protocol/v0_8/ConnectionTest.java
+++ b/systests/protocol-tests-amqp-0-8/src/test/java/org/apache/qpid/tests/protocol/v0_8/ConnectionTest.java
@@ -20,18 +20,27 @@
*/
package org.apache.qpid.tests.protocol.v0_8;
-import static org.hamcrest.CoreMatchers.both;
+import static org.apache.qpid.tests.protocol.SaslUtils.generateCramMD5ClientResponse;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assume.assumeThat;
import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
+import org.apache.qpid.server.protocol.ErrorCodes;
import org.apache.qpid.server.protocol.v0_8.transport.ChannelOpenOkBody;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionCloseBody;
import org.apache.qpid.server.protocol.v0_8.transport.ConnectionCloseOkBody;
@@ -47,6 +56,10 @@ import org.apache.qpid.tests.utils.BrokerAdminUsingTestBase;
public class ConnectionTest extends BrokerAdminUsingTestBase
{
+ private static final String ANONYMOUS = "ANONYMOUS";
+ private static final String PLAIN = "PLAIN";
+ private static final String CRAM_MD5 = "CRAM-MD5";
+
private InetSocketAddress _brokerAddress;
@Before
@@ -79,7 +92,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse();
@@ -88,6 +101,28 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
}
@Test
+ @SpecificationTest(section = "1.4.2.2",
+ description = "If the mechanism field does not contain one of the security mechanisms proposed by the "
+ + "server in the Start method, the server MUST close the connection without sending any "
+ + "further data.")
+ public void connectionStartOkUnsupportedMechanism() throws Exception
+ {
+ try (FrameTransport transport = new FrameTransport(_brokerAddress).connect())
+ {
+ final Interaction interaction = transport.newInteraction();
+ interaction.negotiateProtocol()
+ .consumeResponse(ConnectionStartBody.class)
+ .connection().startOkMechanism("NOT-A-MECHANISM")
+ .startOk();
+
+ final ConnectionCloseBody res = interaction.consumeResponse()
+ .getLatestResponse(ConnectionCloseBody.class);
+ assertThat(res.getReplyCode(), is(equalTo(ErrorCodes.CONNECTION_FORCED)));
+
+ }
+ }
+
+ @Test
@SpecificationTest(section = "1.4.2.6", description = "negotiate connection tuning parameters")
public void connectionTuneOkAndOpen() throws Exception
{
@@ -96,7 +131,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -110,6 +145,125 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
}
@Test
+ @SpecificationTest(section = "1.4.2.3", description = "security challenge data")
+ public void connectionSecure() throws Exception
+ {
+ assumeThat(getBrokerAdmin().isSASLMechanismSupported(PLAIN), is(true));
+
+ final InetSocketAddress addr = getBrokerAdmin().getBrokerAddress(BrokerAdmin.PortType.AMQP);
+
+ try (FrameTransport transport = new FrameTransport(addr).connect())
+ {
+ final byte[] initialResponse = String.format("\0%s\0%s",
+ getBrokerAdmin().getValidUsername(),
+ getBrokerAdmin().getValidPassword())
+ .getBytes(StandardCharsets.US_ASCII);
+
+ final Interaction interaction = transport.newInteraction();
+ final ConnectionStartBody start = interaction.negotiateProtocol()
+ .consumeResponse()
+ .getLatestResponse(ConnectionStartBody.class);
+
+ assertThat(Arrays.asList(new String(start.getMechanisms()).split(" ")), hasItem(PLAIN));
+
+ final ConnectionSecureBody secure = interaction.connection()
+ .startOkMechanism(PLAIN)
+ .startOk()
+ .consumeResponse().getLatestResponse(ConnectionSecureBody.class);
+ assertThat(secure.getChallenge(), is(anyOf(nullValue(), equalTo(new byte[0]))));
+
+ final ConnectionTuneBody tune = interaction.connection().secureOk(initialResponse)
+ .consumeResponse()
+ .getLatestResponse(ConnectionTuneBody.class);
+
+ interaction.connection()
+ .tuneOkChannelMax(tune.getChannelMax())
+ .tuneOkFrameMax(tune.getFrameMax())
+ .tuneOk()
+ .connection().open()
+ .consumeResponse(ConnectionOpenOkBody.class);
+ }
+ }
+
+ @Test
+ @SpecificationTest(section = "1.4.2.3", description = "security challenge data")
+ public void connectionSecureWithChallengeResponse() throws Exception
+ {
+ assumeThat(getBrokerAdmin().isSASLMechanismSupported(CRAM_MD5), is(true));
+
+ final InetSocketAddress addr = getBrokerAdmin().getBrokerAddress(BrokerAdmin.PortType.AMQP);
+
+ try (FrameTransport transport = new FrameTransport(addr).connect())
+ {
+ final Interaction interaction = transport.newInteraction();
+ final ConnectionStartBody start = interaction.negotiateProtocol()
+ .consumeResponse()
+ .getLatestResponse(ConnectionStartBody.class);
+
+ assertThat(Arrays.asList(new String(start.getMechanisms()).split(" ")), hasItem(CRAM_MD5));
+
+ final ConnectionSecureBody secure = interaction.connection()
+ .startOkMechanism(CRAM_MD5)
+ .startOk()
+ .consumeResponse()
+ .getLatestResponse(ConnectionSecureBody.class);
+
+ byte[] response = generateCramMD5ClientResponse(getBrokerAdmin().getValidUsername(),
+ getBrokerAdmin().getValidPassword(),
+ secure.getChallenge());
+
+ final ConnectionTuneBody tune = interaction.connection()
+ .secureOk(response)
+ .consumeResponse()
+ .getLatestResponse(ConnectionTuneBody.class);
+
+ interaction.connection()
+ .tuneOkChannelMax(tune.getChannelMax())
+ .tuneOkFrameMax(tune.getFrameMax())
+ .tuneOk()
+ .connection().open()
+ .consumeResponse(ConnectionOpenOkBody.class);
+ }
+ }
+
+ @Test
+ @SpecificationTest(section = "1.4.2.3", description = "security challenge data")
+ public void connectionSecureUnsuccessfulAuthentication() throws Exception
+ {
+ assumeThat(getBrokerAdmin().isSASLMechanismSupported(PLAIN), is(true));
+
+ final InetSocketAddress addr = getBrokerAdmin().getBrokerAddress(BrokerAdmin.PortType.AMQP);
+
+ try (FrameTransport transport = new FrameTransport(addr).connect())
+ {
+ final byte[] initialResponse = String.format("\0%s\0%s",
+ getBrokerAdmin().getValidUsername(),
+ "badpassword")
+ .getBytes(StandardCharsets.US_ASCII);
+
+ final Interaction interaction = transport.newInteraction();
+ final ConnectionStartBody start = interaction.negotiateProtocol()
+ .consumeResponse()
+ .getLatestResponse(ConnectionStartBody.class);
+
+ assertThat(Arrays.asList(new String(start.getMechanisms()).split(" ")), hasItem(PLAIN));
+
+ final ConnectionCloseBody close = interaction.connection()
+ .startOkMechanism(PLAIN)
+ .startOk()
+ .consumeResponse(ConnectionSecureBody.class)
+ .connection()
+ .secureOk(initialResponse)
+ .consumeResponse()
+ .getLatestResponse(ConnectionCloseBody.class);
+
+ assertThat(close.getReplyCode(), is(equalTo(ErrorCodes.NOT_ALLOWED)));
+ assertThat(String.valueOf(close.getReplyText()).toLowerCase(), containsString("authentication failed"));
+
+ }
+ }
+
+ @Test
@SpecificationTest(section = "1.4.2.6", description = "[...] the minimum negotiated value for frame-max is also"
+ " frame-min-size [4096].")
public void tooSmallFrameSize() throws Exception
@@ -119,7 +273,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -145,7 +299,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -169,7 +323,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -245,7 +399,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("PLAIN").startOk().consumeResponse(ConnectionSecureBody.class)
+ .connection().startOkMechanism(PLAIN).startOk().consumeResponse(ConnectionSecureBody.class)
.connection().tuneOk()
.connection().open()
.consumeResponse(ConnectionCloseBody.class, ChannelClosedResponse.class);
@@ -263,7 +417,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -299,7 +453,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -337,7 +491,7 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
final Interaction interaction = transport.newInteraction();
ConnectionTuneBody response = interaction.negotiateProtocol()
.consumeResponse(ConnectionStartBody.class)
- .connection().startOkMechanism("ANONYMOUS")
+ .connection().startOkMechanism(ANONYMOUS)
.startOk()
.consumeResponse().getLatestResponse(ConnectionTuneBody.class);
@@ -357,4 +511,34 @@ public class ConnectionTest extends BrokerAdminUsingTestBase
transport.assertNoMoreResponsesAndChannelClosed();
}
}
+
+ @Test
+ @SpecificationTest(section = "1.4.2.7", description = "The client tried to work with an unknown virtual host.")
+ public void connectionOpenUnknownVirtualHost() throws Exception
+ {
+ try (FrameTransport transport = new FrameTransport(_brokerAddress).connect())
+ {
+ final Interaction interaction = transport.newInteraction();
+ ConnectionTuneBody tune = interaction.negotiateProtocol()
+ .consumeResponse(ConnectionStartBody.class)
+ .connection().startOkMechanism(ANONYMOUS)
+ .startOk()
+ .consumeResponse().getLatestResponse(ConnectionTuneBody.class);
+
+ ConnectionCloseBody close = interaction.connection()
+ .tuneOkChannelMax(tune.getChannelMax())
+ .tuneOkFrameMax(tune.getFrameMax())
+ .tuneOkHeartbeat(tune.getHeartbeat())
+ .tuneOk()
+ .connection()
+ .openVirtualHost("unknown-virtualhost")
+ .open()
+ .consumeResponse()
+ .getLatestResponse(ConnectionCloseBody.class);
+
+ // Spec requires INVALID_PATH, but implementation uses NOT_FOUND
+ assertThat(close.getReplyCode(), is(anyOf(equalTo(ErrorCodes.NOT_FOUND), equalTo(ErrorCodes.INVALID_PATH))));
+ assertThat(String.valueOf(close.getReplyText()).toLowerCase(), containsString("unknown virtual host"));
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/cd13129a/systests/protocol-tests-amqp-1-0/src/test/java/org/apache/qpid/tests/protocol/v1_0/transport/security/sasl/SaslTest.java
----------------------------------------------------------------------
diff --git a/systests/protocol-tests-amqp-1-0/src/test/java/org/apache/qpid/tests/protocol/v1_0/transport/security/sasl/SaslTest.java b/systests/protocol-tests-amqp-1-0/src/test/java/org/apache/qpid/tests/protocol/v1_0/transport/security/sasl/SaslTest.java
index 1b81507..f02d703 100644
--- a/systests/protocol-tests-amqp-1-0/src/test/java/org/apache/qpid/tests/protocol/v1_0/transport/security/sasl/SaslTest.java
+++ b/systests/protocol-tests-amqp-1-0/src/test/java/org/apache/qpid/tests/protocol/v1_0/transport/security/sasl/SaslTest.java
@@ -20,6 +20,7 @@
package org.apache.qpid.tests.protocol.v1_0.transport.security.sasl;
+import static org.apache.qpid.tests.protocol.SaslUtils.generateCramMD5ClientResponse;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
@@ -33,10 +34,6 @@ import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import javax.xml.bind.DatatypeConverter;
-
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import org.junit.Before;
@@ -196,7 +193,7 @@ public class SaslTest extends BrokerAdminUsingTestBase
assertThat(saslChallenge.getChallenge(), is(notNullValue()));
byte[] response = generateCramMD5ClientResponse(_username, _password,
- saslChallenge.getChallenge().getArray());
+ saslChallenge.getChallenge().getArray());
final SaslOutcome saslOutcome = interaction.saslResponseResponse(new Binary(response))
.saslResponse()
@@ -351,16 +348,4 @@ public class SaslTest extends BrokerAdminUsingTestBase
transport.assertNoMoreResponsesAndChannelClosed();
}
}
-
- private static byte[] generateCramMD5ClientResponse(String userName, String userPassword, byte[] challengeBytes)
- throws Exception
- {
- String macAlgorithm = "HmacMD5";
- Mac mac = Mac.getInstance(macAlgorithm);
- mac.init(new SecretKeySpec(userPassword.getBytes(StandardCharsets.UTF_8), macAlgorithm));
- final byte[] messageAuthenticationCode = mac.doFinal(challengeBytes);
- String responseAsString = userName + " " + DatatypeConverter.printHexBinary(messageAuthenticationCode)
- .toLowerCase();
- return responseAsString.getBytes();
- }
}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/cd13129a/systests/protocol-tests-core/src/main/java/org/apache/qpid/tests/protocol/SaslUtils.java
----------------------------------------------------------------------
diff --git a/systests/protocol-tests-core/src/main/java/org/apache/qpid/tests/protocol/SaslUtils.java b/systests/protocol-tests-core/src/main/java/org/apache/qpid/tests/protocol/SaslUtils.java
new file mode 100644
index 0000000..5833599
--- /dev/null
+++ b/systests/protocol-tests-core/src/main/java/org/apache/qpid/tests/protocol/SaslUtils.java
@@ -0,0 +1,41 @@
+/*
+ * 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.tests.protocol;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+
+public class SaslUtils
+{
+ public static byte[] generateCramMD5ClientResponse(String userName, String userPassword, byte[] challengeBytes)
+ throws Exception
+ {
+ String macAlgorithm = "HmacMD5";
+ Mac mac = Mac.getInstance(macAlgorithm);
+ mac.init(new SecretKeySpec(userPassword.getBytes(StandardCharsets.UTF_8), macAlgorithm));
+ final byte[] messageAuthenticationCode = mac.doFinal(challengeBytes);
+ String responseAsString = userName + " " + DatatypeConverter.printHexBinary(messageAuthenticationCode)
+ .toLowerCase();
+ return responseAsString.getBytes();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org