summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorAlex Rudyy <orudyy@apache.org>2013-05-04 22:17:08 +0000
committerAlex Rudyy <orudyy@apache.org>2013-05-04 22:17:08 +0000
commit8c52b5056d0e70491ca2629843c88ee2ba5bf63f (patch)
tree38c5c07aa043f57aef10d586be227caf56cbfea5 /java
parentf93a0693e031a20948e0647d48b28e8895c1d26e (diff)
downloadqpid-python-8c52b5056d0e70491ca2629843c88ee2ba5bf63f.tar.gz
QPID-4813: Protect operations to update queue and exchange attributes with ACL
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1479200 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java')
-rw-r--r--java/broker/etc/broker_example.acl1
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java74
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java25
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java4
-rw-r--r--java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java21
-rw-r--r--java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java21
-rw-r--r--java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java38
-rw-r--r--java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java235
-rw-r--r--java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java189
11 files changed, 643 insertions, 4 deletions
diff --git a/java/broker/etc/broker_example.acl b/java/broker/etc/broker_example.acl
index bb85ef5e57..6cab707a89 100644
--- a/java/broker/etc/broker_example.acl
+++ b/java/broker/etc/broker_example.acl
@@ -57,6 +57,7 @@ ACL ALLOW webadmins ACCESS MANAGEMENT
# All rules below are required for console admin users
# to perform create/update/delete operations
ACL ALLOW-LOG webadmins CREATE QUEUE
+ACL ALLOW-LOG webadmins UPDATE QUEUE
ACL ALLOW-LOG webadmins DELETE QUEUE
ACL ALLOW-LOG webadmins PURGE QUEUE
ACL ALLOW-LOG webadmins CREATE EXCHANGE
diff --git a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java
index eb2d0dd7e2..39e979174a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java
@@ -222,4 +222,19 @@ final class BindingAdapter extends AbstractAdapter implements Binding
}
return false;
}
+
+ @Override
+ public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ throw new UnsupportedOperationException("Changing attributes on binding is not supported.");
+ }
+
+ @Override
+ public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ throw new UnsupportedOperationException("Changing attributes on binding is not supported.");
+ }
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java
index 5d5f3f7378..a081f03f09 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java
@@ -384,6 +384,30 @@ final class ExchangeAdapter extends AbstractAdapter implements Exchange, org.apa
return false;
}
+ @Override
+ protected void changeAttributes(Map<String, Object> attributes)
+ {
+ throw new UnsupportedOperationException("Changing attributes on exchange is not supported.");
+ }
+
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ if (!_vhost.getSecurityManager().authoriseUpdate(_exchange))
+ {
+ throw new AccessControlException("Setting of exchange attribute is denied");
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ if (!_vhost.getSecurityManager().authoriseUpdate(_exchange))
+ {
+ throw new AccessControlException("Setting of exchange attributes is denied");
+ }
+ }
+
private class ExchangeStatistics implements Statistics
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java
index 8ac869900c..0916c4e730 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java
@@ -20,6 +20,7 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.lang.reflect.Type;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Collection;
@@ -31,16 +32,15 @@ import java.util.Map;
import org.apache.qpid.AMQException;
import org.apache.qpid.AMQStoreException;
import org.apache.qpid.server.binding.Binding;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.ConfiguredObjectFinder;
import org.apache.qpid.server.model.Consumer;
-import org.apache.qpid.server.model.Connection;
import org.apache.qpid.server.model.Exchange;
import org.apache.qpid.server.model.IllegalStateTransitionException;
import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.model.QueueNotificationListener;
-import org.apache.qpid.server.model.Session;
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.Statistics;
import org.apache.qpid.server.protocol.AMQConnectionModel;
@@ -51,6 +51,19 @@ import org.apache.qpid.server.util.MapValueConverter;
final class QueueAdapter extends AbstractAdapter implements Queue, AMQQueue.SubscriptionRegistrationListener, AMQQueue.NotificationListener
{
+ @SuppressWarnings("serial")
+ static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{
+ put(ALERT_REPEAT_GAP, Long.class);
+ put(ALERT_THRESHOLD_MESSAGE_AGE, Long.class);
+ put(ALERT_THRESHOLD_MESSAGE_SIZE, Long.class);
+ put(ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, Long.class);
+ put(ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, Long.class);
+ put(QUEUE_FLOW_CONTROL_SIZE_BYTES, Long.class);
+ put(QUEUE_FLOW_RESUME_SIZE_BYTES, Long.class);
+ put(MAXIMUM_DELIVERY_ATTEMPTS, Integer.class);
+ put(EXCLUSIVE, Boolean.class);
+ put(DESCRIPTION, String.class);
+ }});
static final Map<String, String> ATTRIBUTE_MAPPINGS = new HashMap<String, String>();
static
@@ -775,4 +788,61 @@ final class QueueAdapter extends AbstractAdapter implements Queue, AMQQueue.Subs
return false;
}
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ if (!_vhost.getSecurityManager().authoriseUpdate(_queue))
+ {
+ throw new AccessControlException("Setting of queue attribute is denied");
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ if (!_vhost.getSecurityManager().authoriseUpdate(_queue))
+ {
+ throw new AccessControlException("Setting of queue attributes is denied");
+ }
+ }
+
+ @Override
+ protected void changeAttributes(final Map<String, Object> attributes)
+ {
+ Map<String, Object> convertedAttributes = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ validateAttributes(convertedAttributes);
+
+ super.changeAttributes(convertedAttributes);
+ }
+
+ private void validateAttributes(Map<String, Object> convertedAttributes)
+ {
+ Long queueFlowControlSize = (Long) convertedAttributes.get(QUEUE_FLOW_CONTROL_SIZE_BYTES);
+ Long queueFlowControlResumeSize = (Long) convertedAttributes.get(QUEUE_FLOW_RESUME_SIZE_BYTES);
+ if (queueFlowControlSize != null || queueFlowControlResumeSize != null )
+ {
+ if (queueFlowControlSize == null)
+ {
+ queueFlowControlSize = (Long)getAttribute(QUEUE_FLOW_CONTROL_SIZE_BYTES);
+ }
+ if (queueFlowControlResumeSize == null)
+ {
+ queueFlowControlResumeSize = (Long)getAttribute(QUEUE_FLOW_RESUME_SIZE_BYTES);
+ }
+ if (queueFlowControlResumeSize > queueFlowControlSize)
+ {
+ throw new IllegalConfigurationException("Flow resume size can't be greater than flow control size");
+ }
+ }
+ for (Map.Entry<String, Object> entry: convertedAttributes.entrySet())
+ {
+ Object value = entry.getValue();
+ if (value instanceof Number && ((Number)value).longValue() < 0)
+ {
+ throw new IllegalConfigurationException("Only positive integer value can be specified for the attribute "
+ + entry.getKey());
+ }
+ }
+ }
+
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index f0570943cf..09e79d3ae9 100755
--- a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -52,6 +52,7 @@ import static org.apache.qpid.server.security.access.Operation.DELETE;
import static org.apache.qpid.server.security.access.Operation.PUBLISH;
import static org.apache.qpid.server.security.access.Operation.PURGE;
import static org.apache.qpid.server.security.access.Operation.UNBIND;
+import static org.apache.qpid.server.security.access.Operation.UPDATE;
import javax.security.auth.Subject;
import java.net.SocketAddress;
@@ -386,6 +387,30 @@ public class SecurityManager implements ConfigurationChangeListener
});
}
+
+ public boolean authoriseUpdate(final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(AccessControl plugin)
+ {
+ return plugin.authorise(UPDATE, QUEUE, new ObjectProperties(queue));
+ }
+ });
+ }
+
+
+ public boolean authoriseUpdate(final Exchange exchange)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(AccessControl plugin)
+ {
+ return plugin.authorise(UPDATE, EXCHANGE, new ObjectProperties(exchange.getName()));
+ }
+ });
+ }
+
public boolean authoriseDelete(final Exchange exchange)
{
return checkAllPlugins(new AccessCheck()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
index e93f487bdb..048d9a8fc9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
@@ -43,8 +43,8 @@ public enum ObjectType
ALL(Operation.ALL),
VIRTUALHOST(Operation.ALL, ACCESS),
MANAGEMENT(Operation.ALL, ACCESS),
- QUEUE(Operation.ALL, CREATE, DELETE, PURGE, CONSUME),
- EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
+ QUEUE(Operation.ALL, CREATE, DELETE, PURGE, CONSUME, UPDATE),
+ EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH, UPDATE),
LINK, // Not allowed in the Java broker
ROUTE, // Not allowed in the Java broker
METHOD(Operation.ALL, ACCESS, UPDATE),
diff --git a/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java b/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java
index 372db8f560..9a57429062 100644
--- a/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java
@@ -127,4 +127,25 @@ public class BindingRestTest extends QpidRestTestCase
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");
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT", attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("/rest/binding/test/amq.direct/queue/" + bindingName);
+
+ Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
+
+ attributes.put(Binding.ID, binding.get(Binding.ID));
+ attributes.put(Binding.ARGUMENTS, null);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT", attributes);
+ assertEquals("Update should be unsupported", 409, responseCode);
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
index ec9791db13..1da1c6394e 100644
--- a/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
@@ -21,6 +21,7 @@
package org.apache.qpid.systest.rest;
import java.net.URLDecoder;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -62,6 +63,26 @@ public class ExchangeRestTest extends QpidRestTestCase
}
}
+ public void testSetExchangeAttributesUnsupported() throws Exception
+ {
+ String exchangeName = getTestName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.TYPE, "direct");
+ int responseCode =getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "PUT", attributes);
+
+ Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList("/rest/exchange/test/" + exchangeName);
+ assertNotNull("Exchange not found", exchange);
+
+ attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange");
+
+ responseCode = getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "PUT", attributes);
+ assertEquals("Exchange update should be unsupported", 409, responseCode);
+ }
+
private void assertExchange(String exchangeName, Map<String, Object> exchange)
{
assertNotNull("Exchange with name " + exchangeName + " is not found", exchange);
diff --git a/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java b/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java
index 1f441e7cbb..d6eae154cf 100644
--- a/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java
@@ -127,6 +127,44 @@ public class QueueRestTest extends QpidRestTestCase
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);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "PUT", attributes);
+
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ 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);
+ attributes.put(Queue.EXCLUSIVE, true);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "PUT", attributes);
+ assertEquals("Setting of queue attribites should be allowed", 200, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ 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) );
+ assertEquals("Unexpected " + Queue.EXCLUSIVE, true, queueData.get(Queue.EXCLUSIVE) );
+ }
+
public void testPutCreateBinding() throws Exception
{
String queueName = getTestQueueName();
diff --git a/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java b/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java
new file mode 100644
index 0000000000..b39d994198
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java
@@ -0,0 +1,235 @@
+/*
+ *
+ * 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.commons.configuration.ConfigurationException;
+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.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;
+
+public class ExchangeRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_USER = "user1";
+ private static final String DENIED_USER = "user2";
+
+ @Override
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "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(TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ public void testCreateExchangeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists(exchangeName);
+ }
+
+ public void testCreateExchangeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+ assertEquals("Exchange creation should be denied", 403, responseCode);
+
+ assertExchangeDoesNotExist(exchangeName);
+ }
+
+ public void testDeleteExchangeAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists(exchangeName);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "DELETE", null);
+ assertEquals("Exchange deletion should be allowed", 200, responseCode);
+
+ assertExchangeDoesNotExist(TEST2_VIRTUALHOST);
+ }
+
+ public void testDeleteExchangeDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+ assertEquals("Exchange creation should be allowed", 201, responseCode);
+
+ assertExchangeExists(exchangeName);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ responseCode = getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "DELETE", null);
+ assertEquals("Exchange deletion should be denied", 403, responseCode);
+
+ assertExchangeExists(exchangeName);
+ }
+
+ public void testSetExchangeAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+
+ assertExchangeExists(exchangeName);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange");
+
+ responseCode = getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "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);
+
+ String exchangeName = getTestName();
+
+ int responseCode = createExchange(exchangeName);
+ assertExchangeExists(exchangeName);
+
+ 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("/rest/exchange/test/" + exchangeName, "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(String exchangeName) throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Exchange.NAME, exchangeName);
+ attributes.put(Exchange.TYPE, "direct");
+ return getRestTestHelper().submitRequest("/rest/exchange/test/" + exchangeName, "PUT", attributes);
+ }
+
+ private void assertExchangeDoesNotExist(String exchangeName) throws Exception
+ {
+ assertExchangeExistence(exchangeName, false);
+ }
+
+ private void assertExchangeExists(String exchangeName) throws Exception
+ {
+ assertExchangeExistence(exchangeName, true);
+ }
+
+ private void assertExchangeExistence(String exchangeName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("/rest/exchange/test/" + exchangeName);
+ 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, "queue");
+ attributes.put(Binding.EXCHANGE, "amq.direct");
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/binding/test/amq.direct/queue/" + 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("/rest/binding/test/amq.direct/queue/" + bindingName);
+ assertEquals("Unexpected result", exists, !bindings.isEmpty());
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java b/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java
new file mode 100644
index 0000000000..b187ca955a
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java
@@ -0,0 +1,189 @@
+/*
+ *
+ * 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.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.management.plugin.HttpManagement;
+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";
+
+ @Override
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ super.customizeConfiguration();
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "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(TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+ HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+ }
+
+ public void testCreateQueueAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists(queueName);
+ }
+
+ public void testCreateQueueDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+ assertEquals("Queue creation should be denied", 403, responseCode);
+
+ assertQueueDoesNotExist(queueName);
+ }
+
+ public void testDeleteQueueAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists(queueName);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "DELETE", null);
+ assertEquals("Queue deletion should be allowed", 200, responseCode);
+
+ assertQueueDoesNotExist(TEST2_VIRTUALHOST);
+ }
+
+ public void testDeleteQueueDenied() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+ assertEquals("Queue creation should be allowed", 201, responseCode);
+
+ assertQueueExists(queueName);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ responseCode = getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "DELETE", null);
+ assertEquals("Queue deletion should be denied", 403, responseCode);
+
+ assertQueueExists(queueName);
+ }
+
+ public void testSetQueueAttributesAllowed() throws Exception
+ {
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+
+ assertQueueExists(queueName);
+
+ 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("/rest/queue/test/" + queueName, "PUT", attributes);
+ assertEquals("Setting of queue attribites should be allowed", 200, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ 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);
+
+ String queueName = getTestName();
+
+ int responseCode = createQueue(queueName);
+ assertQueueExists(queueName);
+
+ 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("/rest/queue/test/" + queueName, "PUT", attributes);
+ assertEquals("Setting of queue attribites should be allowed", 403, responseCode);
+
+ Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ 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(String queueName) throws Exception
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.NAME, queueName);
+
+ return getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "PUT", attributes);
+ }
+
+ private void assertQueueDoesNotExist(String queueName) throws Exception
+ {
+ assertQueueExistence(queueName, false);
+ }
+
+ private void assertQueueExists(String queueName) throws Exception
+ {
+ assertQueueExistence(queueName, true);
+ }
+
+ private void assertQueueExistence(String queueName, boolean exists) throws Exception
+ {
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test/" + queueName);
+ assertEquals("Unexpected result", exists, !queues.isEmpty());
+ }
+}