summaryrefslogtreecommitdiff
path: root/qpid/java/systests/src/test/java/org/apache/qpid/systest
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/systests/src/test/java/org/apache/qpid/systest')
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java119
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java285
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java164
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java148
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java140
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java482
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java324
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java869
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java211
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java261
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java37
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java288
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java115
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java337
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java122
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java131
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java85
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java86
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java77
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java242
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java141
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java281
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java120
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java373
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java109
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java91
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java272
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java63
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java105
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java355
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java366
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java199
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java114
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java262
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java384
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java129
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java263
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java150
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java100
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java191
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java631
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java1009
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java244
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java193
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java99
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java188
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java197
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java195
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java145
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java155
50 files changed, 11647 insertions, 0 deletions
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java
new file mode 100644
index 0000000000..f6b56f64ce
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.systest.management.jmx;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Tests the JMX API for the Managed Broker.
+ *
+ */
+public class BrokerManagementTest extends QpidBrokerTestCase
+{
+ private static final String VIRTUAL_HOST = "test";
+
+ /**
+ * JMX helper.
+ */
+ private JMXTestUtils _jmxUtils;
+ private ManagedBroker _managedBroker;
+
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+ _jmxUtils.open();
+ _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Tests queue creation/deletion also verifying the automatic binding to the default exchange.
+ */
+ public void testCreateQueueAndDeletion() throws Exception
+ {
+ final String queueName = getTestQueueName();
+
+
+ _managedBroker.createNewQueue(queueName, "testowner", true);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+
+ // Now delete the queue
+ _managedBroker.deleteQueue(queueName);
+
+
+ }
+
+ /**
+ * Tests exchange creation/deletion via JMX API.
+ */
+ public void testCreateExchangeAndUnregister() throws Exception
+ {
+ String exchangeName = getTestName();
+ _managedBroker.createNewExchange(exchangeName, "topic", true);
+
+ ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName);
+ assertNotNull("Exchange should exist", exchange);
+
+ _managedBroker.unregisterExchange(exchangeName);
+ }
+
+ /**
+ * Tests that it is disallowed to unregister the default exchange.
+ */
+ public void testUnregisterOfAmqDirectExchangeDisallowed() throws Exception
+ {
+ String amqDirectExchangeName = "amq.direct";
+
+ ManagedExchange amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName);
+ assertNotNull("Exchange should exist", amqDirectExchange);
+ try
+ {
+ _managedBroker.unregisterExchange(amqDirectExchangeName);
+ fail("Exception not thrown");
+ }
+ catch (UnsupportedOperationException e)
+ {
+ // PASS
+ assertEquals("'"+amqDirectExchangeName+"' is a reserved exchange and can't be deleted", e.getMessage());
+ }
+ amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName);
+ assertNotNull("Exchange should exist", amqDirectExchange);
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java
new file mode 100644
index 0000000000..34b13dfaca
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.systest.management.jmx;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class ConnectionManagementTest extends QpidBrokerTestCase
+{
+ private static final String VIRTUAL_HOST_NAME = "test";
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+ _jmxUtils.open();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception
+ {
+ assertEquals("Expected no managed connections", 0, getManagedConnections().size());
+
+ _connection = getConnection();
+ assertEquals("Expected one managed connection", 1, getManagedConnections().size());
+
+ _connection.close();
+ assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size());
+ }
+
+ public void testGetAttributes() throws Exception
+ {
+ _connection = getConnection();
+ final ManagedConnection mBean = getConnectionMBean();
+
+ checkAuthorisedId(mBean);
+ checkClientVersion(mBean);
+ checkClientId(mBean);
+ }
+
+ public void testNonTransactedSession() throws Exception
+ {
+ _connection = getConnection();
+
+ boolean transactional = false;
+ boolean flowBlocked = false;
+
+ _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE);
+
+ final ManagedConnection mBean = getConnectionMBean();
+ final CompositeDataSupport row = getTheOneChannelRow(mBean);
+ assertChannelRowData(row, 0, transactional, flowBlocked);
+ }
+
+ public void testTransactedSessionWithUnackMessages() throws Exception
+ {
+ _connection = getConnection();
+ _connection.start();
+
+ boolean transactional = true;
+ int numberOfMessages = 2;
+ final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED);
+ final Destination destination = session.createQueue(getTestQueueName());
+ final MessageConsumer consumer = session.createConsumer(destination);
+
+ sendMessage(session, destination, numberOfMessages);
+ receiveMessagesWithoutCommit(consumer, numberOfMessages);
+
+ final ManagedConnection mBean = getConnectionMBean();
+ final CompositeDataSupport row = getTheOneChannelRow(mBean);
+ boolean flowBlocked = false;
+ assertChannelRowData(row, numberOfMessages, transactional, flowBlocked);
+
+ // check that commit advances the lastIoTime
+ final Date initialLastIOTime = mBean.getLastIoTime();
+ session.commit();
+ assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime));
+
+ // check that channels() now returns one session with no unacknowledged messages
+ final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean);
+ final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT);
+ assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit);
+ }
+
+
+ public void testProducerFlowBlocked() throws Exception
+ {
+ _connection = getConnection();
+ _connection.start();
+
+ String queueName = getTestQueueName();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ Queue queue = session.createQueue(queueName);
+ createQueueOnBroker(session, queue);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l);
+ managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l);
+
+ final ManagedConnection managedConnection = getConnectionMBean();
+
+ // Check that producer flow is not block before test
+ final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowBeforeSend, false);
+
+
+ // Check that producer flow does not become block too soon
+ sendMessage(session, queue, 3);
+ final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowBeforeFull, false);
+
+ // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block)
+ sendMessage(session, queue, 1);
+ final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowAfterFull, true);
+
+ // Consume two to bring the queue down to the resume capacity
+ MessageConsumer consumer = session.createConsumer(queue);
+ assertNotNull("Could not receive first message", consumer.receive(1000));
+ assertNotNull("Could not receive second message", consumer.receive(1000));
+ session.commit();
+
+ // Check that producer flow is no longer blocked
+ final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowAfterReceive, false);
+ }
+
+ private void createQueueOnBroker(Session session, Destination destination) throws JMSException
+ {
+ session.createConsumer(destination).close(); // Create a consumer only to cause queue creation
+ }
+
+ private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked)
+ {
+ assertNotNull(row);
+ assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL));
+ assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT));
+ assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED));
+ }
+
+ private void assertFlowBlocked(final CompositeData row, boolean flowBlocked)
+ {
+ assertNotNull(row);
+ assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED));
+ }
+
+ private void checkAuthorisedId(ManagedConnection mBean) throws Exception
+ {
+ assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId());
+ }
+
+ private void checkClientVersion(ManagedConnection mBean) throws Exception
+ {
+ String expectedVersion = QpidProperties.getReleaseVersion();
+ assertTrue(StringUtils.isNotBlank(expectedVersion));
+
+ assertEquals("Unexpected version", expectedVersion, mBean.getVersion());
+ }
+
+ private void checkClientId(ManagedConnection mBean) throws Exception
+ {
+ String expectedClientId = _connection.getClientID();
+ assertTrue(StringUtils.isNotBlank(expectedClientId));
+
+ assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId());
+ }
+
+ private ManagedConnection getConnectionMBean()
+ {
+ List<ManagedConnection> connections = getManagedConnections();
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+ return mBean;
+ }
+
+ private List<ManagedConnection> getManagedConnections()
+ {
+ return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME);
+ }
+
+ private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception
+ {
+ TabularData channelsData = getChannelsDataWithRetry(mBean);
+
+ assertEquals("Unexpected number of rows in channel table", 1, channelsData.size());
+
+ @SuppressWarnings("unchecked")
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator();
+ final CompositeDataSupport row = rowItr.next();
+ return row;
+ }
+
+ private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception
+ {
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = consumer.receive(1000l);
+ assertNotNull("Message " + i + " is not received", m);
+ }
+ }
+
+ private TabularData getChannelsDataWithRetry(final ManagedConnection mBean)
+ throws IOException, JMException
+ {
+ TabularData channelsData = mBean.channels();
+ int retries = 0;
+ while(channelsData.size() == 0 && retries < 5)
+ {
+ sleep();
+ channelsData = mBean.channels();
+ retries++;
+ }
+ return channelsData;
+ }
+
+ private void sleep()
+ {
+ try
+ {
+ Thread.sleep(50);
+ }
+ catch (InterruptedException ie)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java
new file mode 100644
index 0000000000..8c0a11b7cc
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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.systest.management.jmx;
+
+import java.util.Collections;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class ExchangeManagementTest extends QpidBrokerTestCase
+{
+ private static final String MESSAGE_PROPERTY_INDEX = "index";
+ private static final String MESSAGE_PROPERTY_TEST = "test";
+ private static final String MESSAGE_PROPERTY_DUMMY = "dummy";
+ private static final String SELECTOR_ARGUMENT = AMQPFilterTypes.JMS_SELECTOR.toString();
+ private static final String SELECTOR = MESSAGE_PROPERTY_TEST + "='test'";
+ private static final String VIRTUAL_HOST = "test";
+
+ private JMXTestUtils _jmxUtils;
+ private ManagedBroker _managedBroker;
+ private String _testQueueName;
+ private ManagedExchange _directExchange;
+ private ManagedExchange _topicExchange;
+ private ManagedExchange _fanoutExchange;
+ private ManagedExchange _headersExchange;
+ private Connection _connection;
+ private Session _session;
+
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ // to test exchange selectors the publishing of unroutable messages should be allowed
+ getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false);
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+
+ _jmxUtils.open();
+
+ _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ _testQueueName = getTestName();
+ _managedBroker.createNewQueue(_testQueueName, null, true);
+ _directExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DIRECT_EXCHANGE_NAME);
+ _topicExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.TOPIC_EXCHANGE_NAME);
+ _fanoutExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.FANOUT_EXCHANGE_NAME);
+ _headersExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.HEADERS_EXCHANGE_NAME);
+
+ _connection = getConnection();
+ _connection.start();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ }
+
+ public void testCreateNewBindingWithArgumentsOnDirectExchange() throws Exception
+ {
+ String bindingKey = "test-direct-binding";
+
+ _directExchange.createNewBinding(_testQueueName, bindingKey,
+ Collections.<String, Object> singletonMap(SELECTOR_ARGUMENT, SELECTOR));
+
+ bindingTest(_session.createQueue(bindingKey));
+ }
+
+ public void testCreateNewBindingWithArgumentsOnTopicExchange() throws Exception
+ {
+ String bindingKey = "test-topic-binding";
+
+ _topicExchange.createNewBinding(_testQueueName, bindingKey,
+ Collections.<String, Object> singletonMap(SELECTOR_ARGUMENT, SELECTOR));
+
+ bindingTest(_session.createTopic(bindingKey));
+ }
+
+ public void testCreateNewBindingWithArgumentsOnFanoutExchange() throws Exception
+ {
+ _fanoutExchange.createNewBinding(_testQueueName, null,
+ Collections.<String, Object> singletonMap(SELECTOR_ARGUMENT, SELECTOR));
+
+ bindingTest(_session.createQueue("fanout://amq.fanout//?routingkey='routing-key-must-not-be-null'"));
+ }
+
+ public void testCreateNewBindingWithArgumentsOnHeadersExchange() throws Exception
+ {
+ // headers exchange uses 'dummy' property to match messages
+ // i.e. all test messages have matching header value
+ _headersExchange.createNewBinding(_testQueueName, "x-match=any,dummy=test",
+ Collections.<String, Object> singletonMap(SELECTOR_ARGUMENT, SELECTOR));
+
+ bindingTest(_session.createQueue("headers://amq.match//?routingkey='routing-key-must-not-be-null'"));
+ }
+
+ private void bindingTest(Destination destination) throws JMSException
+ {
+ publishMessages(destination, 4);
+ receiveAndAssertMessages(2);
+ }
+
+ private void publishMessages(Destination destination, int messageNumber) throws JMSException
+ {
+ MessageProducer producer = _session.createProducer(destination);
+
+ for (int i = 0; i < messageNumber; i++)
+ {
+ Message m = _session.createMessage();
+ m.setStringProperty(MESSAGE_PROPERTY_TEST, i % 2 == 0 ? MESSAGE_PROPERTY_TEST : "");
+ m.setIntProperty(MESSAGE_PROPERTY_INDEX, i);
+ m.setStringProperty(MESSAGE_PROPERTY_DUMMY, "test");
+ producer.send(m);
+ }
+ _session.commit();
+ }
+
+ private void receiveAndAssertMessages(int messageNumber) throws JMSException
+ {
+ MessageConsumer consumer = _session.createConsumer(_session.createQueue(_testQueueName));
+
+ for (int i = 0; i < messageNumber; i++)
+ {
+ int index = i * 2;
+ Message message = consumer.receive(1000l);
+ assertNotNull("Expected message is not received at " + i, message);
+ assertEquals("Unexpected test property at " + i, MESSAGE_PROPERTY_TEST,
+ message.getStringProperty(MESSAGE_PROPERTY_TEST));
+ assertEquals("Unexpected index property at " + i, index, message.getIntProperty(MESSAGE_PROPERTY_INDEX));
+ }
+
+ Message message = consumer.receive(1000l);
+ assertNull("Unexpected message received", message);
+ _session.commit();
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java
new file mode 100644
index 0000000000..3717c1594d
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.systest.management.jmx;
+
+import java.io.File;
+import java.util.List;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.server.logging.log4j.LoggingManagementFacadeTest;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.FileUtils;
+import org.apache.qpid.util.LogMonitor;
+
+/**
+ * System test for Logging Management. <b>These tests rely on value set within
+ * test-profiles/log4j-test.xml</b>.
+ *
+ * @see LoggingManagementMBeanTest
+ * @see LoggingManagementFacadeTest
+ *
+ */
+public class LoggingManagementTest extends QpidBrokerTestCase
+{
+ private JMXTestUtils _jmxUtils;
+ private LoggingManagement _loggingManagement;
+ private LogMonitor _monitor;
+
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ // System test normally run with log for4j test config from beneath test-profiles. We need to
+ // copy it as some of our tests write to this file.
+
+ File tmpLogFile = File.createTempFile("log4j" + "." + getName(), ".xml");
+ tmpLogFile.deleteOnExit();
+ FileUtils.copy(getBrokerCommandLog4JFile(), tmpLogFile);
+ setBrokerCommandLog4JFile(tmpLogFile);
+
+ super.setUp();
+ _jmxUtils.open();
+
+ _loggingManagement = _jmxUtils.getLoggingManagement();
+ _monitor = new LogMonitor(_outputFile);
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testViewEffectiveRuntimeLoggerLevels() throws Exception
+ {
+ final String qpidMainLogger = "org.apache.qpid";
+
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row = table.get(new String[] {qpidMainLogger} );
+ assertChannelRow(row, qpidMainLogger, "DEBUG");
+ }
+
+ public void testViewConfigFileLoggerLevels() throws Exception
+ {
+ final String operationalLoggingLogger = "qpid.message";
+
+ TabularData table = _loggingManagement.viewConfigFileLoggerLevels();
+ final CompositeData row = table.get(new String[] {operationalLoggingLogger} );
+ assertChannelRow(row, operationalLoggingLogger, "INFO");
+ }
+
+ public void testTurnOffOrgApacheQpidAtRuntime() throws Exception
+ {
+ final String logger = "org.apache.qpid";
+ _monitor.markDiscardPoint();
+ _loggingManagement.setRuntimeLoggerLevel(logger, "OFF");
+
+ List<String> matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'org.apache.qpid'", 5000);
+ assertEquals(1, matches.size());
+
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row1 = table.get(new String[] {logger} );
+ assertChannelRow(row1, logger, "OFF");
+ }
+
+ public void testChangesToConfigFileBecomeEffectiveAfterReload() throws Exception
+ {
+ final String operationalLoggingLogger = "qpid.message";
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO");
+
+ _monitor.markDiscardPoint();
+ _loggingManagement.setConfigFileLoggerLevel(operationalLoggingLogger, "OFF");
+
+ List<String> matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'qpid.message'", 5000);
+ assertEquals(1, matches.size());
+
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO");
+
+ _loggingManagement.reloadConfigFile();
+
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "OFF");
+ }
+
+ private void assertEffectiveLoggingLevel(String operationalLoggingLogger, String expectedLevel)
+ {
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row1 = table.get(new String[] {operationalLoggingLogger} );
+ assertChannelRow(row1, operationalLoggingLogger, expectedLevel);
+ }
+
+ private void assertChannelRow(final CompositeData row, String logger, String level)
+ {
+ assertNotNull("No row for " + logger, row);
+ assertEquals("Unexpected logger name", logger, row.get(LoggingManagement.LOGGER_NAME));
+ assertEquals("Unexpected level", level, row.get(LoggingManagement.LOGGER_LEVEL));
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java
new file mode 100644
index 0000000000..71f911627e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java
@@ -0,0 +1,140 @@
+/*
+ *
+ * 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.systest.management.jmx;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.ObjectName;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl;
+import org.apache.qpid.server.virtualhostnode.memory.MemoryVirtualHostNode;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class MBeanLifeCycleTest extends QpidRestTestCase
+{
+ private final static String TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost="
+ + ObjectName.quote(TEST2_VIRTUALHOST);
+ private JMXTestUtils _jmxUtils;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.open();
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ TestBrokerConfiguration config = getBrokerConfiguration();
+ config.addHttpManagementConfiguration();
+ config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, getRestTestHelper().getHttpPort());
+
+ Map<String, Object> anonymousProviderAttributes = new HashMap<String, Object>();
+ anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+ anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes);
+
+ // set password authentication provider on http port for the tests
+ config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
+ TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ getBrokerConfiguration().addJmxManagementConfiguration();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ public void testVirtualHostMBeanIsRegisteredOnVirtualHostCreation() throws Exception
+ {
+ String nodeName = "ntmp";
+ String hostName = "htmp";
+
+ Map<String, Object> nodeData = new HashMap<>();
+ nodeData.put(VirtualHostNode.NAME, nodeName);
+ nodeData.put(VirtualHostNode.TYPE, MemoryVirtualHostNode.VIRTUAL_HOST_NODE_TYPE);
+ getRestTestHelper().submitRequest("virtualhostnode/" + nodeName, "PUT", nodeData, HttpServletResponse.SC_CREATED);
+
+ Map<String, Object> virtualhostData = new HashMap<>();
+ virtualhostData.put(VirtualHost.NAME, nodeName);
+ virtualhostData.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE);
+ getRestTestHelper().submitRequest("virtualhost/" + nodeName + "/" + hostName,
+ "PUT",
+ virtualhostData,
+ HttpServletResponse.SC_CREATED);
+
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker(hostName);
+ assertNotNull("Host mBean is not created", managedBroker);
+ }
+
+ public void testVirtualHostMBeanIsUnregisteredOnVirtualHostDeletion() throws Exception
+ {
+ boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY);
+ assertTrue("Host mBean is not registered", mBeanExists);
+
+ getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_OK);
+
+ mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY);
+ assertFalse("Host mBean is not unregistered", mBeanExists);
+ }
+
+ public void testVirtualHostMBeanIsUnregisteredOnVirtualHostNodeStop() throws Exception
+ {
+ boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY);
+ assertTrue("Host mBean is not registered", mBeanExists);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker(TEST2_VIRTUALHOST);
+ assertNotNull("Host mBean is not created", managedBroker);
+
+ Map<String, Object> nodeData = new HashMap<String, Object>();
+ nodeData.put(VirtualHostNode.NAME, TEST2_VIRTUALHOST);
+ nodeData.put(VirtualHostNode.DESIRED_STATE, State.STOPPED.name());
+
+ int status = getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "PUT", nodeData);
+ assertEquals("Unexpected code", 200, status);
+
+ mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY);
+ assertFalse("Host mBean is not unregistered", mBeanExists);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java
new file mode 100644
index 0000000000..4358b4b450
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java
@@ -0,0 +1,482 @@
+/*
+ *
+ * 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.systest.management.jmx;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.test.utils.JMXTestUtils;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.management.JMException;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class to test if any change in the broker JMX code is affesting the management console
+ * There are some hardcoding of management feature names and parameter names to create a customized
+ * look in the console.
+ */
+public class ManagementActorLoggingTest extends AbstractTestLogging
+{
+ private JMXTestUtils _jmxUtils;
+ private boolean _closed = false;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ if(!_closed)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Description:
+ * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Client
+ * 3. Connection is closed via Management Console
+ * Output:
+ *
+ * <date> CON-1002 : Close
+ *
+ * Validation Steps:
+ * 4. The CON ID is correct
+ * 5. This must be the last CON message for the Connection
+ * 6. It must be preceded by a CON-1001 for this Connection
+ *
+ * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection}
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ */
+ public void testConnectionCloseViaManagement() throws IOException, Exception
+ {
+ //Create a connection to the broker
+ Connection connection = getConnection();
+
+ // Monitor the connection for an exception being thrown
+ // this should be a DisconnectionException but it is not this tests
+ // job to valiate that. Only use the exception as a synchronisation
+ // to check the log file for the Close message
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ //Failover being attempted.
+ exceptionReceived.countDown();
+ }
+ });
+
+ //Remove the connection close from any 0-10 connections
+ _monitor.markDiscardPoint();
+
+ // Get a managedConnection
+ ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*");
+
+ //Close the connection
+ mangedConnection.closeConnection();
+
+ //Wait for the connection to close
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
+
+ //Validate results
+ List<String> results = waitAndFindMatches("CON-1002");
+
+ assertEquals("Unexpected Connection Close count", 1, results.size());
+ }
+
+ /**
+ * Description:
+ * Exchange creation is possible from the Management Console.
+ * When an exchanged is created in this way then a EXH-1001 create message
+ * is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Exchange Created via Management Console
+ * Output:
+ *
+ * EXH-1001 : Create : [Durable] Type:<value> Name:<value>
+ *
+ * Validation Steps:
+ * 4. The EXH ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException
+ {
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "direct", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "topic", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "fanout", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "headers", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Queue Created via Management Console
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Transient Owner:<name>
+ *
+ * Validation Steps:
+ * 4. The QUE ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ // Validate
+
+ List<String> results = waitAndFindMatches("QUE-1001");
+
+ assertEquals("More than one queue creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct queue name
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Queue created on the broker with no subscribers
+ * 3. Management Console connected
+ * 4. Queue is deleted via Management Console
+ * Output:
+ *
+ * <date> QUE-1002 : Deleted
+ *
+ * Validation Steps:
+ * 5. The QUE ID is correct
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testQueueDeleteViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.deleteQueue(getName());
+
+ List<String> results = waitAndFindMatches("QUE-1002");
+
+ assertEquals("More than one queue deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Management Console
+ * 3. Use Management Console to perform binding
+ * Output:
+ *
+ * <date> BND-1001 : Create
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. This will be the first message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding}
+ */
+ public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Management Console connected
+ * 3. Management Console is used to perform unbind.
+ * Output:
+ *
+ * <date> BND-1002 : Deleted
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. There must have been a BND-1001 Create message first.
+ * 6. This will be the last message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection
+ * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange}
+ */
+ public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "direct", false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.unregisterExchange(getName());
+
+ List<String> results = waitAndFindMatches("EXH-1002");
+
+ assertEquals("More than one exchange deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
new file mode 100644
index 0000000000..cb6eae013e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
@@ -0,0 +1,324 @@
+/*
+ *
+ * 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.systest.management.jmx;
+
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.util.LogMonitor;
+
+/**
+ * Management Console Test Suite
+ *
+ * The Management Console test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the management console messages occur correctly and according to the following format:
+ *
+ * MNG-1001 : <type> Management Startup
+ * MNG-1002 : Starting : <service> : Listening on port <Port>
+ * MNG-1003 : Shutting down : <service> : port <Port>
+ * MNG-1004 : <type> Management Ready
+ * MNG-1005 : <type> Management Stopped
+ * MNG-1006 : Using SSL Keystore : <path>
+ * MNG-1007 : Open : User <username>
+ * MNG-1008 : Close : User <username>
+ */
+public class ManagementLoggingTest extends AbstractTestLogging
+{
+ private static final String MNG_PREFIX = "MNG-";
+
+ public void setUp() throws Exception
+ {
+ setLogMessagePrefix();
+
+ // We either do this here or have a null check in tearDown.
+ // As when this test is run against profiles other than java it will NPE
+ _monitor = new LogMonitor(_outputFile);
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+
+ }
+
+ /**
+ * Description:
+ * Using the startup configuration validate that the management startup
+ * message is logged correctly.
+ * Input:
+ * Standard configuration with management enabled
+ * Output:
+ *
+ * <date> MNG-1001 : Startup
+ *
+ * Constraints:
+ * This is the FIRST message logged by MNG
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This is the FIRST message logged by MNG
+ */
+ public void testManagementStartupEnabled() throws Exception
+ {
+ // This test only works on java brokers
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ // Ensure we have received the MNG log msg.
+ waitForMessage("MNG-1001");
+
+ List<String> results = findMatches(MNG_PREFIX);
+ // Validation
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1001", log);
+
+ //2
+ //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J)
+ results = findMatches("MNG-1001");
+ assertEquals("Unexpected startup message count.",
+ 2, results.size());
+
+ //3
+ assertEquals("Startup log message is not 'Startup'.", "JMX Management Startup",
+ getMessageString(log));
+ }
+ }
+
+ /**
+ * Description:
+ * Verify that when management is disabled in the configuration file the
+ * startup message is not logged.
+ * Input:
+ * Standard configuration with management disabled
+ * Output:
+ * NO MNG messages
+ * Validation Steps:
+ *
+ * 1. Validate that no MNG messages are produced.
+ */
+ public void testManagementStartupDisabled() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(false, false);
+
+ List<String> results = findMatches(MNG_PREFIX);
+ // Validation
+
+ assertEquals("MNGer messages logged", 0, results.size());
+ }
+ }
+
+ /**
+ * The two MNG-1002 messages are logged at the same time so lets test them
+ * at the same time.
+ *
+ * Description:
+ * Using the default configuration validate that the RMI Registry socket is
+ * correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '8999'
+ *
+ * Description:
+ * Using the default configuration validate that the RMI ConnectorServer
+ * socket is correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '9099'
+ */
+ public void testManagementStartupRMIEntries() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ List<String> results = waitAndFindMatches("MNG-1002");
+ // Validation
+
+ //There will be 4 startup messages (two via SystemOut, and two via Log4J)
+ assertEquals("Unexpected MNG-1002 message count", 4, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ //Check the RMI Registry port is as expected
+ int mPort = getManagementPort(getPort());
+ assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(mPort)));
+
+ log = getLogMessage(results, 2);
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ // We expect the RMI Registry port (the defined 'management port') to be
+ // 100 lower than the JMX RMIConnector Server Port (the actual JMX server)
+ int jmxPort = mPort + JMXPORT_CONNECTORSERVER_OFFSET;
+ assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(jmxPort)));
+ }
+ }
+
+ /**
+ * Description:
+ * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006
+ * Input:
+ * Management SSL enabled default configuration.
+ * Output:
+ *
+ * <date> MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The keystore path is as specified in the configuration
+ */
+ public void testManagementStartupSSLKeystore() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ startBrokerAndCreateMonitor(true, true);
+
+ List<String> results = waitAndFindMatches("MNG-1006");
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1006", log);
+
+ // Validate we only have two MNG-1002 (one via stdout, one via log4j)
+ results = findMatches("MNG-1006");
+ assertEquals("Upexpected SSL Keystore message count",
+ 2, results.size());
+
+ // Validate the keystore path is as expected
+ assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
+ getMessageString(log).endsWith("systestsKeyStore"));
+ }
+ }
+
+ /**
+ * Description: Tests the management connection open/close are logged correctly.
+ *
+ * Output:
+ *
+ * <date> MESSAGE MNG-1007 : Open : User <username>
+ * <date> MESSAGE MNG-1008 : Close : User <username>
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The message and username are correct
+ */
+ public void testManagementUserOpenClose() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ final JMXTestUtils jmxUtils = new JMXTestUtils(this);
+ List<String> openResults = null;
+ List<String> closeResults = null;
+ try
+ {
+ jmxUtils.open();
+ openResults = waitAndFindMatches("MNG-1007");
+ }
+ finally
+ {
+ if (jmxUtils != null)
+ {
+ jmxUtils.close();
+ closeResults = waitAndFindMatches("MNG-1008");
+ }
+ }
+
+ assertNotNull("Management Open results null", openResults.size());
+ assertEquals("Management Open logged unexpected number of times", 1, openResults.size());
+
+ assertNotNull("Management Close results null", closeResults.size());
+ assertEquals("Management Close logged unexpected number of times", 1, closeResults.size());
+
+ final String openMessage = getMessageString(getLogMessage(openResults, 0));
+ assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin"));
+ final String closeMessage = getMessageString(getLogMessage(closeResults, 0));
+ assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin"));
+ }
+ }
+
+ private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception
+ {
+ TestBrokerConfiguration config = getBrokerConfiguration();
+
+ if (managementEnabled)
+ {
+ config.addJmxManagementConfiguration();
+ }
+
+ if(useManagementSSL)
+ {
+ // This test requires we have ssl, change the transport and add they keystore to the port config
+ config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ }
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java
new file mode 100644
index 0000000000..d0f133aa73
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java
@@ -0,0 +1,869 @@
+/*
+ * 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.systest.management.jmx;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import javax.naming.NamingException;
+
+import org.apache.commons.lang.time.FastDateFormat;
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.server.queue.NotificationCheckTest;
+import org.apache.qpid.server.queue.QueueArgumentsConverter;
+import org.apache.qpid.server.queue.StandardQueueImpl;
+import org.apache.qpid.test.client.destination.AddressBasedDestinationTest;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Tests the JMX API for the Managed Queue.
+ *
+ */
+public class QueueManagementTest extends QpidBrokerTestCase
+{
+
+ private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class);
+
+ private static final String VIRTUAL_HOST = "test";
+ private static final String TEST_QUEUE_DESCRIPTION = "my description";
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _connection;
+ private Session _session;
+
+ private String _sourceQueueName;
+ private String _destinationQueueName;
+ private Destination _sourceQueue;
+ private Destination _destinationQueue;
+ private ManagedQueue _managedSourceQueue;
+ private ManagedQueue _managedDestinationQueue;
+
+ public void setUp() throws Exception
+ {
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+ _sourceQueueName = getTestQueueName() + "_src";
+ _destinationQueueName = getTestQueueName() + "_dest";
+
+ createConnectionAndSession();
+
+ _sourceQueue = _session.createQueue(_sourceQueueName);
+ _destinationQueue = _session.createQueue(_destinationQueueName);
+ createQueueOnBroker(_sourceQueue);
+ createQueueOnBroker(_destinationQueue);
+
+ _jmxUtils.open();
+
+ createManagementInterfacesForQueues();
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ public void testQueueAttributes() throws Exception
+ {
+ Queue queue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(queue);
+
+ final String queueName = queue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected name", queueName, managedQueue.getName());
+ assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType());
+ }
+
+ public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception
+ {
+ final String subName = "testOwner";
+ _session.createDurableSubscriber(getTestTopic(), subName);
+
+ final String queueName = _connection.getClientID() + ":" + subName;
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNotNull(_connection.getClientID());
+ assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner());
+ }
+
+ public void testNonExclusiveQueueHasNoOwner() throws Exception
+ {
+ Queue nonExclusiveQueue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(nonExclusiveQueue);
+
+ final String queueName = nonExclusiveQueue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNull("Unexpected owner", managedQueue.getOwner());
+ }
+
+ public void testSetNewQueueDescriptionOnExistingQueue() throws Exception
+ {
+ Queue queue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(queue);
+
+ final String queueName = queue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNull("Unexpected description", managedQueue.getDescription());
+
+ managedQueue.setDescription(TEST_QUEUE_DESCRIPTION);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ public void testNewQueueWithDescription() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION);
+ ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ /**
+ * Requires persistent store.
+ */
+ public void testQueueDescriptionSurvivesRestart() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION);
+
+ ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+
+ restartBroker();
+
+ managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ /**
+ * Tests queue creation with {@link QueueArgumentsConverter#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests
+ * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}.
+ */
+ public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Integer deliveryCount = 1;
+ final Map<String, Object> arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount);
+ managedBroker.createNewQueue(queueName, null, true, arguments);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount());
+ }
+
+ public void testCreateQueueWithAlertingThresholdsSet() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Long maximumMessageCount = 100l;
+ final Long maximumMessageSize = 200l;
+ final Long maximumQueueDepth = 300l;
+ final Long maximumMessageAge = 400l;
+ final Map<String, Object> arguments = new HashMap<String, Object>();
+ arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_COUNT, maximumMessageCount);
+ arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_SIZE, maximumMessageSize);
+ arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_QUEUE_DEPTH, maximumQueueDepth);
+ arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_AGE, maximumMessageAge);
+
+ managedBroker.createNewQueue(queueName, null, true, arguments);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected maximum message count", maximumMessageCount, managedQueue.getMaximumMessageCount());
+ assertEquals("Unexpected maximum message size", maximumMessageSize, managedQueue.getMaximumMessageSize());
+ assertEquals("Unexpected maximum queue depth", maximumQueueDepth, managedQueue.getMaximumQueueDepth());
+ assertEquals("Unexpected maximum message age", maximumMessageAge, managedQueue.getMaximumMessageAge());
+ }
+
+ /**
+ * Requires 0-10 as relies on ADDR addresses.
+ * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange
+ */
+ public void testGetSetAlternateExchange() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String altExchange = "amq.fanout";
+ String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange);
+ Queue queue = _session.createQueue(addrWithAltExch);
+
+ createQueueOnBroker(queue);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange());
+
+ String newAltExch = "amq.topic";
+ managedQueue.setAlternateExchange(newAltExch);
+ assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange());
+ }
+
+ /**
+ * Requires 0-10 as relies on ADDR addresses.
+ */
+ public void testRemoveAlternateExchange() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String altExchange = "amq.fanout";
+ String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange);
+ Queue queue = _session.createQueue(addrWithAltExch);
+
+ createQueueOnBroker(queue);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange());
+
+ managedQueue.setAlternateExchange("");
+ assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange());
+ }
+
+ /**
+ * Requires persistent store
+ * Requires 0-10 as relies on ADDR addresses.
+ */
+ public void testAlternateExchangeSurvivesRestart() throws Exception
+ {
+ String nonMandatoryExchangeName = "exch" + getName();
+
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ managedBroker.createNewExchange(nonMandatoryExchangeName, "fanout", true);
+
+ String queueName1 = getTestQueueName() + "1";
+ String altExchange1 = "amq.fanout";
+ String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1);
+ Queue queue1 = _session.createQueue(addr1WithAltExch);
+
+ String queueName2 = getTestQueueName() + "2";
+ String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue}}", queueName2);
+ Queue queue2 = _session.createQueue(addr2WithoutAltExch);
+
+ createQueueOnBroker(queue1);
+ createQueueOnBroker(queue2);
+
+ ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1);
+ assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange());
+
+ ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2);
+ assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange());
+
+ String altExchange2 = nonMandatoryExchangeName;
+ managedQueue2.setAlternateExchange(altExchange2);
+
+ restartBroker();
+
+ managedQueue1 = _jmxUtils.getManagedQueue(queueName1);
+ assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange());
+
+ managedQueue2 = _jmxUtils.getManagedQueue(queueName2);
+ assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange());
+ }
+
+ /**
+ * Tests the ability to receive queue alerts as JMX notifications.
+ *
+ * @see NotificationCheckTest
+ * @see SimpleAMQQueueTest#testNotificationFiredAsync()
+ * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue()
+ */
+ public void testQueueNotification() throws Exception
+ {
+ final String queueName = getName();
+ final long maximumMessageCount = 3;
+
+ Queue queue = _session.createQueue(queueName);
+ createQueueOnBroker(queue);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ managedQueue.setMaximumMessageCount(maximumMessageCount);
+
+ RecordingNotificationListener listener = new RecordingNotificationListener(1);
+
+ _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null);
+
+ // Send two messages - this should *not* trigger the notification
+ sendMessage(_session, queue, 2);
+
+ assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived());
+
+ // A further message should trigger the message count alert
+ sendMessage(_session, queue, 1);
+
+ listener.awaitExpectedNotifications(5, TimeUnit.SECONDS);
+
+ assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived());
+
+ Notification notification = listener.getLastNotification();
+ assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage());
+ }
+
+ /**
+ * Tests {@link ManagedQueue#viewMessages(long, long)} interface.
+ */
+ public void testViewSingleMessage() throws Exception
+ {
+ final List<Message> sentMessages = sendMessage(_session, _sourceQueue, 1);
+ syncSession(_session);
+ final Message sentMessage = sentMessages.get(0);
+
+ assertEquals("Unexpected queue depth", 1, _managedSourceQueue.getMessageCount().intValue());
+
+ // Check the contents of the message
+ final TabularData tab = _managedSourceQueue.viewMessages(1l, 1l);
+ assertEquals("Unexpected number of rows in table", 1, tab.size());
+ final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator();
+
+ final CompositeData row1 = rowItr.next();
+ assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID));
+ assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS));
+ assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED));
+
+ // Check the contents of header (encoded in a string array)
+ final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER);
+ assertNotNull("Expected message header array", headerArray);
+ final Map<String, String> headers = headerArrayToMap(headerArray);
+
+ final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID();
+ final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp());
+ assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID"));
+ assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority"));
+ assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp"));
+ }
+
+ /**
+ * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface.
+ */
+ public void testMoveMessagesBetweenQueues() throws Exception
+ {
+ final int numberOfMessagesToSend = 10;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move first three messages to destination
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(2);
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after first move", 3, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after first move", 7, _managedSourceQueue.getMessageCount().intValue());
+
+ // Now move a further two messages to destination
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second move", 5, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second move", 5, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8);
+ }
+
+ /**
+ * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface.
+ */
+ public void testCopyMessagesBetweenQueues() throws Exception
+ {
+ final int numberOfMessagesToSend = 10;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Copy first three messages to destination
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(2);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after first copy", 3, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after first copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ // Now copy a further two messages to destination
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second copy", 5, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8);
+ }
+
+
+ /**
+ * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface.
+ */
+ public void testCopyMessagesBetweenQueuesWithDuplicates() throws Exception
+ {
+ final int numberOfMessagesToSend = 10;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send",
+ numberOfMessagesToSend,
+ _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Copy first three messages to destination
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(2);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after first copy",
+ 3,
+ _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after first copy",
+ numberOfMessagesToSend,
+ _managedSourceQueue.getMessageCount().intValue());
+
+ // Now copy a further two messages to destination
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second copy",
+ 5,
+ _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second copy",
+ numberOfMessagesToSend,
+ _managedSourceQueue.getMessageCount().intValue());
+
+ // Attempt to copy mixture of messages already on and some not already on the queue
+
+ fromMessageId = amqMessagesIds.get(5);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second copy",
+ 7,
+ _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second copy",
+ numberOfMessagesToSend,
+ _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8, 5, 6);
+
+
+ }
+
+ public void testMoveMessagesBetweenQueuesWithActiveConsumerOnSourceQueue() throws Exception
+ {
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString());
+ Connection asyncConnection = getConnection();
+ asyncConnection.start();
+
+ final int numberOfMessagesToSend = 50;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1);
+
+ CountDownLatch consumerReadToHalfwayLatch = new CountDownLatch(numberOfMessagesToSend / 2);
+ AtomicInteger totalConsumed = new AtomicInteger(0);
+ startAsyncConsumerOn(_sourceQueue, asyncConnection, consumerReadToHalfwayLatch, totalConsumed);
+
+ boolean halfwayPointReached = consumerReadToHalfwayLatch.await(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Did not read half of messages within time allowed", halfwayPointReached);
+
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ asyncConnection.stop();
+
+ // The exact number of messages moved will be non deterministic, as the number of messages processed
+ // by the consumer cannot be predicted. There is also the possibility that a message can remain
+ // on the source queue. This situation will arise if a message has been acquired by the consumer, but not
+ // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs.
+ //
+ // The number of messages moved + the number consumed + any messages remaining on source should
+ // *always* be equal to the number we originally sent.
+
+ int numberOfMessagesReadByConsumer = totalConsumed.intValue();
+ int numberOfMessagesOnDestinationQueue = _managedDestinationQueue.getMessageCount().intValue();
+ int numberOfMessagesRemainingOnSourceQueue = _managedSourceQueue.getMessageCount().intValue();
+
+ LOGGER.debug("Async consumer read : " + numberOfMessagesReadByConsumer
+ + " Number of messages moved to destination : " + numberOfMessagesOnDestinationQueue
+ + " Number of messages remaining on source : " + numberOfMessagesRemainingOnSourceQueue);
+ assertEquals("Unexpected number of messages after move", numberOfMessagesToSend, numberOfMessagesReadByConsumer + numberOfMessagesOnDestinationQueue + numberOfMessagesRemainingOnSourceQueue);
+ }
+
+ public void testMoveMessagesBetweenQueuesWithActiveConsumerOnDestinationQueue() throws Exception
+ {
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString());
+ Connection asyncConnection = getConnection();
+ asyncConnection.start();
+
+ final int numberOfMessagesToSend = 50;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1);
+
+ AtomicInteger totalConsumed = new AtomicInteger(0);
+ CountDownLatch allMessagesConsumedLatch = new CountDownLatch(numberOfMessagesToSend);
+ startAsyncConsumerOn(_destinationQueue, asyncConnection, allMessagesConsumedLatch, totalConsumed);
+
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ allMessagesConsumedLatch.await(5000, TimeUnit.MILLISECONDS);
+ assertEquals("Did not consume all messages from destination queue", numberOfMessagesToSend, totalConsumed.intValue());
+ }
+
+ /**
+ * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface.
+ */
+ public void testMoveMessageBetweenQueuesWithBrokerRestart() throws Exception
+ {
+ final int numberOfMessagesToSend = 1;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ restartBroker();
+
+ createManagementInterfacesForQueues();
+ createConnectionAndSession();
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move messages to destination
+ long messageId = amqMessagesIds.get(0);
+ _managedSourceQueue.moveMessages(messageId, messageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after move", 1, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after move", 0, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0);
+ }
+
+ /**
+ * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface.
+ */
+ public void testCopyMessageBetweenQueuesWithBrokerRestart() throws Exception
+ {
+ final int numberOfMessagesToSend = 1;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ restartBroker();
+
+ createManagementInterfacesForQueues();
+ createConnectionAndSession();
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move messages to destination
+ long messageId = amqMessagesIds.get(0);
+ _managedSourceQueue.copyMessages(messageId, messageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after copy", 1, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after copy", 1, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0);
+ }
+
+ /**
+ * Tests {@link ManagedQueue#deleteMessages(long, long)} interface.
+ */
+ public void testDeleteMessages() throws Exception
+ {
+ final int numberOfMessagesToSend = 15;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+ // Current expected queue state, in terms of message header indices: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
+
+ // Delete the first message (Remember the amqMessagesIds list, and the message indices added as a property when sending, are both 0-based index)
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = fromMessageId;
+ _managedSourceQueue.deleteMessages(fromMessageId, toMessageId);
+ assertEquals("Unexpected message count after first deletion", numberOfMessagesToSend - 1, _managedSourceQueue.getMessageCount().intValue());
+ // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
+
+ // Delete the 9th-10th messages, in the middle of the queue
+ fromMessageId = amqMessagesIds.get(8);
+ toMessageId = amqMessagesIds.get(9);
+ _managedSourceQueue.deleteMessages(fromMessageId, toMessageId);
+ assertEquals("Unexpected message count after third deletion", numberOfMessagesToSend - 3, _managedSourceQueue.getMessageCount().intValue());
+ // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,10,11,12,13,14]
+
+ // Delete the 11th and 12th messages, but still include the IDs for the 9th and 10th messages in the
+ // range to ensure their IDs are 'skipped' until the matching messages are found
+ fromMessageId = amqMessagesIds.get(8);
+ toMessageId = amqMessagesIds.get(11);
+ _managedSourceQueue.deleteMessages(fromMessageId, toMessageId);
+ assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 5, _managedSourceQueue.getMessageCount().intValue());
+ // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,X,X,12,13,14]
+
+ // Delete the 8th message and the 13th message, including the IDs for the 9th-12th messages in the
+ // range to ensure their IDs are 'skipped' and the other matching message is found
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(12);
+ _managedSourceQueue.deleteMessages(fromMessageId, toMessageId);
+ assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 7, _managedSourceQueue.getMessageCount().intValue());
+ // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,14]
+
+ // Delete the last message message
+ fromMessageId = amqMessagesIds.get(numberOfMessagesToSend -1);
+ toMessageId = fromMessageId;
+ _managedSourceQueue.deleteMessages(fromMessageId, toMessageId);
+ assertEquals("Unexpected message count after second deletion", numberOfMessagesToSend - 8, _managedSourceQueue.getMessageCount().intValue());
+ // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,X]
+
+ // Verify the message indices with a consumer
+ assertMessageIndicesOn(_sourceQueue, 1,2,3,4,5,6,13);
+ }
+
+ public void testGetMessageGroupKey() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Object messageGroupKey = "test";
+ final Map<String, Object> arguments = Collections.singletonMap(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey);
+ managedBroker.createNewQueue(queueName, null, true, arguments);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+
+ assertNotNull("Manager queue expected to be available", managedQueue);
+ assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey());
+ assertEquals("Unexpected message group sharing", false, managedQueue.isMessageGroupSharedGroups());
+ }
+
+ public void testIsMessageGroupSharedGroups() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Object messageGroupKey = "test";
+ final Map<String, Object> arguments = new HashMap<String, Object>(2);
+ arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey);
+ arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP, StandardQueueImpl.SHARED_MSG_GROUP_ARG_VALUE);
+ managedBroker.createNewQueue(queueName, null, true, arguments);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+
+ assertNotNull("Manager queue expected to be available", managedQueue);
+ assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey());
+ assertEquals("Unexpected message group sharing", true, managedQueue.isMessageGroupSharedGroups());
+ }
+
+ @Override
+ public Message createNextMessage(Session session, int messageNumber) throws JMSException
+ {
+ Message message = session.createTextMessage(getContentForMessageNumber(messageNumber));
+ message.setIntProperty(INDEX, messageNumber);
+ return message;
+ }
+
+ private void startAsyncConsumerOn(Destination queue, Connection asyncConnection,
+ final CountDownLatch requiredNumberOfMessagesRead, final AtomicInteger totalConsumed) throws Exception
+ {
+ Session session = asyncConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(queue);
+ consumer.setMessageListener(new MessageListener()
+ {
+
+ @Override
+ public void onMessage(Message arg0)
+ {
+ totalConsumed.incrementAndGet();
+ requiredNumberOfMessagesRead.countDown();
+ }
+ });
+ }
+
+ private void assertMessageIndicesOn(Destination queue, int... expectedIndices) throws Exception
+ {
+ MessageConsumer consumer = _session.createConsumer(queue);
+
+ for (int i : expectedIndices)
+ {
+ TextMessage message = (TextMessage)consumer.receive(1000);
+ assertNotNull("Expected message with index " + i, message);
+ assertEquals("Expected message with index " + i, i, message.getIntProperty(INDEX));
+ assertEquals("Expected message content", getContentForMessageNumber(i), message.getText());
+ }
+
+ assertNull("Unexpected message encountered", consumer.receive(1000));
+ }
+
+ private List<Long> getAMQMessageIdsOn(ManagedQueue managedQueue, long startIndex, long endIndex) throws Exception
+ {
+ final SortedSet<Long> messageIds = new TreeSet<Long>();
+
+ final TabularData tab = managedQueue.viewMessages(startIndex, endIndex);
+ final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator();
+ while(rowItr.hasNext())
+ {
+ final CompositeData row = rowItr.next();
+ long amqMessageId = (Long)row.get(ManagedQueue.MSG_AMQ_ID);
+ messageIds.add(amqMessageId);
+ }
+
+ return new ArrayList<Long>(messageIds);
+ }
+
+ /**
+ *
+ * Utility method to convert array of Strings in the form x = y into a
+ * map with key/value x =&gt; y.
+ *
+ */
+ private Map<String,String> headerArrayToMap(final String[] headerArray)
+ {
+ final Map<String, String> headerMap = new HashMap<String, String>();
+ final List<String> headerList = Arrays.asList(headerArray);
+ for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();)
+ {
+ final String nameValuePair = iterator.next();
+ final String[] nameValue = nameValuePair.split(" *= *", 2);
+ headerMap.put(nameValue[0], nameValue[1]);
+ }
+ return headerMap;
+ }
+
+ private void createQueueOnBroker(Destination destination) throws JMSException
+ {
+ _session.createConsumer(destination).close(); // Create a consumer only to cause queue creation
+ }
+
+ private void syncSession(Session session) throws Exception
+ {
+ ((AMQSession<?,?>)session).sync();
+ }
+
+ private void createConnectionAndSession() throws JMSException,
+ NamingException
+ {
+ _connection = getConnection();
+ _connection.start();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ }
+
+ private void createManagementInterfacesForQueues()
+ {
+ _managedSourceQueue = _jmxUtils.getManagedQueue(_sourceQueueName);
+ _managedDestinationQueue = _jmxUtils.getManagedQueue(_destinationQueueName);
+ }
+
+ private String getContentForMessageNumber(int msgCount)
+ {
+ return "Message count " + msgCount;
+ }
+
+ private final class RecordingNotificationListener implements NotificationListener
+ {
+ private final CountDownLatch _notificationReceivedLatch;
+ private final AtomicInteger _numberOfNotifications;
+ private final AtomicReference<Notification> _lastNotification;
+
+ private RecordingNotificationListener(int expectedNumberOfNotifications)
+ {
+ _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications);
+ _numberOfNotifications = new AtomicInteger(0);
+ _lastNotification = new AtomicReference<Notification>();
+ }
+
+ @Override
+ public void handleNotification(Notification notification, Object handback)
+ {
+ _lastNotification.set(notification);
+ _numberOfNotifications.incrementAndGet();
+ _notificationReceivedLatch.countDown();
+ }
+
+ public int getNumberOfNotificationsReceived()
+ {
+ return _numberOfNotifications.get();
+ }
+
+ public Notification getLastNotification()
+ {
+ return _lastNotification.get();
+ }
+
+ public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException
+ {
+ _notificationReceivedLatch.await(timeout, timeunit);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java
new file mode 100644
index 0000000000..4ea071f3ac
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.systest.management.jmx;
+
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class StatisticsTest extends QpidBrokerTestCase
+{
+ private static final String TEST_VIRTUALHOST1 = "test1";
+ private static final String TEST_VIRTUALHOST2 = "test2";
+
+ private static final String TEST_USER = "admin";
+ private static final String TEST_PASSWORD = "admin";
+ private static final int MESSAGE_COUNT_TEST = 5;
+ private static final int MESSAGE_COUNT_DEV = 9;
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _vhost1Connection, _vhost2Connection;
+ private Session _vhost1Session, _vhost2Session;
+ private Queue _vhost1Queue, _vhost2Queue;
+ protected String _brokerUrl;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ createTestVirtualHostNode(0, TEST_VIRTUALHOST1);
+ createTestVirtualHostNode(0, TEST_VIRTUALHOST2);
+
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD);
+
+ super.setUp();
+
+ _brokerUrl = getBroker().toString();
+ _vhost1Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST1);
+ _vhost2Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST2);
+ _vhost1Connection.start();
+ _vhost2Connection.start();
+
+ _vhost1Session = _vhost1Connection.createSession(true, Session.SESSION_TRANSACTED);
+ _vhost2Session = _vhost2Connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ _vhost1Queue = _vhost2Session.createQueue(getTestQueueName());
+ _vhost2Queue = _vhost1Session.createQueue(getTestQueueName());
+
+ //Create queues by opening and closing consumers
+ final MessageConsumer vhost1Consumer = _vhost1Session.createConsumer(_vhost2Queue);
+ vhost1Consumer.close();
+ final MessageConsumer vhost2Consumer = _vhost2Session.createConsumer(_vhost1Queue);
+ vhost2Consumer.close();
+
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmxUtils.close();
+
+ super.tearDown();
+ }
+
+ public void testInitialStatisticValues() throws Exception
+ {
+ //Check initial values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(0, 0, 0, 0);
+ }
+
+ public void testSendOnSingleVHost() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ }
+
+ public void testSendOnTwoVHosts() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0);
+ }
+
+ public void testSendAndConsumeOnSingleVHost() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ }
+
+ public void testSendAndConsumeOnTwoVHosts() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+ consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ consumeMessages(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE);
+ }
+
+ private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception
+ {
+ //Send messages via connection on and sync
+ sendMessage(session, queue, numberOfMessages);
+ ((AMQSession<?,?>)session).sync();
+ }
+
+ private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception
+ {
+ //consume the messages on the virtual host
+ final MessageConsumer consumer = session.createConsumer(queue);
+ for (int i = 0 ; i < numberOfMessages ; i++)
+ {
+ assertNotNull("an expected message was not received", consumer.receive(1500));
+ }
+ session.commit();
+ consumer.close();
+ }
+
+ private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ List<ManagedConnection> managedConnections = _jmxUtils.getManagedConnections(vHostName);
+ assertEquals(1, managedConnections.size());
+
+ ManagedConnection managedConnection = managedConnections.get(0);
+
+ assertEquals(messagesSent, managedConnection.getTotalMessagesReceived());
+ assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, managedConnection.getTotalDataReceived());
+ assertEquals(dataReceived, managedConnection.getTotalDataDelivered());
+ }
+
+ private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName);
+
+ assertEquals(messagesSent, vhost.getTotalMessagesReceived());
+ assertEquals(messagesReceived, vhost.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, vhost.getTotalDataReceived());
+ assertEquals(dataReceived, vhost.getTotalDataDelivered());
+ }
+
+ private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ ServerInformation broker = _jmxUtils.getServerInformation();
+
+ assertEquals(messagesSent, broker.getTotalMessagesReceived());
+ assertEquals(messagesReceived, broker.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, broker.getTotalDataReceived());
+ assertEquals(dataReceived, broker.getTotalDataDelivered());
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
new file mode 100644
index 0000000000..25b09f04c3
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.systest.management.jmx;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.tools.security.Passwd;
+
+/**
+ * System test for User Management.
+ *
+ */
+public class UserManagementTest extends QpidBrokerTestCase
+{
+ private static final String TEST_NEWPASSWORD = "newpassword";
+ private static final String TEST_PASSWORD = "password";
+ private JMXTestUtils _jmxUtils;
+ private String _testUserName;
+ private File _passwordFile;
+ private UserManagement _userManagement;
+ private Passwd _passwd;
+
+ public void setUp() throws Exception
+ {
+ _passwd = createPasswordEncodingUtility();
+ _passwordFile = createTemporaryPasswordFileWithJmxAdminUser();
+
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(AuthenticationProvider.TYPE, getAuthenticationManagerType());
+ newAttributes.put("path", _passwordFile.getAbsolutePath());
+ getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes);
+ getBrokerConfiguration().addJmxManagementConfiguration();
+
+ _jmxUtils = new JMXTestUtils(this);
+
+ super.setUp();
+ _jmxUtils.open();
+
+ _testUserName = getTestName() + System.currentTimeMillis();
+
+ _userManagement = _jmxUtils.getUserManagement(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ }
+
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testCreateUser() throws Exception
+ {
+ final int initialNumberOfUsers = _userManagement.viewUsers().size();
+ assertFileDoesNotContainsPasswordForUser(_testUserName);
+
+ boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD);
+ assertTrue("Should have been able to create new user " + _testUserName, success);
+ assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size());
+
+ assertFileContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginForNewUser() throws Exception
+ {
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ testCreateUser();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ final int initialNumberOfUsers = _userManagement.viewUsers().size();
+
+ testCreateUser();
+
+ boolean success = _userManagement.deleteUser(_testUserName);
+ assertTrue("Should have been able to delete new user " + _testUserName, success);
+ assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size());
+ assertFileDoesNotContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginNotPossibleForDeletedUser() throws Exception
+ {
+ testDeleteUser();
+
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testSetPassword() throws Exception
+ {
+ testCreateUser();
+
+ _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD);
+
+ assertFileContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginForPasswordChangedUser() throws Exception
+ {
+ testSetPassword();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD);
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testReload() throws Exception
+ {
+ writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD);
+
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+
+ _userManagement.reloadData();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testGetAuthenticationProviderType() throws Exception
+ {
+ String actualType = _userManagement.getAuthenticationProviderType();
+ assertEquals("unexpected authentication provider type", getAuthenticationManagerType(), actualType);
+ }
+
+ protected Passwd createPasswordEncodingUtility()
+ {
+ return new Passwd()
+ {
+ @Override
+ public String getOutput(String username, String password)
+ {
+ return username + ":" + password;
+ }
+ };
+ }
+
+ protected String getAuthenticationManagerType()
+ {
+ return PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE;
+ }
+
+ private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception
+ {
+ File passwordFile = File.createTempFile("passwd", "pwd");
+ passwordFile.deleteOnExit();
+ writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD);
+ return passwordFile;
+ }
+
+ private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception
+ {
+ FileWriter writer = null;
+ try
+ {
+ writer = new FileWriter(passwordFile);
+ for (int i = 0; i < userNamePasswordPairs.length; i=i+2)
+ {
+ String username = userNamePasswordPairs[i];
+ String password = userNamePasswordPairs[i+1];
+ writer.append(_passwd.getOutput(username, password) + "\n");
+ }
+ }
+ finally
+ {
+ writer.close();
+ }
+ }
+
+
+ private void assertFileContainsPasswordForUser(String username) throws IOException
+ {
+ assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username));
+ }
+
+ private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException
+ {
+ assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username));
+ }
+
+ private boolean passwordFileContainsUser(String username) throws IOException
+ {
+ BufferedReader reader = null;
+ try
+ {
+ reader = new BufferedReader(new FileReader(_passwordFile));
+ String line = reader.readLine();
+ while(line != null)
+ {
+ if (line.startsWith(username))
+ {
+ return true;
+ }
+ line = reader.readLine();
+ }
+
+ return false;
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ private void assertJmsConnectionSucceeds(String username, String password) throws Exception
+ {
+ Connection connection = getConnection(username, password);
+ assertNotNull(connection);
+ }
+
+ private void assertJmsConnectionFails(String username, String password) throws Exception
+ {
+ try
+ {
+ getConnection(username, password);
+ fail("Exception not thrown");
+ }
+ catch (JMSException e)
+ {
+ // PASS
+ }
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
new file mode 100644
index 0000000000..ff441169b3
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.systest.management.jmx;
+
+import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager;
+import org.apache.qpid.tools.security.Passwd;
+
+public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest
+{
+ @Override
+ protected Passwd createPasswordEncodingUtility()
+ {
+ return new Passwd();
+ }
+
+ @Override
+ protected String getAuthenticationManagerType()
+ {
+ return Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE;
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java
new file mode 100644
index 0000000000..4140c9c12c
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java
@@ -0,0 +1,288 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.server.BrokerOptions;
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AccessControlProvider;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.security.access.FileAccessControlProviderConstants;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class AccessControlProviderRestTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "allowed";
+ private static final String DENIED_USER = "denied";
+ private static final String OTHER_USER = "other";
+
+ private String _aclFileContent1 =
+ "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" +
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" +
+ "ACL DENY-LOG ALL ALL";
+
+ private String _aclFileContent2 =
+ "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" +
+ "ACL ALLOW-LOG " + OTHER_USER + " ACCESS MANAGEMENT\n" +
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" +
+ "ACL DENY-LOG ALL ALL";
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER);
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ public void testCreateAccessControlProvider() throws Exception
+ {
+ String accessControlProviderName = getTestName();
+
+ //verify that the access control provider doesn't exist, and
+ //in doing so implicitly verify that the 'denied' user can
+ //actually currently connect because no ACL is in effect yet
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ //create the access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //verify it exists with the 'allowed' user
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ //verify the 'denied' user can no longer access the management interface
+ //due to the just-created ACL file now preventing it
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName, false);
+ }
+
+ public void testRemoveAccessControlProvider() throws Exception
+ {
+ String accessControlProviderName = getTestName();
+
+ //verify that the access control provider doesn't exist, and
+ //in doing so implicitly verify that the 'denied' user can
+ //actually currently connect because no ACL is in effect yet
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ //create the access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //verify it exists with the 'allowed' user
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ //verify the 'denied' user can no longer access the management interface
+ //due to the just-created ACL file now preventing it
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName, false);
+
+ //remove the access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE");
+ assertEquals("Access control provider deletion should be allowed", 200, responseCode);
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ //verify it is gone again, using the 'denied' user to implicitly confirm it is
+ //now able to connect to the management interface again because the ACL was removed.
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+ }
+
+ public void testReplaceAccessControlProvider() throws Exception
+ {
+ String accessControlProviderName1 = getTestName() + "1";
+
+ //verify that the access control provider doesn't exist, and
+ //in doing so implicitly verify that the 'denied' user can
+ //actually currently connect because no ACL is in effect yet
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertAccessControlProviderExistence(accessControlProviderName1, false);
+
+ //create the access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //verify it exists with the 'allowed' user
+ assertAccessControlProviderExistence(accessControlProviderName1, true);
+
+ //verify the 'denied' and 'other' user can no longer access the management
+ //interface due to the just-created ACL file now preventing them
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName1, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName1, false);
+
+ //create the replacement access control provider using the 'allowed' user.
+ String accessControlProviderName2 = getTestName() + "2";
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //Verify that it took effect immediately, replacing the first access control provider
+
+ //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN.
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, true);
+
+ //remove the original access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName1, "DELETE");
+ assertEquals("Access control provider deletion should be allowed", 200, responseCode);
+ assertAccessControlProviderExistence(accessControlProviderName1, false);
+
+ //verify the 'denied' user still can't access the management interface, the 'other' user still can, thus
+ //confirming that the second access control provider is still in effect
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, true);
+ }
+
+
+ public void testAddAndRemoveSecondAccessControlProviderReinstatesOriginal() throws Exception
+ {
+ String accessControlProviderName1 = getTestName() + "1";
+
+ //verify that the access control provider doesn't exist, and
+ //in doing so implicitly verify that the 'denied' user can
+ //actually currently connect because no ACL is in effect yet
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertAccessControlProviderExistence(accessControlProviderName1, false);
+
+ //create the access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //verify it exists with the 'allowed' user
+ assertAccessControlProviderExistence(accessControlProviderName1, true);
+
+ //verify the 'denied' and 'other' user can no longer access the management
+ //interface due to the just-created ACL file now preventing them
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName1, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName1, false);
+
+ //create the replacement access control provider using the 'allowed' user.
+ String accessControlProviderName2 = getTestName() + "2";
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ //Verify that it took effect immediately, replacing the first access control provider
+
+ //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN.
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, true);
+
+ //remove the second access control provider using the 'allowed' user
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName2, "DELETE");
+ assertEquals("Access control provider deletion should be allowed", 200, responseCode);
+ assertAccessControlProviderExistence(accessControlProviderName2, false);
+
+ //verify the 'denied' user still can't access the management interface, the
+ //'other' now CANT again, the 'allowed' still can, thus confirming that the
+ //first access control provider is now in effect once again
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, false);
+ getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, false);
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ assertCanAccessManagementInterface(accessControlProviderName2, true);
+ }
+
+ public void testRemovalOfAccessControlProviderInErrorStateUsingManagementMode() throws Exception
+ {
+ stopBroker();
+
+ File file = new File(TMP_FOLDER, getTestName());
+ if (file.exists())
+ {
+ file.delete();
+ }
+ assertFalse("ACL file should not exist", file.exists());
+ UUID id = getBrokerConfiguration().addAclFileConfiguration(file.getAbsolutePath());
+ getBrokerConfiguration().setSaved(false);
+ startBroker(0, true);
+
+ getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD);
+
+ Map<String, Object> acl = getRestTestHelper().getJsonAsSingletonList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE);
+ assertEquals("Unexpected id", id.toString(), acl.get(AccessControlProvider.ID));
+ assertEquals("Unexpected path", file.getAbsolutePath() , acl.get(FileAccessControlProviderConstants.PATH));
+ assertEquals("Unexpected state", State.ERRORED.name() , acl.get(AccessControlProvider.STATE));
+
+ int status = getRestTestHelper().submitRequest("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE, "DELETE");
+ assertEquals("ACL was not deleted", 200, status);
+
+ List<Map<String, Object>> acls = getRestTestHelper().getJsonAsList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE);
+ assertEquals("ACL exists", 0, acls.size());
+ }
+
+ private void assertCanAccessManagementInterface(String accessControlProviderName, boolean canAccess) throws Exception
+ {
+ int expected = canAccess ? 200 : 403;
+ int responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "GET");
+ assertEquals("Unexpected response code", expected, responseCode);
+ }
+
+ private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception
+ {
+ String path = "accesscontrolprovider/" + accessControlProviderName;
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList(path);
+ assertEquals("Unexpected result", exists, !providers.isEmpty());
+ }
+
+ private int createAccessControlProvider(String accessControlProviderName, String content) throws Exception
+ {
+ File file = TestFileUtils.createTempFile(this, ".acl", content);
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AccessControlProvider.NAME, accessControlProviderName);
+ attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE);
+ attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile());
+
+ return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java
new file mode 100644
index 0000000000..3f944da8c7
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class AnonymousAccessRestTest extends QpidRestTestCase
+{
+ @Override
+ public void startBroker()
+ {
+ // prevent broker from starting in setUp
+ }
+
+ public void startBrokerNow() throws Exception
+ {
+ super.startBroker();
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ TestBrokerConfiguration config = getBrokerConfiguration();
+
+ Map<String, Object> anonymousAuthProviderAttributes = new HashMap<String, Object>();
+ anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+ anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER);
+ config.addObjectConfiguration(AuthenticationProvider.class, anonymousAuthProviderAttributes);
+
+ // set anonymous authentication provider on http port for the tests
+ config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
+ TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER);
+ config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false);
+
+ // reset credentials
+ getRestTestHelper().setUsernameAndPassword(null, null);
+ }
+
+ public void testGetWithAnonymousProvider() throws Exception
+ {
+ startBrokerNow();
+
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertNotNull("Unexpected broker attributes", brokerDetails);
+ assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID));
+ }
+
+ public void testPutAnonymousProvider() throws Exception
+ {
+ startBrokerNow();
+
+ Map<String, Object> brokerAttributes = new HashMap<String, Object>();
+ brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST);
+
+ int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response", 200, response);
+
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertNotNull("Unexpected broker attributes", brokerDetails);
+ assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID));
+ assertEquals("Unexpected default virtual host", TEST3_VIRTUALHOST, brokerDetails.get(Broker.DEFAULT_VIRTUAL_HOST));
+ }
+
+ public void testGetWithPasswordAuthProvider() throws Exception
+ {
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
+ TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ startBrokerNow();
+
+ int response = getRestTestHelper().submitRequest("broker", "GET");
+ assertEquals("Anonymous access should be denied", 401, response);
+ }
+
+ public void testPutWithPasswordAuthProvider() throws Exception
+ {
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
+ TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ startBrokerNow();
+
+ Map<String, Object> brokerAttributes = new HashMap<String, Object>();
+ brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST);
+
+ int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes);
+ assertEquals("Anonymous access should be denied", 401, response);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
new file mode 100644
index 0000000000..2467705903
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
@@ -0,0 +1,337 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.server.BrokerOptions;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class AuthenticationProviderRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 2, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ boolean managesPrincipals = true;
+ String type = PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE;
+ if (ANONYMOUS_AUTHENTICATION_PROVIDER.equals(provider.get(AuthenticationProvider.NAME)))
+ {
+ type = AnonymousAuthenticationManager.PROVIDER_TYPE;
+ managesPrincipals = false;
+ }
+ assertProvider(managesPrincipals, type , provider);
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/"
+ + provider.get(AuthenticationProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data);
+ assertProvider(managesPrincipals, type, data);
+ }
+ }
+
+ public void testPutCreateSecondPlainPrincipalDatabaseProviderSucceeds() throws Exception
+ {
+ File principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"});
+
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("failed to create authentication provider", 201, responseCode);
+ }
+
+ public void testPutCreateNewAnonymousProvider() throws Exception
+ {
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName);
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ Map<String, Object> provider = providerDetails.get(0);
+ assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, provider);
+ }
+
+ public void testUpdateAuthenticationProviderIdFails() throws Exception
+ {
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ attributes.put(AuthenticationProvider.ID, UUID.randomUUID());
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Update with new ID should fail", 409, responseCode);
+ }
+
+ public void testDeleteOfUsedAuthenticationProviderFails() throws Exception
+ {
+ // create provider
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Unexpected response code for provider creation", 201, responseCode);
+
+ // create port
+ String portName = "test-port";
+ Map<String, Object> portAttributes = new HashMap<String, Object>();
+ portAttributes.put(Port.NAME, portName);
+ portAttributes.put(Port.AUTHENTICATION_PROVIDER, providerName);
+ portAttributes.put(Port.PORT, findFreePort());
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", portAttributes);
+ assertEquals("Unexpected response code for port creation", 201, responseCode);
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 409, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName);
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, providerDetails.get(0));
+ }
+
+ public void testDeleteOfUnusedAuthenticationProvider() throws Exception
+ {
+ // create provider
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Unexpected response code for provider creation", 201, responseCode);
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName);
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 0, providerDetails.size());
+ }
+
+ public void testRemovalOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception
+ {
+ stopBroker();
+
+ File file = new File(TMP_FOLDER, getTestName());
+ if (file.exists())
+ {
+ file.delete();
+ }
+ assertFalse("Group file should not exist", file.exists());
+
+ TestBrokerConfiguration config = getBrokerConfiguration();
+
+ String providerName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile());
+
+ UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes);
+ config.setSaved(false);
+ startBroker(0, true);
+
+ getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD);
+
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+ assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID));
+ assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME));
+ assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH));
+ assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE));
+
+ int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE");
+ assertEquals("ACL was not deleted", 200, status);
+
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName);
+ assertEquals("Provider exists", 0, providers.size());
+ }
+
+ public void testUpdateOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception
+ {
+ stopBroker();
+
+ File file = new File(TMP_FOLDER, getTestName());
+ if (file.exists())
+ {
+ file.delete();
+ }
+ assertFalse("Group file should not exist", file.exists());
+
+ TestBrokerConfiguration config = getBrokerConfiguration();
+
+ String providerName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile());
+
+ UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes);
+ config.setSaved(false);
+ startBroker(0, true);
+
+ getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD);
+
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+ assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID));
+ assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME));
+ assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH));
+ assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE));
+
+ File principalDatabase = null;
+ try
+ {
+ principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"});
+ attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.ID, id);
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath());
+
+ int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("ACL was not deleted", 200, status);
+
+ provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+ assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID));
+ assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME));
+ assertEquals("Unexpected path", principalDatabase.getAbsolutePath() , provider.get(
+ ExternalFileBasedAuthenticationManager.PATH));
+ assertEquals("Unexpected state", State.ACTIVE.name() , provider.get(AuthenticationProvider.STATE));
+ }
+ finally
+ {
+ if (principalDatabase != null)
+ {
+ principalDatabase.delete();
+ }
+ }
+ }
+
+ public void testCreateAndDeletePasswordAuthenticationProviderWithNonExistingFile() throws Exception
+ {
+ stopBroker();
+ getBrokerConfiguration().setSaved(false);
+ getBrokerConfiguration().removeObjectConfiguration(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+
+ startBroker();
+
+ File file = new File(TMP_FOLDER + File.separator + getTestName());
+ if (file.exists())
+ {
+ file.delete();
+ }
+ assertFalse("File " + file.getAbsolutePath() + " should not exist", file.exists());
+
+ // create provider
+ String providerName = "test-provider";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Password provider was not created", 201, responseCode);
+
+
+ Map<String, Object> providerDetails = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected name", providerName, providerDetails.get(AuthenticationProvider.NAME));
+ assertEquals("Unexpected type", PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE, providerDetails.get(AuthenticationProvider.TYPE));
+ assertEquals("Unexpected path", file.getAbsolutePath(), providerDetails.get(
+ ExternalFileBasedAuthenticationManager.PATH));
+
+ assertTrue("User file should be created", file.exists());
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName);
+ assertNotNull("Providers details cannot be null", providers);
+ assertEquals("Unexpected number of providers", 0, providers.size());
+
+ assertFalse("File " + file.getAbsolutePath() + " should be deleted", file.exists());
+ }
+
+ private void assertProvider(boolean managesPrincipals, String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(
+ AuthenticationProvider.class),
+ AuthenticationProvider.DESCRIPTION, ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE, ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME, ConfiguredObject.LAST_UPDATED_BY, ConfiguredObject.LAST_UPDATED_TIME);
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(),
+ provider.get(AuthenticationProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE,
+ provider.get(AuthenticationProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type,
+ provider.get(AuthenticationProvider.TYPE));
+
+ if (managesPrincipals)
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> users = (List<Map<String, Object>>) provider.get("users");
+ assertNotNull("Users are not found", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+ }
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
new file mode 100644
index 0000000000..c51457cdab
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class BasicAuthRestTest extends QpidRestTestCase
+{
+ private static final String USERNAME = "admin";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+
+ //don't call super method, we will configure the broker in the test before doing so
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ //do nothing, we will configure this locally
+ }
+
+ private void configure(boolean useSsl) throws IOException
+ {
+ getRestTestHelper().setUseSsl(useSsl);
+ if (useSsl)
+ {
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ }
+ super.customizeConfiguration();
+ }
+
+ private void verifyGetBrokerAttempt(int responseCode) throws IOException
+ {
+ assertEquals(responseCode, getRestTestHelper().submitRequest("broker", "GET"));
+ }
+
+ public void testBasicAuthWhenEnabledWithHttps() throws Exception
+ {
+ configure(true);
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+
+ // Try the attempt with authentication, it should succeed because
+ // BASIC auth is enabled by default on secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_OK);
+ }
+
+ public void testBasicAuthWhenDisabledWithHttp() throws Exception
+ {
+ configure(false);
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false);
+ super.setUp();
+
+ // Try the attempt with authentication, it should fail because
+ // BASIC auth is disabled by default on non-secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ public void testEnablingForHttp() throws Exception
+ {
+ configure(false);
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ super.setUp();
+
+ // Try the attempt with authentication, it should succeed because
+ // BASIC auth is now enabled on non-secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_OK);
+ }
+
+ public void testDisablingForHttps() throws Exception
+ {
+ configure(true);
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "httpsBasicAuthenticationEnabled", false);
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+
+ // Try the attempt with authentication, it should fail because
+ // BASIC auth is now disabled on secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java
new file mode 100644
index 0000000000..368bc90d3d
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java
@@ -0,0 +1,131 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+
+public class BindingRestTest extends QpidRestTestCase
+{
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ getRestTestHelper().createTestQueues();
+ }
+
+ public void testGetAllBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("binding/test");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size());
+ for (Map<String, Object> binding : bindings)
+ {
+ Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size());
+ for (String queueName : RestTestHelper.EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, "amq.direct", binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeQueueBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+ }
+
+
+ public void testDeleteBinding() throws Exception
+ {
+ String bindingUrl = "binding/test/test/amq.direct/queue/queue";
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList(bindingUrl);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+
+ int responseCode = getRestTestHelper().submitRequest(bindingUrl, "DELETE");
+ assertEquals("Unexpected response code", 200, responseCode);
+
+ bindings = getRestTestHelper().getJsonAsList(bindingUrl);
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testDeleteBindingById() throws Exception
+ {
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("binding/test/test/amq.direct/queue");
+ int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE");
+ assertEquals("Unexpected response code", 200, responseCode);
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue");
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testCreateBinding() throws Exception
+ {
+ String bindingName = getTestName();
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.QUEUE, "queue");
+ bindingData.put(Binding.EXCHANGE, "amq.direct");
+
+ String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName;
+
+ int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", bindingData);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl);
+ Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
+ }
+
+ public void testSetBindingAttributesUnsupported() throws Exception
+ {
+ String bindingName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Binding.NAME, bindingName);
+ attributes.put(Binding.QUEUE, "queue");
+ attributes.put(Binding.EXCHANGE, "amq.direct");
+
+ String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName;
+ int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl);
+ Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
+
+ attributes.put(Binding.ARGUMENTS, "blah");
+
+ responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes);
+ assertEquals("Update should be unsupported", 409, responseCode);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java
new file mode 100644
index 0000000000..74db3e7040
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class BrokerRestHttpAndHttpsTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP));
+ newAttributes.put(Port.TRANSPORTS, Arrays.asList(Transport.SSL, Transport.TCP));
+ newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes);
+ getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER,
+ "secureOnlyMechanisms",
+ "[\"PLAIN\"]");
+
+ }
+
+ public void testGetWithHttps() throws Exception
+ {
+ Collection<String> results = getMechanisms(true);
+ assertTrue("mechanisms did not contain PLAIN: " + results, results.contains("PLAIN"));
+ }
+
+
+ public void testGetWithHttp() throws Exception
+ {
+ Collection<String> results = getMechanisms(false);
+ assertFalse("mechanisms incorrectly contain PLAIN: " + results, results.contains("PLAIN"));
+ }
+
+
+ private Collection<String> getMechanisms(final boolean useSsl) throws IOException
+ {
+ getRestTestHelper().setUseSsl(useSsl);
+ Map<String, Object> mechanisms = getRestTestHelper().getJsonAsMap("/service/sasl");
+ return (Collection<String>) mechanisms.get("mechanisms");
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java
new file mode 100644
index 0000000000..5b8d919d3e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class BrokerRestHttpsClientCertAuthTest extends QpidRestTestCase
+{
+
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+ setSystemProperty("javax.net.ssl.keystore", KEYSTORE);
+ setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD);
+
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().setUseSslAuth(true);
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP));
+ newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ newAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
+ newAttributes.put(Port.NEED_CLIENT_AUTH,"true");
+
+
+ Map<String, Object> externalProviderAttributes = new HashMap<String, Object>();
+ externalProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE);
+ externalProviderAttributes.put(AuthenticationProvider.NAME, EXTERNAL_AUTHENTICATION_PROVIDER);
+ getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class, externalProviderAttributes);
+
+ // set password authentication provider on http port for the tests
+ getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
+ EXTERNAL_AUTHENTICATION_PROVIDER);
+
+ getBrokerConfiguration().setObjectAttributes(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, newAttributes);
+ }
+
+ public void testGetWithHttps() throws Exception
+ {
+ Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("/service/sasl");
+
+ Asserts.assertAttributesPresent(saslData, "user");
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
new file mode 100644
index 0000000000..319cc1c9da
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class BrokerRestHttpsTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().setUseSsl(true);
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP));
+ newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes);
+ }
+
+ public void testGetWithHttps() throws Exception
+ {
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+
+ Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Broker.class),
+ Broker.PROCESS_PID,
+ ConfiguredObject.TYPE,
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java
new file mode 100644
index 0000000000..bae27b802c
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java
@@ -0,0 +1,242 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.test.client.UnroutableMessageTestExceptionListener;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.util.SystemUtils;
+
+public class BrokerRestTest extends QpidRestTestCase
+{
+ private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders";
+ private static final String BROKER_PORTS_ATTRIBUTE = "ports";
+ private static final String BROKER_VIRTUALHOST_NODES_ATTRIBUTE = "virtualhostnodes";
+ private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics";
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+
+ assertBrokerAttributes(brokerDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" });
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> nodes = (List<Map<String, Object>>) brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE);
+ assertEquals("Unexpected number of virtual hosts", 3, nodes.size());
+
+ for (String nodeName: EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> nodeAttributes = getRestTestHelper().find(VirtualHostNode.NAME, nodeName, nodes);
+ assertNotNull("Node attributes are not found for node with name " + nodeName, nodeAttributes);
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ for (Map<String, Object> port : ports)
+ {
+ Asserts.assertPortAttributes(port);
+ }
+
+ Map<String, Object> amqpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, ports);
+ Map<String, Object> httpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, ports);
+
+ assertEquals("Unexpected binding address", "*", amqpPort.get(Port.BINDING_ADDRESS));
+ assertNotNull("Cannot find AMQP port", amqpPort);
+ assertNotNull("Cannot find HTTP port", httpPort);
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port1Protocols = (Collection<String>) amqpPort.get(Port.PROTOCOLS);
+ assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols != null && port1Protocols.contains("HTTP"));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port2Protocols = (Collection<String>) httpPort.get(Port.PROTOCOLS);
+ assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet<String>(Arrays.asList("HTTP")),
+ new HashSet<String>(port2Protocols));
+ }
+
+ public void testPutToUpdateWithValidAttributeValues() throws Exception
+ {
+ Map<String, Object> brokerAttributes = getValidBrokerAttributes();
+
+ int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response", 200, response);
+
+ restartBroker();
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertBrokerAttributes(brokerAttributes, brokerDetails);
+ }
+
+ public void testPutUpdateWhereNumericAttributesAreSetAsStringValues() throws Exception
+ {
+ Map<String, Object> validAttributes = getValidBrokerAttributes();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+
+ for (Map.Entry<String, Object> entry : validAttributes.entrySet())
+ {
+ Object value = entry.getValue();
+ if (value instanceof Number)
+ {
+ value = String.valueOf(value);
+ }
+ attributes.put(entry.getKey(), value);
+ }
+
+ int response = getRestTestHelper().submitRequest("broker", "PUT", attributes);
+ assertEquals("Unexpected update response", 200, response);
+
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertBrokerAttributes(validAttributes, brokerDetails);
+ }
+
+ public void testPutToUpdateWithInvalidAttributeValues() throws Exception
+ {
+ Map<String, Object> invalidAttributes = new HashMap<String, Object>();
+ invalidAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, "non-existing-host");
+ invalidAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, -10);
+ invalidAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, -11000);
+ invalidAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, -12000);
+
+ for (Map.Entry<String, Object> entry : invalidAttributes.entrySet())
+ {
+ Map<String, Object> brokerAttributes = getValidBrokerAttributes();
+ brokerAttributes.put(entry.getKey(), entry.getValue());
+ int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response for invalid attribute " + entry.getKey() + "=" + entry.getValue(), 409, response);
+ }
+
+ }
+
+ public void testSetCloseOnNoRoute() throws Exception
+ {
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertTrue("closeOnNoRoute should be true", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE));
+
+ Map<String, Object> brokerAttributes = new HashMap<String, Object>();
+ brokerAttributes.put(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false);
+
+ int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes);
+ assertEquals("Unexpected update response", 200, response);
+
+ brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertFalse("closeOnNoRoute should be false", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE));
+
+ Connection connection = getConnection();
+ UnroutableMessageTestExceptionListener exceptionListener = new UnroutableMessageTestExceptionListener();
+ connection.setExceptionListener(exceptionListener);
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ MessageProducer producer = session.createProducer(getTestQueue());
+ TextMessage message = session.createTextMessage("Test");
+ producer.send(message);
+
+ session.commit();
+
+ exceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName());
+ }
+
+ private Map<String, Object> getValidBrokerAttributes()
+ {
+ Map<String, Object> brokerAttributes = new HashMap<String, Object>();
+ brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST);
+ brokerAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, 10);
+ brokerAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, 11000);
+ brokerAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, 12000);
+ brokerAttributes.put(Broker.STATISTICS_REPORTING_RESET_ENABLED, true);
+ return brokerAttributes;
+ }
+
+ private void assertBrokerAttributes(Map<String, Object> expectedAttributes, Map<String, Object> actualAttributes)
+ {
+ for (Map.Entry<String, Object> entry : expectedAttributes.entrySet())
+ {
+ String attributeName = entry.getKey();
+ Object attributeValue = entry.getValue();
+
+ Object currentValue = actualAttributes.get(attributeName);
+ assertEquals("Unexpected attribute " + attributeName + " value:", attributeValue, currentValue);
+ }
+ }
+
+ protected void assertBrokerAttributes(Map<String, Object> brokerDetails)
+ {
+ Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(
+ Broker.class),
+ Broker.PROCESS_PID,
+ ConfiguredObject.TYPE,
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE);
+
+ assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(),
+ brokerDetails.get(Broker.BUILD_VERSION));
+ assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, SystemUtils.getOSString(),
+ brokerDetails.get(Broker.OPERATING_SYSTEM));
+ assertEquals(
+ "Unexpected value of attribute " + Broker.PLATFORM,
+ System.getProperty("java.vendor") + " "
+ + System.getProperty("java.runtime.version", System.getProperty("java.version")),
+ brokerDetails.get(Broker.PLATFORM));
+ assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE));
+ assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ brokerDetails.get(Broker.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME));
+ assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE));
+
+ assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID));
+ assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute virtual host nodes", brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE));
+
+ assertNotNull("Unexpected value of attribute supportedVirtualHostTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOST_TYPES));
+ assertNotNull("Unexpected value of attribute supportedVirtualHostNodeTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOSTNODE_TYPES));
+
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java
new file mode 100644
index 0000000000..891b44cd25
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java
@@ -0,0 +1,141 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.LinkedHashMap;
+import java.util.zip.GZIPInputStream;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class CompressedResponsesRestTest extends QpidRestTestCase
+{
+
+ private boolean _compress;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getBrokerConfiguration().setObjectAttribute(Plugin.class,
+ TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ "compressResponses",
+ _compress);
+ }
+
+ public void testCompressionOffAcceptOff() throws Exception
+ {
+ doCompressionTest(false, false);
+ }
+
+ public void testCompressionOffAcceptOn() throws Exception
+ {
+ doCompressionTest(false, true);
+ }
+
+ public void testCompressionOnAcceptOff() throws Exception
+ {
+ doCompressionTest(true, false);
+ }
+
+ public void testCompressionOnAcceptOn() throws Exception
+ {
+ doCompressionTest(true, true);
+
+ }
+
+ private void doCompressionTest(final boolean allowCompression,
+ final boolean acceptCompressed) throws Exception
+ {
+ final boolean expectCompression = allowCompression && acceptCompressed;
+ _compress = allowCompression;
+ super.setUp();
+
+ HttpURLConnection conn = getRestTestHelper().openManagementConnection("/service/metadata", "GET");
+ if(acceptCompressed)
+ {
+ conn.setRequestProperty("Accept-Encoding", "gzip");
+ }
+
+ conn.connect();
+
+ String contentEncoding = conn.getHeaderField("Content-Encoding");
+
+ if(expectCompression)
+ {
+ assertEquals("gzip", contentEncoding);
+ }
+ else
+ {
+ if(contentEncoding != null)
+ {
+ assertEquals("identity", contentEncoding);
+ }
+ }
+
+ ByteArrayOutputStream contentBuffer = new ByteArrayOutputStream();
+
+ InputStream connectionInputStream = conn.getInputStream();
+ byte[] buf = new byte[1024];
+ int read;
+ while((read = connectionInputStream.read(buf))!= -1)
+ {
+ contentBuffer.write(buf,0,read);
+ }
+
+ InputStream jsonStream;
+
+ if(expectCompression)
+ {
+ jsonStream = new GZIPInputStream(new ByteArrayInputStream(contentBuffer.toByteArray()));
+ }
+ else
+ {
+ jsonStream = new ByteArrayInputStream(contentBuffer.toByteArray());
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ try
+ {
+ mapper.readValue(jsonStream, LinkedHashMap.class);
+ }
+ catch (JsonParseException | JsonMappingException e)
+ {
+ fail("Message was not in correct format");
+ }
+ }
+
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java
new file mode 100644
index 0000000000..439e592a7e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java
@@ -0,0 +1,281 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Session;
+
+public class ConnectionRestTest extends QpidRestTestCase
+{
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 5;
+ private static final int MESSAGE_SIZE = 6;
+
+ private static final String SESSIONS_ATTRIBUTE = "sessions";
+
+ private javax.jms.Connection _connection;
+ private javax.jms.Session _session;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _connection = getConnection();
+ _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ MessageConsumer consumer = _session.createConsumer(queue);
+ MessageProducer producer = _session.createProducer(queue);
+ _connection.start();
+
+ // send messages
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(_session.createTextMessage("Test-" + i));
+ }
+ _session.commit();
+ Message m = consumer.receive(1000l);
+ assertNotNull("First message was not received", m);
+ _session.commit();
+
+ // receive the rest of messages for rollback
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Subsequent messages were not received", m);
+ }
+ _session.rollback();
+
+ // receive them again
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message was not received after rollback", m);
+ }
+
+ // Session left open
+ }
+
+ public void testGetAllConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("connection");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetVirtualHostConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("connection/test/test");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetConnectionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ Map<String, Object> connectionDetails = getRestTestHelper().getJsonAsSingletonList("connection/test/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertConnection(connectionDetails);
+ }
+
+ public void testDeleteConnection() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("connection/test/test");
+ assertEquals("Unexpected number of connections before deletion", 1, connections.size());
+
+ String connectionUrl = "connection/test/test/" + URLDecoder.decode(connectionName, "UTF-8");
+ getRestTestHelper().submitRequest(connectionUrl, "DELETE", HttpServletResponse.SC_OK);
+
+ connections = getRestTestHelper().getJsonAsList("connection/test/test");
+ assertEquals("Unexpected number of connections before deletion", 0, connections.size());
+
+ try
+ {
+ _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED);
+ fail("Exception not thrown");
+ }
+ catch (JMSException je)
+ {
+ // PASS
+ }
+ }
+
+ public void testGetAllSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetVirtualHostSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetConnectionSessions() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetSessionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/"
+ + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId());
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testProducerSessionOpenHasTransactionStartAndUpdateTimes() throws Exception
+ {
+ Destination queue = _session.createQueue(getTestQueueName());
+ MessageProducer producer = _session.createProducer(queue);
+ producer.send(_session.createMessage());
+ // session left open
+ ((AMQSession)_session).sync();
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/"
+ + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId());
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+
+ final Map<String, Object> sessionData = sessions.get(0);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) sessionData.get(Asserts.STATISTICS_ATTRIBUTE);
+
+ long transactionStartTime = ((Number) statistics.get("transactionStartTime")).longValue();
+ long transactionUpdateTime = ((Number) statistics.get("transactionUpdateTime")).longValue();
+
+ assertTrue("Unexpected transaction start value for open transaction " + transactionStartTime, transactionStartTime > 0);
+ assertTrue("Unexpected transaction update value for open transaction " + transactionUpdateTime, transactionUpdateTime > 0);
+ assertTrue("Expected transaction update value " + transactionUpdateTime + " to be greater than transaction start time " + transactionStartTime, transactionUpdateTime >= transactionStartTime);
+
+
+ }
+
+ private void assertConnection(Map<String, Object> connectionDetails) throws JMSException
+ {
+ Asserts.assertConnection(connectionDetails, (AMQConnection) _connection);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected value of connection statistics attribute " + "bytesIn", MESSAGE_NUMBER
+ * MESSAGE_SIZE, statistics.get("bytesIn"));
+ assertEquals("Unexpected value of connection statistics attribute " + "bytesOut", MESSAGE_SIZE
+ + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get("bytesOut"));
+ assertEquals("Unexpected value of connection statistics attribute " + "messagesIn", MESSAGE_NUMBER,
+ statistics.get("messagesIn"));
+ assertEquals("Unexpected value of connection statistics attribute " + "messagesOut",
+ MESSAGE_NUMBER * 2 - 1, statistics.get("messagesOut"));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> sessions = (List<Map<String, Object>>) connectionDetails.get(SESSIONS_ATTRIBUTE);
+ assertNotNull("Sessions cannot be found", sessions);
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ private void assertSession(Map<String, Object> sessionData, AMQSession<?, ?> session)
+ {
+ assertNotNull("Session map cannot be null", sessionData);
+ Asserts.assertAttributesPresent(sessionData, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(
+ Session.class),
+ ConfiguredObject.TYPE,
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE,
+ Session.STATE,
+ Session.DURABLE,
+ Session.LIFETIME_POLICY);
+ assertEquals("Unexpected value of attribute " + Session.NAME, session.getChannelId() + "",
+ sessionData.get(Session.NAME));
+ assertEquals("Unexpected value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE,
+ sessionData.get(Session.PRODUCER_FLOW_BLOCKED));
+ assertEquals("Unexpected value of attribute " + Session.CHANNEL_ID, session.getChannelId(),
+ sessionData.get(Session.CHANNEL_ID));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) sessionData.get(Asserts.STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, "consumerCount",
+ "localTransactionBegins", "localTransactionOpen",
+ "localTransactionRollbacks", "unacknowledgedMessages",
+ "transactionStartTime", "transactionUpdateTime");
+
+ assertEquals("Unexpected value of statistic attribute " + "unacknowledgedMessages", MESSAGE_NUMBER - 1,
+ statistics.get("unacknowledgedMessages"));
+ assertEquals("Unexpected value of statistic attribute " + "localTransactionBegins", 4,
+ statistics.get("localTransactionBegins"));
+ assertEquals("Unexpected value of statistic attribute " + "localTransactionRollbacks", 1,
+ statistics.get("localTransactionRollbacks"));
+ assertEquals("Unexpected value of statistic attribute " + "consumerCount", 1,
+ statistics.get("consumerCount"));
+ }
+
+ private String getConnectionName() throws IOException
+ {
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test/test");
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Map<String, Object> connection = connections.get(0);
+ String connectionName = (String) connection.get(Connection.NAME);
+ return connectionName;
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
new file mode 100644
index 0000000000..51cb6dde1a
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
@@ -0,0 +1,120 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Exchange;
+
+public class ExchangeRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ getRestTestHelper().createTestQueues();
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("exchange");
+ assertNotNull("Exchanges cannot be null", exchanges);
+ assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_VIRTUALHOSTS.length * EXPECTED_EXCHANGES.length);
+ for (Map<String, Object> exchange : exchanges)
+ {
+ Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange);
+ }
+ }
+
+ public void testGetHostExchanges() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("exchange/test");
+ assertNotNull("Users cannot be null", exchanges);
+ assertEquals("Unexpected number of exchanges", exchanges.size(), EXPECTED_EXCHANGES.length);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().find(Exchange.NAME, exchangeName, exchanges);
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ public void testGetHostExchangeByName() throws Exception
+ {
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/"
+ + URLDecoder.decode(exchangeName, "UTF-8"));
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ public void testSetExchangeSupported() throws Exception
+ {
+ String exchangeName = getTestName();
+ String exchangeUrl = "exchange/test/test/" + exchangeName;
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.TYPE, "direct");
+ int responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes);
+ assertEquals("Exchange should be created", 201, responseCode);
+
+ Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl);
+ assertNotNull("Exchange not found", exchange);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, "amq.direct");
+
+ responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes);
+ assertEquals("Exchange update should be supported", 200, responseCode);
+ exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl);
+ assertNotNull("Exchange not found", exchange);
+ assertEquals("amq.direct",exchange.get(Exchange.ALTERNATE_EXCHANGE));
+ }
+
+ private void assertExchange(String exchangeName, Map<String, Object> exchange)
+ {
+ assertNotNull("Exchange with name " + exchangeName + " is not found", exchange);
+ String type = (String) exchange.get(Exchange.TYPE);
+ Asserts.assertExchange(exchangeName, type, exchange);
+ if ("direct".equals(type))
+ {
+ assertBindings(exchange);
+ }
+ }
+
+ private void assertBindings(Map<String, Object> exchange)
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ for (String queueName : RestTestHelper.EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java
new file mode 100644
index 0000000000..4f1c1ad7a7
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java
@@ -0,0 +1,373 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+
+import org.apache.qpid.server.BrokerOptions;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Group;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProvider;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class GroupProviderRestTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE;
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("groupprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, provider);
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/"
+ + provider.get(GroupProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(GroupProvider.NAME), data);
+ assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data);
+ }
+ }
+
+ public void testCreateNewGroup() throws Exception
+ {
+ String groupName = "newGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().createGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testRemoveGroup() throws Exception
+ {
+ String groupName = "myGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().removeGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 0);
+ }
+
+ public void testCreateNewFileGroupProviderFromExistingGroupFile() throws Exception
+ {
+ String[] groupMemberNames = {"test1","test2"};
+ File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=" + groupMemberNames[0] + "," + groupMemberNames[1]);
+ try
+ {
+ String providerName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Group provider was not created", 201, responseCode);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName + "?depth=2");
+ assertProvider(providerName, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data);
+ assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME));
+ assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groups");
+ assertEquals("Unexpected group size", 1, groups.size());
+ Map<String, Object> group = groups.get(0);
+ assertEquals("Unexpected group name", "testusers",group.get("name"));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groupMemberList = (List<Map<String, Object>>) group.get("groupmembers");
+ assertEquals("Unexpected group members size", 2, groupMemberList.size());
+
+ for (String memberName : groupMemberNames)
+ {
+ boolean found = false;
+ for (Map<String, Object> memberData : groupMemberList)
+ {
+ Object name = memberData.get("name");
+ if (memberName.equals(name))
+ {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Cannot find group member " + memberName + " in " + groupMemberList , found);
+ }
+ }
+ finally
+ {
+ groupFile.delete();
+ }
+ }
+
+ public void testCreationOfNewFileGroupProviderFailsWhenPathIsMissed() throws Exception
+ {
+ String providerName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Group provider was created", 409, responseCode);
+ }
+
+ public void testCreateNewFileGroupProviderFromNonExistingGroupFile() throws Exception
+ {
+ File groupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups");
+ assertFalse("Group file should not exist", groupFile.exists());
+ try
+ {
+ String providerName = getTestName();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Group provider was not created", 201, responseCode);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName);
+ assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME));
+ assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groups");
+ assertNull("Unexpected groups", groups);
+
+ assertTrue("Group file has not been created", groupFile.exists());
+ }
+ finally
+ {
+ groupFile.delete();
+ groupFile.getParentFile().delete();
+ }
+ }
+
+ public void testCreateNewFileGroupProviderForTheSameGroupFileFails() throws Exception
+ {
+ File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2");
+ String providerName = getTestName();
+ try
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Group provider was not created", 201, responseCode);
+
+ attributes.put(GroupProvider.NAME, providerName + 2);
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName + 2, "PUT", attributes);
+ assertEquals("Group provider for the same group file was created", 409, responseCode);
+ }
+ finally
+ {
+ groupFile.delete();
+ }
+ }
+
+ public void testDeleteGroupProvider() throws Exception
+ {
+ File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2");
+ String providerName = getTestName();
+ try
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Expected to fail because we can have only one password provider", 201, responseCode);
+
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName , "DELETE");
+ assertEquals("Group provider was not deleted", 200, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("groupprovider/" + providerName);
+ assertEquals("Provider was not deleted", 0, providerDetails.size());
+ assertFalse("Groups file should be deleted", groupFile.exists());
+ }
+ finally
+ {
+ groupFile.delete();
+ }
+ }
+
+ public void testUpdateGroupProviderAttributesFails() throws Exception
+ {
+ File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2");
+ String providerName = getTestName();
+ try
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, providerName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Expected to fail because we can have only one password provider", 201, responseCode);
+
+ File newGroupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups");
+ attributes.put(FileBasedGroupProvider.PATH, newGroupFile.getAbsolutePath());
+
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes);
+ assertEquals("Expected to fail because we can have only one password provider", 409, responseCode);
+ }
+ finally
+ {
+ groupFile.delete();
+ }
+ }
+
+ public void testRemovalOfGroupProviderInErrorStateUsingManagementMode() throws Exception
+ {
+ stopBroker();
+
+ File file = new File(TMP_FOLDER, getTestName());
+ if (file.exists())
+ {
+ file.delete();
+ }
+ assertFalse("Group file should not exist", file.exists());
+
+ TestBrokerConfiguration config = getBrokerConfiguration();
+ config.removeObjectConfiguration(GroupProvider.class, TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE);
+ UUID id = config.addGroupFileConfiguration(file.getAbsolutePath());
+ config.setSaved(false);
+ startBroker(0, true);
+
+ getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD);
+
+ Map<String, Object> groupProvider = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE);
+ assertEquals("Unexpected id", id.toString(), groupProvider.get(GroupProvider.ID));
+ assertEquals("Unexpected path", file.getAbsolutePath() , groupProvider.get(FileBasedGroupProvider.PATH));
+ assertEquals("Unexpected state", State.ERRORED.name() , groupProvider.get(GroupProvider.STATE));
+
+ int status = getRestTestHelper().submitRequest("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE, "DELETE");
+ assertEquals("ACL was not deleted", 200, status);
+
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE);
+ assertEquals("Provider exists", 0, providers.size());
+ }
+
+ private void assertProvider(String name, String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(
+ GroupProvider.class),
+ ConfiguredObject.TYPE,
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE);
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.STATE, State.ACTIVE.name(),
+ provider.get(GroupProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(GroupProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.DURABLE, Boolean.TRUE,
+ provider.get(GroupProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.TYPE, type,
+ provider.get(GroupProvider.TYPE));
+
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.NAME, name,
+ (String) provider.get(GroupProvider.NAME));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) provider.get("groups");
+ assertNotNull("Groups were not found", groups);
+ assertEquals("Unexpected number of groups", 1, groups.size());
+ for (Map<String, Object> group : groups)
+ {
+
+ final String groupName = (String) group.get(Group.NAME);
+ assertNotNull("Attribute " + Group.NAME, groupName);
+
+ assertNotNull("Attribute " + Group.ID, group.get(Group.ID));
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put("myGroup.users", "guest");
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java
new file mode 100644
index 0000000000..eeb9511289
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.server.model.GroupMember;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class GroupRestTest extends QpidRestTestCase
+{
+ private static final String GROUP_NAME = "myGroup";
+ private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE;
+ private static final String EXISTING_MEMBER = "user1";
+ private static final String NEW_MEMBER = "user2";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup");
+ List<Map<String, Object>> groupmembers = (List<Map<String, Object>>) group.get("groupmembers");
+ assertEquals(1, groupmembers.size());
+
+ Map<String, Object> member1 = groupmembers.get(0);
+ assertEquals(EXISTING_MEMBER, (String)member1.get(GroupMember.NAME));
+ }
+
+ public void testCreateNewMemberOfGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, GROUP_NAME, NEW_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 2);
+ }
+
+ public void testRemoveMemberFromGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, GROUP_NAME, EXISTING_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 0);
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(GROUP_NAME + ".users", EXISTING_MEMBER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java
new file mode 100644
index 0000000000..abafb7fcaf
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class HttpManagementRestTest extends QpidRestTestCase
+{
+
+ public void testGetHttpManagement() throws Exception
+ {
+ Map<String, Object> details = getRestTestHelper().getJsonAsSingletonList(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+
+ assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS,
+ details.get(HttpManagement.TIME_OUT));
+ assertEquals("Unexpected http basic auth enabled", true,
+ details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https basic auth enabled", true,
+ details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected http sasl auth enabled", true,
+ details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https sasl auth enabled", true,
+ details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED));
+ }
+
+ public void testUpdateAttributes() throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+ attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.TIME_OUT, 10000);
+
+ getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes);
+
+ Map<String, Object> details = getRestTestHelper().getJsonAsSingletonList(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+
+ assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT));
+ assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED));
+ }
+
+ public void testUpdateAttributesWithInvalidValues() throws Exception
+ {
+ Map<String, Object> invalidAttributes = new HashMap<String, Object>();
+ invalidAttributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, 1);
+ invalidAttributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, 2);
+ invalidAttributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, 3);
+ invalidAttributes.put(HttpManagement.TIME_OUT, "undefined");
+
+ for (Map.Entry<String, Object> invalidAttribute : invalidAttributes.entrySet())
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(invalidAttribute.getKey(), invalidAttribute.getValue());
+ int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes);
+ assertEquals("Update should fail for attribute " + invalidAttribute.getKey() + " with value " + invalidAttribute.getValue() , 409, response);
+ }
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(HttpManagement.TIME_OUT, -1l);
+ int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes);
+ assertEquals("Update should fail for invalid session timeout", 409, response);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java
new file mode 100644
index 0000000000..4b881d1e9f
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java
@@ -0,0 +1,272 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.security.FileKeyStore;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestSSLConstants;
+
+public class KeyStoreRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ // not calling super.setUp() to avoid broker start-up until
+ // after any necessary configuration
+ }
+
+ public void testGet() throws Exception
+ {
+ super.setUp();
+
+ //verify existence of the default keystore used by the systests
+ List<Map<String, Object>> keyStores = assertNumberOfKeyStores(1);
+
+ Map<String, Object> keystore = keyStores.get(0);
+ assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testCreate() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+ String certAlias = "app2";
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, certAlias);
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStores = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details cannot be null", keyStores);
+
+ assertKeyStoreAttributes(keyStores.get(0), name, TestSSLConstants.KEYSTORE, certAlias);
+ }
+
+ public void testDelete() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+ String certAlias = "app2";
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, certAlias);
+ assertNumberOfKeyStores(2);
+
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertTrue("details should be empty as the keystore no longer exists", keyStore.isEmpty());
+
+ //check only the default systests key store remains
+ List<Map<String, Object>> keyStores = assertNumberOfKeyStores(1);
+ Map<String, Object> keystore = keyStores.get(0);
+ assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testDeleteFailsWhenKeyStoreInUse() throws Exception
+ {
+ String name = "testDeleteFailsWhenKeyStoreInUse";
+
+ //add a new key store config to use
+ Map<String, Object> sslKeyStoreAttributes = new HashMap<String, Object>();
+ sslKeyStoreAttributes.put(KeyStore.NAME, name);
+ sslKeyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.BROKER_KEYSTORE);
+ sslKeyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD);
+ getBrokerConfiguration().addObjectConfiguration(KeyStore.class,sslKeyStoreAttributes);
+
+ //add the SSL port using it
+ Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
+ sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ sslPortAttributes.put(Port.KEY_STORE, name);
+ getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes);
+
+ super.setUp();
+
+ //verify the keystore is there
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null);
+
+ //try to delete it, which should fail as it is in use
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 409, responseCode);
+
+ //check its still there
+ assertNumberOfKeyStores(2);
+ keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testUpdateWithGoodPathSucceeds() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, null);
+ assertNumberOfKeyStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(FileKeyStore.PATH, TestSSLConstants.UNTRUSTED_KEYSTORE);
+
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.UNTRUSTED_KEYSTORE, null);
+ }
+
+ public void testUpdateWithNonExistentPathFails() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, null);
+ assertNumberOfKeyStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(FileKeyStore.PATH, "does.not.exist");
+
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 409, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ //verify the details remain unchanged
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null);
+ }
+
+ public void testUpdateCertificateAlias() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, "app1");
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app1");
+
+ //Update the certAlias from app1 to app2
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(FileKeyStore.CERTIFICATE_ALIAS, "app2");
+
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app2");
+
+ //Update the certAlias to clear it (i.e go from from app1 to null)
+ attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(FileKeyStore.CERTIFICATE_ALIAS, null);
+
+ responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsList("keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null);
+ }
+
+ private List<Map<String, Object>> assertNumberOfKeyStores(int numberOfKeystores) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> keyStores = getRestTestHelper().getJsonAsList("keystore");
+ assertNotNull("keystores should not be null", keyStores);
+ assertEquals("Unexpected number of keystores", numberOfKeystores, keyStores.size());
+
+ return keyStores;
+ }
+
+ private void createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> keyStoreAttributes = new HashMap<String, Object>();
+ keyStoreAttributes.put(KeyStore.NAME, name);
+ keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE);
+ keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD);
+ keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias);
+
+ int responseCode = getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private void assertKeyStoreAttributes(Map<String, Object> keystore, String name, String path, String certAlias)
+ {
+ assertEquals("default systests key store is missing",
+ name, keystore.get(KeyStore.NAME));
+ assertEquals("unexpected path to key store",
+ path, keystore.get(FileKeyStore.PATH));
+ assertEquals("unexpected (dummy) password of default systests key store",
+ AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD));
+ assertEquals("unexpected type of default systests key store",
+ java.security.KeyStore.getDefaultType(), keystore.get(FileKeyStore.KEY_STORE_TYPE));
+ assertEquals("unexpected certificateAlias value",
+ certAlias, keystore.get(FileKeyStore.CERTIFICATE_ALIAS));
+ if(certAlias == null)
+ {
+ assertFalse("should not be a certificateAlias attribute",
+ keystore.containsKey(FileKeyStore.CERTIFICATE_ALIAS));
+ }
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java
new file mode 100644
index 0000000000..4d06c7b624
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class LogRecordsRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> logs = getRestTestHelper().getJsonAsList("/service/logrecords");
+ assertNotNull("Logs data cannot be null", logs);
+ assertTrue("Logs are not found", logs.size() > 0);
+ Map<String, Object> record = getRestTestHelper().find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs);
+
+ assertNotNull("BRK-1004 message is not found", record);
+ assertNotNull("Message id cannot be null", record.get("id"));
+ assertNotNull("Message timestamp cannot be null", record.get("timestamp"));
+ assertEquals("Unexpected log level", "INFO", record.get("level"));
+ assertEquals("Unexpected thread", "main", record.get("thread"));
+ assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger"));
+ }
+
+ public void testGetLogsFromGivenId() throws Exception
+ {
+ List<Map<String, Object>> logs = getRestTestHelper().getJsonAsList("/service/logrecords");
+ assertNotNull("Logs data cannot be null", logs);
+ assertTrue("Logs are not found", logs.size() > 0);
+
+ Map<String, Object> lastLog = logs.get(logs.size() -1);
+ Object lastId = lastLog.get("id");
+
+ //make sure that new logs are created
+ getConnection();
+
+ List<Map<String, Object>> newLogs = getRestTestHelper().getJsonAsList("/service/logrecords?lastLogId=" + lastId);
+ assertNotNull("Logs data cannot be null", newLogs);
+ assertTrue("Logs are not found", newLogs.size() > 0);
+
+ Object nextId = newLogs.get(0).get("id");
+
+ assertEquals("Unexpected next log id", ((Number)lastId).longValue() + 1, ((Number)nextId).longValue());
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java
new file mode 100644
index 0000000000..f2fb2581f7
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java
@@ -0,0 +1,105 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.qpid.server.BrokerOptions;
+
+public class LogViewerTest extends QpidRestTestCase
+{
+ public static final String DEFAULT_FILE_APPENDER_NAME = "FileAppender";
+ private String _expectedLogFileName;
+
+ public void setUp() throws Exception
+ {
+ setSystemProperty("logsuffix", "-" + getTestQueueName());
+ _expectedLogFileName = System.getProperty("logprefix", "") + "qpid" + System.getProperty("logsuffix", "") + ".log";
+
+ // use real broker log file
+ File brokerLogFile = new File(System.getProperty(QPID_HOME), BrokerOptions.DEFAULT_LOG_CONFIG_FILE);
+ setBrokerCommandLog4JFile(brokerLogFile);
+
+ super.setUp();
+ }
+
+ public void testGetLogFiles() throws Exception
+ {
+ List<Map<String, Object>> logFiles = getRestTestHelper().getJsonAsList("/service/logfilenames");
+ assertNotNull("Log files data cannot be null", logFiles);
+
+ // 1 file appender is configured in QPID default log4j xml:
+ assertTrue("Unexpected number of log files", logFiles.size() > 0);
+
+ Map<String, Object> logFileDetails = logFiles.get(0);
+ assertEquals("Unexpected log file name", _expectedLogFileName, logFileDetails.get("name"));
+ assertEquals("Unexpected log file mime type", "text/plain", logFileDetails.get("mimeType"));
+ assertEquals("Unexpected log file appender",DEFAULT_FILE_APPENDER_NAME, logFileDetails.get("appenderName"));
+ assertTrue("Unexpected log file size", ((Number)logFileDetails.get("size")).longValue()>0);
+ assertTrue("Unexpected log file modification time", ((Number)logFileDetails.get("lastModified")).longValue()>0);
+ }
+
+ public void testDownloadExistingLogFiles() throws Exception
+ {
+ byte[] bytes = getRestTestHelper().getBytes("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F" + _expectedLogFileName);
+
+ ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));
+ try
+ {
+ ZipEntry entry = zis.getNextEntry();
+ assertEquals("Unexpected broker log file name", DEFAULT_FILE_APPENDER_NAME + "/" + _expectedLogFileName, entry.getName());
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = zis.read(buffer)) > 0)
+ {
+ baos.write(buffer, 0, len);
+ }
+ baos.close();
+ assertTrue("Unexpected broker log file content", new String(baos.toByteArray()).contains("BRK-1004"));
+ assertNull("Unexpepected log file entry", zis.getNextEntry());
+ }
+ finally
+ {
+ zis.close();
+ }
+ }
+
+ public void testDownloadNonExistingLogFiles() throws Exception
+ {
+ int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F"
+ + _expectedLogFileName + "_" + System.currentTimeMillis(), "GET");
+
+ assertEquals("Unexpected response code", 404, responseCode);
+ }
+
+ public void testDownloadNonLogFiles() throws Exception
+ {
+ int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=config.json", "GET");
+ assertEquals("Unexpected response code", 400, responseCode);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java
new file mode 100644
index 0000000000..efa4776afd
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java
@@ -0,0 +1,355 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class MessagesRestTest extends QpidRestTestCase
+{
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 12;
+
+ private Connection _connection;
+ private Session _session;
+ private MessageProducer _producer;
+ private long _startTime;
+ private long _ttl;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _startTime = System.currentTimeMillis();
+ _connection = getConnection();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ _session.createConsumer(queue).close();
+ _producer = _session.createProducer(queue);
+
+ _ttl = TimeUnit.DAYS.toMillis(1);
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ Message m = _session.createTextMessage("Test-" + i);
+ m.setIntProperty("index", i);
+ if (i % 2 == 0)
+ {
+ _producer.send(m);
+ }
+ else
+ {
+ _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl);
+ }
+ }
+ _session.commit();
+ }
+
+ public void testGet() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ int position = 0;
+ for (Map<String, Object> message : messages)
+ {
+ assertMessage(position, message);
+ position++;
+ }
+ }
+
+ public void testGetMessageContent() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // add bytes message
+ BytesMessage byteMessage = _session.createBytesMessage();
+ byte[] messageBytes = "Test".getBytes();
+ byteMessage.writeBytes(messageBytes);
+ byteMessage.setStringProperty("test", "value");
+ _producer.send(byteMessage);
+ _session.commit();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ Map<String, Object> message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + ids.get(0));
+ assertMessageAttributes(message);
+ assertMessageAttributeValues(message, true);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> headers = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", headers);
+ assertEquals("Unexpected message header", 0, headers.get("index"));
+
+ Long lastMessageId = ids.get(ids.size() - 1);
+ message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + lastMessageId);
+ assertMessageAttributes(message);
+ assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType"));
+ assertEquals("Unexpected message attribute size", 4, message.get("size"));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> bytesMessageHeader = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", bytesMessageHeader);
+ assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test"));
+
+ // get content
+ byte[] data = getRestTestHelper().getBytes("/service/message-content/test/" + queueName + "/" + lastMessageId);
+ assertTrue("Unexpected message", Arrays.equals(messageBytes, data));
+
+ }
+
+ public void testPostMoveMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // move half of the messages
+ int movedNumber = ids.size() / 2;
+ List<Long> movedMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < movedNumber; i++)
+ {
+ movedMessageIds.add(ids.remove(i));
+ }
+
+ // move messages
+
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", movedMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+ messagesData.put("move", Boolean.TRUE);
+
+ getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK);
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size());
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertNull("Moved message " + id + " is found on original queue", message);
+ }
+ }
+
+ public void testPostCopyMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // copy half of the messages
+ int copyNumber = ids.size() / 2;
+ List<Long> copyMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < copyNumber; i++)
+ {
+ copyMessageIds.add(ids.remove(i));
+ }
+
+ // copy messages
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", copyMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+
+ getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK);
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size());
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ }
+
+ public void testDeleteMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // delete half of the messages
+ int deleteNumber = ids.size() / 2;
+ StringBuilder queryString = new StringBuilder();
+ List<Long> deleteMessageIds = new ArrayList<>();
+ for (int i = 0; i < deleteNumber; i++)
+ {
+ Long id = ids.remove(i);
+ deleteMessageIds.add(id);
+ if (queryString.length() > 0)
+ {
+ queryString.append("&");
+ }
+ queryString.append("id=").append(id);
+ }
+
+ // delete messages
+ getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?" + queryString.toString(), "DELETE", HttpServletResponse.SC_OK);
+
+ // check messages on queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : deleteMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertNull("Message with id " + id + " was not deleted", message);
+ }
+ }
+
+ public void testClearQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // clear queue
+ getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?clear=true", "DELETE", HttpServletResponse.SC_OK);
+
+ // check messages on queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", 0, messages.size());
+ }
+
+
+ private List<Long> getMesssageIds(String queueName) throws IOException, JsonMappingException
+ {
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName);
+ List<Long> ids = new ArrayList<Long>();
+ for (Map<String, Object> message : messages)
+ {
+ ids.add(((Number) message.get("id")).longValue());
+ }
+ return ids;
+ }
+
+ private void assertMessage(int position, Map<String, Object> message)
+ {
+ assertMessageAttributes(message);
+
+ assertEquals("Unexpected message attribute position", position, message.get("position"));
+ assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size"));
+ boolean even = position % 2 == 0;
+ assertMessageAttributeValues(message, even);
+ }
+
+ private void assertMessageAttributeValues(Map<String, Object> message, boolean even)
+ {
+ if (even)
+ {
+ assertNull("Unexpected message attribute expirationTime", message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 4, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent"));
+ }
+ else
+ {
+ assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue()
+ + _ttl, message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 5, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent"));
+ }
+ assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType"));
+ assertEquals("Unexpected message attribute userId", "guest", message.get("userId"));
+ assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount"));
+ assertEquals("Unexpected message attribute state", "Available", message.get("state"));
+ }
+
+ private void assertMessageAttributes(Map<String, Object> message)
+ {
+ assertNotNull("Message map cannot be null", message);
+ assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount"));
+ assertNotNull("Unexpected message attribute state", message.get("state"));
+ assertNotNull("Unexpected message attribute id", message.get("id"));
+ assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime"));
+ assertNotNull("Message timestamp cannot be null", message.get("timestamp"));
+ assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime);
+ assertNotNull("Message messageId cannot be null", message.get("messageId"));
+ assertNotNull("Unexpected message attribute mimeType", message.get("mimeType"));
+ assertNotNull("Unexpected message attribute userId", message.get("userId"));
+ assertNotNull("Message priority cannot be null", message.get("priority"));
+ assertNotNull("Message persistent cannot be null", message.get("persistent"));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java
new file mode 100644
index 0000000000..8b86163aa6
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java
@@ -0,0 +1,366 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.net.ServerSocket;
+import java.net.URLDecoder;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.BrokerOptions;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.port.JmxPort;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.test.utils.PortHelper;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class PortRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("port/");
+ assertNotNull("Port data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT;
+ Map<String, Object> portData = getRestTestHelper().find(Port.NAME, httpPortName, ports);
+ assertNotNull("Http port " + httpPortName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+
+ String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports);
+ assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData);
+ Asserts.assertPortAttributes(amqpPortData);
+ }
+
+ public void testGetPort() throws Exception
+ {
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("port/");
+ assertNotNull("Ports data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+ for (Map<String, Object> portMap : ports)
+ {
+ String portName = (String) portMap.get(Port.NAME);
+ assertNotNull("Port name attribute is not found", portName);
+ Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(portName, "UTF-8"));
+ assertNotNull("Port " + portName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+ }
+ }
+
+ public void testPutAmqpPortWithMinimumAttributes() throws Exception
+ {
+ String portName = "test-port";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.PORT, findFreePort());
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ List<Map<String, Object>> portDetails = getRestTestHelper().getJsonAsList("port/" + portName);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size());
+ Map<String, Object> port = portDetails.get(0);
+ Asserts.assertPortAttributes(port);
+
+ // make sure that port is there after broker restart
+ restartBroker();
+
+ portDetails = getRestTestHelper().getJsonAsList("port/" + portName);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size());
+ }
+
+ public void testPutRmiPortWithMinimumAttributes() throws Exception
+ {
+ String portNameRMI = "test-port-rmi";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portNameRMI);
+ int rmiPort = findFreePort();
+ attributes.put(Port.PORT, rmiPort);
+ attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI));
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+
+ List<Map<String, Object>> portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size());
+ Map<String, Object> port = portDetails.get(0);
+ Asserts.assertPortAttributes(port, State.QUIESCED);
+
+ String portNameJMX = "test-port-jmx";
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portNameJMX);
+ int jmxPort = getNextAvailable(rmiPort + 1);
+ attributes.put(Port.PORT, jmxPort);
+ attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.JMX_RMI));
+ attributes.put(JmxPort.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portNameJMX, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+
+ portDetails = getRestTestHelper().getJsonAsList("port/" + portNameJMX);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size());
+ port = portDetails.get(0);
+ Asserts.assertPortAttributes(port, State.QUIESCED);
+
+
+ attributes.put(Plugin.TYPE, "MANAGEMENT-JMX");
+ attributes.put(Plugin.NAME, "JmxPlugin");
+ responseCode = getRestTestHelper().submitRequest("plugin/JmxPlugin", "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+
+ // make sure that port is there after broker restart
+ stopBroker();
+
+ // We shouldn't need to await the ports to be free, but it seems sometimes an RMI TCP Accept
+ // thread is seen to close the socket *after* the broker has finished stopping.
+ new PortHelper().waitUntilPortsAreFree(new HashSet<Integer>(Arrays.asList(jmxPort, rmiPort)));
+
+ startBroker();
+
+ portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size());
+ port = portDetails.get(0);
+ Asserts.assertPortAttributes(port, State.ACTIVE);
+
+ // try to add a second RMI port
+ portNameRMI = portNameRMI + "2";
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portNameRMI);
+ attributes.put(Port.PORT, findFreePort());
+ attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI));
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes);
+ assertEquals("Adding of a second RMI port should fail", 409, responseCode);
+ }
+
+ public void testPutCreateAndUpdateAmqpPort() throws Exception
+ {
+ String portName = "test-port";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.PORT, findFreePort());
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response code for port creation", 201, responseCode);
+
+ List<Map<String, Object>> portDetails = getRestTestHelper().getJsonAsList("port/" + portName);
+ assertNotNull("Port details cannot be null", portDetails);
+ assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size());
+ Map<String, Object> port = portDetails.get(0);
+ Asserts.assertPortAttributes(port);
+
+ Map<String, Object> authProviderAttributes = new HashMap<String, Object>();
+ authProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+ authProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER);
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER, "PUT", authProviderAttributes);
+ assertEquals("Unexpected response code for authentication provider creation", 201, responseCode);
+
+ attributes = new HashMap<String, Object>(port);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER);
+ attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.AMQP_0_9_1));
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response code for port update", 200, responseCode);
+ }
+
+ public void testUpdatePortTransportFromTCPToSSLWhenKeystoreIsConfigured() throws Exception
+ {
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Transport has not been changed to SSL " , 200, responseCode);
+
+ Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+
+ @SuppressWarnings("unchecked")
+ Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS);
+ assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(Transport.SSL.name())),
+ new HashSet<String>(transports));
+
+ String keyStore = (String) port.get(Port.KEY_STORE);
+ assertEquals("Unexpected auth provider", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keyStore);
+ }
+
+ public void testUpdateTransportFromTCPToSSLWithoutKeystoreConfiguredFails() throws Exception
+ {
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Creation of SSL port without keystore should fail", 409, responseCode);
+ }
+
+ public void testUpdateWantNeedClientAuth() throws Exception
+ {
+ String portName = TestBrokerConfiguration.ENTRY_NAME_SSL_PORT;
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ attributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("SSL port was not added", 201, responseCode);
+
+ attributes.put(Port.NEED_CLIENT_AUTH, true);
+ attributes.put(Port.WANT_CLIENT_AUTH, true);
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Attributes for need/want client auth are not set", 200, responseCode);
+
+ Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+ assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, true, port.get(Port.NEED_CLIENT_AUTH));
+ assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, true, port.get(Port.WANT_CLIENT_AUTH));
+ assertEquals("Unexpected " + Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, port.get(Port.KEY_STORE));
+ @SuppressWarnings("unchecked")
+ Collection<String> trustStores = (Collection<String>) port.get(Port.TRUST_STORES);
+ assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)),
+ new HashSet<String>(trustStores));
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP));
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Should not be able to change transport to TCP without reseting of attributes for need/want client auth", 409, responseCode);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP));
+ attributes.put(Port.NEED_CLIENT_AUTH, false);
+ attributes.put(Port.WANT_CLIENT_AUTH, false);
+
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Should be able to change transport to TCP ", 200, responseCode);
+
+ port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+ assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, false, port.get(Port.NEED_CLIENT_AUTH));
+ assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, false, port.get(Port.WANT_CLIENT_AUTH));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS);
+ assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(Transport.TCP.name())),
+ new HashSet<String>(transports));
+ }
+
+ public void testUpdateSettingWantNeedCertificateFailsForNonSSLPort() throws Exception
+ {
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.NEED_CLIENT_AUTH, true);
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response when trying to set 'needClientAuth' on non-SSL port", 409, responseCode);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.WANT_CLIENT_AUTH, true);
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response when trying to set 'wantClientAuth' on non-SSL port", 409, responseCode);
+ }
+
+ public void testUpdatePortAuthenticationProvider() throws Exception
+ {
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, "non-existing");
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response when trying to change auth provider to non-existing one", 409, responseCode);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Unexpected response when trying to change auth provider to existing one", 200, responseCode);
+
+ Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+ assertEquals("Unexpected auth provider", ANONYMOUS_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER));
+ }
+
+ public void testDefaultAmqpPortIsQuiescedWhenInManagementMode() throws Exception
+ {
+ // restart Broker in management port
+ stopBroker();
+ startBroker(0, true);
+ getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD);
+
+ String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8"));
+ Asserts.assertPortAttributes(portData, State.QUIESCED);
+ }
+
+ public void testNewPortErroredIfPortNumberInUse() throws Exception
+ {
+ String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8"));
+ int amqpPort = (Integer)portData.get(Port.PORT);
+
+ ServerSocket socket = new ServerSocket(0);
+ int occupiedPort = socket.getLocalPort();
+
+ int deleteResponseCode = getRestTestHelper().submitRequest("port/" + ampqPortName, "DELETE");
+ assertEquals("Port deletion should be allowed", 200, deleteResponseCode);
+
+ String newPortName = "reused-port";
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, newPortName);
+ attributes.put(Port.PORT, occupiedPort); // port in use
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + newPortName, "PUT", attributes);
+ assertEquals("Unexpected response code for port creation", 201, responseCode);
+
+ portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(newPortName, "UTF-8"));
+ Asserts.assertPortAttributes(portData, State.ERRORED);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java
new file mode 100644
index 0000000000..6db204b9ca
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java
@@ -0,0 +1,199 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class PreferencesProviderRestTest extends QpidRestTestCase
+{
+ private Map<String, File> _preferencesProviderFiles;
+ private File _authenticationProviderFile;
+
+ public void setUp() throws Exception
+ {
+ _authenticationProviderFile = TestFileUtils.createTempFile(this, ".test.prefs.txt", "test:test");
+ _preferencesProviderFiles = new HashMap<String, File>();
+ super.setUp();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ if (_authenticationProviderFile != null)
+ {
+ _authenticationProviderFile.delete();
+ }
+ for (File file : _preferencesProviderFiles.values())
+ {
+ file.delete();
+ }
+ }
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ Map<String, Object> anonymousAuthProviderAttributes = new HashMap<String, Object>();
+ anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2");
+ anonymousAuthProviderAttributes.put(ExternalFileBasedAuthenticationManager.PATH, _authenticationProviderFile.getAbsolutePath());
+ getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class,anonymousAuthProviderAttributes);
+ }
+
+ public void testCreateAndGetProvider() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider");
+ assertEquals("Unexpected number of providers", 0, providerDetails.size());
+
+ createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1");
+ createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2", "test2");
+
+ providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider");
+ assertEquals("Unexpected number of providers", 2, providerDetails.size());
+
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider(provider);
+ }
+
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList(
+ "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1");
+ assertProvider(provider);
+ assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME));
+
+ Map<String, Object> provider2 = getRestTestHelper().getJsonAsSingletonList(
+ "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2/test2");
+ assertProvider(provider);
+ assertEquals("Unexpected provider name ", "test2", provider2.get(PreferencesProvider.NAME));
+ }
+
+ public void testDeleteProvider() throws Exception
+ {
+ createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1");
+ String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1";
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList(providerUrl);
+ assertProvider(provider);
+ assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME));
+
+ int responseCode = getRestTestHelper().submitRequest(providerUrl, "DELETE");
+ assertEquals("Failed to delete preferences provider", 200, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList(providerUrl);
+ assertEquals("Unexpected number of providers", 0, providerDetails.size());
+ }
+
+ public void testUpdateProvider() throws Exception
+ {
+ createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1");
+ String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1";
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList(providerUrl);
+ assertProvider(provider);
+ assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME));
+
+ File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"something\": \"somethingValue\"}}");
+ _preferencesProviderFiles.put("new-test1", file);
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest(providerUrl, "PUT", newAttributes);
+ assertEquals("Failed to update preferences provider", 200, responseCode);
+
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList(providerUrl);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+
+ provider = providerDetails.get(0);
+ assertProviderCommonAttributes(provider);
+ String name = (String) provider.get(PreferencesProvider.NAME);
+ assertEquals("Unexpected name", "test1", name);
+ assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH),
+ file.getAbsolutePath());
+ }
+
+ private void assertProvider(Map<String, Object> provider)
+ {
+ assertProviderCommonAttributes(provider);
+
+ String name = (String) provider.get(PreferencesProvider.NAME);
+ assertNotNull("Name cannot be null", name);
+ assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH),
+ _preferencesProviderFiles.get(name).getAbsolutePath());
+ }
+
+ public void assertProviderCommonAttributes(Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider,
+ BrokerModel.getInstance().getTypeRegistry().getAttributeNames(
+ PreferencesProvider.class),
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE);
+ assertEquals("Unexpected value of provider attribute " + PreferencesProvider.STATE, State.ACTIVE.name(),
+ provider.get(PreferencesProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + PreferencesProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(PreferencesProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + PreferencesProvider.DURABLE, Boolean.TRUE,
+ provider.get(PreferencesProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + PreferencesProvider.TYPE,
+ FileSystemPreferencesProvider.PROVIDER_TYPE, provider.get(PreferencesProvider.TYPE));
+ }
+
+ private void createPreferencesProvider(String authenticationProvider, String providerName) throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(PreferencesProvider.NAME, providerName);
+ attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE);
+ File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"language\": \"en\"}}");
+ _preferencesProviderFiles.put(providerName, file);
+ attributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "preferencesprovider/" + authenticationProvider + "/" + providerName, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java
new file mode 100644
index 0000000000..bd72391522
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class PreferencesRestTest extends QpidRestTestCase
+{
+ private File _preferencesProviderFile;
+
+ public void setUp() throws Exception
+ {
+ _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json",
+ "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}}");
+ super.setUp();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ if (_preferencesProviderFile != null)
+ {
+ _preferencesProviderFile.delete();
+ }
+ }
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+
+ TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(PreferencesProvider.NAME, "test");
+ attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE);
+ attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath());
+ brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER,
+ attributes);
+
+ }
+
+ public void testGetPreferences() throws Exception
+ {
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap("/service/preferences");
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected language preference", "en", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs"));
+ }
+
+ public void testUpdatePreferences() throws Exception
+ {
+ Map<String, Object> additionalPreferences = new HashMap<String, Object>();
+ additionalPreferences.put("timezone", "Europe/London");
+ additionalPreferences.put("test", 1);
+
+ int status = getRestTestHelper().submitRequest("/service/preferences", "POST", additionalPreferences);
+ assertEquals("Unexpected response code", 200, status);
+
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap("/service/preferences");
+ assertEquals("Unexpected number of preferences", 4, preferences.size());
+ assertEquals("Unexpected language preference", "en", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs"));
+ assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone"));
+ assertEquals("Unexpected test preference", 1, preferences.get("test"));
+ }
+
+ public void testReplacePreferences() throws Exception
+ {
+ Map<String, Object> additionalPreferences = new HashMap<String, Object>();
+ additionalPreferences.put("timezone", "Europe/London");
+ additionalPreferences.put("test", 1);
+
+ int status = getRestTestHelper().submitRequest("/service/preferences", "PUT", additionalPreferences);
+ assertEquals("Unexpected response code", 200, status);
+
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap("/service/preferences");
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone"));
+ assertEquals("Unexpected test preference", 1, preferences.get("test"));
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java
new file mode 100644
index 0000000000..baebc9a28e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java
@@ -0,0 +1,262 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.BrokerModel;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Queue;
+
+public class QueueRestTest extends QpidRestTestCase
+{
+ private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers";
+ private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings";
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 2;
+ private static final int MESSAGE_PAYLOAD_SIZE = 6;
+ private static final int ENQUEUED_MESSAGES = 1;
+ private static final int DEQUEUED_MESSAGES = 1;
+ private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+ private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = session.createQueue(queueName);
+ MessageConsumer consumer = session.createConsumer(queue);
+ MessageProducer producer = session.createProducer(queue);
+
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(session.createTextMessage("Test-" + i));
+ }
+ session.commit();
+ _connection.start();
+ Message m = consumer.receive(1000l);
+ assertNotNull("Message is not received", m);
+ session.commit();
+ }
+
+ public void testGetVirtualHostQueues() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("queue/test");
+ assertEquals("Unexpected number of queues", 1, queues.size());
+ String[] expectedQueues = new String[]{queueName};
+
+ for (String name : expectedQueues)
+ {
+ Map<String, Object> queueDetails = getRestTestHelper().find(Queue.NAME, name, queues);
+ Asserts.assertQueue(name, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(name, "amq.direct", directExchangeBinding);
+ }
+ }
+
+ public void testGetByName() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+ assertStatistics(queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> consumers = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS);
+ assertNotNull("Queue consumers are not found", consumers);
+ assertEquals("Unexpected number of consumers", 1, consumers.size());
+ assertConsumer(consumers.get(0));
+ }
+
+ public void testUpdateQueue() throws Exception
+ {
+ String queueName = getTestName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, queueName);
+
+ String queueUrl = "queue/test/test/" + queueName;
+ int responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes);
+ assertEquals("Queue was not created", 201, responseCode);
+
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList(queueUrl);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, queueName);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000);
+ attributes.put(Queue.ALERT_REPEAT_GAP, 10000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000);
+ attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000);
+ attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000);
+ attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 10);
+
+ responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes);
+ assertEquals("Setting of queue attributes should be allowed", 200, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList(queueUrl);
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) );
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) );
+ assertEquals("Unexpected " + Queue.ALERT_REPEAT_GAP, 10000, queueData.get(Queue.ALERT_REPEAT_GAP) );
+ assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_AGE) );
+ assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_SIZE) );
+ assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES) );
+ assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES) );
+ }
+
+ public void testPutCreateBinding() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String bindingName = queueName + 2;
+ String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match" };
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ createBinding(bindingName, exchanges[i], queueName);
+ }
+
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", exchanges.length + 1, bindings.size());
+
+ Map<String, Object> searchAttributes = new HashMap<String, Object>();
+ searchAttributes.put(Binding.NAME, bindingName);
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ searchAttributes.put(Binding.EXCHANGE, exchanges[i]);
+ Map<String, Object> binding = getRestTestHelper().find(searchAttributes, bindings);
+ Asserts.assertBinding(bindingName, queueName, exchanges[i], binding);
+ }
+ }
+
+ private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException
+ {
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.EXCHANGE, exchangeName);
+ bindingData.put(Binding.QUEUE, queueName);
+
+ String url = "binding/test/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName;
+ int responseCode = getRestTestHelper().submitRequest(url, "PUT", bindingData);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private void assertConsumer(Map<String, Object> consumer)
+ {
+ assertNotNull("Consumer map should not be null", consumer);
+ Asserts.assertAttributesPresent(consumer,
+ BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Consumer.class), Consumer.STATE,
+ Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR,
+ Consumer.NO_LOCAL,
+ ConfiguredObject.TYPE,
+ ConfiguredObject.CREATED_BY,
+ ConfiguredObject.CREATED_TIME,
+ ConfiguredObject.LAST_UPDATED_BY,
+ ConfiguredObject.LAST_UPDATED_TIME,
+ ConfiguredObject.DESCRIPTION,
+ ConfiguredObject.CONTEXT,
+ ConfiguredObject.DESIRED_STATE);
+
+ assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME));
+ assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE));
+ assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.DELETE_ON_SESSION_END.name(),
+ consumer.get(Consumer.LIFETIME_POLICY));
+ assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE",
+ consumer.get(Consumer.DISTRIBUTION_MODE));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) consumer.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertNotNull("Consumer statistics is not present", statistics);
+ Asserts.assertAttributesPresent(statistics, "bytesOut", "messagesOut", "unacknowledgedBytes", "unacknowledgedMessages");
+ }
+
+ private void assertStatistics(Map<String, Object> queueDetails)
+ {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES,
+ statistics.get("persistentDequeuedMessages"));
+ assertEquals("Unexpected queue statistics attribute " + "queueDepthMessages", ENQUEUED_MESSAGES,
+ statistics.get("queueDepthMessages"));
+ assertEquals("Unexpected queue statistics attribute " + "consumerCount", 1,
+ statistics.get("consumerCount"));
+ assertEquals("Unexpected queue statistics attribute " + "consumerCountWithCredit", 1,
+ statistics.get("consumerCountWithCredit"));
+ assertEquals("Unexpected queue statistics attribute " + "bindingCount", 1, statistics.get("bindingCount"));
+ assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES,
+ statistics.get("persistentDequeuedMessages"));
+ assertEquals("Unexpected queue statistics attribute " + "totalDequeuedMessages", DEQUEUED_MESSAGES,
+ statistics.get("totalDequeuedMessages"));
+ assertEquals("Unexpected queue statistics attribute " + "totalDequeuedBytes", DEQUEUED_BYTES,
+ statistics.get("totalDequeuedBytes"));
+ assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedBytes", DEQUEUED_BYTES,
+ statistics.get("totalDequeuedBytes"));
+ assertEquals("Unexpected queue statistics attribute " + "persistentEnqueuedBytes", ENQUEUED_BYTES
+ + DEQUEUED_BYTES, statistics.get("persistentEnqueuedBytes"));
+ assertEquals("Unexpected queue statistics attribute " + "totalEnqueuedBytes", ENQUEUED_BYTES + DEQUEUED_BYTES,
+ statistics.get("totalEnqueuedBytes"));
+ assertEquals("Unexpected queue statistics attribute " + "queueDepthBytes", ENQUEUED_BYTES,
+ statistics.get("queueDepthBytes"));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
new file mode 100644
index 0000000000..547b7b1b00
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
@@ -0,0 +1,384 @@
+/*
+ *
+ * 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.systest.rest;
+
+import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5ClientResponse;
+import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5HexClientResponse;
+import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generatePlainClientResponse;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.codec.binary.Base64;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.tools.security.Passwd;
+
+public class SaslRestTest extends QpidRestTestCase
+{
+ @Override
+ public void startBroker()
+ {
+ // prevent broker from starting in setUp
+ }
+
+ public void startBrokerNow() throws Exception
+ {
+ super.startBroker();
+
+ getRestTestHelper().setUsernameAndPassword(null,null);
+ }
+
+ public void testGetMechanismsWithBrokerPlainPasswordPrincipalDatabase() throws Exception
+ {
+ startBrokerNow();
+
+ Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("/service/sasl");
+ assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms"));
+
+ @SuppressWarnings("unchecked")
+ List<String> mechanisms = (List<String>) saslData.get("mechanisms");
+ String[] expectedMechanisms = { "CRAM-MD5" };
+ for (String mechanism : expectedMechanisms)
+ {
+ assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism));
+ }
+ assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user"));
+ }
+
+ public void testGetMechanismsWithBrokerBase64MD5FilePrincipalDatabase() throws Exception
+ {
+ configureBase64MD5FilePrincipalDatabase();
+ startBrokerNow();
+
+ Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("/service/sasl");
+ assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms"));
+
+ @SuppressWarnings("unchecked")
+ List<String> mechanisms = (List<String>) saslData.get("mechanisms");
+ String[] expectedMechanisms = { "CRAM-MD5-HEX", "CRAM-MD5-HASHED" };
+ for (String mechanism : expectedMechanisms)
+ {
+ assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism));
+ }
+
+ assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user"));
+ }
+
+ public void testPlainSaslAuthenticationForValidCredentials() throws Exception
+ {
+ startBrokerNow();
+
+ byte[] responseBytes = generatePlainClientResponse("admin", "admin");
+ String responseData = Base64.encodeBase64String(responseBytes);
+ String parameters= "mechanism=PLAIN&response=" + responseData;
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST");
+ OutputStream os = connection.getOutputStream();
+ os.write(parameters.getBytes());
+ os.flush();
+
+ int code = getRestTestHelper().submitRequest("/service/sasl", "POST", parameters.getBytes());
+ assertEquals("Unexpected response code", 200, code);
+
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // 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 testPlainSaslAuthenticationForIncorrectPassword() throws Exception
+ {
+ startBrokerNow();
+
+ byte[] responseBytes = generatePlainClientResponse("admin", "incorrect");
+ String responseData = Base64.encodeBase64String(responseBytes);
+ String parameters= "mechanism=PLAIN&response=" + responseData;
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST");
+ OutputStream os = connection.getOutputStream();
+ os.write(parameters.getBytes());
+ os.flush();
+
+ int code = connection.getResponseCode();
+ assertEquals("Unexpected response code", 401, code);
+
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // 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"));
+ }
+
+ public void testPlainSaslAuthenticationForNonExistingUser() throws Exception
+ {
+ startBrokerNow();
+
+ byte[] responseBytes = generatePlainClientResponse("nonexisting", "admin");
+ String responseData = Base64.encodeBase64String(responseBytes);
+ String parameters= "mechanism=PLAIN&response=" + responseData;
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST");
+ OutputStream os = connection.getOutputStream();
+ os.write(parameters.getBytes());
+ os.flush();
+
+ int code = connection.getResponseCode();
+ assertEquals("Unexpected response code", 401, code);
+
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // 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"));
+ }
+
+ public void testCramMD5SaslAuthenticationForValidCredentials() throws Exception
+ {
+ startBrokerNow();
+
+ // request the challenge for CRAM-MD5
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // authenticate user with correct credentials
+ int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5");
+ 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 testCramMD5SaslAuthenticationForIncorrectPassword() throws Exception
+ {
+ startBrokerNow();
+
+ // request the challenge for CRAM-MD5
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // authenticate user with correct credentials
+ int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5");
+ 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"));
+ }
+
+ public void testCramMD5SaslAuthenticationForNonExistingUser() throws Exception
+ {
+ startBrokerNow();
+
+ // request the challenge for CRAM-MD5
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // authenticate user with correct credentials
+ int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5");
+ 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"));
+ }
+
+ public void testCramMD5HexSaslAuthenticationForValidCredentials() throws Exception
+ {
+ configureBase64MD5FilePrincipalDatabase();
+ startBrokerNow();
+
+ // request the challenge for CRAM-MD5-HEX
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // authenticate user with correct credentials
+ int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5-HEX");
+ 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 testCramMD5HexSaslAuthenticationForIncorrectPassword() throws Exception
+ {
+ configureBase64MD5FilePrincipalDatabase();
+ startBrokerNow();
+
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // try to authenticate user with incorrect passowrd
+ int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5-HEX");
+ 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"));
+ }
+
+ public void testCramMD5HexSaslAuthenticationForNonExistingUser() throws Exception
+ {
+ configureBase64MD5FilePrincipalDatabase();
+ startBrokerNow();
+
+ HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX");
+ List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
+
+ // try to authenticate non-existing user
+ int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5-HEX");
+ 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");
+ OutputStream os = connection.getOutputStream();
+ os.write(("mechanism=" + mechanism).getBytes());
+ os.flush();
+ return connection;
+ }
+
+ public int authenticateUser(HttpURLConnection requestChallengeConnection, String userName, String userPassword, String mechanism)
+ throws IOException, JsonParseException, JsonMappingException, Exception
+ {
+ // get the response
+ Map<String, Object> response = getRestTestHelper().readJsonResponseAsMap(requestChallengeConnection);
+ String challenge = (String) response.get("challenge");
+ assertNotNull("Challenge is not found", challenge);
+
+ // preserve cookies to have the same server session
+ List<String> cookies = requestChallengeConnection.getHeaderFields().get("Set-Cookie");
+
+ // generate the authentication response for the challenge received
+ byte[] challengeBytes = Base64.decodeBase64(challenge);
+ byte[] responseBytes = generateClientResponse(mechanism, userName, userPassword, challengeBytes);
+ String responseData = Base64.encodeBase64String(responseBytes);
+ String requestParameters = ("id=" + response.get("id") + "&response=" + responseData);
+
+ // re-open connection
+ HttpURLConnection authenticateConnection = getRestTestHelper().openManagementConnection("/service/sasl", "POST");
+
+ // set cookies to use the same server session
+ applyCookiesToConnection(cookies, authenticateConnection);
+ OutputStream os = authenticateConnection.getOutputStream();
+ os.write(requestParameters.getBytes());
+ os.flush();
+ return authenticateConnection.getResponseCode();
+ }
+
+ private byte[] generateClientResponse(String mechanism, String userName, String userPassword, byte[] challengeBytes) throws Exception
+ {
+ byte[] responseBytes = null;
+ if ("CRAM-MD5-HEX".equalsIgnoreCase(mechanism))
+ {
+ responseBytes = generateCramMD5HexClientResponse(userName, userPassword, challengeBytes);
+ }
+ else if ("CRAM-MD5".equalsIgnoreCase(mechanism))
+ {
+ responseBytes = generateCramMD5ClientResponse(userName, userPassword, challengeBytes);
+ }
+ else
+ {
+ throw new RuntimeException("Not implemented test mechanism " + mechanism);
+ }
+ return responseBytes;
+ }
+
+ private void applyCookiesToConnection(List<String> cookies, HttpURLConnection connection)
+ {
+ for (String cookie : cookies)
+ {
+ connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
+ }
+ }
+
+ private void configureBase64MD5FilePrincipalDatabase() throws IOException
+ {
+ // generate user password entry
+ String passwordFileEntry;
+ try
+ {
+ passwordFileEntry = new Passwd().getOutput("admin", "admin");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ // store the entry in the file
+ File passwordFile = File.createTempFile("passwd", "pwd");
+ passwordFile.deleteOnExit();
+
+ FileWriter writer = null;
+ try
+ {
+ writer = new FileWriter(passwordFile);
+ writer.write(passwordFileEntry);
+ }
+ finally
+ {
+ writer.close();
+ }
+
+ // configure broker to use Base64MD5PasswordFilePrincipalDatabase
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put("path", passwordFile.getAbsolutePath());
+ newAttributes.put(AuthenticationProvider.TYPE, Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java
new file mode 100644
index 0000000000..daefc05e2a
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java
@@ -0,0 +1,129 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class StructureRestTest extends QpidRestTestCase
+{
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ getRestTestHelper().createTestQueues();
+ }
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> structure = getRestTestHelper().getJsonAsMap("/service/structure");
+ assertNotNull("Structure data cannot be null", structure);
+ assertNode(structure, "Broker");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhostnodes = (List<Map<String, Object>>) structure.get("virtualhostnodes");
+ assertEquals("Unexpected number of virtual hosts", 3, virtualhostnodes.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) structure.get("ports");
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders");
+ assertEquals("Unexpected number of authentication providers", 2, providers.size());
+
+ for (String nodeName : EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> node = getRestTestHelper().find("name", nodeName, virtualhostnodes);
+ assertNotNull("Node " + nodeName + " is not found ", node);
+ assertNode(node, nodeName);
+ }
+
+ String hostName = "test";
+ Map<String, Object> node = getRestTestHelper().find("name", hostName, virtualhostnodes);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) node.get("virtualhosts");
+
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, virtualhosts);
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) host.get("queues");
+ assertNotNull("Host " + hostName + " queues are not found ", queues);
+ for (String queueName : RestTestHelper.EXPECTED_QUEUES)
+ {
+ Map<String, Object> queue = getRestTestHelper().find("name", queueName, queues);
+ assertNotNull(hostName + " queue " + queueName + " is not found ", queue);
+ assertNode(queue, queueName);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queue.get("bindings");
+ assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues);
+ for (Map<String, Object> binding : bindings)
+ {
+ assertNode(binding, queueName);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) host.get("exchanges");
+ assertNotNull("Host " + hostName + " exchanges are not found ", exchanges);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().find("name", exchangeName, exchanges);
+ assertNotNull("Exchange " + exchangeName + " is not found ", exchange);
+ assertNode(exchange, exchangeName);
+ if (ExchangeDefaults.DIRECT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName) ||
+ ExchangeDefaults.DEFAULT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName))
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings);
+ for (String queueName : RestTestHelper.EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find("name", queueName, bindings);
+ assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding);
+ assertNode(binding, queueName);
+ }
+ }
+ }
+
+ String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT;
+ Map<String, Object> portData = getRestTestHelper().find(Port.NAME, httpPortName, ports);
+ assertNotNull("Http Port " + httpPortName + " is not found", portData);
+ assertNode(portData, httpPortName);
+
+ String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ Map<String, Object> amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports);
+ assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData);
+ assertNode(amqpPortData, amqpPortName);
+ }
+
+ private void assertNode(Map<String, Object> node, String name)
+ {
+ assertEquals("Unexpected name", name, node.get("name"));
+ assertNotNull("Unexpected id", node.get("id"));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java
new file mode 100644
index 0000000000..5d2e9de3fa
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java
@@ -0,0 +1,263 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.security.FileTrustStore;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestSSLConstants;
+
+public class TrustStoreRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ // not calling super.setUp() to avoid broker start-up until
+ // after any necessary configuration
+ }
+
+ public void testGet() throws Exception
+ {
+ super.setUp();
+
+ //verify existence of the default trust store used by the systests
+ List<Map<String, Object>> trustStores = assertNumberOfTrustStores(1);
+
+ Map<String, Object> truststore = trustStores.get(0);
+ assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false);
+ }
+
+ public void testCreate() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, true);
+ assertNumberOfTrustStores(2);
+
+ List<Map<String, Object>> trustStores = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details cannot be null", trustStores);
+
+ assertTrustStoreAttributes(trustStores.get(0), name, TestSSLConstants.TRUSTSTORE, true);
+ }
+
+ public void testDelete() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrue("details should be empty as the truststore no longer exists", trustStore.isEmpty());
+
+ //check only the default systests trust store remains
+ List<Map<String, Object>> trustStores = assertNumberOfTrustStores(1);
+ Map<String, Object> truststore = trustStores.get(0);
+ assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false);
+ }
+
+ public void testDeleteFailsWhenTrustStoreInUse() throws Exception
+ {
+ String name = "testDeleteFailsWhenTrustStoreInUse";
+
+ //add a new trust store config to use
+ Map<String, Object> sslTrustStoreAttributes = new HashMap<String, Object>();
+ sslTrustStoreAttributes.put(TrustStore.NAME, name);
+ sslTrustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+ sslTrustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ getBrokerConfiguration().addObjectConfiguration(TrustStore.class,sslTrustStoreAttributes);
+
+ //add the SSL port using it
+ Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
+ sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(name));
+ getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes);
+
+ super.setUp();
+
+ //verify the truststore is there
+ assertNumberOfTrustStores(2);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+
+ //try to delete it, which should fail as it is in use
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE");
+ assertEquals("Unexpected response code for provider deletion", 409, responseCode);
+
+ //check its still there
+ assertNumberOfTrustStores(2);
+ trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdateWithGoodPathSucceeds() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for truststore update", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdateWithNonExistentPathFails() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(FileTrustStore.PATH, "does.not.exist");
+
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 409, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ //verify the details remain unchanged
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdatePeersOnly() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ //update the peersOnly attribute from false to true
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(FileTrustStore.PEERS_ONLY, true);
+
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, true);
+
+ //Update peersOnly to clear it (i.e go from from true to null, which will default to false)
+ attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(FileTrustStore.PEERS_ONLY, null);
+
+ responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 200, responseCode);
+
+ trustStore = getRestTestHelper().getJsonAsList("truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ private List<Map<String, Object>> assertNumberOfTrustStores(int numberOfTrustStores) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> trustStores = getRestTestHelper().getJsonAsList("truststore");
+ assertNotNull("trust stores should not be null", trustStores);
+ assertEquals("Unexpected number of trust stores", numberOfTrustStores, trustStores.size());
+
+ return trustStores;
+ }
+
+ private void createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> trustStoreAttributes = new HashMap<String, Object>();
+ trustStoreAttributes.put(TrustStore.NAME, name);
+ //deliberately using the client trust store to differentiate from the one we are already for broker
+ trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+ trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly);
+
+ int responseCode = getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private void assertTrustStoreAttributes(Map<String, Object> truststore, String name, String path, boolean peersOnly)
+ {
+ assertEquals("default systests trust store is missing",
+ name, truststore.get(TrustStore.NAME));
+ assertEquals("unexpected path to trust store",
+ path, truststore.get(FileTrustStore.PATH));
+ assertEquals("unexpected (dummy) password of default systests trust store",
+ AbstractConfiguredObject.SECURED_STRING_VALUE, truststore.get(FileTrustStore.PASSWORD));
+ assertEquals("unexpected type of default systests trust store",
+ java.security.KeyStore.getDefaultType(), truststore.get(FileTrustStore.TRUST_STORE_TYPE));
+ assertEquals("unexpected peersOnly value",
+ peersOnly, truststore.get(FileTrustStore.PEERS_ONLY));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java
new file mode 100644
index 0000000000..a0902912ce
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class UserPreferencesRestTest extends QpidRestTestCase
+{
+ private File _preferencesProviderFile;
+
+ public void setUp() throws Exception
+ {
+ _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json",
+ "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true},"
+ + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}" + "}");
+ super.setUp();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ if (_preferencesProviderFile != null)
+ {
+ _preferencesProviderFile.delete();
+ }
+ }
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+
+ TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration();
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(PreferencesProvider.NAME, "test");
+ attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE);
+ attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath());
+ brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER,
+ attributes);
+
+ }
+
+ public void testGetUserPreferences() throws Exception
+ {
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap(
+ "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin");
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected language preference", "en", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs"));
+ }
+
+ public void testGetUserListForAuthenticationProvider() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList(
+ "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+ assertEquals("Unexpected number of users", 2, users.size());
+ String[] expectedUsers = { "webadmin", "admin" };
+ for (int i = 0; i < expectedUsers.length; i++)
+ {
+ Map<String, Object> user = findUser(expectedUsers[i], users);
+ assertNotNull(String.format("User %s is not found", expectedUsers[i]), user);
+ }
+ }
+
+ public void testGetUserList() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/service/userpreferences");
+ assertEquals("Unexpected number of users", 2, users.size());
+ String[] expectedUsers = { "webadmin", "admin" };
+ for (int i = 0; i < expectedUsers.length; i++)
+ {
+ Map<String, Object> user = findUser(expectedUsers[i], users);
+ assertNotNull(String.format("User %s is not found", expectedUsers[i]), user);
+ }
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ int status = getRestTestHelper().submitRequest(
+ "/service/userpreferences?user="
+ + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin",
+ "UTF-8"), "DELETE");
+ assertEquals("Unexpected status ", 200, status);
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/service/userpreferences");
+ assertEquals("Unexpected number of users", 1, users.size());
+ Map<String, Object> user = findUser("admin", users);
+ assertNotNull("User admin is not found", user);
+ assertNull("User webadmin is found", findUser("webadmin", users));
+ }
+
+ public void testDeleteMultipleUser() throws Exception
+ {
+ int status = getRestTestHelper().submitRequest("/service/userpreferences?user="
+ + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin", "UTF-8")
+ + "&user=" + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/admin", "UTF-8"),
+ "DELETE");
+ assertEquals("Unexpected status ", 200, status);
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/service/userpreferences");
+ assertEquals("Unexpected number of users", 0, users.size());
+ }
+
+ private Map<String, Object> findUser(String userName, List<Map<String, Object>> users)
+ {
+ for (Map<String, Object> map : users)
+ {
+ if (userName.equals(map.get(User.NAME)))
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java
new file mode 100644
index 0000000000..5df8a4ed9a
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class UserRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ getRestTestHelper().configureTemporaryPasswordFile(this, "user1", "user2");
+
+ super.setUp(); // do this last because it starts the broker, using the modified config
+ getRestTestHelper().setUsernameAndPassword("user1", "user1");
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertUser(user);
+ }
+ }
+
+ public void testGetUserByName() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ String userName = (String) user.get(User.NAME);
+ assertNotNull("Attribute " + User.NAME, userName);
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("user/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+ }
+
+ public void testPut() throws Exception
+ {
+ String userName = getTestName();
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
+
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("user/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+
+ public void testDelete() throws Exception
+ {
+ String userName = getTestName();
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
+
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("user/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName);
+ String id = (String) userDetails.get(User.ID);
+
+ getRestTestHelper().removeUserById(id);
+
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("user/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName);
+ assertEquals("User should be deleted", 0, users.size());
+ }
+
+ private void assertUser(Map<String, Object> user)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java
new file mode 100644
index 0000000000..9569b90251
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java
@@ -0,0 +1,191 @@
+/*
+ *
+ * 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.systest.rest;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+/**
+ *
+ * TODO: Add test to test the mutation of the storePath. If the store path is mutated
+ * whilst active then the store should be deleted next time we stop or close.
+ */
+public class VirtualHostNodeRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> virtualhostNodes = getRestTestHelper().getJsonAsList("virtualhostnode");
+ assertNotNull("Virtualhostnodes data cannot be null", virtualhostNodes);
+ assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, virtualhostNodes.size());
+ for (String nodeName : EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> node = getRestTestHelper().find("name", nodeName, virtualhostNodes);
+ Asserts.assertVirtualHostNode(nodeName, node);
+ }
+ }
+
+ public void testCreateAndDeleteVirtualHostNode() throws Exception
+ {
+ String virtualhostNodeType = getTestProfileVirtualHostNodeType();
+ String nodeName = "virtualhostnode-" + getTestName();
+ File storePathAsFile = new File(getStoreLocation(nodeName));
+
+ createAndDeleteVirtualHostNode(virtualhostNodeType, nodeName, storePathAsFile);
+ assertFalse("Store should not exist after deletion", storePathAsFile.exists());
+ }
+
+ public void testCreateVirtualHostNodeWithDefaultStorePath() throws Exception
+ {
+ String virtualhostNodeType = getTestProfileVirtualHostNodeType();
+ String nodeName = "virtualhostnode-" + getTestName();
+
+ createVirtualHostNode(nodeName, virtualhostNodeType);
+
+ String restUrl = "virtualhostnode/" + nodeName;
+ Map<String, Object> virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ Asserts.assertVirtualHostNode(nodeName, virtualhostNode);
+ assertNull("Virtualhostnode should not automatically get a virtualhost child",
+ virtualhostNode.get("virtualhosts"));
+
+ getRestTestHelper().submitRequest(restUrl, "DELETE", HttpServletResponse.SC_OK);
+
+ List<Map<String, Object>> virtualHostNodes = getRestTestHelper().getJsonAsList(restUrl);
+ assertEquals("Host should be deleted", 0, virtualHostNodes.size());
+ }
+
+ public void testRecoverVirtualHostNodeWithDesiredStateStopped() throws Exception
+ {
+ stopBroker();
+
+ TestBrokerConfiguration config = getBrokerConfiguration();
+ config.setObjectAttribute(VirtualHostNode.class, TEST3_VIRTUALHOST, ConfiguredObject.DESIRED_STATE, "STOPPED");
+ config.setSaved(false);
+
+ startBroker();
+
+ String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST;
+ assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED");
+ }
+
+ public void testMutateState() throws Exception
+ {
+ String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST;
+
+ assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE");
+
+ mutateVirtualHostNodeDesiredState(restUrl, "STOPPED");
+ assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED");
+
+ mutateVirtualHostNodeDesiredState(restUrl, "ACTIVE");
+ assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE");
+ }
+
+ public void testMutateAttributes() throws Exception
+ {
+ String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST;
+
+ Map<String, Object> virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ assertNull(virtualhostNode.get(VirtualHostNode.DESCRIPTION));
+
+ String newDescription = "My virtualhost node";
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(VirtualHostNode.DESCRIPTION, newDescription);
+
+ getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ assertEquals(newDescription, virtualhostNode.get(VirtualHostNode.DESCRIPTION));
+ }
+
+ private void createAndDeleteVirtualHostNode(final String virtualhostNodeType,
+ final String nodeName,
+ final File storePathAsFile) throws Exception
+ {
+ assertFalse("Store should not exist", storePathAsFile.exists());
+
+ createVirtualHostNode(nodeName, storePathAsFile.getAbsolutePath(), virtualhostNodeType);
+ assertTrue("Store should exist after creation of node", storePathAsFile.exists());
+
+ String restUrl = "virtualhostnode/" + nodeName;
+ Map<String, Object> virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ Asserts.assertVirtualHostNode(nodeName, virtualhostNode);
+ assertNull("Virtualhostnode should not automatically get a virtualhost child",
+ virtualhostNode.get("virtualhosts"));
+
+ getRestTestHelper().submitRequest(restUrl, "DELETE", HttpServletResponse.SC_OK);
+
+ List<Map<String, Object>> virtualHostNodes = getRestTestHelper().getJsonAsList(restUrl);
+ assertEquals("Host should be deleted", 0, virtualHostNodes.size());
+ }
+
+ private void assertActualAndDesireStates(final String restUrl,
+ final String expectedDesiredState,
+ final String expectedActualState) throws IOException
+ {
+ Map<String, Object> virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhostNode);
+ }
+
+ private void mutateVirtualHostNodeDesiredState(final String restUrl, final String newState) throws IOException
+ {
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(VirtualHostNode.DESIRED_STATE, newState);
+
+ getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+ }
+
+ private void createVirtualHostNode(String nodeName, String configStorePath, final String storeType) throws Exception
+ {
+ Map<String, Object> nodeData = new HashMap<String, Object>();
+ nodeData.put(VirtualHostNode.NAME, nodeName);
+ nodeData.put(VirtualHostNode.TYPE, storeType);
+ if (configStorePath != null)
+ {
+ nodeData.put(JsonVirtualHostNode.STORE_PATH, configStorePath);
+ }
+
+ getRestTestHelper().submitRequest("virtualhostnode/" + nodeName,
+ "PUT",
+ nodeData,
+ HttpServletResponse.SC_CREATED);
+ }
+
+ private void createVirtualHostNode(String nodeName, final String storeType) throws Exception
+ {
+ createVirtualHostNode(nodeName, null, storeType);
+ }
+
+ private String getStoreLocation(String hostName)
+ {
+ return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java
new file mode 100644
index 0000000000..45cbee205d
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java
@@ -0,0 +1,631 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Session;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.LastValueQueue;
+import org.apache.qpid.server.queue.PriorityQueue;
+import org.apache.qpid.server.queue.SortedQueue;
+import org.apache.qpid.server.virtualhost.AbstractVirtualHost;
+
+import org.apache.qpid.server.virtualhost.derby.DerbyVirtualHostImpl;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNodeImpl;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class VirtualHostRestTest extends QpidRestTestCase
+{
+ private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges";
+ public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues";
+ public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections";
+
+ public static final String EMPTY_VIRTUALHOSTNODE_NAME = "emptyVHN";
+
+ private AMQConnection _connection;
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+
+ TestBrokerConfiguration config = getBrokerConfiguration();
+ createTestVirtualHostNode(0, EMPTY_VIRTUALHOSTNODE_NAME, false);
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhost");
+ assertNotNull("Hosts data cannot be null", hosts);
+ assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, hosts.size());
+ for (String hostName : EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, hosts);
+ Asserts.assertVirtualHost(hostName, host);
+ }
+ }
+
+ public void testGetHost() throws Exception
+ {
+ // create AMQP connection to get connection JSON details
+ _connection = (AMQConnection) getConnection();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ session.createConsumer(getTestQueue());
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+ Asserts.assertVirtualHost("test", hostDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+
+ assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, statistics.get(
+ "exchangeCount"));
+ assertEquals("Unexpected number of queues in statistics", 1, statistics.get("queueCount"));
+ assertEquals("Unexpected number of connections in statistics", 1, statistics.get("connectionCount"));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size());
+ Asserts.assertDurableExchange("amq.fanout", "fanout", getRestTestHelper().find(Exchange.NAME, "amq.fanout", exchanges));
+ Asserts.assertDurableExchange("amq.topic", "topic", getRestTestHelper().find(Exchange.NAME, "amq.topic", exchanges));
+ Asserts.assertDurableExchange("amq.direct", "direct", getRestTestHelper().find(Exchange.NAME, "amq.direct", exchanges));
+ Asserts.assertDurableExchange("amq.match", "headers", getRestTestHelper().find(Exchange.NAME, "amq.match", exchanges));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE);
+ assertEquals("Unexpected number of queues", 1, queues.size());
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, getTestQueueName(), queues);
+ Asserts.assertQueue(getTestQueueName(), "standard", queue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, queue.get(Queue.DURABLE));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), _connection);
+ }
+
+ public void testPutCreateProvidedVirtualHost() throws Exception
+ {
+ String hostName = getTestName();
+ createVirtualHost(hostName, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + hostName);
+ Asserts.assertVirtualHost(hostName, hostDetails);
+
+ assertNewVirtualHost(hostDetails);
+ }
+
+ public void testPutCreateVirtualHost() throws Exception
+ {
+ String hostName = getTestName();
+ String vhnType = getTestProfileVirtualHostNodeType();
+ if (JsonVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE.equals(vhnType))
+ {
+ vhnType = DerbyVirtualHostImpl.VIRTUAL_HOST_TYPE;
+ }
+ createVirtualHost(hostName, vhnType);
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + hostName);
+ Asserts.assertVirtualHost(hostName, hostDetails);
+
+ assertNewVirtualHost(hostDetails);
+ }
+
+ public void testDeleteHost() throws Exception
+ {
+ getRestTestHelper().submitRequest("virtualhost/" + TEST3_VIRTUALHOST + "/" + TEST3_VIRTUALHOST,
+ "DELETE",
+ HttpServletResponse.SC_OK);
+
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + TEST3_VIRTUALHOST);
+ assertEquals("Host should be deleted", 0, hosts.size());
+ }
+
+ public void testDeleteDefaultHostFails() throws Exception
+ {
+ getRestTestHelper().submitRequest("virtualhost/" + TEST1_VIRTUALHOST, "DELETE", HttpServletResponse.SC_CONFLICT);
+ }
+
+ public void testMutateAttributes() throws Exception
+ {
+ String hostToUpdate = TEST3_VIRTUALHOST;
+ String restHostUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate;
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl);
+ Asserts.assertVirtualHost(hostToUpdate, hostDetails);
+
+ Map<String, Object> newAttributes = Collections.<String, Object>singletonMap(VirtualHost.DESCRIPTION, "This is a virtual host");
+ getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ Map<String, Object> rereadHostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl);
+ Asserts.assertVirtualHost(hostToUpdate, rereadHostDetails);
+ assertEquals("This is a virtual host", rereadHostDetails.get(VirtualHost.DESCRIPTION));
+ }
+
+ public void testMutateState() throws Exception
+ {
+ String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST;
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE");
+ assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE");
+
+ Map<String, Object> newAttributes = Collections.<String, Object>singletonMap(VirtualHost.DESIRED_STATE, "STOPPED");
+ getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED");
+ assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED");
+
+ newAttributes = Collections.<String, Object>singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE");
+ getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE");
+
+ assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE");
+ }
+
+ public void testMutateStateOfVirtualHostWithQueuesAndMessages() throws Exception
+ {
+ String testQueueName = getTestQueueName();
+ String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST;
+ String restQueueUrl = "queue/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST + "/" + testQueueName;
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE");
+ assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE");
+
+ Connection connection = getConnection();
+ Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+ Destination dest = session.createQueue(testQueueName);
+ session.createConsumer(dest).close();
+ session.createProducer(dest).send(session.createTextMessage("My test message"));
+ session.commit();
+ connection.close();
+
+ assertQueueDepth(restQueueUrl, "Unexpected number of messages before stopped", 1);
+
+ Map<String, Object> newAttributes = Collections.<String, Object>singletonMap(VirtualHost.DESIRED_STATE, "STOPPED");
+ getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED");
+ assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED");
+
+ newAttributes = Collections.<String, Object>singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE");
+ getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE");
+
+ assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE");
+
+ assertQueueDepth(restQueueUrl, "Unexpected number of messages after restart", 1);
+ }
+
+ public void testRecoverVirtualHostInDesiredStateStoppedWithDescription() throws Exception
+ {
+ String hostToUpdate = TEST3_VIRTUALHOST;
+ String restUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate;
+
+ assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE");
+
+ Map<String, Object> newAttributes = new HashMap<>();
+ newAttributes.put(VirtualHost.DESIRED_STATE, "STOPPED");
+ newAttributes.put(VirtualHost.DESCRIPTION, "My description");
+
+ getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK);
+
+ assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED");
+
+ restartBroker();
+
+ Map<String, Object> rereadVirtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ Asserts.assertActualAndDesiredState("STOPPED", "STOPPED", rereadVirtualhost);
+
+ assertEquals("Unexpected description after restart", "My description", rereadVirtualhost.get(VirtualHost.DESCRIPTION));
+ }
+
+ public void testPutCreateQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ createQueue(queueName + "-standard", "standard", null);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
+
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES));
+ }
+
+ public void testPutCreateExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+
+ createExchange(exchangeName + "-direct", "direct");
+ createExchange(exchangeName + "-topic", "topic");
+ createExchange(exchangeName + "-headers", "headers");
+ createExchange(exchangeName + "-fanout", "fanout");
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ Map<String, Object> directExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-direct" , exchanges);
+ Map<String, Object> topicExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-topic" , exchanges);
+ Map<String, Object> headersExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-headers" , exchanges);
+ Map<String, Object> fanoutExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-fanout" , exchanges);
+
+ Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange);
+ Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange);
+ Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange);
+ Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE));
+
+ }
+
+ public void testPutCreateLVQWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-lvq";
+ createQueue(queueName, "lvq", null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "lvq", lvqQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected lvq key attribute", LastValueQueue.DEFAULT_LVQ_KEY, lvqQueue.get(LastValueQueue.LVQ_KEY));
+ }
+
+ public void testPutCreateSortedQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName() + "-sorted";
+ int responseCode = tryCreateQueue(queueName, "sorted", null);
+ assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> testQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ assertNull("Sorted queue without a key was created ", testQueue);
+ }
+
+ public void testPutCreatePriorityQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-priority";
+ createQueue(queueName, "priority", null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "priority", priorityQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected number of priorities", 10, priorityQueue.get(PriorityQueue.PRIORITIES));
+ }
+
+ public void testPutCreateStandardQueueWithoutType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "standard", queue);
+ }
+
+ public void testPutCreateQueueOfUnsupportedType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ int responseCode = tryCreateQueue(queueName, "unsupported", null);
+ assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ assertNull("Queue of unsupported type was created", queue);
+ }
+
+ public void testDeleteQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ String queueUrl = "queue/test/test/" + queueName;
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList(queueUrl);
+ assertEquals("Queue should exist", 1, queues.size());
+
+ int statusCode = getRestTestHelper().submitRequest(queueUrl, "DELETE");
+ assertEquals("Unexpected response code", 200, statusCode);
+ queues = getRestTestHelper().getJsonAsList(queueUrl);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteQueueById() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName);
+ int statusCode = getRestTestHelper().submitRequest("queue/test/test?id=" + queueDetails.get(Queue.ID), "DELETE");
+ assertEquals("Unexpected response code", 200, statusCode);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("queue/test/test/" + queueName);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+
+ int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "DELETE");
+
+ assertEquals("Unexpected response code", 200, statusCode);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchangeById() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+ Map<String, Object> echangeDetails = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" + exchangeName);
+
+ int statusCode = getRestTestHelper().submitRequest("exchange/test/test?id=" + echangeDetails.get(Exchange.ID), "DELETE");
+
+ assertEquals("Unexpected response code", 200, statusCode);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testPutCreateQueueWithAttributes() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.ALERT_REPEAT_GAP, 1000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000);
+ attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800);
+ attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000);
+
+ createQueue(queueName + "-standard", "standard", attributes);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.putAll(attributes);
+ sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.putAll(attributes);
+ priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.putAll(attributes);
+ lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
+
+ attributes.put(Queue.DURABLE, Boolean.TRUE);
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes);
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testCreateQueueWithDLQEnabled() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AbstractVirtualHost.CREATE_DLQ_ON_CREATION, true);
+
+ //verify the starting state
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ assertNull("queue "+ queueName + " should not have already been present", getRestTestHelper().find(Queue.NAME, queueName , queues));
+ assertNull("queue "+ queueName + "_DLQ should not have already been present", getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues));
+ assertNull("exchange should not have already been present", getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges));
+
+ //create the queue
+ createQueue(queueName, "standard", attributes);
+
+ //verify the new queue, as well as the DLQueue and DLExchange have been created
+ hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test");
+ queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+ Map<String, Object> dlqQueue = getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues);
+ Map<String, Object> dlExchange = getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges);
+ assertNotNull("queue should have been present", queue);
+ assertNotNull("queue should have been present", dlqQueue);
+ assertNotNull("exchange should have been present", dlExchange);
+
+ //verify that the alternate exchange is set as expected on the new queue
+ Map<String, Object> queueAttributes = new HashMap<String, Object>();
+ queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE");
+
+ Asserts.assertQueue(queueName, "standard", queue, queueAttributes);
+ Asserts.assertQueue(queueName, "standard", queue, null);
+ }
+
+ private void createExchange(String exchangeName, String exchangeType) throws IOException
+ {
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Exchange.NAME, exchangeName);
+ queueData.put(Exchange.DURABLE, Boolean.TRUE);
+ queueData.put(Exchange.TYPE, exchangeType);
+
+ int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "PUT", queueData);
+ assertEquals("Unexpected response code", 201, statusCode);
+ }
+
+ private void createQueue(String queueName, String queueType, Map<String, Object> attributes) throws Exception
+ {
+ int responseCode = tryCreateQueue(queueName, queueType, attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private int tryCreateQueue(String queueName, String queueType, Map<String, Object> attributes) throws Exception
+ {
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Queue.NAME, queueName);
+ queueData.put(Queue.DURABLE, Boolean.TRUE);
+ if (queueType != null)
+ {
+ queueData.put(Queue.TYPE, queueType);
+ }
+ if (attributes != null)
+ {
+ queueData.putAll(attributes);
+ }
+
+ return getRestTestHelper().submitRequest("queue/test/test/" + queueName, "PUT", queueData);
+ }
+
+ private void createVirtualHost(final String virtualHostName,
+ final String virtualHostType) throws IOException
+ {
+ Map<String, Object> virtualhostData = new HashMap<>();
+ virtualhostData.put(VirtualHost.NAME, virtualHostName);
+ virtualhostData.put(VirtualHost.TYPE, virtualHostType);
+
+ getRestTestHelper().submitRequest("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + virtualHostName,
+ "PUT",
+ virtualhostData,
+ HttpServletResponse.SC_CREATED);
+ }
+
+ private void assertNewVirtualHost(Map<String, Object> hostDetails)
+ {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length,
+ statistics.get("exchangeCount"));
+ assertEquals("Unexpected number of queues in statistics", 0, statistics.get("queueCount"));
+ assertEquals("Unexpected number of connections in statistics", 0, statistics.get("connectionCount"));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size());
+ RestTestHelper restTestHelper = getRestTestHelper();
+ Asserts.assertDurableExchange("amq.fanout", "fanout", restTestHelper.find(Exchange.NAME, "amq.fanout", exchanges));
+ Asserts.assertDurableExchange("amq.topic", "topic", restTestHelper.find(Exchange.NAME, "amq.topic", exchanges));
+ Asserts.assertDurableExchange("amq.direct", "direct", restTestHelper.find(Exchange.NAME, "amq.direct", exchanges));
+ Asserts.assertDurableExchange("amq.match", "headers", restTestHelper.find(Exchange.NAME, "amq.match", exchanges));
+
+ assertNull("Unexpected queues", hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE));
+ assertNull("Unexpected connections", hostDetails.get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE));
+ }
+
+ private void assertActualAndDesireStates(final String restUrl,
+ final String expectedDesiredState,
+ final String expectedActualState) throws IOException
+ {
+ Map<String, Object> virtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl);
+ Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhost);
+ }
+
+ private void assertQueueDepth(String restQueueUrl, String message, int expectedDepth) throws IOException
+ {
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList(restQueueUrl);
+ assertNotNull(queueDetails);
+ Map<String, Object> statistics = (Map<String, Object>) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertNotNull(statistics);
+
+ assertEquals(message, expectedDepth, statistics.get("queueDepthMessages"));
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java
new file mode 100644
index 0000000000..8c4effd685
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java
@@ -0,0 +1,1009 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AccessControlProvider;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProvider;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl;
+import org.apache.qpid.server.security.FileKeyStore;
+import org.apache.qpid.server.security.FileTrustStore;
+import org.apache.qpid.server.security.access.FileAccessControlProviderConstants;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+import org.apache.qpid.test.utils.TestSSLConstants;
+
+public class BrokerACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+ private String _secondaryAclFileContent = "";
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER",
+ "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER",
+ "ACL DENY-LOG ALL ALL");
+
+ _secondaryAclFileContent =
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT\n" +
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" +
+ "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER\n" +
+ "ACL DENY-LOG ALL ALL";
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ /* === AuthenticationProvider === */
+
+ public void testCreateAuthenticationProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String authenticationProviderName = getTestName();
+
+ int responseCode = createAuthenticationProvider(authenticationProviderName);
+ assertEquals("Provider creation should be allowed", 201, responseCode);
+
+ assertAuthenticationProviderExists(authenticationProviderName);
+ }
+
+ public void testCreateAuthenticationProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String authenticationProviderName = getTestName();
+
+ int responseCode = createAuthenticationProvider(authenticationProviderName);
+ assertEquals("Provider creation should be denied", 403, responseCode);
+
+ assertAuthenticationProviderDoesNotExist(authenticationProviderName);
+ }
+
+ public void testDeleteAuthenticationProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String providerName = getTestName();
+
+ int responseCode = createAuthenticationProvider(providerName);
+ assertEquals("Provider creation should be allowed", 201, responseCode);
+
+ assertAuthenticationProviderExists(providerName);
+
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE");
+ assertEquals("Provider deletion should be allowed", 200, responseCode);
+
+ assertAuthenticationProviderDoesNotExist(TEST2_VIRTUALHOST);
+ }
+
+ public void testDeleteAuthenticationProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String providerName = getTestName();
+
+ int responseCode = createAuthenticationProvider(providerName);
+ assertEquals("Provider creation should be allowed", 201, responseCode);
+
+ assertAuthenticationProviderExists(providerName);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE");
+ assertEquals("Provider deletion should be denied", 403, responseCode);
+
+ assertAuthenticationProviderExists(providerName);
+ }
+
+ public void testSetAuthenticationProviderAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER;
+
+ assertAuthenticationProviderExists(providerName);
+
+ File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n"
+ + DENIED_USER + ":" + DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Setting of provider attribites should be allowed", 200, responseCode);
+ }
+
+ public void testSetAuthenticationProviderAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER;
+
+ Map<String, Object> providerData = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+
+ File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n"
+ + DENIED_USER + ":" + DENIED_USER);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, providerName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+ attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath());
+
+ int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes);
+ assertEquals("Setting of provider attribites should be allowed", 403, responseCode);
+
+ Map<String, Object> provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName);
+ assertEquals("Unexpected PATH attribute value",
+ providerData.get(ExternalFileBasedAuthenticationManager.PATH),
+ provider.get(ExternalFileBasedAuthenticationManager.PATH));
+ }
+
+ /* === Port === */
+
+ public void testCreatePortAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String portName = getTestName();
+
+ int responseCode = createPort(portName);
+ assertEquals("Port creation should be allowed", 201, responseCode);
+
+ assertPortExists(portName);
+ }
+
+ public void testCreatePortDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String portName = getTestName();
+
+ int responseCode = createPort(portName);
+ assertEquals("Port creation should be denied", 403, responseCode);
+
+ assertPortDoesNotExist(portName);
+ }
+
+ public void testDeletePortDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ assertPortExists(portName);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE");
+ assertEquals("Port deletion should be denied", 403, responseCode);
+
+ assertPortExists(portName);
+ }
+
+ public void testDeletePortAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
+ assertPortExists(portName);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE");
+ assertEquals("Port deletion should be allowed", 200, responseCode);
+
+ assertPortDoesNotExist(portName);
+ }
+
+ // TODO: test disabled until allowing the updating of active ports outside management mode
+ public void DISABLED_testSetPortAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String portName = getTestName();
+
+ int responseCode = createPort(portName);
+ assertEquals("Port creation should be allowed", 201, responseCode);
+
+ assertPortExists(portName);
+
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Setting of port attribites should be allowed", 200, responseCode);
+
+ Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+ assertEquals("Unexpected authentication provider attribute value", ANONYMOUS_AUTHENTICATION_PROVIDER,
+ port.get(Port.AUTHENTICATION_PROVIDER));
+ }
+
+ public void testSetPortAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String portName = getTestName();
+
+ int responseCode = createPort(portName);
+ assertEquals("Port creation should be allowed", 201, responseCode);
+
+ assertPortExists(portName);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.PROTOCOLS, Arrays.asList(Protocol.AMQP_0_9));
+ attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER);
+ responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ assertEquals("Setting of port attribites should be denied", 403, responseCode);
+
+ Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName);
+ assertEquals("Unexpected authentication provider attribute value",
+ TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER));
+ }
+
+ /* === KeyStore === */
+
+ public void testCreateKeyStoreAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String keyStoreName = getTestName();
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, "app1");
+ assertEquals("keyStore creation should be allowed", 201, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+ }
+
+ public void testCreateKeyStoreDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String keyStoreName = getTestName();
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, "app1");
+ assertEquals("keyStore creation should be allowed", 403, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, false);
+ }
+
+ public void testDeleteKeyStoreDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String keyStoreName = getTestName();
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, "app1");
+ assertEquals("keyStore creation should be allowed", 201, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE");
+ assertEquals("keystore deletion should be denied", 403, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+ }
+
+ public void testDeleteKeyStoreAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String keyStoreName = getTestName();
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, "app1");
+ assertEquals("keyStore creation should be allowed", 201, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE");
+ assertEquals("keystore deletion should be allowed", 200, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, false);
+ }
+
+ public void testSetKeyStoreAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String keyStoreName = getTestName();
+ String initialCertAlias = "app1";
+ String updatedCertAlias = "app2";
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, initialCertAlias);
+ assertEquals("keyStore creation should be allowed", 201, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+ Map<String, Object> keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName);
+ assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS));
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, keyStoreName);
+ attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias);
+ responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes);
+ assertEquals("Setting of keystore attributes should be allowed", 200, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName);
+ assertEquals("Unexpected certificateAlias attribute value", updatedCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS));
+ }
+
+ public void testSetKeyStoreAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String keyStoreName = getTestName();
+ String initialCertAlias = "app1";
+ String updatedCertAlias = "app2";
+
+ assertKeyStoreExistence(keyStoreName, false);
+
+ int responseCode = createKeyStore(keyStoreName, initialCertAlias);
+ assertEquals("keyStore creation should be allowed", 201, responseCode);
+
+ assertKeyStoreExistence(keyStoreName, true);
+ Map<String, Object> keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName);
+ assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS));
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, keyStoreName);
+ attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias);
+ responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes);
+ assertEquals("Setting of keystore attributes should be denied", 403, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName);
+ assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS));
+ }
+
+ /* === TrustStore === */
+
+ public void testCreateTrustStoreAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String trustStoreName = getTestName();
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, false);
+ assertEquals("trustStore creation should be allowed", 201, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+ }
+
+ public void testCreateTrustStoreDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String trustStoreName = getTestName();
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, false);
+ assertEquals("trustStore creation should be allowed", 403, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, false);
+ }
+
+ public void testDeleteTrustStoreDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String trustStoreName = getTestName();
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, false);
+ assertEquals("trustStore creation should be allowed", 201, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE");
+ assertEquals("truststore deletion should be denied", 403, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+ }
+
+ public void testDeleteTrustStoreAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String trustStoreName = getTestName();
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, false);
+ assertEquals("trustStore creation should be allowed", 201, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE");
+ assertEquals("truststore deletion should be allowed", 200, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, false);
+ }
+
+ public void testSetTrustStoreAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String trustStoreName = getTestName();
+ boolean initialPeersOnly = false;
+ boolean updatedPeersOnly = true;
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, initialPeersOnly);
+ assertEquals("trustStore creation should be allowed", 201, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+ Map<String, Object> trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName);
+ assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY));
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, trustStoreName);
+ attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly);
+ responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes);
+ assertEquals("Setting of truststore attributes should be allowed", 200, responseCode);
+
+ trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName);
+ assertEquals("Unexpected peersOnly attribute value", updatedPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY));
+ }
+
+ public void testSetTrustStoreAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String trustStoreName = getTestName();
+ boolean initialPeersOnly = false;
+ boolean updatedPeersOnly = true;
+
+ assertTrustStoreExistence(trustStoreName, false);
+
+ int responseCode = createTrustStore(trustStoreName, initialPeersOnly);
+ assertEquals("trustStore creation should be allowed", 201, responseCode);
+
+ assertTrustStoreExistence(trustStoreName, true);
+ Map<String, Object> trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName);
+ assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY));
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, trustStoreName);
+ attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly);
+ responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes);
+ assertEquals("Setting of truststore attributes should be denied", 403, responseCode);
+
+ trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName);
+ assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY));
+ }
+
+ /* === Broker === */
+
+ public void testSetBrokerAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int initialSessionCountLimit = 256;
+ int updatedSessionCountLimit = 299;
+
+ Map<String, Object> brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertEquals("Unexpected alert repeat gap", initialSessionCountLimit,
+ brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT));
+
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit);
+
+ int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes);
+ assertEquals("Setting of port attribites should be allowed", 200, responseCode);
+
+ brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertEquals("Unexpected default alert repeat gap", updatedSessionCountLimit,
+ brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT));
+ }
+
+ public void testSetBrokerAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int initialSessionCountLimit = 256;
+ int updatedSessionCountLimit = 299;
+
+ Map<String, Object> brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertEquals("Unexpected alert repeat gap", initialSessionCountLimit,
+ brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT));
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ Map<String, Object> newAttributes = new HashMap<String, Object>();
+ newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit);
+
+ int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes);
+ assertEquals("Setting of port attribites should be allowed", 403, responseCode);
+
+ brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker");
+ assertEquals("Unexpected default alert repeat gap", initialSessionCountLimit,
+ brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT));
+ }
+
+ /* === GroupProvider === */
+
+ public void testCreateGroupProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be allowed", 201, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+ }
+
+ public void testCreateGroupProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be denied", 403, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, false);
+ }
+
+ public void testDeleteGroupProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be allowed", 201, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE");
+ assertEquals("Group provider deletion should be denied", 403, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+ }
+
+ public void testDeleteGroupProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be allowed", 201, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE");
+ assertEquals("Group provider deletion should be allowed", 200, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, false);
+ }
+
+ public void testSetGroupProviderAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be allowed", 201, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, groupProviderName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, "/path/to/file");
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes);
+ assertEquals("Setting of group provider attributes should be allowed but not supported", 409, responseCode);
+ }
+
+ public void testSetGroupProviderAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String groupProviderName = getTestName();
+
+ assertGroupProviderExistence(groupProviderName, false);
+
+ int responseCode = createGroupProvider(groupProviderName);
+ assertEquals("Group provider creation should be allowed", 201, responseCode);
+
+ assertGroupProviderExistence(groupProviderName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, groupProviderName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, "/path/to/file");
+ responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes);
+ assertEquals("Setting of group provider attributes should be denied", 403, responseCode);
+ }
+
+ /* === AccessControlProvider === */
+
+ public void testCreateAccessControlProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+ }
+
+ public void testCreateAccessControlProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be denied", 403, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+ }
+
+ public void testDeleteAccessControlProviderDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE");
+ assertEquals("Access control provider deletion should be denied", 403, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+ }
+
+ public void testDeleteAccessControlProviderAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE");
+ assertEquals("Access control provider deletion should be allowed", 200, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+ }
+
+ public void testSetAccessControlProviderAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, accessControlProviderName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, "/path/to/file");
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes);
+ assertEquals("Setting of access control provider attributes should be allowed", 200, responseCode);
+ }
+
+ public void testSetAccessControlProviderAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String accessControlProviderName = getTestName();
+
+ assertAccessControlProviderExistence(accessControlProviderName, false);
+
+ int responseCode = createAccessControlProvider(accessControlProviderName);
+ assertEquals("Access control provider creation should be allowed", 201, responseCode);
+
+ assertAccessControlProviderExistence(accessControlProviderName, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, accessControlProviderName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, "/path/to/file");
+ responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes);
+ assertEquals("Setting of access control provider attributes should be denied", 403, responseCode);
+ }
+
+ /* === HTTP management === */
+
+ public void testSetHttpManagementAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+ attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.TIME_OUT, 10000);
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes);
+ assertEquals("Setting of http management should be allowed", 200, responseCode);
+
+ Map<String, Object> details = getRestTestHelper().getJsonAsSingletonList(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+
+ assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT));
+ assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED));
+ }
+
+ public void testSetHttpManagementAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+ attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false);
+ attributes.put(HttpManagement.TIME_OUT, 10000);
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes);
+ assertEquals("Setting of http management should be denied", 403, responseCode);
+
+ Map<String, Object> details = getRestTestHelper().getJsonAsSingletonList(
+ "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT);
+
+ assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS,
+ details.get(HttpManagement.TIME_OUT));
+ assertEquals("Unexpected http basic auth enabled", true,
+ details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https basic auth enabled", true,
+ details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected http sasl auth enabled", true,
+ details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED));
+ assertEquals("Unexpected https sasl auth enabled", true,
+ details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED));
+ }
+
+ /* === Utility Methods === */
+
+ private int createPort(String portName) throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.NAME, portName);
+ attributes.put(Port.PORT, findFreePort());
+ attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER);
+
+ return getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes);
+ }
+
+ private void assertPortExists(String portName) throws Exception
+ {
+ assertPortExistence(portName, true);
+ }
+
+ private void assertPortDoesNotExist(String portName) throws Exception
+ {
+ assertPortExistence(portName, false);
+ }
+
+ private void assertPortExistence(String portName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("port/" + portName);
+ assertEquals("Unexpected result", exists, !hosts.isEmpty());
+ }
+
+ private void assertKeyStoreExistence(String keyStoreName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> keyStores = getRestTestHelper().getJsonAsList("keystore/" + keyStoreName);
+ assertEquals("Unexpected result", exists, !keyStores.isEmpty());
+ }
+
+ private void assertTrustStoreExistence(String trustStoreName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> trustStores = getRestTestHelper().getJsonAsList("truststore/" + trustStoreName);
+ assertEquals("Unexpected result", exists, !trustStores.isEmpty());
+ }
+
+ private int createAuthenticationProvider(String authenticationProviderName) throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AuthenticationProvider.NAME, authenticationProviderName);
+ attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE);
+
+ return getRestTestHelper().submitRequest("authenticationprovider/" + authenticationProviderName, "PUT", attributes);
+ }
+
+ private void assertAuthenticationProviderDoesNotExist(String authenticationProviderName) throws Exception
+ {
+ assertAuthenticationProviderExistence(authenticationProviderName, false);
+ }
+
+ private void assertAuthenticationProviderExists(String authenticationProviderName) throws Exception
+ {
+ assertAuthenticationProviderExistence(authenticationProviderName, true);
+ }
+
+ private void assertAuthenticationProviderExistence(String authenticationProviderName, boolean exists) throws Exception
+ {
+ String path = "authenticationprovider/" + authenticationProviderName;
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList(path);
+ assertEquals("Unexpected result", exists, !providers.isEmpty());
+ }
+
+ private int createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> keyStoreAttributes = new HashMap<String, Object>();
+ keyStoreAttributes.put(KeyStore.NAME, name);
+ keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE);
+ keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD);
+ keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias);
+
+ return getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes);
+ }
+
+ private int createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> trustStoreAttributes = new HashMap<String, Object>();
+ trustStoreAttributes.put(TrustStore.NAME, name);
+ trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.KEYSTORE);
+ trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD);
+ trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly);
+
+ return getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes);
+ }
+
+ private void assertGroupProviderExistence(String groupProviderName, boolean exists) throws Exception
+ {
+ String path = "groupprovider/" + groupProviderName;
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList(path);
+ assertEquals("Unexpected result", exists, !providers.isEmpty());
+ }
+
+ private int createGroupProvider(String groupProviderName) throws Exception
+ {
+ File file = TestFileUtils.createTempFile(this, ".groups");
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(GroupProvider.NAME, groupProviderName);
+ attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE);
+ attributes.put(FileBasedGroupProvider.PATH, file.getAbsoluteFile());
+
+ return getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes);
+ }
+
+ private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception
+ {
+ String path = "accesscontrolprovider/" + accessControlProviderName;
+ List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList(path);
+ assertEquals("Unexpected result", exists, !providers.isEmpty());
+ }
+
+ private int createAccessControlProvider(String accessControlProviderName) throws Exception
+ {
+ File file = TestFileUtils.createTempFile(this, ".acl", _secondaryAclFileContent);
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AccessControlProvider.NAME, accessControlProviderName);
+ attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE);
+ attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile());
+
+ return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java
new file mode 100644
index 0000000000..b0c66cb3af
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java
@@ -0,0 +1,244 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExchangeRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+ private String _queueName;
+ private String _exchangeName;
+ private String _exchangeUrl;
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE EXCHANGE",
+ "ACL DENY-LOG " + DENIED_USER + " CREATE EXCHANGE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE EXCHANGE",
+ "ACL DENY-LOG " + DENIED_USER + " UPDATE EXCHANGE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE EXCHANGE",
+ "ACL DENY-LOG " + DENIED_USER + " DELETE EXCHANGE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " BIND EXCHANGE",
+ "ACL DENY-LOG " + DENIED_USER + " BIND EXCHANGE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " UNBIND EXCHANGE",
+ "ACL DENY-LOG " + DENIED_USER + " UNBIND EXCHANGE",
+ "ACL DENY-LOG ALL ALL");
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _queueName = getTestQueueName();
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Queue.NAME, _queueName);
+ queueData.put(Queue.DURABLE, Boolean.TRUE);
+ int status = getRestTestHelper().submitRequest("queue/test/test/" + _queueName, "PUT", queueData);
+ assertEquals("Unexpected status", 201, status);
+
+ _exchangeName = getTestName();
+ _exchangeUrl = "exchange/test/test/" + _exchangeName;
+ }
+
+ public void testCreateExchangeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createExchange();
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists();
+ }
+
+ public void testCreateExchangeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = createExchange();
+ assertEquals("Exchange creation should be denied", 403, responseCode);
+
+ assertExchangeDoesNotExist();
+ }
+
+ public void testDeleteExchangeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createExchange();
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists();
+
+
+ responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE");
+ assertEquals("Exchange deletion should be allowed", 200, responseCode);
+
+ assertExchangeDoesNotExist();
+ }
+
+ public void testDeleteExchangeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createExchange();
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists();
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE");
+ assertEquals("Exchange deletion should be denied", 403, responseCode);
+
+ assertExchangeExists();
+ }
+
+ public void testSetExchangeAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createExchange();
+
+ assertExchangeExists();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, _exchangeName);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange");
+
+ responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes);
+ assertEquals("Setting of exchange attribites should be allowed but it is currently unsupported", 409, responseCode);
+ }
+
+ public void testSetExchangeAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createExchange();
+ assertExchangeExists();
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, _exchangeName);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange");
+
+ responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes);
+ assertEquals("Setting of exchange attribites should be allowed", 403, responseCode);
+ }
+
+ public void testBindToExchangeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String bindingName = getTestName();
+ int responseCode = createBinding(bindingName);
+ assertEquals("Binding creation should be allowed", 201, responseCode);
+
+ assertBindingExists(bindingName);
+ }
+
+ public void testBindToExchangeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String bindingName = getTestName();
+ int responseCode = createBinding(bindingName);
+ assertEquals("Binding creation should be denied", 403, responseCode);
+
+ assertBindingDoesNotExist(bindingName);
+ }
+
+ private int createExchange() throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, _exchangeName);
+ attributes.put(Exchange.TYPE, "direct");
+ return getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes);
+ }
+
+ private void assertExchangeDoesNotExist() throws Exception
+ {
+ assertExchangeExistence(false);
+ }
+
+ private void assertExchangeExists() throws Exception
+ {
+ assertExchangeExistence(true);
+ }
+
+ private void assertExchangeExistence(boolean exists) throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList(_exchangeUrl);
+ assertEquals("Unexpected result", exists, !exchanges.isEmpty());
+ }
+
+ private int createBinding(String bindingName) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Binding.NAME, bindingName);
+ attributes.put(Binding.QUEUE, _queueName);
+ attributes.put(Binding.EXCHANGE, "amq.direct");
+
+ int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct/" + _queueName + "/" + bindingName, "PUT", attributes);
+ return responseCode;
+ }
+
+ private void assertBindingDoesNotExist(String bindingName) throws Exception
+ {
+ assertBindingExistence(bindingName, false);
+ }
+
+ private void assertBindingExists(String bindingName) throws Exception
+ {
+ assertBindingExistence(bindingName, true);
+ }
+
+ private void assertBindingExistence(String bindingName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/" + _queueName + "/" + bindingName);
+ assertEquals("Unexpected result", exists, !bindings.isEmpty());
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
new file mode 100644
index 0000000000..3ebfafb8da
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
@@ -0,0 +1,193 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class GroupRestACLTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE;
+
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "admin";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+ getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath());
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testCreateGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().createGroup("newGroup", FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ getRestTestHelper().createGroup("anotherNewGroup", FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+ }
+
+ public void testDeleteGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testUpdateGroupAddMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember", HttpServletResponse.SC_FORBIDDEN);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember");
+ assertNumberOfGroupMembers(OTHER_GROUP, 2);
+ }
+
+ public void testUpdateGroupDeleteMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER, HttpServletResponse.SC_FORBIDDEN);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER);
+ assertNumberOfGroupMembers(OTHER_GROUP, 0);
+ }
+
+ private void assertNumberOfGroupMembers(String groupName, int expectedNumberOfMembers) throws IOException
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/" + groupName);
+ getRestTestHelper().assertNumberOfGroupMembers(group, expectedNumberOfMembers);
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java
new file mode 100644
index 0000000000..1b14e3b10e
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.IOException;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class LogViewerACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS_LOGS BROKER",
+ "ACL DENY-LOG " + DENIED_USER + " ACCESS_LOGS BROKER",
+ "ACL DENY-LOG ALL ALL");
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ public void testGetLogRecordsAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET");
+ assertEquals("Access to log records should be allowed", 200, responseCode);
+ }
+
+ public void testGetLogRecordsDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET");
+ assertEquals("Access to log records should be denied", 403, responseCode);
+ }
+
+ public void testGetLogFilesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET");
+ assertEquals("Access to log files should be allowed", 200, responseCode);
+ }
+
+ public void testGetLogFilesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET");
+ assertEquals("Access to log files should be denied", 403, responseCode);
+ }
+
+ public void testDownloadLogFileAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET");
+ assertEquals("Access to log files should be allowed", 404, responseCode);
+ }
+
+ public void testDownloadLogFileDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET");
+ assertEquals("Access to log files should be denied", 403, responseCode);
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java
new file mode 100644
index 0000000000..a123de2984
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java
@@ -0,0 +1,188 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class QueueRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+ private String _queueUrl;
+ private String _queueName;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _queueName = getTestName();
+ _queueUrl = "queue/test/test/" + _queueName;
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE",
+ "ACL DENY-LOG " + DENIED_USER + " CREATE QUEUE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE QUEUE",
+ "ACL DENY-LOG " + DENIED_USER + " UPDATE QUEUE",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE QUEUE",
+ "ACL DENY-LOG " + DENIED_USER + " DELETE QUEUE",
+ "ACL DENY-LOG ALL ALL");
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ public void testCreateQueueAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createQueue();
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists();
+ }
+
+ public void testCreateQueueDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = createQueue();
+ assertEquals("Queue creation should be denied", 403, responseCode);
+
+ assertQueueDoesNotExist();
+ }
+
+ public void testDeleteQueueAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createQueue();
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists();
+
+ responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE");
+ assertEquals("Queue deletion should be allowed", 200, responseCode);
+
+ assertQueueDoesNotExist();
+ }
+
+ public void testDeleteQueueDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createQueue();
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists();
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE");
+ assertEquals("Queue deletion should be denied", 403, responseCode);
+
+ assertQueueExists();
+ }
+
+
+
+ public void testSetQueueAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createQueue();
+
+ assertQueueExists();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, _queueName);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000);
+
+ responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes);
+ assertEquals("Setting of queue attribites should be allowed", 200, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl);
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) );
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) );
+ }
+
+ public void testSetQueueAttributesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ int responseCode = createQueue();
+ assertQueueExists();
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, _queueName);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000);
+
+ responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes);
+ assertEquals("Setting of queue attribites should be allowed", 403, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl);
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) );
+ assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) );
+ }
+
+ private int createQueue() throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, _queueName);
+
+ return getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes);
+ }
+
+ private void assertQueueDoesNotExist() throws Exception
+ {
+ assertQueueExistence(false);
+ }
+
+ private void assertQueueExists() throws Exception
+ {
+ assertQueueExistence(true);
+ }
+
+ private void assertQueueExistence(boolean exists) throws Exception
+ {
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList(_queueUrl);
+ assertEquals("Unexpected result", exists, !queues.isEmpty());
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java
new file mode 100644
index 0000000000..b626b821c8
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java
@@ -0,0 +1,197 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.PreferencesProvider;
+import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+
+public class UserPreferencesRestACLTest extends QpidRestTestCase
+{
+
+ private static final String REST_USER_PREFERENCES_BASE_URL = "/service/userpreferences";
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String TEST_USER_PREFERENCES_GET_URL = REST_USER_PREFERENCES_BASE_URL + "/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/%s";
+
+ private File _preferencesProviderFile;
+
+ public void setUp() throws Exception
+ {
+ _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json",
+ "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}," + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}"
+ + "}");
+ super.setUp();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ if (_preferencesProviderFile != null)
+ {
+ _preferencesProviderFile.delete();
+ }
+ }
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", "ACL ALLOW-LOG " + ALLOWED_USER
+ + " UPDATE USER", "ACL DENY-LOG " + DENIED_USER + " UPDATE USER", "ACL DENY-LOG ALL ALL");
+
+ TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration();
+ brokerConfiguration.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(PreferencesProvider.NAME, "test");
+ attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE);
+ attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath());
+ brokerConfiguration
+ .addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, attributes);
+ }
+
+ public void testListUsersWithPreferencesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL);
+ assertUsers(users);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL);
+ assertUsers(users);
+ }
+
+ public void testViewOtherUserPreferencesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER);
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl);
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected language preference", "fr", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs"));
+ }
+
+ public void testViewOtherUserPreferencesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "/service/userpreferences?user="
+ + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"),
+ "DELETE");
+ assertEquals("Preferences deletion should be denied", 403, responseCode);
+ }
+
+ public void testDeleteOtherUserPreferencesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER);
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl);
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected language preference", "fr", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs"));
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "/service/userpreferences?user="
+ + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + DENIED_USER, "UTF-8"),
+ "DELETE");
+ assertEquals("Preferences deletion should be allowed", 200, responseCode);
+
+ preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl);
+ assertEquals("Unexpected number of preferences after deletion", 0, preferences.size());
+ }
+
+ public void testDeleteOtherUserPreferencesDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, ALLOWED_USER);
+ Map<String, Object> preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl);
+ assertEquals("Unexpected number of preferences", 2, preferences.size());
+ assertEquals("Unexpected language preference", "en", preferences.get("language"));
+ assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs"));
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ int responseCode = getRestTestHelper().submitRequest(
+ "/service/userpreferences?user="
+ + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"),
+ "DELETE");
+ assertEquals("Preferences deletion should be denied", 403, responseCode);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl);
+ assertEquals("Unexpected number of preferences after deletion", 2, preferences.size());
+ }
+
+
+ private void assertUsers(List<Map<String, Object>> users)
+ {
+ assertEquals("Unexpected number of users", 2, users.size());
+ Map<String, Object> webadmin = findUser("webadmin", users);
+ assertEquals("Unexpected name", "webadmin", webadmin.get("name"));
+ assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, webadmin.get("authenticationProvider"));
+ Map<String, Object> admin = findUser("admin", users);
+ assertEquals("Unexpected name", "admin", admin.get("name"));
+ assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, admin.get("authenticationProvider"));
+ }
+
+ private Map<String, Object> findUser(String name, List<Map<String, Object>> users)
+ {
+ for (Map<String, Object> user : users)
+ {
+ if (name.equals(user.get("name")))
+ {
+ return user;
+ }
+ }
+ return null;
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
new file mode 100644
index 0000000000..d80c8e14b2
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class UserRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "other";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+ getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath());
+
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER);
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testAddUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newUser = "newUser";
+ String password = "password";
+
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ getRestTestHelper().createOrUpdateUser(newUser, password, HttpServletResponse.SC_FORBIDDEN);
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(newUser, password);
+ assertUserExists(newUser);
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().removeUser(OTHER_USER, HttpServletResponse.SC_FORBIDDEN);
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeUser(OTHER_USER);
+ assertUserDoesNotExist(OTHER_USER);
+ }
+
+ public void testUpdateUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newPassword = "newPassword";
+
+ checkPassword(OTHER_USER, OTHER_USER, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_FORBIDDEN);
+
+ checkPassword(OTHER_USER, newPassword, false);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_OK); // expect SC_OK rather than the default SC_CREATED
+
+ checkPassword(OTHER_USER, newPassword, true);
+ checkPassword(OTHER_USER, OTHER_USER, false);
+ }
+
+ private void checkPassword(String username, String password, boolean passwordExpectedToBeCorrect) throws IOException
+ {
+ getRestTestHelper().setUsernameAndPassword(username, password);
+
+ int responseCode = getRestTestHelper().submitRequest("user/"
+ + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/", "GET", (byte[])null);
+ boolean passwordIsCorrect = responseCode == HttpServletResponse.SC_OK;
+
+ assertEquals(passwordExpectedToBeCorrect, passwordIsCorrect);
+ }
+
+ private void assertUserDoesNotExist(String newUser) throws JsonParseException, JsonMappingException, IOException
+ {
+ String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + newUser;
+ List<Map<String, Object>> userDetailsList = getRestTestHelper().getJsonAsList(path);
+ assertTrue(userDetailsList.isEmpty());
+ }
+
+ private void assertUserExists(String username) throws IOException
+ {
+ String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + username;
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList(path);
+
+ assertEquals(
+ "User returned by " + path + " should have name=" + username + ". The returned JSON was: " + userDetails,
+ username,
+ userDetails.get("name"));
+ }
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java
new file mode 100644
index 0000000000..45123325e3
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class VirtualHostACLTest extends QpidRestTestCase
+{
+ private static final String VHN_WITHOUT_VH = "myVhnWithoutVh";
+
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOST",
+ "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOST",
+ "ACL DENY-LOG ALL ALL");
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+
+ Map<String, Object> virtualHostNodeAttributes = new HashMap<>();
+ virtualHostNodeAttributes.put(VirtualHostNode.NAME, VHN_WITHOUT_VH);
+ virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+ // TODO need better way to determine the VHN's optional attributes
+ virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(VHN_WITHOUT_VH));
+
+ getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes);
+ }
+
+ public void testCreateVirtualHostAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String hostName = getTestName();
+
+ int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName);
+ assertEquals("Virtual host creation should be allowed", HttpServletResponse.SC_CREATED, responseCode);
+
+ assertVirtualHostExists(VHN_WITHOUT_VH, hostName);
+ }
+
+ public void testCreateVirtualHostDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String hostName = getTestName();
+
+ int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName);
+ assertEquals("Virtual host creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode);
+
+ assertVirtualHostDoesNotExist(VHN_WITHOUT_VH, hostName);
+ }
+
+ public void testDeleteVirtualHostDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_FORBIDDEN);
+
+ assertVirtualHostExists(TEST2_VIRTUALHOST, TEST2_VIRTUALHOST);
+ }
+
+ public void testUpdateVirtualHostDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put(VirtualHost.NAME, TEST2_VIRTUALHOST);
+ attributes.put(VirtualHost.DESCRIPTION, "new description");
+
+ getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "PUT", attributes, HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ /* === Utility Methods === */
+
+ private int createVirtualHost(final String testVirtualHostNode, String virtualHostName) throws Exception
+ {
+ Map<String, Object> data = new HashMap<>();
+ data.put(VirtualHost.NAME, virtualHostName);
+ data.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE);
+
+ return getRestTestHelper().submitRequest("virtualhost/" + testVirtualHostNode + "/" + virtualHostName, "PUT", data);
+ }
+
+ private void assertVirtualHostDoesNotExist(final String virtualHostNodeName, String virtualHostName) throws Exception
+ {
+ assertVirtualHostExistence(virtualHostNodeName, virtualHostName, false);
+ }
+
+ private void assertVirtualHostExists(final String virtualHostNodeName, String virtualHostName) throws Exception
+ {
+ assertVirtualHostExistence(virtualHostNodeName, virtualHostName, true);
+ }
+
+ private void assertVirtualHostExistence(final String virtualHostNodeName, String virtualHostName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + virtualHostNodeName + "/" + virtualHostName);
+ assertEquals("Node " + virtualHostName + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty());
+ }
+
+ private String getStoreLocation(String hostName)
+ {
+ return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
+ }
+
+}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java
new file mode 100644
index 0000000000..4809962f24
--- /dev/null
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AccessControlProvider;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProvider;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl;
+import org.apache.qpid.server.security.FileKeyStore;
+import org.apache.qpid.server.security.FileTrustStore;
+import org.apache.qpid.server.security.access.FileAccessControlProviderConstants;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.server.virtualhost.memory.MemoryVirtualHost;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+import org.apache.qpid.test.utils.TestSSLConstants;
+
+public class VirtualHostNodeACLTest extends QpidRestTestCase
+{
+ private static final String TEST_VIRTUAL_HOST_NODE = "myTestVirtualHostNode";
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+
+ @Override
+ protected void customizeConfiguration() throws IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOSTNODE",
+ "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOSTNODE",
+ "ACL DENY-LOG ALL ALL");
+
+ getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+
+ Map<String, Object> virtualHostNodeAttributes = new HashMap<>();
+ virtualHostNodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE);
+ virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+ // TODO need better way to determine the VHN's optional attributes
+ virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(TEST_VIRTUAL_HOST_NODE));
+
+
+ getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes);
+ }
+
+ public void testCreateVirtualHostNodeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String hostName = getTestName();
+
+ int responseCode = createVirtualHostNode(hostName);
+ assertEquals("Virtual host node creation should be allowed", HttpServletResponse.SC_CREATED, responseCode);
+
+ assertVirtualHostNodeExists(hostName);
+ }
+
+ public void testCreateVirtualHostNodeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String hostName = getTestName();
+
+ int responseCode = createVirtualHostNode(hostName);
+ assertEquals("Virtual host node creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode);
+
+ assertVirtualHostNodeDoesNotExist(hostName);
+ }
+
+ public void testDeleteVirtualHostNodeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().submitRequest("virtualhostnode/" + TEST_VIRTUAL_HOST_NODE, "DELETE", HttpServletResponse.SC_FORBIDDEN);
+
+ assertVirtualHostNodeExists(TEST_VIRTUAL_HOST_NODE);
+ }
+
+ /* === Utility Methods === */
+
+ private int createVirtualHostNode(String virtualHostNodeName) throws Exception
+ {
+ Map<String, Object> data = new HashMap<>();
+ data.put(VirtualHostNode.NAME, virtualHostNodeName);
+ data.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+ data.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(virtualHostNodeName));
+
+ return getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostNodeName, "PUT", data);
+ }
+
+ private void assertVirtualHostNodeDoesNotExist(String name) throws Exception
+ {
+ assertVirtualHostNodeExistence(name, false);
+ }
+
+ private void assertVirtualHostNodeExists(String name) throws Exception
+ {
+ assertVirtualHostNodeExistence(name, true);
+ }
+
+ private void assertVirtualHostNodeExistence(String name, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhostnode/" + name);
+ assertEquals("Node " + name + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty());
+ }
+
+ private String getStoreLocation(String hostName)
+ {
+ return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
+ }
+
+}