summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2010-05-31 16:03:41 +0000
committerRobert Gemmell <robbie@apache.org>2010-05-31 16:03:41 +0000
commit48e49bef0775e91625ba7b5c03823dbaca943bf7 (patch)
treef987246a0d61c3a23e5c52b9a233778d57e3fca4
parenta2d26b71f141f3166bdd0342b481723d98b0bb99 (diff)
downloadqpid-python-48e49bef0775e91625ba7b5c03823dbaca943bf7.tar.gz
QPID-2606: Access Control Modifications
Applied patch from Andrew Kennedy <andrew.international@gmail.com> git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@949781 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--java/broker/etc/config.xml5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java52
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/Main.java19
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java79
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java22
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java18
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java13
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java8
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java28
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java19
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java24
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java20
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java9
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java10
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java22
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java11
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java33
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java288
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java70
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java3
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java21
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java11
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java120
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java5
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java69
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java139
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/Result.java46
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java384
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java47
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java54
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java (renamed from java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java)17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java323
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java70
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java33
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java65
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java63
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java315
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java90
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java (renamed from java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java)48
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java35
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java68
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java99
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java68
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java110
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java51
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java85
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java81
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java71
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java16
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java (renamed from java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java)67
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java7
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java18
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java35
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java1
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java326
-rwxr-xr-xjava/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java2
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java130
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java4
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java (renamed from java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java)10
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java74
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java4
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java3
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java112
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java67
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQSecurityException.java54
-rw-r--r--java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java19
-rw-r--r--java/systests/etc/config-systests-aclv2-settings.xml33
-rw-r--r--java/systests/etc/config-systests-aclv2.xml30
-rw-r--r--java/systests/etc/global-default.txt31
-rw-r--r--java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt24
-rw-r--r--java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt25
-rw-r--r--java/systests/etc/test-default.txt73
-rw-r--r--java/systests/etc/test-externalacljmx-deleteexchangefailure.txt26
-rw-r--r--java/systests/etc/test-externalacljmx.txt35
-rw-r--r--java/systests/etc/test2-default.txt21
-rw-r--r--java/systests/etc/virtualhosts-systests-acl-settings.xml50
-rw-r--r--java/systests/etc/virtualhosts-systests-aclv2-settings.xml48
-rw-r--r--java/systests/etc/virtualhosts-systests-aclv2.xml29
-rw-r--r--java/systests/etc/virtualhosts-systests-firewall-2.xml6
-rw-r--r--java/systests/etc/virtualhosts-systests-firewall-3.xml6
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java2
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java285
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java195
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java184
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java244
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java (renamed from java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java)26
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java186
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java646
-rw-r--r--java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java16
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java8
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java228
-rw-r--r--java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java55
-rwxr-xr-xjava/test-profiles/CPPExcludes7
-rw-r--r--java/test-profiles/JavaInVMExcludes3
110 files changed, 4328 insertions, 2620 deletions
diff --git a/java/broker/etc/config.xml b/java/broker/etc/config.xml
index 2f78003afb..87101678c0 100644
--- a/java/broker/etc/config.xml
+++ b/java/broker/etc/config.xml
@@ -25,6 +25,7 @@
<conf>${prefix}/etc</conf>
<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>
+ <cache-directory>${QPID_WORK}/cache</cache-directory>
<connector>
<!-- To enable SSL edit the keystorePath and keystorePassword
@@ -83,9 +84,7 @@
</principal-database>
</principal-databases>
- <access>
- <class>org.apache.qpid.server.security.access.plugins.AllowAll</class>
- </access>
+ <allow-all />
<msg-auth>false</msg-auth>
diff --git a/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
index 8bb1a6b9fa..7e999a720b 100644
--- a/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
+++ b/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
@@ -1063,7 +1063,14 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable
public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory,
final Long request)
{
- _obj.purge(request);
+ try
+ {
+ _obj.purge(request);
+ } catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException();
+ }
return factory.createResponseCommand();
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
index b2e43b4f0d..811e45f4ae 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java
@@ -1,5 +1,4 @@
/*
- *
* 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
@@ -16,24 +15,6 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
- */
-/*
- *
- * Copyright (c) 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
*/
package org.apache.qpid.server;
@@ -189,8 +170,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
* @param type
* @param durable
* @throws JMException
+ * @throws MBeanException
*/
- public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException
+ public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException, MBeanException
{
CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
try
@@ -216,7 +198,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
catch (AMQException ex)
{
- throw new MBeanException(ex, "Error in creating exchange " + exchangeName);
+ JMException jme = new JMException(ex.toString());
+ throw new MBeanException(jme, "Error in creating exchange " + exchangeName);
}
finally
{
@@ -229,8 +212,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
*
* @param exchangeName
* @throws JMException
+ * @throws MBeanException
*/
- public void unregisterExchange(String exchangeName) throws JMException
+ public void unregisterExchange(String exchangeName) throws JMException, MBeanException
{
// TODO
// Check if the exchange is in use.
@@ -244,7 +228,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
catch (AMQException ex)
{
- throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName);
+ JMException jme = new JMException(ex.toString());
+ throw new MBeanException(jme, "Error in unregistering exchange " + exchangeName);
}
finally
{
@@ -260,8 +245,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
* @param durable
* @param owner
* @throws JMException
+ * @throws MBeanException
*/
- public void createNewQueue(String queueName, String owner, boolean durable) throws JMException
+ public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException
{
AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName));
if (queue != null)
@@ -278,8 +264,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
ownerShortString = new AMQShortString(owner);
}
- queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false,
- getVirtualHost(), null);
+ queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, getVirtualHost(), null);
if (queue.isDurable() && !queue.isAutoDelete())
{
_durableConfig.createQueue(queue);
@@ -289,8 +274,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
catch (AMQException ex)
{
- JMException jme = new JMException(ex.getMessage());
- jme.initCause(ex);
+ JMException jme = new JMException(ex.toString());
throw new MBeanException(jme, "Error in creating queue " + queueName);
}
finally
@@ -309,13 +293,14 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
*
* @param queueName
* @throws JMException
+ * @throws MBeanException
*/
- public void deleteQueue(String queueName) throws JMException
+ public void deleteQueue(String queueName) throws JMException, MBeanException
{
AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName));
if (queue == null)
{
- throw new JMException("The Queue " + queueName + " is not a registerd queue.");
+ throw new JMException("The Queue " + queueName + " is not a registered queue.");
}
CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
@@ -329,8 +314,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
catch (AMQException ex)
{
- JMException jme = new JMException(ex.getMessage());
- jme.initCause(ex);
+ JMException jme = new JMException(ex.toString());
throw new MBeanException(jme, "Error in deleting queue " + queueName);
}
finally
@@ -339,14 +323,16 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr
}
}
+ @Override
public ManagedObject getParentObject()
{
return _virtualHostMBean;
}
// This will have a single instance for a virtual host, so not having the name property in the ObjectName
+ @Override
public ObjectName getObjectName() throws MalformedObjectNameException
{
return getObjectNameForSingleInstanceMBean();
}
-} // End of MBean class
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 7d0163510a..8a0e49f537 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQMethodBody;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -244,9 +245,12 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
return _channelId;
}
- public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException
+ public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQSecurityException
{
-
+ if (!getVirtualHost().getSecurityManager().authorisePublish(info.isImmediate(), info.getRoutingKey().asString(), e.getName()))
+ {
+ throw new AMQSecurityException("Permission denied: " + e.getName());
+ }
_currentMessage = new IncomingMessage(info);
_currentMessage.setExchange(e);
}
@@ -421,7 +425,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel
{
throw new AMQException("Consumer already exists with same tag: " + tag);
}
-
+
Subscription subscription =
SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/Main.java b/java/broker/src/main/java/org/apache/qpid/server/Main.java
index 90afd2e4ac..d52267ad57 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/Main.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/Main.java
@@ -25,12 +25,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
-import java.util.Properties;
-import java.util.Set;
+import java.util.Arrays;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
-import java.util.Collection;
-import java.util.Arrays;
+import java.util.Properties;
+import java.util.Set;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
@@ -42,8 +42,6 @@ import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.QpidLog4JConfigurator;
-import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.*;
import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.server.configuration.ServerConfiguration;
@@ -56,21 +54,18 @@ import org.apache.qpid.server.logging.management.LoggingManagementMBean;
import org.apache.qpid.server.logging.messages.BrokerMessages;
import org.apache.qpid.server.protocol.AMQProtocolEngineFactory;
import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory;
+import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.transport.ServerConnection;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.ssl.SSLContextFactory;
import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.network.mina.MINANetworkDriver;
-import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION;
/**
* Main entry point for AMQPD.
*
*/
-@SuppressWarnings({"AccessStaticViaInstance"})
public class Main
{
private static Logger _logger;
@@ -83,7 +78,6 @@ public class Main
private static final int IPV4_ADDRESS_LENGTH = 4;
private static final char IPV4_LITERAL_SEPARATOR = '.';
- private static final Collection<VERSION> ALL_VERSIONS = Arrays.asList(VERSION.values());
protected static class InitException extends Exception
{
@@ -123,6 +117,7 @@ public class Main
}
}
+ @SuppressWarnings("static-access")
protected void setOptions(Options options)
{
Option help = new Option("h", "help", false, "print this message");
@@ -403,7 +398,7 @@ public class Main
NetworkDriver driver = new MINANetworkDriver();
- Set<VERSION> supported = new HashSet<VERSION>(ALL_VERSIONS);
+ Set<VERSION> supported = EnumSet.allOf(VERSION.class);
if(exclude_0_10.contains(port))
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
index 5423f02107..59626a7b13 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java
@@ -20,7 +20,12 @@
*/
package org.apache.qpid.server.binding;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.configuration.BindingConfig;
@@ -35,13 +40,8 @@ import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
public class BindingFactory
{
-
private final VirtualHost _virtualHost;
private final DurableConfigurationStore.Source _configSource;
private final Exchange _defaultExchange;
@@ -51,14 +51,14 @@ public class BindingFactory
public BindingFactory(final VirtualHost vhost)
{
- this(vhost,vhost.getExchangeRegistry().getDefaultExchange());
+ this(vhost, vhost.getExchangeRegistry().getDefaultExchange());
}
public BindingFactory(final DurableConfigurationStore.Source configSource, final Exchange defaultExchange)
{
_configSource = configSource;
_defaultExchange = defaultExchange;
- if(configSource instanceof VirtualHost)
+ if (configSource instanceof VirtualHost)
{
_virtualHost = (VirtualHost) configSource;
}
@@ -83,7 +83,7 @@ public class BindingFactory
private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments)
{
- super(queue.getVirtualHost().getConfigStore().createId(),bindingKey, queue, exchange, arguments);
+ super(queue.getVirtualHost().getConfigStore().createId(), bindingKey, queue, exchange, arguments);
_logSubject = new BindingLogSubject(bindingKey,exchange,queue);
}
@@ -94,7 +94,7 @@ public class BindingFactory
removeBinding(this);
}
- public void onClose(final Exchange exchange)
+ public void onClose(final Exchange exchange) throws AMQSecurityException
{
removeBinding(this);
}
@@ -138,7 +138,7 @@ public class BindingFactory
- public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments)
+ public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) throws AMQSecurityException
{
return makeBinding(bindingKey, queue, exchange, arguments, false, false);
}
@@ -147,37 +147,43 @@ public class BindingFactory
public boolean replaceBinding(final String bindingKey,
final AMQQueue queue,
final Exchange exchange,
- final Map<String, Object> arguments)
+ final Map<String, Object> arguments) throws AMQSecurityException
{
return makeBinding(bindingKey, queue, exchange, arguments, false, true);
}
- private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments, boolean restore, boolean force)
+ private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments, boolean restore, boolean force) throws AMQSecurityException
{
assert queue != null;
- if(bindingKey == null)
+ if (bindingKey == null)
{
bindingKey = "";
}
- if(exchange == null)
+ if (exchange == null)
{
exchange = _defaultExchange;
}
- if(arguments == null)
+ if (arguments == null)
{
- arguments = Collections.EMPTY_MAP;
+ arguments = Collections.emptyMap();
}
-
+
+ //Perform ACLs
+ if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey)))
+ {
+ throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ }
+
BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments);
BindingImpl existingMapping = _bindings.putIfAbsent(b,b);
- if(existingMapping == null || force)
+ if (existingMapping == null || force)
{
- if(existingMapping != null)
+ if (existingMapping != null)
{
removeBinding(existingMapping);
}
- if(b.isDurable() && !restore)
+ if (b.isDurable() && !restore)
{
try
{
@@ -185,7 +191,7 @@ public class BindingFactory
}
catch (AMQException e)
{
- throw new RuntimeException(e);
+ throw new RuntimeException(e); // FIXME
}
}
@@ -201,8 +207,6 @@ public class BindingFactory
{
return false;
}
-
-
}
private ConfigStore getConfigStore()
@@ -210,43 +214,49 @@ public class BindingFactory
return getVirtualHost().getConfigStore();
}
- public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> argumentMap)
+ public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> argumentMap) throws AMQSecurityException
{
makeBinding(bindingKey,queue,exchange,argumentMap,true, false);
}
- public void removeBinding(final Binding b)
+ public void removeBinding(final Binding b) throws AMQSecurityException
{
removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments());
}
- public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments)
+ public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) throws AMQSecurityException
{
assert queue != null;
- if(bindingKey == null)
+ if (bindingKey == null)
{
bindingKey = "";
}
- if(exchange == null)
+ if (exchange == null)
{
exchange = _defaultExchange;
}
- if(arguments == null)
+ if (arguments == null)
{
- arguments = Collections.EMPTY_MAP;
+ arguments = Collections.emptyMap();
}
+ // Check access
+ if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue))
+ {
+ throw new AMQSecurityException("Permission denied: binding " + bindingKey);
+ }
+
BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments));
- if(b != null)
+ if (b != null)
{
exchange.removeBinding(b);
queue.removeBinding(b);
exchange.removeCloseTask(b);
queue.removeQueueDeleteTask(b);
- if(b.isDurable())
+ if (b.isDurable())
{
try
{
@@ -257,12 +267,11 @@ public class BindingFactory
}
catch (AMQException e)
{
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ throw new RuntimeException(e); // FIXME
}
}
b.logDestruction();
getConfigStore().removeConfiguredObject(b);
-
}
return b;
@@ -281,7 +290,7 @@ public class BindingFactory
}
if(arguments == null)
{
- arguments = Collections.EMPTY_MAP;
+ arguments = Collections.emptyMap();
}
BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
index 7fef4558c8..f62022922a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java
@@ -25,6 +25,7 @@ import java.util.List;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
public class QueueConfiguration extends ConfigurationPlugin
@@ -109,7 +110,7 @@ public class QueueConfiguration extends ConfigurationPlugin
public String getExchange()
{
- return getStringValue("exchange", null);
+ return getStringValue("exchange", ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString());
}
public List getRoutingKeys()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index 9f1a4c52f2..f8fc27e86a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -20,6 +20,15 @@
package org.apache.qpid.server.configuration;
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
@@ -27,26 +36,17 @@ import org.apache.commons.configuration.ConfigurationFactory;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
-import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.transport.NetworkDriverConfiguration;
import sun.misc.Signal;
import sun.misc.SignalHandler;
-import java.io.File;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-
public class ServerConfiguration extends ConfigurationPlugin implements SignalHandler
{
protected static final Logger _logger = Logger.getLogger(ServerConfiguration.class);
@@ -63,17 +63,22 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
public static final int DEFAULT_SSL_PORT = 8672;
public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L;
public static final int DEFAULT_JMXPORT = 8999;
+
+ public static final String QPID_HOME = "QPID_HOME";
+ public static final String QPID_WORK = "QPID_WORK";
+ public static final String LIB_DIR = "lib";
+ public static final String PLUGIN_DIR = "plugins";
+ public static final String CACHE_DIR = "cache";
private Map<String, VirtualHostConfiguration> _virtualHosts = new HashMap<String, VirtualHostConfiguration>();
private File _configFile;
private File _vhostsFile;
- private Logger _log = LoggerFactory.getLogger(this.getClass());
+ private Logger _log = Logger.getLogger(this.getClass());
private ConfigurationManagementMBean _mbean;
-
// Map of environment variables to config items
private static final Map<String, String> envVarMap = new HashMap<String, String>();
@@ -142,6 +147,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
}
catch (IllegalArgumentException e)
{
+ _logger.error("Signal HUP not supported for OS: " + System.getProperty("os.name"));
// We're on something that doesn't handle SIGHUP, how sad, Windows.
}
}
@@ -192,7 +198,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
public String[] getElementsProcessed()
{
- return new String[]{""};
+ return new String[] { "" };
}
@Override
@@ -308,7 +314,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
*/
public Locale getLocale()
{
-
String localeString = getStringValue(ADVANCED_LOCALE);
// Expecting locale of format langauge_country_variant
@@ -432,10 +437,15 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
_logger.warn(SECURITY_CONFIG_RELOADED);
}
}
-
+
public String getQpidWork()
{
- return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir"));
+ return System.getProperty(QPID_WORK, System.getProperty("java.io.tmpdir"));
+ }
+
+ public String getQpidHome()
+ {
+ return System.getProperty(QPID_HOME);
}
public void setJMXManagementPort(int mport)
@@ -467,11 +477,16 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa
{
return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]);
}
-
+
public String getPluginDirectory()
{
return getStringValue("plugin-directory");
}
+
+ public String getCacheDirectory()
+ {
+ return getStringValue("cache-directory");
+ }
public VirtualHostConfiguration getVirtualHostConfig(String name)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
index ece8bc90fe..0dca91b7be 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.exchange;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.management.ManagedObjectRegistry;
@@ -32,6 +34,7 @@ import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.framing.AMQShortString;
import javax.management.openmbean.*;
+import javax.management.MBeanException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
@@ -133,7 +136,15 @@ public abstract class AbstractExchangeMBean<T extends AbstractExchange> extends
}
CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger()));
- vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null);
+ try
+ {
+ vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null);
+ }
+ catch (AMQException ex)
+ {
+ JMException jme = new JMException(ex.toString());
+ throw new MBeanException(jme, "Error creating new binding " + binding);
+ }
CurrentActor.remove();
}
-} // End of MBean class
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
index 9be8bddd28..7837a9bc38 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java
@@ -26,9 +26,12 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
+import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.AMQUnknownExchangeType;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.qmf.ManagementExchange;
import org.apache.qpid.server.configuration.VirtualHostConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
@@ -79,27 +82,26 @@ public class DefaultExchangeFactory implements ExchangeFactory
public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete)
throws AMQException
{
- ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(new AMQShortString(type));
- if (exchType == null)
- {
-
- throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null);
- }
- Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete);
- return e;
-
+ return createExchange(new AMQShortString(exchange), new AMQShortString(type), durable, autoDelete, 0);
}
public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete,
int ticket)
throws AMQException
{
+ // Check access
+ if (!_host.getSecurityManager().authoriseCreateExchange(autoDelete, durable, exchange, null, null, null, type))
+ {
+ String description = "Permission denied: exchange-name '" + exchange.asString() + "'";
+ throw new AMQSecurityException(description);
+ }
+
ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(type);
if (exchType == null)
{
-
throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null);
}
+
Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete);
return e;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
index 84444450c9..0e7459498a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java
@@ -20,18 +20,18 @@
*/
package org.apache.qpid.server.exchange;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.ExchangeInitialiser;
import org.apache.qpid.server.queue.IncomingMessage;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import java.util.Collection;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
public class DefaultExchangeRegistry implements ExchangeRegistry
{
private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class);
@@ -87,7 +87,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry
public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException
{
+ // Check access
+ if (!_host.getSecurityManager().authoriseDelete(_exchangeMap.get(name)))
+ {
+ throw new AMQSecurityException();
+ }
+
// TODO: check inUse argument
+
Exchange e = _exchangeMap.remove(name);
_exchangeMapStr.remove(name.toString());
if (e != null)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
index 8a31b1bab1..13fe767d3f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.exchange;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
@@ -138,6 +139,6 @@ public interface Exchange extends ExchangeReferrer, ExchangeConfig
public static interface Task
{
- public void onClose(Exchange exchange);
+ public void onClose(Exchange exchange) throws AMQSecurityException;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
index aa4cc1ec24..92795487e4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java
@@ -22,8 +22,6 @@ package org.apache.qpid.server.exchange;
import java.util.Collection;
-import org.apache.commons.configuration.Configuration;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.configuration.VirtualHostConfiguration;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
index ae578eb196..a4974c75ff 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
@@ -674,13 +674,22 @@ public class Bridge implements BridgeConfig
options.put("qpid.trace.exclude", _link.getFederationTag());
options.put("qpid.trace.id",_link.getRemoteFederationTag());
- _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName,
+ try
+ {
+ _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName,
isDurable(),
_link.getFederationTag(),
false,
false,
- getVirtualHost(), options);
-
+ getVirtualHost(),
+ options);
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
+
FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize());
Subscription_0_10 sub = new Subscription_0_10((ServerSession)session,
@@ -695,14 +704,13 @@ public class Bridge implements BridgeConfig
try
{
_queue.registerSubscription(sub, true);
+ getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.<String, Object>emptyMap());
}
catch (AMQException e)
{
// TODO
throw new RuntimeException(e);
}
-
- getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.EMPTY_MAP);
}
public void close()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
index 50019090d9..a5999711bc 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
@@ -51,9 +51,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
{
AMQProtocolSession protocolConnection = stateManager.getProtocolSession();
-
-
-
AMQChannel channel = protocolConnection.getChannel(channelId);
VirtualHost vHost = protocolConnection.getVirtualHost();
@@ -93,17 +90,9 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic
}
else
{
-
final AMQShortString consumerTagName;
- // Check authz
- if (!vHost.getAccessManager().authoriseConsume(protocolConnection,
- body.getExclusive(), body.getNoAck(),
- body.getNoLocal(), body.getNowait(), queue))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- else if (queue.isExclusive() && !queue.isDurable())
+ if (queue.isExclusive() && !queue.isDurable())
{
AMQSessionModel session = queue.getExclusiveOwningSession();
if (session == null || session.getConnectionModel() != protocolConnection)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
index 2ab0b04fb9..83ca526578 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java
@@ -92,13 +92,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB
}
else
{
-
- //Perform ACLs
- if (!vHost.getAccessManager().authoriseConsume(protocolConnection, body.getNoAck(), queue))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- else if (queue.isExclusive())
+ if (queue.isExclusive())
{
AMQSessionModel session = queue.getExclusiveOwningSession();
if (session == null || session.getConnectionModel() != protocolConnection)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
index a7d3ad6217..8f23b1c4d4 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java
@@ -23,14 +23,13 @@ package org.apache.qpid.server.handler;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.BasicPublishBody;
import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicPublishBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.server.exchange.Exchange;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -59,18 +58,17 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic
_logger.debug("Publish received on channel " + channelId);
}
- AMQShortString exchange = body.getExchange();
+ AMQShortString exchangeName = body.getExchange();
// TODO: check the delivery tag field details - is it unique across the broker or per subscriber?
- if (exchange == null)
+ if (exchangeName == null)
{
- exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME;
-
+ exchangeName = ExchangeDefaults.DEFAULT_EXCHANGE_NAME;
}
VirtualHost vHost = session.getVirtualHost();
- Exchange e = vHost.getExchangeRegistry().getExchange(exchange);
+ Exchange exch = vHost.getExchangeRegistry().getExchange(exchangeName);
// if the exchange does not exist we raise a channel exception
- if (e == null)
+ if (exch == null)
{
throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name");
}
@@ -86,17 +84,9 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic
throw body.getChannelNotFoundException(channelId);
}
- //Access Control
- if (!vHost.getAccessManager().authorisePublish(session,
- body.getImmediate(), body.getMandatory(),
- body.getRoutingKey(), e))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
-
MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body);
- info.setExchange(exchange);
- channel.setPublishFrame(info, e);
+ info.setExchange(exchangeName);
+ channel.setPublishFrame(info, exch);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
index f5c2b93f46..6d874ee971 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java
@@ -20,15 +20,19 @@
*/
package org.apache.qpid.server.handler;
-import java.util.UUID;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.UUID;
+import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
+import org.apache.qpid.framing.ChannelOpenBody;
+import org.apache.qpid.framing.ChannelOpenOkBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
+import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
@@ -39,6 +43,8 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenBody>
{
+ private static final Logger _logger = Logger.getLogger(ChannelOpenHandler.class);
+
private static ChannelOpenHandler _instance = new ChannelOpenHandler();
public static ChannelOpenHandler getInstance()
@@ -54,19 +60,16 @@ public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenB
{
AMQProtocolSession session = stateManager.getProtocolSession();
VirtualHost virtualHost = session.getVirtualHost();
-
// Protect the broker against out of order frame request.
if (virtualHost == null)
{
throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null);
}
+ _logger.info("Connecting to: " + virtualHost.getName());
- final AMQChannel channel = new AMQChannel(session,channelId,
- virtualHost.getMessageStore());
-
+ final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getMessageStore());
-
session.addChannel(channel);
ChannelOpenOkBody response;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
index b5194084f2..76d1e5378f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java
@@ -20,18 +20,18 @@
*/
package org.apache.qpid.server.handler;
+import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91;
-import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
-import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ConnectionOpenBody;
+import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.log4j.Logger;
public class ConnectionOpenMethodHandler implements StateAwareMethodListener<ConnectionOpenBody>
{
@@ -57,7 +57,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con
{
AMQProtocolSession session = stateManager.getProtocolSession();
-
//ignore leading '/'
String virtualHostName;
if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/')
@@ -77,14 +76,15 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con
}
else
{
- session.setVirtualHost(virtualHost);
-
- //Perform ACL
- if (!virtualHost.getAccessManager().authoriseConnect(session, virtualHost))
+ // Check virtualhost access
+ if (!virtualHost.getSecurityManager().accessVirtualhost(virtualHostName, session.getRemoteAddress().toString()))
{
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
+ throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied: '" + virtualHost.getName() + "'");
}
+ session.setVirtualHost(virtualHost);
+ _logger.error(session.getPrincipal().getName());
+
// See Spec (0.8.2). Section 3.1.2 Virtual Hosts
if (session.getContextKey() == null)
{
@@ -97,8 +97,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con
stateManager.changeState(AMQState.CONNECTION_OPEN);
session.writeFrame(responseBody.generateFrame(channelId));
-
-
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
index a2a6faf21b..cda8cff25a 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
@@ -97,7 +97,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener
ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay());
session.writeFrame(tuneBody.generateFrame(0));
session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID()));
- disposeSaslServer(session);
+ disposeSaslServer(session);
break;
case CONTINUE:
stateManager.changeState(AMQState.CONNECTION_NOT_AUTH);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
index 6698ae888a..6512ff1a14 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
@@ -60,11 +60,11 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
public void methodReceived(AMQStateManager stateManager, ConnectionStartOkBody body, int channelId) throws AMQException
{
AMQProtocolSession session = stateManager.getProtocolSession();
-
+
_logger.info("SASL Mechanism selected: " + body.getMechanism());
_logger.info("Locale selected: " + body.getLocale());
- AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager();
+ AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();
SaslServer ss = null;
try
@@ -73,8 +73,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
if (ss == null)
{
- throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism()
- );
+ throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism());
}
session.setSaslServer(ss);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
index 7cfd1fc121..98a0d33487 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java
@@ -45,8 +45,6 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
return _instance;
}
-
-
private ExchangeDeclareHandler()
{
}
@@ -58,28 +56,15 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
- if (!body.getPassive())
- {
- // Perform ACL if request is not passive
- if (!virtualHost.getAccessManager().authoriseCreateExchange(session, body.getAutoDelete(),
- body.getDurable(), body.getExchange(), body.getInternal(), body.getNowait(), body.getPassive(),
- body.getType()))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
-
- }
-
if (_logger.isDebugEnabled())
{
_logger.debug("Request to declare exchange of type " + body.getType() + " with name " + body.getExchange());
}
+
synchronized(exchangeRegistry)
{
Exchange exchange = exchangeRegistry.getExchange(body.getExchange());
-
-
if (exchange == null)
{
if(body.getPassive() && ((body.getType() == null) || body.getType().length() ==0))
@@ -90,7 +75,6 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
{
try
{
-
exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(),
body.getType() == null ? null : body.getType().intern(),
body.getDurable(),
@@ -113,14 +97,12 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange
throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getTypeShortString() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null);
}
-
}
if(!body.getNowait())
{
MethodRegistry methodRegistry = session.getMethodRegistry();
AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody();
session.writeFrame(responseBody.generateFrame(channelId));
-
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
index 8dbd457cc9..586aaf9336 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java
@@ -27,7 +27,6 @@ import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.exchange.ExchangeInUseException;
import org.apache.qpid.server.exchange.ExchangeRegistry;
import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -51,13 +50,6 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD
VirtualHost virtualHost = session.getVirtualHost();
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseDelete(session,
- exchangeRegistry.getExchange(body.getExchange())))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
-
try
{
if(exchangeRegistry.getExchange(body.getExchange()) == null)
@@ -75,6 +67,5 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD
throw body.getChannelException(AMQConstant.IN_USE, "Exchange in use");
// TODO: sort out consistent channel close mechanism that does all clean up etc.
}
-
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
index 594edb090c..0eb69e4b16 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java
@@ -65,7 +65,6 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody>
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
-
final AMQQueue queue;
final AMQShortString routingKey;
@@ -113,14 +112,7 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody>
try
{
-
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseBind(protocolConnection, exch,
- queue, routingKey))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- else if (queue.isExclusive() && !queue.isDurable())
+ if (queue.isExclusive() && !queue.isDurable())
{
AMQSessionModel session = queue.getExclusiveOwningSession();
if (session == null || session.getConnectionModel() != protocolConnection)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
index 4f7d275e71..8939cfa334 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
@@ -69,21 +69,9 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
-
- if (!body.getPassive())
- {
- // Perform ACL if request is not passive
- if (!virtualHost.getAccessManager().authoriseCreateQueue(protocolConnection, body.getAutoDelete(), body.getDurable(),
- body.getExclusive(), body.getNowait(), body.getPassive(), body.getQueue()))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- }
-
final AMQShortString queueName;
// if we aren't given a queue name, we create one which we return to the client
-
if ((body.getQueue() == null) || (body.getQueue().length() == 0))
{
queueName = createName();
@@ -94,11 +82,11 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
}
AMQQueue queue;
+
//TODO: do we need to check that the queue already exists with exactly the same "configuration"?
synchronized (queueRegistry)
{
-
queue = queueRegistry.getQueue(queueName);
AMQSessionModel owningSession = null;
@@ -110,7 +98,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
if (queue == null)
{
-
if (body.getPassive())
{
String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ").";
@@ -129,9 +116,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
queue.setDeleteOnNoConsumers(true);
}
queueRegistry.registerQueue(queue);
- if(body.getExclusive())
+ if (body.getExclusive())
{
-
queue.setExclusiveOwningSession(protocolConnection.getChannel(channelId));
queue.setPrincipalHolder(protocolConnection);
@@ -153,7 +139,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
}
});
}
-
}
if (autoRegister)
{
@@ -239,7 +224,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(),
body.getExclusive(),virtualHost, body.getArguments());
-
if (body.getExclusive() && !body.getDurable())
{
final AMQProtocolSession.Task deleteQueueTask =
@@ -263,7 +247,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar
session.removeSessionCloseTask(deleteQueueTask);
}
});
- }// if exclusive and not durable
+ }
return queue;
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
index 4a1940ee01..da52268e52 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
@@ -99,25 +99,18 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB
{
// TODO - Error code
throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used.");
-
}
else
{
-
AMQSessionModel session = queue.getExclusiveOwningSession();
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseDelete(protocolConnection, queue))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- else if (queue.isExclusive() && !queue.isDurable() && (session == null || session.getConnectionModel() != protocolConnection))
+ if (queue.isExclusive() && !queue.isDurable() && (session == null || session.getConnectionModel() != protocolConnection))
{
throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
"Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection.");
}
+
int purged = queue.delete();
-
if (queue.isDurable())
{
store.removeQueue(queue);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
index a465c5a20f..759eec0129 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
@@ -101,12 +101,7 @@ public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBod
{
AMQSessionModel session = queue.getExclusiveOwningSession();
- //Perform ACLs
- if (!virtualHost.getAccessManager().authorisePurge(protocolConnection, queue))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
- else if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection))
+ if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection))
{
throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
"Queue is exclusive, but not created on this Connection.");
diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index 29c30de9cc..8391a4b184 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -20,24 +20,23 @@ package org.apache.qpid.server.handler;
*
*/
-
import org.apache.log4j.Logger;
-
-import org.apache.qpid.framing.*;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.QueueUnbindBody;
import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9;
-import org.apache.qpid.server.state.StateAwareMethodListener;
-import org.apache.qpid.server.state.AMQStateManager;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.security.access.Permission;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQInvalidRoutingKeyException;
-import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.state.AMQStateManager;
+import org.apache.qpid.server.state.StateAwareMethodListener;
+import org.apache.qpid.server.virtualhost.VirtualHost;
public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindBody>
{
@@ -100,12 +99,6 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB
throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist.");
}
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseUnbind(session, exch, routingKey, queue))
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied");
- }
-
if(virtualHost.getBindingFactory().getBinding(String.valueOf(routingKey), queue, exch, FieldTable.convertToMap(body.getArguments())) == null)
{
throw body.getChannelException(AMQConstant.NOT_FOUND,"No such binding");
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
index 0ee5763d91..7e7ac94d06 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
@@ -20,34 +20,36 @@
*/
package org.apache.qpid.server.management;
-import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
-import org.apache.qpid.management.common.mbeans.LoggingManagement;
-import org.apache.qpid.management.common.mbeans.UserManagement;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.server.logging.actors.ManagementActor;
-import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
-import org.apache.log4j.Logger;
-
-import javax.management.remote.MBeanServerForwarder;
-import javax.management.remote.JMXPrincipal;
-import javax.management.remote.JMXConnectionNotification;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-import javax.management.MBeanInfo;
-import javax.management.MBeanOperationInfo;
-import javax.management.JMException;
-import javax.management.NotificationListener;
-import javax.management.Notification;
-import javax.security.auth.Subject;
import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
-import java.security.AccessControlContext;
-import java.util.HashSet;
-import java.util.Set;
import java.util.Properties;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.JMException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXPrincipal;
+import javax.management.remote.MBeanServerForwarder;
+import javax.security.auth.Subject;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.ManagementActor;
+import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
/**
* This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements
@@ -65,18 +67,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
private MBeanServer _mbs;
private static Properties _userRoles = new Properties();
private static ManagementActor _logActor;
-
- private static HashSet<String> _adminOnlyMethods = new HashSet<String>();
- {
- _adminOnlyMethods.add(UserManagement.TYPE);
- _adminOnlyMethods.add(LoggingManagement.TYPE);
- _adminOnlyMethods.add(ConfigurationManagement.TYPE);
- }
public static MBeanServerForwarder newProxyInstance()
{
final InvocationHandler handler = new MBeanInvocationHandlerImpl();
- final Class[] interfaces = new Class[]{MBeanServerForwarder.class};
+ final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class };
_logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger());
@@ -87,7 +82,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
- final String methodName = method.getName();
+ final String methodName = getMethodName(method, args);
if (methodName.equals("getMBeanServer"))
{
@@ -112,145 +107,165 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
- // Allow operations performed locally on behalf of the connector server itself
- if (subject == null)
- {
- return method.invoke(_mbs, args);
- }
-
- if (args == null || DELEGATE.equals(args[0]))
- {
- return method.invoke(_mbs, args);
- }
-
- // Restrict access to "createMBean" and "unregisterMBean" to any user
- if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
- {
- _logger.debug("User trying to create or unregister an MBean");
- throw new SecurityException("Access denied");
- }
-
- // Retrieve JMXPrincipal from Subject
- Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
- if (principals == null || principals.isEmpty())
- {
- throw new SecurityException("Access denied");
- }
-
- Principal principal = principals.iterator().next();
- String identity = principal.getName();
-
- if (isAdminMethod(args))
+ try
{
- if (isAdmin(identity))
+ // Allow operations performed locally on behalf of the connector server itself
+ if (subject == null)
+ {
+ return method.invoke(_mbs, args);
+ }
+
+ if (args == null || DELEGATE.equals(args[0]))
{
return method.invoke(_mbs, args);
}
+
+ // Restrict access to "createMBean" and "unregisterMBean" to any user
+ if (methodName.equals("createMBean") || methodName.equals("unregisterMBean"))
+ {
+ _logger.debug("User trying to create or unregister an MBean");
+ throw new SecurityException("Access denied: " + methodName);
+ }
+
+ // Allow querying available object names
+ if (methodName.equals("queryNames"))
+ {
+ return method.invoke(_mbs, args);
+ }
+
+ // Retrieve JMXPrincipal from Subject
+ Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
+ if (principals == null || principals.isEmpty())
+ {
+ throw new SecurityException("Access denied: no principal");
+ }
+
+ // Save the principal
+ Principal principal = principals.iterator().next();
+ SecurityManager.setThreadPrincipal(principal);
+
+ // Get the component, type and impact, which may be null
+ String type = getType(method, args);
+ String vhost = getVirtualHost(method, args);
+ int impact = getImpact(method, args);
+
+ // Get the security manager for the virtual host (if set)
+ SecurityManager security;
+ if (vhost == null)
+ {
+ security = ApplicationRegistry.getInstance().getSecurityManager();
+ }
else
{
- throw new SecurityException("Access denied");
+ security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager();
}
+
+ if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO)
+ {
+ // Check for read-only method invocation permission
+ if (!security.authoriseMethod(Operation.ACCESS, type, methodName))
+ {
+ throw new SecurityException("Permission denied: Access " + methodName);
+ }
+ }
+ else if (isUpdateMethod(methodName))
+ {
+ // Check for setting properties permission
+ if (!security.authoriseMethod(Operation.UPDATE, type, methodName))
+ {
+ throw new SecurityException("Permission denied: Update " + methodName);
+ }
+ }
+ else
+ {
+ // Check for invoking/executing method action/operation permission
+ if (!security.authoriseMethod(Operation.EXECUTE, type, methodName))
+ {
+ throw new SecurityException("Permission denied: Execute " + methodName);
+ }
+ }
+
+ // Actually invoke the method
+ return method.invoke(_mbs, args);
}
-
- // Following users can perform any operation other than "createMBean" and "unregisterMBean"
- if (isAllowedToModify(identity))
- {
- return method.invoke(_mbs, args);
- }
-
- // These users can only call "getAttribute" on the MBeanServerDelegate MBean
- // Here we can add other fine grained permissions like specific method for a particular mbean
- if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args))
+ catch (InvocationTargetException e)
{
- return method.invoke(_mbs, args);
+ throw e.getTargetException();
}
+ }
- throw new SecurityException("Access denied");
+ private String getType(Method method, Object[] args)
+ {
+ if (args[0] instanceof ObjectName)
+ {
+ ObjectName object = (ObjectName) args[0];
+ String type = object.getKeyProperty("type");
+
+ return type;
+ }
+ return null;
}
- private boolean isAdminMethod(Object[] args)
- {
+ private String getVirtualHost(Method method, Object[] args)
+ {
if (args[0] instanceof ObjectName)
{
ObjectName object = (ObjectName) args[0];
+ String vhost = object.getKeyProperty("VirtualHost");
- return _adminOnlyMethods.contains(object.getKeyProperty("type"));
- }
- return false;
- }
-
- // Initialises the user roles
- public static void setAccessRights(Properties accessRights)
- {
- _userRoles = accessRights;
- }
-
- private boolean isAdmin(String userName)
- {
- if (ADMIN.equals(_userRoles.getProperty(userName)))
- {
- return true;
+ return vhost;
}
- return false;
+ return null;
}
-
- private boolean isAllowedToModify(String userName)
+
+ private String getMethodName(Method method, Object[] args)
{
- if (ADMIN.equals(_userRoles.getProperty(userName))
- || READWRITE.equals(_userRoles.getProperty(userName)))
- {
- return true;
- }
- return false;
- }
+ String methodName = method.getName();
- private boolean isReadOnlyUser(String userName)
- {
- if (READONLY.equals(_userRoles.getProperty(userName)))
+ // if arguments are set, try and work out real method name
+ if (args != null && args.length >= 1 && args[0] instanceof ObjectName)
{
- return true;
+ if (methodName.equals("getAttribute"))
+ {
+ methodName = "get" + (String) args[1];
+ }
+ else if (methodName.equals("setAttribute"))
+ {
+ methodName = "set" + ((Attribute) args[1]).getName();
+ }
+ else if (methodName.equals("invoke"))
+ {
+ methodName = (String) args[1];
+ }
}
- return false;
+
+ return methodName;
}
- private boolean isReadOnlyMethod(Method method, Object[] args)
+ private int getImpact(Method method, Object[] args)
{
- String methodName = method.getName();
-
- //handle standard get/set/query and select 'is' methods from MBeanServer
- if (methodName.startsWith("query") || methodName.startsWith("get")
- ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered"))
- {
- return true;
- }
- else if (methodName.startsWith("set"))
- {
- return false;
- }
-
//handle invocation of other methods on mbeans
- if ((args[0] instanceof ObjectName) && (methodName.equals("invoke")))
+ if ((args[0] instanceof ObjectName) && (method.getName().equals("invoke")))
{
-
//get invoked method name
String mbeanMethod = (args.length > 1) ? (String) args[1] : null;
if (mbeanMethod == null)
{
- return false;
+ return -1;
}
-
+
try
{
- //check if the given method is tagged with an INFO impact attribute
+ //Get the impact attribute
MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]);
if (mbeanInfo != null)
{
MBeanOperationInfo[] opInfos = mbeanInfo.getOperations();
for (MBeanOperationInfo opInfo : opInfos)
{
- if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO))
+ if (opInfo.getName().equals(mbeanMethod))
{
- return true;
+ return opInfo.getImpact();
}
}
}
@@ -261,7 +276,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
}
}
- return false;
+ return -1;
+ }
+
+ private boolean isAccessMethod(String methodName)
+ {
+ //handle standard get/query/is methods from MBeanServer
+ return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is"));
+ }
+
+
+ private boolean isUpdateMethod(String methodName)
+ {
+ //handle standard set methods from MBeanServer
+ return methodName.startsWith("set");
}
public void handleNotification(Notification notification, Object handback)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index 4260307d04..25571f1022 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -20,16 +20,52 @@
*/
package org.apache.qpid.server.protocol;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.JMException;
+import javax.security.sasl.SaslServer;
+
import org.apache.log4j.Logger;
import org.apache.mina.transport.vmpipe.VmPipeAddress;
-
import org.apache.qpid.AMQChannelException;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.codec.AMQCodecFactory;
import org.apache.qpid.codec.AMQDecoder;
import org.apache.qpid.common.ClientProperties;
-import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQProtocolHeaderException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ChannelCloseBody;
+import org.apache.qpid.framing.ChannelCloseOkBody;
+import org.apache.qpid.framing.ConnectionCloseBody;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodDispatcher;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.pool.Job;
import org.apache.qpid.pool.ReferenceCountingExecutorService;
import org.apache.qpid.protocol.AMQConstant;
@@ -61,25 +97,6 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.Sender;
-import javax.management.JMException;
-import javax.security.sasl.SaslServer;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.ByteBuffer;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig
{
private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class);
@@ -117,6 +134,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
private Object _lastSent;
protected volatile boolean _closed;
+
// maximum number of channels this session should have
private long _maxNoOfChannels = 1000;
@@ -358,14 +376,12 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
public void methodFrameReceived(int channelId, AMQMethodBody methodBody)
{
-
final AMQMethodEvent<AMQMethodBody> evt = new AMQMethodEvent<AMQMethodBody>(channelId, methodBody);
try
{
try
{
-
boolean wasAnyoneInterested = _stateManager.methodReceived(evt);
if (!_frameListeners.isEmpty())
@@ -418,10 +434,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
_logger.info(e.getMessage() + " whilst processing:" + methodBody);
closeConnection(channelId, e, false);
}
+ catch (AMQSecurityException e)
+ {
+ AMQConnectionException ce = evt.getMethod().getConnectionException(AMQConstant.ACCESS_REFUSED, e.getMessage());
+ _logger.info(e.getMessage() + " whilst processing:" + methodBody);
+ closeConnection(channelId, ce, false);
+ }
}
catch (Exception e)
{
-
for (AMQMethodListener listener : _frameListeners)
{
listener.error(e);
@@ -999,7 +1020,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol
{
if (throwable instanceof AMQProtocolHeaderException)
{
-
writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
_networkDriver.close();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 366abd3f7c..8b53257e88 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.protocol.AMQConnectionModel;
@@ -194,7 +195,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer
void deleteMessageFromTop();
- long clearQueue();
+ long clearQueue() throws AMQException;
/**
* Checks the status of messages on the queue, purging expired ones, firing age related alerts etc.
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
index 3340c1e20a..a547205d27 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
@@ -21,6 +21,7 @@
package org.apache.qpid.server.queue;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -29,7 +30,6 @@ import org.apache.qpid.server.configuration.QueueConfiguration;
import java.util.Map;
import java.util.HashMap;
-
public class AMQQueueFactory
{
public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities");
@@ -128,22 +128,20 @@ public class AMQQueueFactory
};
-
+ /** @see #createAMQQueueImpl(String, boolean, String, boolean, boolean, VirtualHost, Map) */
public static AMQQueue createAMQQueueImpl(AMQShortString name,
boolean durable,
AMQShortString owner,
boolean autoDelete,
- boolean exclusive,
- VirtualHost virtualHost,
- final FieldTable arguments)
+ boolean exclusive,
+ VirtualHost virtualHost, final FieldTable arguments) throws AMQException
{
return createAMQQueueImpl(name == null ? null : name.toString(),
durable,
owner == null ? null : owner.toString(),
autoDelete,
exclusive,
- virtualHost,
- FieldTable.convertToMap(arguments));
+ virtualHost, FieldTable.convertToMap(arguments));
}
@@ -152,8 +150,15 @@ public class AMQQueueFactory
String owner,
boolean autoDelete,
boolean exclusive,
- VirtualHost virtualHost, Map<String, Object> arguments)
+ VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException
{
+ // Access check
+ if (!virtualHost.getSecurityManager().authoriseCreateQueue(autoDelete, durable, exclusive, null, null, new AMQShortString(queueName), owner))
+ {
+ String description = "Permission denied: queue-name '" + queueName + "'";
+ throw new AMQSecurityException(description);
+ }
+
int priorities = 1;
String conflationKey = null;
if(arguments != null)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index af1f412843..806b7f3744 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -28,6 +28,7 @@ import org.apache.qpid.framing.ContentHeaderBody;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor;
import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.ManagedObject;
import org.apache.qpid.server.message.ServerMessage;
@@ -39,6 +40,7 @@ import org.apache.qpid.server.txn.LocalTransaction;
import org.apache.qpid.transport.MessageProperties;
import javax.management.JMException;
+import javax.management.MBeanException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.OperationsException;
@@ -336,7 +338,14 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que
*/
public Long clearQueue() throws JMException
{
- return _queue.clearQueue();
+ try
+ {
+ return _queue.clearQueue();
+ }
+ catch (AMQException ex)
+ {
+ throw new MBeanException(ex, "Error clearing queue " + _queueName);
+ }
}
/**
diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index afc7fb6480..7e78fd0481 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -1,11 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
package org.apache.qpid.server.queue;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.pool.ReadWriteRunnable;
import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.AMQChannel;
import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.server.protocol.AMQSessionModel;
@@ -50,26 +70,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-/*
-*
-* 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.
-*
-*/
public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
{
private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
@@ -386,9 +386,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
// ------ Manage Subscriptions
- public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException
+ public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive)
+ throws AMQSecurityException, ExistingExclusiveSubscription, ExistingSubscriptionPreventsExclusive
{
-
+ // Access control
+ if (!getVirtualHost().getSecurityManager().authoriseConsume(this))
+ {
+ throw new AMQSecurityException("Permission denied");
+ }
+
+
if (hasExclusiveSubscriber())
{
throw new ExistingExclusiveSubscription();
@@ -403,7 +410,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
else
{
_exclusiveSubscriber = subscription;
-
}
}
@@ -1212,38 +1218,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
- public void purge(final long request)
+ public void purge(final long request) throws AMQException
{
- if(request == 0l)
- {
- clearQueue();
- }
- else if(request > 0l)
- {
-
- QueueEntryIterator queueListIterator = _entries.iterator();
- long count = 0;
-
- ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog());
-
- while (queueListIterator.advance())
- {
- QueueEntry node = queueListIterator.getNode();
- if (!node.isDeleted() && node.acquire())
- {
- dequeueEntry(node, txn);
- if(++count == request)
- {
- break;
- }
- }
-
- }
-
- txn.commit();
-
-
- }
+ clear(request);
}
public long getCreateTime()
@@ -1270,9 +1247,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
}
}
- public long clearQueue()
- {
+ public long clearQueue() throws AMQException
+ {
+ return clear(0l);
+ }
+ private long clear(final long request) throws AMQSecurityException
+ {
+ //Perform ACLs
+ if (!getVirtualHost().getSecurityManager().authorisePurge(this))
+ {
+ throw new AMQSecurityException("Permission denied: queue " + getName());
+ }
+
QueueEntryIterator queueListIterator = _entries.iterator();
long count = 0;
@@ -1284,7 +1271,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
if (!node.isDeleted() && node.acquire())
{
dequeueEntry(node, txn);
- count++;
+ if(++count == request)
+ {
+ break;
+ }
}
}
@@ -1292,7 +1282,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
txn.commit();
return count;
-
}
private void dequeueEntry(final QueueEntry node)
@@ -1329,12 +1318,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
_deleteTaskList.remove(task);
}
- public int delete() throws AMQException
+ // TODO list all thrown exceptions
+ public int delete() throws AMQSecurityException, AMQException
{
if (!_deleted.getAndSet(true))
{
+ // Check access
+ if (!_virtualHost.getSecurityManager().authoriseDelete(this))
+ {
+ throw new AMQSecurityException("Permission denied: " + getName());
+ }
- for(Binding b : getBindings())
+ for (Binding b : getBindings())
{
_virtualHost.getBindingFactory().removeBinding(b);
}
@@ -1606,6 +1601,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
public void flushSubscription(Subscription sub) throws AMQException
{
+ // Access control
+ if (!getVirtualHost().getSecurityManager().authoriseConsume(this))
+ {
+ throw new AMQSecurityException("Permission denied: " + getName());
+ }
flushSubscription(sub, Long.MAX_VALUE);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index 4cb3d9e209..9adab58a0c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -124,7 +124,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
@SuppressWarnings("finally")
public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception
{
- _logger.error("initialise(IApplicationRegistry instance, int instanceID)");
if (instance != null)
{
_logger.info("Initialising Application Registry(" + instance + "):" + instanceID);
@@ -142,7 +141,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
try
{
- _logger.error("instance.initialise(instanceID)");
instance.initialise(instanceID);
}
catch (Exception e)
@@ -237,12 +235,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
public void configure() throws ConfigurationException
{
-
_configurationManager = new ConfigurationManager();
try
{
- _pluginManager = new PluginManager(_configuration.getPluginDirectory());
+ _pluginManager = new PluginManager(_configuration.getPluginDirectory(), _configuration.getCacheDirectory());
}
catch (Exception e)
{
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java
new file mode 100644
index 0000000000..8c9c2050e8
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
+
+/**
+ * This is intended as the parent for all simple plugins.
+ */
+public abstract class AbstractPlugin implements SecurityPlugin
+{
+ protected final Logger _logger = Logger.getLogger(getClass());
+
+ public ConfigurationPlugin _config;
+
+ public String getPluginName()
+ {
+ return getClass().getSimpleName();
+ }
+
+ public Result getDefault()
+ {
+ return Result.ABSTAIN;
+ }
+
+ public abstract Result access(ObjectType object, Object instance);
+
+ public abstract Result authorise(Operation operation, ObjectType object, ObjectProperties properties);
+
+ public boolean isConfigured()
+ {
+ if (_config == null)
+ {
+ return false;
+ }
+
+ for (String key : _config.getElementsProcessed())
+ {
+ if (!_config.getConfig().containsKey(key) && _config.getConfig().subset(key).isEmpty())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
new file mode 100644
index 0000000000..7f3b89b46b
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
@@ -0,0 +1,139 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
+
+/**
+ * This {@link SecurityPlugin} proxies the authorise calls to a serries of methods, one per {@link Operation}.
+ *
+ * Plugins that extend this class should override the relevant authorise method and implement their own
+ * {@link #setConfiguration(Configuration)} method.
+ */
+public abstract class AbstractProxyPlugin extends AbstractPlugin
+{
+ public Result authoriseConsume(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authorisePublish(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseCreate(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseAccess(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseBind(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseUnbind(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseDelete(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authorisePurge(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseExecute(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result authoriseUpdate(ObjectType object, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ public Result accessBroker(Object instance)
+ {
+ return getDefault();
+ }
+
+ public Result accessVirtualhost(Object instance)
+ {
+ return getDefault();
+ }
+
+ @Override
+ public Result access(ObjectType objectType, Object instance)
+ {
+ switch (objectType)
+ {
+ case BROKER:
+ return accessBroker(instance);
+ case VIRTUALHOST:
+ return accessVirtualhost(instance);
+ }
+
+ return getDefault();
+ }
+
+ @Override
+ public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties)
+ {
+ switch (operation)
+ {
+ case CONSUME:
+ return authoriseConsume(objectType, properties);
+ case PUBLISH:
+ return authorisePublish(objectType, properties);
+ case CREATE:
+ return authoriseCreate(objectType, properties);
+ case ACCESS:
+ return authoriseAccess(objectType, properties);
+ case BIND:
+ return authoriseBind(objectType, properties);
+ case UNBIND:
+ return authoriseUnbind(objectType, properties);
+ case DELETE:
+ return authoriseDelete(objectType, properties);
+ case PURGE:
+ return authorisePurge(objectType, properties);
+ case EXECUTE:
+ return authoriseExecute(objectType, properties);
+ case UPDATE:
+ return authoriseUpdate(objectType, properties);
+ }
+
+ return getDefault();
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/Result.java b/java/broker/src/main/java/org/apache/qpid/server/security/Result.java
new file mode 100644
index 0000000000..f79721799e
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/Result.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security;
+
+/**
+ * The result of a security plugin decision, normally {@link #ALLOWED} or {@link #DENIED}.
+ */
+public enum Result
+{
+ /**
+ * The request is allowed.
+ */
+ ALLOWED,
+
+ /**
+ * The request is denied.
+ */
+ DENIED,
+
+ /**
+ * Indicates that a plugin does not handle a particular type of request.
+ */
+ ABSTAIN,
+
+ /**
+ * A plugin instance cannot make a decision on a request it is able to handle,
+ * and another instance of the plugin should be checked.
+ */
+ DEFER;
+} \ No newline at end of file
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
new file mode 100755
index 0000000000..035b7fa854
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.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.server.security;
+
+import static org.apache.qpid.server.security.access.ObjectType.*;
+import static org.apache.qpid.server.security.access.Operation.*;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.plugins.PluginManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+/**
+ * The security manager contains references to all loaded {@link SecurityPlugin}s and delegates security decisions to them based
+ * on virtual host name. The plugins can be external <em>OSGi</em> .jar files that export the required classes or just internal
+ * objects for simpler plugins.
+ *
+ * @see SecurityPlugin
+ */
+public class SecurityManager
+{
+ private static final Logger _logger = Logger.getLogger(SecurityManager.class);
+
+ /** Container for the {@link Principal} that is using to this thread. */
+ private static final ThreadLocal<Principal> _principal = new ThreadLocal<Principal>();
+
+ private PluginManager _pluginManager;
+ private Map<String, SecurityPluginFactory> _pluginFactories = new HashMap<String, SecurityPluginFactory>();
+ private Map<String, SecurityPlugin> _globalPlugins = new HashMap<String, SecurityPlugin>();
+ private Map<String, SecurityPlugin> _hostPlugins = new HashMap<String, SecurityPlugin>();
+
+ public SecurityManager(SecurityManager parent) throws ConfigurationException
+ {
+ _pluginManager = parent._pluginManager;
+ _pluginFactories = parent._pluginFactories;
+
+ // our global plugins are the parent's host plugins
+ _globalPlugins = parent._hostPlugins;
+ }
+
+ public SecurityManager(ConfigurationPlugin configuration, PluginManager manager) throws ConfigurationException
+ {
+ this(configuration, manager, null);
+ }
+
+ public SecurityManager(ConfigurationPlugin configuration, PluginManager manager, SecurityPluginFactory plugin) throws ConfigurationException
+ {
+ _pluginManager = manager;
+ if (manager == null) // No plugin manager, no plugins
+ {
+ return;
+ }
+
+ _pluginFactories = _pluginManager.getSecurityPlugins();
+ if (plugin != null)
+ {
+ _pluginFactories.put(plugin.getPluginName(), plugin);
+ }
+
+ configureHostPlugins(configuration);
+ }
+
+ public static Principal getThreadPrincipal()
+ {
+ return _principal.get();
+ }
+
+ public static void setThreadPrincipal(Principal principal)
+ {
+ _principal.set(principal);
+ }
+
+ public static void setThreadPrincipal(String authId)
+ {
+ setThreadPrincipal(new UsernamePrincipal(authId));
+ }
+
+ public void configureHostPlugins(ConfigurationPlugin hostConfig) throws ConfigurationException
+ {
+ _hostPlugins = configurePlugins(hostConfig);
+ }
+
+ public void configureGlobalPlugins(ConfigurationPlugin configuration) throws ConfigurationException
+ {
+ _globalPlugins = configurePlugins(configuration);
+ }
+
+ public Map<String, SecurityPlugin> configurePlugins(ConfigurationPlugin hostConfig) throws ConfigurationException
+ {
+ Map<String, SecurityPlugin> plugins = new HashMap<String, SecurityPlugin>();
+ for (SecurityPluginFactory<?> factory : _pluginFactories.values())
+ {
+ SecurityPlugin plugin = factory.newInstance(hostConfig);
+ if (plugin.isConfigured())
+ {
+ plugins.put(factory.getPluginName(), plugin);
+ }
+ }
+ return plugins;
+ }
+
+ public void addHostPlugin(SecurityPlugin plugin)
+ {
+ _hostPlugins.put(plugin.getClass().getName(), plugin);
+ }
+
+ public static Logger getLogger()
+ {
+ return _logger;
+ }
+
+ private abstract class AccessCheck
+ {
+ abstract Result allowed(SecurityPlugin plugin);
+ }
+
+ private boolean checkAllPlugins(AccessCheck checker)
+ {
+ HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins);
+
+ for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet())
+ {
+ // Create set of global only plugins
+ SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey());
+ if (globalPlugin != null)
+ {
+ remainingPlugins.remove(hostEntry.getKey());
+ }
+
+ Result host = checker.allowed(hostEntry.getValue());
+
+ if (host == Result.DENIED)
+ {
+ // Something vetoed the access, we're done
+ return false;
+ }
+
+ // host allow overrides global allow, so only check global on abstain or defer
+ if (host != Result.ALLOWED)
+ {
+ if (globalPlugin == null)
+ {
+ if (host == Result.DEFER)
+ {
+ host = hostEntry.getValue().getDefault();
+ }
+ if (host == Result.DENIED)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ Result global = checker.allowed(globalPlugin);
+ if (global == Result.DEFER)
+ {
+ global = globalPlugin.getDefault();
+ }
+ if (global == Result.ABSTAIN && host == Result.DEFER)
+ {
+ global = hostEntry.getValue().getDefault();
+ }
+ if (global == Result.DENIED)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ for (SecurityPlugin plugin : remainingPlugins.values())
+ {
+ Result remaining = checker.allowed(plugin);
+ if (remaining == Result.DEFER)
+ {
+ remaining = plugin.getDefault();
+ }
+ if (remaining == Result.DENIED)
+ {
+ return false;
+ }
+ }
+
+ // getting here means either allowed or abstained from all plugins
+ return true;
+ }
+
+ public boolean authoriseBind(final Exchange exch, final AMQQueue queue, final AMQShortString routingKey)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(BIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey));
+ }
+ });
+ }
+
+ // TODO not implemented yet, awaiting consensus
+ public boolean authoriseObject(final String packageName, final String className)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ ObjectProperties properties = new ObjectProperties();
+ properties.put(ObjectProperties.Property.PACKAGE, packageName);
+ properties.put(ObjectProperties.Property.CLASS, className);
+ return plugin.authorise(ACCESS, OBJECT, properties);
+ }
+ });
+ }
+
+ public boolean authoriseMethod(final Operation operation, final String componentName, final String methodName)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ ObjectProperties properties = new ObjectProperties();
+ properties.setName(methodName);
+ if (componentName != null)
+ {
+ // Only set the property if there is a component name
+ properties.put(ObjectProperties.Property.COMPONENT, componentName);
+ }
+ return plugin.authorise(operation, METHOD, properties);
+ }
+ });
+ }
+
+ // TODO not implemented yet, awaiting consensus
+ public boolean accessBroker(final AMQProtocolSession session)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.access(BROKER, session);
+ }
+ });
+ }
+
+ public boolean accessVirtualhost(final String vhostname, final String remoteAddress)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.access(VIRTUALHOST, remoteAddress);
+ }
+ });
+ }
+
+ public boolean authoriseConsume(final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(queue));
+ }
+ });
+ }
+
+ public boolean authoriseConsume(final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(exclusive, noAck, noLocal, nowait, queue));
+ }
+ });
+ }
+
+ public boolean authoriseCreateExchange(final Boolean autoDelete, final Boolean durable, final AMQShortString exchangeName,
+ final Boolean internal, final Boolean nowait, final Boolean passive, final AMQShortString exchangeType)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(CREATE, EXCHANGE, new ObjectProperties(autoDelete, durable, exchangeName,
+ internal, nowait, passive, exchangeType));
+ }
+ });
+ }
+
+ public boolean authoriseCreateQueue(final Boolean autoDelete, final Boolean durable, final Boolean exclusive,
+ final Boolean nowait, final Boolean passive, final AMQShortString queueName, final String owner)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(CREATE, QUEUE, new ObjectProperties(autoDelete, durable, exclusive, nowait, passive, queueName, owner));
+ }
+ });
+ }
+
+ public boolean authoriseDelete(final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(DELETE, QUEUE, new ObjectProperties(queue));
+ }
+ });
+ }
+
+ public boolean authoriseDelete(final Exchange exchange)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(DELETE, EXCHANGE, new ObjectProperties(exchange.getName()));
+ }
+ });
+ }
+
+ public boolean authorisePublish(final boolean immediate, final String routingKey, final String exchangeName)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(PUBLISH, EXCHANGE, new ObjectProperties(exchangeName, routingKey, immediate));
+ }
+ });
+ }
+
+ public boolean authorisePurge(final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(PURGE, QUEUE, new ObjectProperties(queue));
+ }
+ });
+ }
+
+ public boolean authoriseUnbind(final Exchange exch, final AMQShortString routingKey, final AMQQueue queue)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(UNBIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey));
+ }
+ });
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java
new file mode 100644
index 0000000000..c3c06bf206
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security;
+
+import org.apache.qpid.server.plugins.Plugin;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
+
+/**
+ * The two methods, {@link #access(ObjectType, Object)} and {@link #authorise(Operation, ObjectType, ObjectProperties)},
+ * return the {@link Result} of the security decision, which may be to {@link Result#ABSTAIN} if no decision is made
+ * by this plugin.
+ */
+public interface SecurityPlugin extends Plugin
+{
+ /**
+ * Default result for {@link #access(ObjectType, Object)} or {@link #authorise(Operation, ObjectType, ObjectProperties)}.
+ */
+ Result getDefault();
+
+ /**
+ * Authorise access granted to an object instance.
+ */
+ Result access(ObjectType objectType, Object instance);
+
+ /**
+ * Authorise an operation on an object defined by a set of properties.
+ */
+ Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties);
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java
new file mode 100644
index 0000000000..789bdd0073
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java
@@ -0,0 +1,54 @@
+package org.apache.qpid.server.security;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An OSGi {@link BundleActivator} that loads a {@link SecurityPluginFactory}.
+ */
+public abstract class SecurityPluginActivator implements BundleActivator
+{
+ private static final Logger _logger = Logger.getLogger(SecurityPluginActivator.class);
+
+ private SecurityPluginFactory _factory;
+ private ConfigurationPluginFactory _config;
+ private BundleContext _ctx;
+ private String _bundleName;
+
+ /** Implement this to return the factory this plugin activates. */
+ public abstract SecurityPluginFactory getFactory();
+
+ /** Implement this to return the factory this plugin activates. */
+ public abstract ConfigurationPluginFactory getConfigurationFactory();
+
+ /**
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext ctx) throws Exception
+ {
+ _ctx = ctx;
+ _factory = getFactory();
+ _config = getConfigurationFactory();
+ _bundleName = ctx.getBundle().getSymbolicName();
+
+ // register the service
+ _logger.info("Registering security plugin: " + _bundleName);
+ _ctx.registerService(SecurityPluginFactory.class.getName(), _factory, null);
+ _ctx.registerService(ConfigurationPluginFactory.class.getName(), _config, null);
+ }
+
+ /**
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception
+ {
+ _logger.info("Stopping security plugin: " + _bundleName);
+
+ // null object references
+ _factory = null;
+ _config = null;
+ _ctx = null;
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java
index 895ed52222..fe81cba282 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java
@@ -1,6 +1,5 @@
-package org.apache.qpid.server.security.access;
/*
- *
+ *
* 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
@@ -8,20 +7,24 @@ package org.apache.qpid.server.security.access;
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
+package org.apache.qpid.server.security;
+import org.apache.qpid.server.plugins.PluginFactory;
-public class AuthorizationManager
+/**
+ * The factory that generates instances of security plugins. Usually implemented as a static member class in the plugin itself.
+ */
+public interface SecurityPluginFactory<S extends SecurityPlugin> extends PluginFactory<S>
{
-
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java
deleted file mode 100644
index 7d6ae285c5..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.log4j.Logger;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.configuration.SecurityConfiguration;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.plugins.PluginManager;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
-import org.apache.qpid.server.security.PrincipalHolder;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-public class ACLManager
-{
- private static final Logger _logger = Logger.getLogger(ACLManager.class);
- private PluginManager _pluginManager;
- private Map<String, ACLPluginFactory> _allSecurityPlugins = new HashMap<String, ACLPluginFactory>();
- private Map<String, ACLPlugin> _globalPlugins = new HashMap<String, ACLPlugin>();
- private Map<String, ACLPlugin> _hostPlugins = new HashMap<String, ACLPlugin>();
-
- public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException
- {
- this(configuration, manager, null);
- }
-
- public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException
- {
- _pluginManager = manager;
-
- if (manager == null) // No plugin manager, no plugins
- {
- return;
- }
-
- _allSecurityPlugins = _pluginManager.getSecurityPlugins();
- if (securityPlugin != null)
- {
- _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin);
- }
-
- configureGlobalPlugins(configuration);
- }
-
- public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException
- {
- _hostPlugins = configurePlugins(hostConfig);
- }
-
- public void configureGlobalPlugins(SecurityConfiguration configuration) throws ConfigurationException
- {
- _globalPlugins = configurePlugins(configuration);
- }
-
- public Map<String, ACLPlugin> configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException
- {
- Configuration securityConfig = hostConfig.getConfiguration();
- Map<String, ACLPlugin> plugins = new HashMap<String, ACLPlugin>();
- Iterator keys = securityConfig.getKeys();
- Collection<String> handledTags = new HashSet();
- while (keys.hasNext())
- {
- // Splitting the string is necessary here because of the way that getKeys() returns only
- // bottom level children
- String tag = ((String) keys.next()).split("\\.", 2)[0];
- if (!handledTags.contains(tag))
- {
- for (ACLPluginFactory plugin : _allSecurityPlugins.values())
- {
- if (plugin.supportsTag(tag))
- {
- _logger.info("Plugin handling security section "+tag+" is "+plugin);
- handledTags.add(tag);
- plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig));
- }
- }
- }
- if (!handledTags.contains(tag))
- {
- _logger.warn("No plugin handled security section "+tag);
- }
- }
- return plugins;
- }
-
- public static Logger getLogger()
- {
- return _logger;
- }
-
- private abstract class AccessCheck
- {
- abstract AuthzResult allowed(ACLPlugin plugin);
- }
-
- private boolean checkAllPlugins(AccessCheck checker)
- {
- AuthzResult result = AuthzResult.ABSTAIN;
- HashMap<String, ACLPlugin> remainingPlugins = new HashMap<String, ACLPlugin>();
- remainingPlugins.putAll(_globalPlugins);
- for (Entry<String, ACLPlugin> plugin : _hostPlugins.entrySet())
- {
- result = checker.allowed(plugin.getValue());
- if (result == AuthzResult.DENIED)
- {
- // Something vetoed the access, we're done
- return false;
- }
- else if (result == AuthzResult.ALLOWED)
- {
- // Remove plugin from global check list since
- // host allow overrides global allow
- remainingPlugins.remove(plugin.getKey());
- }
- }
-
- for (ACLPlugin plugin : remainingPlugins.values())
- {
- result = checker.allowed(plugin);
- if (result == AuthzResult.DENIED)
- {
- return false;
- }
- }
- return true;
- }
-
- public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue,
- final AMQShortString routingKey)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseBind(session, exch, queue, routingKey);
- }
-
- });
- }
-
- public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseConnect(session, virtualHost);
- }
-
- });
- }
-
- public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseConsume(session, noAck, queue);
- }
-
- });
- }
-
- public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck,
- final boolean noLocal, final boolean nowait, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue);
- }
-
- });
- }
-
- public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete,
- final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait,
- final boolean passive, final AMQShortString exchangeType)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait,
- passive, exchangeType);
- }
-
- });
- }
-
- public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete,
- final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive,
- final AMQShortString queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue);
- }
-
- });
- }
-
- public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseDelete(session, queue);
- }
-
- });
- }
-
- public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseDelete(session, exchange);
- }
-
- });
- }
-
- public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory,
- final AMQShortString routingKey, final Exchange e)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authorisePublish(session, immediate, mandatory, routingKey, e);
- }
-
- });
- }
-
- public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authorisePurge(session, queue);
- }
-
- });
- }
-
- public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch,
- final AMQShortString routingKey, final AMQQueue queue)
- {
- return checkAllPlugins(new AccessCheck()
- {
-
- @Override
- AuthzResult allowed(ACLPlugin plugin)
- {
- return plugin.authoriseUnbind(session, exch, routingKey, queue);
- }
-
- });
- }
-
- public void addHostPlugin(ACLPlugin aclPlugin)
- {
- _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin);
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java
deleted file mode 100644
index cf8a3fede9..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.security.PrincipalHolder;
-
-public interface ACLPlugin
-{
- public enum AuthzResult
- {
- ALLOWED,
- DENIED,
- ABSTAIN
- }
-
- void setConfiguration(Configuration config) throws ConfigurationException;
-
- // These return true if the plugin thinks the action should be allowed, and false if not.
-
- AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey);
-
- AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable,
- AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType);
-
- AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive,
- boolean nowait, boolean passive, AMQShortString queue);
-
- AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost);
-
- AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue);
-
- AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal,
- boolean nowait, AMQQueue queue);
-
- AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue);
-
- AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange);
-
- AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory,
- AMQShortString routingKey, Exchange e);
-
- AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue);
-
- AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue);
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java
deleted file mode 100644
index 256f093477..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.security.access;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-
-public interface ACLPluginFactory
-{
-
- public boolean supportsTag(String name);
-
- public ACLPlugin newInstance(Configuration config) throws ConfigurationException;
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java
deleted file mode 100644
index d722da4ae0..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-public class AccessResult
-{
- public enum AccessStatus
- {
- GRANTED, REFUSED
- }
-
- private String _authorizer;
- private AccessStatus _status;
-
- public AccessResult(ACLPlugin authorizer, AccessStatus status)
- {
- _status = status;
- _authorizer = authorizer.getClass().getSimpleName();
- }
-
- public void setAuthorizer(ACLPlugin authorizer)
- {
- _authorizer += authorizer.getClass().getSimpleName();
- }
-
- public String getAuthorizer()
- {
- return _authorizer;
- }
-
- public void setStatus(AccessStatus status)
- {
- _status = status;
- }
-
- public AccessStatus getStatus()
- {
- return _status;
- }
-
- public void addAuthorizer(ACLPlugin accessManager)
- {
- _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer;
- }
-
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java
deleted file mode 100644
index 1b79a5a0e0..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-public class AccessRights
-{
- public enum Rights
- {
- ANY,
- READ,
- WRITE,
- READWRITE
- }
-
- Rights _right;
-
- public AccessRights(Rights right)
- {
- _right = right;
- }
-
- public boolean allows(Rights rights)
- {
- switch (_right)
- {
- case ANY:
- return (rights.equals(Rights.WRITE)
- || rights.equals(Rights.READ)
- || rights.equals(Rights.READWRITE)
- || rights.equals(Rights.ANY));
- case READ:
- return rights.equals(Rights.READ) || rights.equals(Rights.ANY);
- case WRITE:
- return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY);
- case READWRITE:
- return true;
- }
- return false;
- }
-
- public Rights getRights()
- {
- return _right;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
new file mode 100644
index 0000000000..af47ed6bf9
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security.access;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.queue.AMQQueue;
+
+/**
+ * An set of properties for an access control v2 rule {@link ObjectType}.
+ *
+ * The {@link #matches(ObjectProperties)} method is intended to be used when determining precedence of rules, and
+ * {@link #equals(Object)} and {@link #hashCode()} are intended for use in maps. This is due to the wildcard matching
+ * described above.
+ */
+public class ObjectProperties extends HashMap<ObjectProperties.Property, String>
+{
+ /** serialVersionUID */
+ private static final long serialVersionUID = -1356019341374170495L;
+
+ public static final String STAR= "*";
+
+ public static final ObjectProperties EMPTY = new ObjectProperties();
+
+ public enum Property
+ {
+ ROUTING_KEY,
+ NAME,
+ QUEUE_NAME,
+ OWNER,
+ TYPE,
+ ALTERNATE,
+ IMMEDIATE,
+ INTERNAL,
+ NO_WAIT,
+ NO_LOCAL,
+ NO_ACK,
+ PASSIVE,
+ DURABLE,
+ EXCLUSIVE,
+ TEMPORARY,
+ AUTO_DELETE,
+ COMPONENT,
+ PACKAGE,
+ CLASS;
+
+ public static Property parse(String text)
+ {
+ for (Property property : values())
+ {
+ if (property.getName().equalsIgnoreCase(text))
+ {
+ return property;
+ }
+ }
+ throw new IllegalArgumentException("Not a valid property: " + text);
+ }
+
+ public String getName()
+ {
+ return StringUtils.remove(name(), '_').toLowerCase();
+ }
+
+ public static List<String> getPropertyNames()
+ {
+ List<String> properties = new ArrayList<String>();
+ for (Property property : values())
+ {
+ properties.add(property.getName());
+ }
+ return properties;
+ }
+ }
+
+ public static List<String> getAllPropertyNames()
+ {
+ List<String> properties = new ArrayList<String>();
+ for (Property property : Property.values())
+ {
+ properties.add(StringUtils.remove(property.name(), '_').toLowerCase());
+ }
+ return properties;
+ }
+
+ public ObjectProperties()
+ {
+ super();
+ }
+
+ public ObjectProperties(ObjectProperties copy)
+ {
+ super();
+
+ putAll(copy);
+ }
+
+ public ObjectProperties(String name)
+ {
+ super();
+
+ setName(name);
+ }
+
+
+ public ObjectProperties(AMQShortString name)
+ {
+ super();
+
+ setName(name);
+ }
+
+ public ObjectProperties(AMQQueue queue)
+ {
+ super();
+
+ setName(queue.getName());
+
+ put(Property.AUTO_DELETE, queue.isAutoDelete());
+ put(Property.TEMPORARY, queue.isAutoDelete());
+ put(Property.DURABLE, queue.isDurable());
+ put(Property.EXCLUSIVE, queue.isExclusive());
+ if (queue.getAlternateExchange() != null)
+ {
+ put(Property.ALTERNATE, queue.getAlternateExchange().getName());
+ }
+ if (queue.getOwner() != null)
+ {
+ put(Property.OWNER, queue.getOwner());
+ }
+ else if (queue.getPrincipalHolder() != null)
+ {
+ put(Property.OWNER, queue.getPrincipalHolder().getPrincipal().getName());
+ }
+ }
+
+ public ObjectProperties(Exchange exch, AMQQueue queue, AMQShortString routingKey)
+ {
+ this(queue);
+
+ setName(exch.getName());
+
+ put(Property.QUEUE_NAME, queue.getName());
+ put(Property.ROUTING_KEY, routingKey);
+ }
+
+ public ObjectProperties(Exchange exch, AMQShortString routingKey)
+ {
+ this(exch.getName(), routingKey.asString());
+ }
+
+ public ObjectProperties(String exchangeName, String routingKey, Boolean immediate)
+ {
+ this(exchangeName, routingKey);
+
+ put(Property.IMMEDIATE, immediate);
+ }
+
+ public ObjectProperties(String exchangeName, String routingKey)
+ {
+ super();
+
+ setName(exchangeName);
+
+ put(Property.ROUTING_KEY, routingKey);
+ }
+
+ public ObjectProperties(Boolean autoDelete, Boolean durable, AMQShortString exchangeName,
+ Boolean internal, Boolean nowait, Boolean passive, AMQShortString exchangeType)
+ {
+ super();
+
+ setName(exchangeName);
+
+ put(Property.AUTO_DELETE, autoDelete);
+ put(Property.TEMPORARY, autoDelete);
+ put(Property.DURABLE, durable);
+ put(Property.INTERNAL, internal);
+ put(Property.NO_WAIT, nowait);
+ put(Property.PASSIVE, passive);
+ put(Property.TYPE, exchangeType);
+ }
+
+ public ObjectProperties(Boolean autoDelete, Boolean durable, Boolean exclusive, Boolean nowait, Boolean passive,
+ AMQShortString queueName, String owner)
+ {
+ super();
+
+ setName(queueName);
+
+ put(Property.AUTO_DELETE, autoDelete);
+ put(Property.TEMPORARY, autoDelete);
+ put(Property.DURABLE, durable);
+ put(Property.EXCLUSIVE, exclusive);
+ put(Property.NO_WAIT, nowait);
+ put(Property.PASSIVE, passive);
+ put(Property.OWNER, owner);
+ }
+
+ public ObjectProperties(Boolean exclusive, Boolean noAck, Boolean noLocal, Boolean nowait, AMQQueue queue)
+ {
+ this(queue);
+
+ put(Property.NO_LOCAL, noLocal);
+ put(Property.NO_ACK, noAck);
+ put(Property.EXCLUSIVE, exclusive);
+ put(Property.NO_WAIT, nowait);
+ }
+
+ public List<String> getPropertyNames()
+ {
+ List<String> properties = new ArrayList<String>();
+ for (Property property : keySet())
+ {
+ properties.add(property.getName());
+ }
+ return properties;
+ }
+
+ public Boolean isSet(Property key)
+ {
+ return containsKey(key) && Boolean.valueOf(get(key));
+ }
+
+ public String getName()
+ {
+ return get(Property.NAME);
+ }
+
+ public void setName(String name)
+ {
+ put(Property.NAME, name);
+ }
+
+ public void setName(AMQShortString name)
+ {
+ put(Property.NAME, name);
+ }
+
+ public String put(Property key, AMQShortString value)
+ {
+ return put(key, value == null ? "" : value.asString());
+ }
+
+ @Override
+ public String put(Property key, String value)
+ {
+ return super.put(key, value == null ? "" : value.trim());
+ }
+
+ public void put(Property key, Boolean value)
+ {
+ if (value != null)
+ {
+ super.put(key, Boolean.toString(value));
+ }
+ }
+
+ public boolean matches(ObjectProperties properties)
+ {
+ if (properties.keySet().isEmpty())
+ {
+ return true;
+ }
+
+ if (!keySet().containsAll(properties.keySet()))
+ {
+ return false;
+ }
+
+ for (Property key : properties.keySet())
+ {
+ String ruleValue = properties.get(key);
+ String thisValue = get(key);
+
+ if (!valueMatches(thisValue, ruleValue))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean valueMatches(String thisValue, String ruleValue)
+ {
+ return (StringUtils.isEmpty(ruleValue)
+ || StringUtils.equals(thisValue, ruleValue))
+ || ruleValue.equals(STAR)
+ || (ruleValue.endsWith(STAR)
+ && thisValue != null
+ && thisValue.length() > ruleValue.length()
+ && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2)));
+ }
+}
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
new file mode 100644
index 0000000000..66ef388976
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security.access;
+
+import static org.apache.qpid.server.security.access.Operation.*;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * An enumeration of all possible object types that can form part of an access control v2 rule.
+ *
+ * Each object type is valid only for a certain set of {@link Operation}s, which are passed as a list to
+ * the constructor, and can be checked using the {@link #isAllowed(Operation)} method.
+ */
+public enum ObjectType
+{
+ ALL(Operation.ALL),
+ VIRTUALHOST(ACCESS),
+ QUEUE(CREATE, DELETE, PURGE, CONSUME),
+ TOPIC(CREATE, DELETE, PURGE, CONSUME),
+ EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
+ BROKER(ACCESS),
+ LINK, // Not allowed in the Java broker
+ ROUTE, // Not allowed in the Java broker
+ METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE),
+ OBJECT(ACCESS);
+
+ private EnumSet<Operation> _actions;
+
+ private ObjectType()
+ {
+ _actions = EnumSet.noneOf(Operation.class);
+ }
+
+ private ObjectType(Operation operation)
+ {
+ if (operation == Operation.ALL)
+ {
+ _actions = EnumSet.allOf(Operation.class);
+ }
+ else
+ {
+ _actions = EnumSet.of(operation);
+ }
+ }
+
+ private ObjectType(Operation first, Operation...rest)
+ {
+ _actions = EnumSet.of(first, rest);
+ }
+
+ public Set<Operation> getActions()
+ {
+ return _actions;
+ }
+
+ public boolean isAllowed(Operation operation)
+ {
+ return _actions.contains(operation);
+ }
+
+ public static ObjectType parse(String text)
+ {
+ for (ObjectType object : values())
+ {
+ if (object.name().equalsIgnoreCase(text))
+ {
+ return object;
+ }
+ }
+ throw new IllegalArgumentException("Not a valid object type: " + text);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
index 37a0fd7fc3..7077257d01 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java
@@ -15,35 +15,35 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
- *
*/
package org.apache.qpid.server.security.access;
-import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.security.access.plugins.AllowAll;
-import org.apache.qpid.server.security.PrincipalHolder;
-
-public class ExchangeDenier extends AllowAll
+/**
+ * An enumeration of all possible actions that can form part of an access control v2 rule.
+ */
+public enum Operation
{
-
- public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ ALL,
+ CONSUME,
+ PUBLISH,
+ CREATE,
+ ACCESS,
+ BIND,
+ UNBIND,
+ DELETE,
+ PURGE,
+ UPDATE,
+ EXECUTE;
+
+ public static Operation parse(String text)
{
- public boolean supportsTag(String name)
+ for (Operation operation : values())
{
- return name.startsWith("exchangeDenier");
+ if (operation.name().equalsIgnoreCase(text))
+ {
+ return operation;
+ }
}
-
- public ACLPlugin newInstance(Configuration config)
- {
- return new ExchangeDenier();
- }
- };
-
- @Override
- public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
- {
- return AuthzResult.DENIED;
+ throw new IllegalArgumentException("Not a valid operation: " + text);
}
-}
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
index b65b0cdc6c..49b3a331f9 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
@@ -20,19 +20,28 @@
*/
package org.apache.qpid.server.security.access;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.commons.lang.StringUtils;
+/**
+ * An enumeration of all possible permissions that can be applied to an access control v2 rule.
+ */
public enum Permission
{
- CONSUME,
- PUBLISH,
- CREATEQUEUE,
- CREATEEXCHANGE,
- ACCESS,
- BIND,
- UNBIND,
- DELETE,
- PURGE
-}
+ ALLOW,
+ ALLOW_LOG,
+ DENY,
+ DENY_LOG;
+
+ public static Permission parse(String text)
+ {
+
+ for (Permission permission : values())
+ {
+ if (permission.name().equalsIgnoreCase(StringUtils.replaceChars(text, '-', '_')))
+ {
+ return permission;
+ }
+ }
+ throw new IllegalArgumentException("Not a valid permission: " + text);
+ }
+} \ No newline at end of file
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java
deleted file mode 100644
index 13151a66b8..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-public class VirtualHostAccess
-{
- private String _vhost;
- private AccessRights _rights;
-
- public VirtualHostAccess(String vhostaccess)
- {
- //format <vhost>(<rights>)
- int hostend = vhostaccess.indexOf('(');
-
- if (hostend == -1)
- {
- throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights");
- }
-
- _vhost = vhostaccess.substring(0, hostend);
-
- String rights = vhostaccess.substring(hostend);
-
- if (rights.indexOf('r') != -1)
- {
- if (rights.indexOf('w') != -1)
- {
- _rights = new AccessRights(AccessRights.Rights.READWRITE);
- }
- else
- {
- _rights = new AccessRights(AccessRights.Rights.READ);
- }
- }
- else if (rights.indexOf('w') != -1)
- {
- _rights = new AccessRights(AccessRights.Rights.WRITE);
- }
- }
-
- public AccessRights getAccessRights()
- {
- return _rights;
- }
-
- public String getVirtualHost()
- {
- return _vhost;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
deleted file mode 100644
index f99f3a60f7..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.server.security.access.plugins;
-
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.security.PrincipalHolder;
-
-/**
- * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations.
- */
-public abstract class AbstractACLPlugin implements ACLPlugin
-{
-
- private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN;
-
- public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue,
- AMQShortString routingKey)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal,
- boolean nowait, AMQQueue queue)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable,
- AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType)
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable,
- boolean exclusive, boolean nowait, boolean passive, AMQShortString queue)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory,
- AMQShortString routingKey, Exchange e)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue)
- {
- return DEFAULT_ANSWER;
- }
-
- public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey,
- AMQQueue queue)
- {
- return DEFAULT_ANSWER;
- }
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
index 4af178574b..82963bbadc 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
@@ -15,40 +15,72 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
- *
*/
package org.apache.qpid.server.security.access.plugins;
+import java.util.Arrays;
+import java.util.List;
+
import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLPluginFactory;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.SecurityPluginFactory;
-public class AllowAll extends BasicACLPlugin
+/** Always allow. */
+public class AllowAll extends BasicPlugin
{
+ public static class AllowAllConfiguration extends ConfigurationPlugin {
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
+ {
+ public List<String> getParentPaths()
+ {
+ return Arrays.asList("security", "virtualhosts.virtualhost.security");
+ }
- public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException
+ {
+ ConfigurationPlugin instance = new AllowAllConfiguration();
+ instance.setConfiguration(path, config);
+ return instance;
+ }
+ };
+
+ public String[] getElementsProcessed()
+ {
+ return new String[] { "allow-all" };
+ }
+ }
+
+ public static final SecurityPluginFactory<AllowAll> FACTORY = new SecurityPluginFactory<AllowAll>()
{
- public boolean supportsTag(String name)
+ public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException
{
- return false;
+ AllowAll plugin = new AllowAll(config);
+ plugin.configure();
+ return plugin;
}
- public ACLPlugin newInstance(Configuration config)
+ public String getPluginName()
{
- return new AllowAll();
+ return AllowAll.class.getName();
}
- };
- public String getPluginName()
- {
- return this.getClass().getSimpleName();
+ public Class<AllowAll> getPluginClass()
+ {
+ return AllowAll.class;
+ }
+ };
+
+ @Override
+ public Result getDefault()
+ {
+ return Result.ALLOWED;
}
- @Override
- protected AuthzResult getResult()
+ public AllowAll(ConfigurationPlugin config)
{
- // Always allow
- return AuthzResult.ALLOWED;
+ _config = config.getConfiguration(AllowAllConfiguration.class);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
deleted file mode 100644
index d0df354d78..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access.plugins;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.PrincipalHolder;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-public abstract class BasicACLPlugin implements ACLPlugin
-{
-
- // Returns true or false if the plugin should authorise or deny the request
- protected abstract AuthzResult getResult();
-
- public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch,
- AMQQueue queue, AMQShortString routingKey)
- {
- return getResult();
- }
-
- public AuthzResult authoriseConnect(PrincipalHolder session,
- VirtualHost virtualHost)
- {
- return getResult();
- }
-
- public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck,
- AMQQueue queue)
- {
- return getResult();
- }
-
- public AuthzResult authoriseConsume(PrincipalHolder session,
- boolean exclusive, boolean noAck, boolean noLocal, boolean nowait,
- AMQQueue queue)
- {
- return getResult();
- }
-
- public AuthzResult authoriseCreateExchange(PrincipalHolder session,
- boolean autoDelete, boolean durable, AMQShortString exchangeName,
- boolean internal, boolean nowait, boolean passive,
- AMQShortString exchangeType)
- {
- return getResult();
- }
-
- public AuthzResult authoriseCreateQueue(PrincipalHolder session,
- boolean autoDelete, boolean durable, boolean exclusive,
- boolean nowait, boolean passive, AMQShortString queue)
- {
- return getResult();
- }
-
- public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
- {
- return getResult();
- }
-
- public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange)
- {
- return getResult();
- }
-
- public AuthzResult authorisePublish(PrincipalHolder session,
- boolean immediate, boolean mandatory, AMQShortString routingKey,
- Exchange e)
- {
- return getResult();
- }
-
- public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue)
- {
- return getResult();
- }
-
- public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch,
- AMQShortString routingKey, AMQQueue queue)
- {
- return getResult();
- }
-
- public void setConfiguration(Configuration config)
- {
- // no-op
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java
new file mode 100644
index 0000000000..5fc1ef7795
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.access.plugins;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.security.AbstractPlugin;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.SecurityPlugin;
+import org.apache.qpid.server.security.access.ObjectProperties;
+import org.apache.qpid.server.security.access.ObjectType;
+import org.apache.qpid.server.security.access.Operation;
+
+/**
+ * This {@link SecurityPlugin} simply abstains from all authorisation requests and ignores configuration.
+ */
+public class BasicPlugin extends AbstractPlugin
+{
+ public Result access(ObjectType objectType, Object instance)
+ {
+ return getDefault();
+ }
+
+ public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties)
+ {
+ return getDefault();
+ }
+
+ @Override
+ public void configure() throws ConfigurationException
+ {
+ // Not used
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
index 77d3c4bcdf..24af215a0c 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java
@@ -15,61 +15,72 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
- *
*/
package org.apache.qpid.server.security.access.plugins;
+import java.util.Arrays;
+import java.util.List;
+
import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.AMQConnectionException;
-import org.apache.qpid.framing.AMQMethodBody;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLPluginFactory;
-import org.apache.qpid.server.security.access.AccessResult;
-import org.apache.qpid.server.security.access.Permission;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.SecurityPluginFactory;
-public class DenyAll extends BasicACLPlugin
+/** Always Deny. */
+public class DenyAll extends BasicPlugin
{
- public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
- {
- public boolean supportsTag(String name)
+ public static class DenyAllConfiguration extends ConfigurationPlugin {
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
{
- return false;
- }
+ public List<String> getParentPaths()
+ {
+ return Arrays.asList("security", "virtualhosts.virtualhost.security");
+ }
- public ACLPlugin newInstance(Configuration config)
+ public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException
+ {
+ ConfigurationPlugin instance = new DenyAllConfiguration();
+ instance.setConfiguration(path, config);
+ return instance;
+ }
+ };
+
+ public String[] getElementsProcessed()
{
- return new DenyAll();
+ return new String[] { "deny-all" };
}
- };
+ }
- public AccessResult authorise(AMQProtocolSession session,
- Permission permission, AMQMethodBody body, Object... parameters)
- throws AMQConnectionException
+ public static final SecurityPluginFactory<DenyAll> FACTORY = new SecurityPluginFactory<DenyAll>()
{
+ public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException
+ {
+ DenyAll plugin = new DenyAll(config);
+ plugin.configure();
+ return plugin;
+ }
- if (ACLManager.getLogger().isInfoEnabled())
+ public String getPluginName()
{
- ACLManager.getLogger().info(
- "Denying user:" + session.getPrincipal());
+ return DenyAll.class.getName();
}
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- "DenyAll Plugin");
- }
- public String getPluginName()
- {
- return getClass().getSimpleName();
+ public Class<DenyAll> getPluginClass()
+ {
+ return DenyAll.class;
+ }
+ };
+
+ @Override
+ public Result getDefault()
+ {
+ return Result.DENIED;
}
- @Override
- protected AuthzResult getResult()
+ public DenyAll(ConfigurationPlugin config) throws ConfigurationException
{
- // Always deny
- return AuthzResult.DENIED;
+ _config = config.getConfiguration(DenyAllConfiguration.class);
}
-
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java
new file mode 100644
index 0000000000..2c0994b52a
--- /dev/null
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security.access.plugins;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.security.SecurityPluginFactory;
+
+/** Always Abstain. */
+public class LegacyAccess extends BasicPlugin
+{
+ public static class LegacyAccessConfiguration extends ConfigurationPlugin {
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
+ {
+ public List<String> getParentPaths()
+ {
+ return Arrays.asList("security", "virtualhosts.virtualhost.security");
+ }
+
+ public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException
+ {
+ ConfigurationPlugin instance = new LegacyAccessConfiguration();
+ instance.setConfiguration(path, config);
+ return instance;
+ }
+ };
+
+ public String[] getElementsProcessed()
+ {
+ return new String[] { "principal-databases", "access", "msg-auth", "false", "jmx" };
+ }
+ }
+
+ public static final SecurityPluginFactory<LegacyAccess> FACTORY = new SecurityPluginFactory<LegacyAccess>()
+ {
+ public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException
+ {
+ LegacyAccess plugin = new LegacyAccess(config);
+ plugin.configure();
+ return plugin;
+ }
+
+ public String getPluginName()
+ {
+ return LegacyAccess.class.getName();
+ }
+
+ public Class<LegacyAccess> getPluginClass()
+ {
+ return LegacyAccess.class;
+ }
+ };
+
+ public LegacyAccess(ConfigurationPlugin config) throws ConfigurationException
+ {
+ _config = config.getConfiguration(LegacyAccessConfiguration.class);
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java
deleted file mode 100644
index fc1bc048d4..0000000000
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access.plugins;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.server.security.access.ACLPlugin;
-import org.apache.qpid.server.security.access.ACLPluginFactory;
-
-/**
- *
- * Used to suppress warnings in legacy config files that have things in <security> which aren't handled by a plugin directly.
- *
- */
-public class LegacyAccessPlugin extends BasicACLPlugin
-{
- public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
- {
- private Collection maskedTags = new HashSet<String>();
- {
- maskedTags.add("principal-databases");
- maskedTags.add("access");
- maskedTags.add("msg-auth");
- maskedTags.add("false");
- maskedTags.add("jmx");
- }
-
- public boolean supportsTag(String name)
- {
- return maskedTags .contains(name);
- }
-
- public ACLPlugin newInstance(Configuration config)
- {
- return new LegacyAccessPlugin();
- }
- };
-
- public String getPluginName()
- {
- return getClass().getSimpleName();
- }
-
- @Override
- protected AuthzResult getResult()
- {
- // Always abstain
- return AuthzResult.ABSTAIN;
- }
-
-}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
index 3f846b9dd0..62967ef7eb 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
@@ -20,8 +20,6 @@
*/
package org.apache.qpid.server.security.auth;
-import javax.security.sasl.SaslException;
-
public class AuthenticationResult
{
public enum AuthenticationStatus
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
index 889ce815f4..6ca9c8e762 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
@@ -21,7 +21,7 @@
package org.apache.qpid.server.security.auth.database;
import org.apache.log4j.Logger;
-import org.apache.qpid.server.security.access.management.AMQUserManagementMBean;
+import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
index 2619a69cfd..5cebb7d2d8 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java
@@ -38,7 +38,7 @@ import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
-import org.apache.qpid.server.security.access.management.AMQUserManagementMBean;
+import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean;
import org.apache.qpid.AMQException;
import javax.management.JMException;
@@ -51,7 +51,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception
{
- _logger.info("Initialising PrincipleDatabase authentication manager");
+ _logger.info("Initialising PrincipalDatabase authentication manager");
_databases = initialisePrincipalDatabases(_configuration);
}
@@ -171,16 +171,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
AMQUserManagementMBean _mbean = new AMQUserManagementMBean();
List<String> principalDBs = config.getManagementPrincipalDBs();
-
- if (principalDBs.size() == 0)
+ if (principalDBs.isEmpty())
{
throw new ConfigurationException("No principal-database specified for jmx security");
}
String databaseName = principalDBs.get(0);
-
PrincipalDatabase database = getDatabases().get(databaseName);
-
if (database == null)
{
throw new ConfigurationException("Principal-database '" + databaseName + "' not found");
@@ -189,14 +186,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
_mbean.setPrincipalDatabase(database);
List<String> jmxaccesslist = config.getManagementAccessList();
-
- if (jmxaccesslist.size() == 0)
+ if (jmxaccesslist.isEmpty())
{
throw new ConfigurationException("No access control files specified for jmx security");
}
String jmxaccesssFile = null;
-
+
try
{
jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0));
@@ -205,7 +201,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab
{
throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'");
}
-
+
try
{
_mbean.setAccessFile(jmxaccesssFile);
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java
index 5a2965cb32..153b8c25db 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java
@@ -18,51 +18,50 @@
*
*
*/
-package org.apache.qpid.server.security.access.management;
+package org.apache.qpid.server.security.auth.management;
-import org.apache.qpid.management.common.mbeans.UserManagement;
-import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
-import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
-import org.apache.qpid.server.management.AMQManagedObject;
-import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
-import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
-import org.apache.qpid.util.FileUtils;
-import org.apache.log4j.Logger;
-import org.apache.commons.configuration.ConfigurationException;
-
-import javax.management.JMException;
-import javax.management.remote.JMXPrincipal;
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularDataSupport;
-import javax.management.openmbean.TabularType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.security.auth.login.AccountNotFoundException;
-import javax.security.auth.Subject;
import java.io.File;
import java.io.FileInputStream;
-import java.io.IOException;
import java.io.FileOutputStream;
-import java.util.Properties;
-import java.util.List;
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
-import java.security.Principal;
-import java.security.AccessControlContext;
-import java.security.AccessController;
+
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription;
+import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation;
+import org.apache.qpid.server.management.AMQManagedObject;
+import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */
@MBeanDescription("User Management Interface")
public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement
{
-
private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class);
private PrincipalDatabase _principalDatabase;
@@ -533,6 +532,8 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
{
_logger.debug("Setting Access Rights:" + accessRights);
_accessRights = accessRights;
- MBeanInvocationHandlerImpl.setAccessRights(_accessRights);
+
+ // TODO check where this is used
+ // MBeanInvocationHandlerImpl.setAccessRights(_accessRights);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
index d34d0c4d27..bc771162fd 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
@@ -20,13 +20,12 @@
*/
package org.apache.qpid.server.security.auth.manager;
-import org.apache.qpid.common.Closeable;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
-
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
+import org.apache.qpid.common.Closeable;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+
public interface AuthenticationManager extends Closeable
{
String getMechanisms();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
index 98c060599a..2a967f02af 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
@@ -64,7 +64,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception
{
_logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'")
- + " PrincipleDatabase authentication manager.");
+ + " PrincipalDatabase authentication manager.");
// Fixme This should be done per Vhost but allowing global hack isn't right but ...
// required as authentication is done before Vhost selection
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
index 77040e896c..0cbbccb3b8 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
@@ -99,7 +99,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
}
catch (AccountNotFoundException e)
{
- throw new SecurityException(INVALID_CREDENTIALS);
+ throw new SecurityException(INVALID_CREDENTIALS); // XXX
}
if (authenticated)
diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
index 6850724b10..6cc5e7b019 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
@@ -62,6 +62,7 @@ import org.apache.qpid.server.handler.TxCommitHandler;
import org.apache.qpid.server.handler.TxRollbackHandler;
import org.apache.qpid.server.handler.TxSelectHandler;
import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
/**
@@ -258,6 +259,7 @@ public class AMQStateManager implements AMQMethodListener
public AMQProtocolSession getProtocolSession()
{
+ SecurityManager.setThreadPrincipal(_protocolSession.getPrincipal());
return _protocolSession;
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java
index 5badbad642..1bba2529c6 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java
@@ -20,25 +20,17 @@
*/
package org.apache.qpid.server.subscription;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.flow.FlowCreditManager;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.subscription.SubscriptionFactory;
-import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.AMQPFilterTypes;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.flow.FlowCreditManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
public class SubscriptionFactoryImpl implements SubscriptionFactory
{
-
- /* private SubscriptionFactoryImpl()
- {
-
- }*/
-
public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession,
AMQShortString consumerTag, boolean acks, FieldTable filters,
boolean noLocal, FlowCreditManager creditManager) throws AMQException
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index a56951cf5c..38040ecfce 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.transport;
import org.apache.qpid.transport.*;
+import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -29,16 +30,13 @@ import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslException;
import java.util.*;
-
public class ServerConnectionDelegate extends ServerDelegate
{
-
private String _localFQDN;
private final IApplicationRegistry _appRegistry;
- public ServerConnectionDelegate(IApplicationRegistry appRegistry,
- String localFQDN)
+ public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN)
{
this(new HashMap<String,Object>(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN);
}
@@ -50,6 +48,7 @@ public class ServerConnectionDelegate extends ServerDelegate
String localFQDN)
{
super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales);
+
_appRegistry = appRegistry;
_localFQDN = localFQDN;
}
@@ -65,9 +64,9 @@ public class ServerConnectionDelegate extends ServerDelegate
return list;
}
- @Override public ServerSession getSession(Connection conn, SessionAttach atc)
+ @Override
+ public ServerSession getSession(Connection conn, SessionAttach atc)
{
-
SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry);
ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0);
@@ -75,9 +74,6 @@ public class ServerConnectionDelegate extends ServerDelegate
return ssn;
}
-
-
-
@Override
protected SaslServer createSaslServer(String mechanism) throws SaslException
{
@@ -85,11 +81,10 @@ public class ServerConnectionDelegate extends ServerDelegate
}
-
@Override public void connectionOpen(Connection conn, ConnectionOpen open)
{
ServerConnection sconn = (ServerConnection) conn;
-
+
VirtualHost vhost;
String vhostName;
if(open.hasVirtualHost())
@@ -102,19 +97,27 @@ public class ServerConnectionDelegate extends ServerDelegate
}
vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName);
+ SecurityManager.setThreadPrincipal(conn.getAuthorizationID());
+
if(vhost != null)
{
sconn.setVirtualHost(vhost);
- sconn.invoke(new ConnectionOpenOk(Collections.emptyList()));
-
- sconn.setState(Connection.State.OPEN);
+ if (!vhost.getSecurityManager().accessVirtualhost(vhostName, sconn.getConfig().getAddress()))
+ {
+ sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, "Permission denied '"+vhostName+"'"));
+ sconn.setState(Connection.State.CLOSING);
+ }
+ else
+ {
+ sconn.invoke(new ConnectionOpenOk(Collections.emptyList()));
+ sconn.setState(Connection.State.OPEN);
+ }
}
else
{
- sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '" + vhostName + "'"));
+ sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'"));
sconn.setState(Connection.State.CLOSING);
}
-
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index 8a16867ad8..bc7ba085fc 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -157,7 +157,6 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo
catch (AMQException e)
{
// TODO
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
throw new RuntimeException(e);
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index 541810d2fe..73ec7f1231 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -20,31 +20,78 @@
*/
package org.apache.qpid.server.transport;
-import org.apache.qpid.transport.*;
-import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.exchange.*;
-import org.apache.qpid.server.queue.QueueRegistry;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.AMQUnknownExchangeType;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeInUseException;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.exchange.HeadersExchange;
+import org.apache.qpid.server.flow.FlowCreditManager_0_10;
+import org.apache.qpid.server.flow.WindowCreditManager;
+import org.apache.qpid.server.message.MessageMetaData_0_10;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.server.protocol.AMQSessionModel;
import org.apache.qpid.server.queue.AMQQueue;
import org.apache.qpid.server.queue.AMQQueueFactory;
import org.apache.qpid.server.queue.BaseQueue;
-import org.apache.qpid.server.message.MessageTransferMessage;
-import org.apache.qpid.server.message.MessageMetaData_0_10;
-import org.apache.qpid.server.subscription.Subscription_0_10;
-import org.apache.qpid.server.flow.*;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.StoredMessage;
-import org.apache.qpid.server.store.DurableConfigurationStore;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQUnknownExchangeType;
-import org.apache.qpid.framing.*;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.nio.ByteBuffer;
+import org.apache.qpid.server.subscription.Subscription_0_10;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.transport.Acquired;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.transport.ExchangeBind;
+import org.apache.qpid.transport.ExchangeBound;
+import org.apache.qpid.transport.ExchangeBoundResult;
+import org.apache.qpid.transport.ExchangeDeclare;
+import org.apache.qpid.transport.ExchangeDelete;
+import org.apache.qpid.transport.ExchangeQuery;
+import org.apache.qpid.transport.ExchangeQueryResult;
+import org.apache.qpid.transport.ExchangeUnbind;
+import org.apache.qpid.transport.ExecutionErrorCode;
+import org.apache.qpid.transport.ExecutionException;
+import org.apache.qpid.transport.MessageAccept;
+import org.apache.qpid.transport.MessageAcceptMode;
+import org.apache.qpid.transport.MessageAcquire;
+import org.apache.qpid.transport.MessageAcquireMode;
+import org.apache.qpid.transport.MessageCancel;
+import org.apache.qpid.transport.MessageFlow;
+import org.apache.qpid.transport.MessageFlowMode;
+import org.apache.qpid.transport.MessageFlush;
+import org.apache.qpid.transport.MessageReject;
+import org.apache.qpid.transport.MessageRejectCode;
+import org.apache.qpid.transport.MessageRelease;
+import org.apache.qpid.transport.MessageResume;
+import org.apache.qpid.transport.MessageSetFlowMode;
+import org.apache.qpid.transport.MessageStop;
+import org.apache.qpid.transport.MessageSubscribe;
+import org.apache.qpid.transport.MessageTransfer;
+import org.apache.qpid.transport.Method;
+import org.apache.qpid.transport.QueueDeclare;
+import org.apache.qpid.transport.QueueDelete;
+import org.apache.qpid.transport.QueuePurge;
+import org.apache.qpid.transport.QueueQuery;
+import org.apache.qpid.transport.QueueQueryResult;
+import org.apache.qpid.transport.RangeSet;
+import org.apache.qpid.transport.Session;
+import org.apache.qpid.transport.SessionDelegate;
+import org.apache.qpid.transport.TxCommit;
+import org.apache.qpid.transport.TxRollback;
+import org.apache.qpid.transport.TxSelect;
public class ServerSessionDelegate extends SessionDelegate
{
@@ -58,6 +105,8 @@ public class ServerSessionDelegate extends SessionDelegate
@Override
public void command(Session session, Method method)
{
+ SecurityManager.setThreadPrincipal(session.getConnection().getAuthorizationID());
+
super.command(session, method);
if (method.isSync())
{
@@ -317,7 +366,6 @@ public class ServerSessionDelegate extends SessionDelegate
catch (AMQException e)
{
//TODO
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
throw new RuntimeException(e);
}
}
@@ -371,19 +419,7 @@ public class ServerSessionDelegate extends SessionDelegate
}
else
{
- if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(),
- method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(),
- new AMQShortString(method.getType())))
- {
-
- ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
- String description = "permission denied: exchange-name '" + exchangeName + "'";
-
- exception(session, method, errorCode, description);
-
-
- }
- else if(exchange == null)
+ if (exchange == null)
{
ExchangeRegistry exchangeRegistry = getExchangeRegistry(session);
ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory();
@@ -417,12 +453,18 @@ public class ServerSessionDelegate extends SessionDelegate
{
exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType());
}
+ catch (AMQSecurityException e)
+ {
+ ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
+ String description = "Permission denied: exchange-name '" + exchangeName + "'";
+
+ exception(session, method, errorCode, description);
+ }
catch (AMQException e)
{
//TODO
throw new RuntimeException(e);
}
-
}
else
{
@@ -478,47 +520,38 @@ public class ServerSessionDelegate extends SessionDelegate
VirtualHost virtualHost = getVirtualHost(session);
ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry();
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session,
- exchangeRegistry.getExchange(method.getExchange())))
- {
- exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied");
-
- }
- else
+ try
{
+ Exchange exchange = getExchange(session, method.getExchange());
- try
+ if(exchange != null && exchange.hasReferrers())
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange");
+ }
+ else
{
- Exchange exchange = getExchange(session, method.getExchange());
+ exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused());
- if(exchange != null && exchange.hasReferrers())
- {
- exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange");
- }
- else
+ if (exchange.isDurable() && !exchange.isAutoDelete())
{
- exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused());
-
- if (exchange.isDurable() && !exchange.isAutoDelete())
- {
- DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
- store.removeExchange(exchange);
- }
-
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+ store.removeExchange(exchange);
}
}
- catch (ExchangeInUseException e)
- {
- exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use");
- }
- catch (AMQException e)
- {
- // TODO
- throw new RuntimeException(e);
- }
}
-
+ catch (ExchangeInUseException e)
+ {
+ exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use");
+ }
+ catch (AMQSecurityException e)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + method.getExchange());
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
}
@Override
@@ -582,13 +615,6 @@ public class ServerSessionDelegate extends SessionDelegate
{
exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found");
}
- else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange,
- queue, new AMQShortString(method.getBindingKey())))
- {
- exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange()
- + "' to Queue: '" + method.getQueue()
- + "' not allowed");
- }
else if(exchange.getTypeShortString().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match")))
{
exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header");
@@ -600,8 +626,15 @@ public class ServerSessionDelegate extends SessionDelegate
if (!exchange.isBound(routingKey, fieldTable, queue))
{
- virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments());
-
+ try
+ {
+ virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments());
+ }
+ catch (AMQSecurityException e)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange()
+ + "' to Queue: '" + method.getQueue() + "' not allowed");
+ }
}
else
{
@@ -649,7 +682,14 @@ public class ServerSessionDelegate extends SessionDelegate
}
else
{
- virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null);
+ try
+ {
+ virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null);
+ }
+ catch (AMQSecurityException e)
+ {
+ exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied");
+ }
}
}
@@ -768,25 +808,6 @@ public class ServerSessionDelegate extends SessionDelegate
DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
String queueName = method.getQueue();
-
- if (!method.getPassive())
- {
- // Perform ACL if request is not passive
-
- if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(),
- method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName)))
- {
- ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
- String description = "permission denied: queue-name '" + queueName + "'";
-
- exception(session, method, errorCode, description);
-
- // TODO control flow
- return;
- }
- }
-
-
AMQQueue queue;
QueueRegistry queueRegistry = getQueueRegistry(session);
//TODO: do we need to check that the queue already exists with exactly the same "configuration"?
@@ -879,34 +900,32 @@ public class ServerSessionDelegate extends SessionDelegate
{
final AMQQueue q = queue;
final ServerSession.Task deleteQueueTask = new ServerSession.Task()
- {
-
- public void doTask(ServerSession session)
{
- try
+ public void doTask(ServerSession session)
{
- q.delete();
+ try
+ {
+ q.delete();
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
}
- catch (AMQException e)
- {
- throw new RuntimeException(e);
- }
- }
- };
+ };
final ServerSession s = (ServerSession) session;
s.addSessionCloseTask(deleteQueueTask);
queue.addQueueDeleteTask(new AMQQueue.Task()
- {
-
- public void doTask(AMQQueue queue) throws AMQException
{
- s.removeSessionCloseTask(deleteQueueTask);
- }
- });
+ public void doTask(AMQQueue queue) throws AMQException
+ {
+ s.removeSessionCloseTask(deleteQueueTask);
+ }
+ });
}
else if(method.getExclusive())
{
- {
final AMQQueue q = queue;
final ServerSession.Task removeExclusive = new ServerSession.Task()
{
@@ -928,31 +947,34 @@ public class ServerSessionDelegate extends SessionDelegate
}
});
}
- }
+ }
+ catch (AMQSecurityException e)
+ {
+ String description = "Cannot declare queue('" + queueName + "'), permission denied";
+ ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED;
+ exception(session, method, errorCode, description);
}
catch (AMQException e)
{
+ // TODO
throw new RuntimeException(e);
}
}
}
else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session)))
{
-
String description = "Cannot declare queue('" + queueName + "'),"
+ " as exclusive queue with same name "
+ "declared on another session";
ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED;
-
+
exception(session, method, errorCode, description);
-
+
return;
}
-
}
}
-
protected AMQQueue createQueue(final String queueName,
QueueDeclare body,
VirtualHost virtualHost,
@@ -963,15 +985,14 @@ public class ServerSessionDelegate extends SessionDelegate
String owner = body.getExclusive() ? session.getClientID() : null;
- final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(),
+ final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(),
body.getExclusive(), virtualHost, body.getArguments());
-
if (body.getExclusive() && !body.getDurable())
{
final ServerSession.Task deleteQueueTask =
new ServerSession.Task()
- {
+ {
public void doTask(ServerSession session)
{
if (registry.getQueue(queueName) == queue)
@@ -1006,7 +1027,6 @@ public class ServerSessionDelegate extends SessionDelegate
@Override
public void queueDelete(Session session, QueueDelete method)
{
-
String queueName = method.getQueue();
if(queueName == null || queueName.length()==0)
{
@@ -1041,36 +1061,28 @@ public class ServerSessionDelegate extends SessionDelegate
else
{
VirtualHost virtualHost = getVirtualHost(session);
-
- //Perform ACLs
- if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue))
- {
- exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName);
- }
- else
+
+ try
{
- try
- {
- int purged = queue.delete();
- if (queue.isDurable() && !queue.isAutoDelete())
- {
- DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
- store.removeQueue(queue);
- }
-
- }
- catch (AMQException e)
+ queue.delete();
+ if (queue.isDurable() && !queue.isAutoDelete())
{
- //TODO
- throw new RuntimeException(e);
+ DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
+ store.removeQueue(queue);
}
-
}
-
+ catch (AMQSecurityException e)
+ {
+ exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName);
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
}
}
}
-
}
@Override
@@ -1080,24 +1092,32 @@ public class ServerSessionDelegate extends SessionDelegate
if(queueName == null || queueName.length()==0)
{
exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied");
-
}
else
{
AMQQueue queue = getQueue(session, queueName);
-
if (queue == null)
{
exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found");
}
else
{
- //TODO
- queue.clearQueue();
+ try
+ {
+ queue.clearQueue();
+ }
+ catch (AMQSecurityException e)
+ {
+ exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName);
+ }
+ catch (AMQException e)
+ {
+ // TODO
+ throw new RuntimeException(e);
+ }
}
}
-
}
@Override
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
index 675a6f6a91..98d231a7ea 100755
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
@@ -102,7 +102,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa
if (q == null)
{
- q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost,
+ q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, false, _virtualHost,
arguments);
_virtualHost.getQueueRegistry().registerQueue(q);
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
index 44d178602f..d104209e98 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
@@ -20,16 +20,25 @@
*/
package org.apache.qpid.server.virtualhost;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimerTask;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.NotCompliantMBeanException;
+
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
-
import org.apache.qpid.AMQException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.FieldTable;
import org.apache.qpid.server.AMQBrokerManagerMBean;
-import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory;
-import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin;
import org.apache.qpid.server.binding.BindingFactory;
import org.apache.qpid.server.configuration.BrokerConfig;
import org.apache.qpid.server.configuration.ConfigStore;
@@ -58,29 +67,17 @@ import org.apache.qpid.server.queue.DefaultQueueRegistry;
import org.apache.qpid.server.queue.QueueRegistry;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.security.access.ACLManager;
-import org.apache.qpid.server.security.access.Accessable;
+import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
import org.apache.qpid.server.store.DurableConfigurationStore;
import org.apache.qpid.server.store.MessageStore;
import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin;
+import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory;
-import javax.management.NotCompliantMBeanException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.TimerTask;
-import java.util.UUID;
-import java.util.Map;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-public class VirtualHostImpl implements Accessable, VirtualHost
+public class VirtualHostImpl implements VirtualHost
{
private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class);
@@ -102,7 +99,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost
private AuthenticationManager _authenticationManager;
- private ACLManager _accessManager;
+ private SecurityManager _securityManager;
private final ScheduledThreadPoolExecutor _houseKeepingTasks;
private final IApplicationRegistry _appRegistry;
@@ -117,17 +114,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost
private final ConcurrentHashMap<BrokerLink,BrokerLink> _links = new ConcurrentHashMap<BrokerLink, BrokerLink>();
private static final int HOUSEKEEPING_SHUTDOWN_TIMEOUT = 5;
- public void setAccessableName(String name)
- {
- _logger.warn("Setting Accessable Name for VirualHost is not allowed. ("
- + name + ") ignored remains :" + getAccessableName());
- }
-
- public String getAccessableName()
- {
- return _name;
- }
-
public IConnectionRegistry getConnectionRegistry()
{
return _connectionRegistry;
@@ -140,7 +126,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost
public UUID getId()
{
- return _id; //To change body of implemented methods use File | Settings | File Templates.
+ return _id;
}
public VirtualHostConfigType getConfigType()
@@ -200,12 +186,17 @@ public class VirtualHostImpl implements Accessable, VirtualHost
private VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig, MessageStore store) throws Exception
{
+ if (hostConfig == null)
+ {
+ throw new IllegalAccessException("HostConfig and MessageStore cannot be null");
+ }
+
_appRegistry = appRegistry;
- _broker = appRegistry.getBroker();
+ _broker = _appRegistry.getBroker();
_configuration = hostConfig;
- _name = hostConfig.getName();
+ _name = _configuration.getName();
- _id = appRegistry.getConfigStore().createId();
+ _id = _appRegistry.getConfigStore().createId();
CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name));
@@ -214,6 +205,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost
throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost.");
}
+ _securityManager = new SecurityManager(_appRegistry.getSecurityManager());
+ _securityManager.configureHostPlugins(_configuration);
+
_virtualHostMBean = new VirtualHostMBean();
_connectionRegistry = new ConnectionRegistry();
@@ -223,15 +217,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost
_queueRegistry = new DefaultQueueRegistry(this);
_exchangeFactory = new DefaultExchangeFactory(this);
- _exchangeFactory.initialise(hostConfig);
+ _exchangeFactory.initialise(_configuration);
_exchangeRegistry = new DefaultExchangeRegistry(this);
-
- //Create a temporary RT to store the durable entries from the config file
- // so we can replay them in to the real _RT after it has been loaded.
- /// This should be removed after the _RT has been fully split from the the TL
-
StartupRoutingTable configFileRT = new StartupRoutingTable();
_durableConfigurationStore = configFileRT;
@@ -241,7 +230,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost
_bindingFactory = new BindingFactory(this);
- initialiseModel(hostConfig);
+ initialiseModel(_configuration);
if (store != null)
{
@@ -250,36 +239,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost
}
else
{
- if (hostConfig == null)
- {
- throw new IllegalAccessException("HostConfig and MessageStore cannot be null");
- }
- initialiseMessageStore(hostConfig);
- }
-
-
-
- //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config
- // file and write them in to the new routing Table.
-/* for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue)
- {
- getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments);
+ initialiseMessageStore(hostConfig);
}
-
- for (Exchange exchange : configFileRT.exchange)
- {
- getDurableConfigurationStore().createExchange(exchange);
- }
-
- for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings)
- {
- getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments);
- }*/
-
- _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig);
-
- _accessManager = ApplicationRegistry.getInstance().getAccessManager();
- _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration());
+
+ _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, _configuration);
_brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
_brokerMBean.register();
@@ -330,8 +293,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost
}
Map<String, VirtualHostPluginFactory> plugins =
- ApplicationRegistry.getInstance().
- getPluginManager().getVirtualHostPlugins();
+ ApplicationRegistry.getInstance().getPluginManager().getVirtualHostPlugins();
if (plugins != null)
{
@@ -340,24 +302,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost
try
{
VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this);
-
- TimeUnit units = TimeUnit.MILLISECONDS;
-
- if (plugin.getTimeUnit() != null)
- {
- try
- {
- units = TimeUnit.valueOf(plugin.getTimeUnit());
- }
- catch (IllegalArgumentException iae)
- {
- _logger.warn("Plugin:" + pluginName +
- " provided an illegal TimeUnit value:"
- + plugin.getTimeUnit());
- // Warn and use default of millseconds
- // Should not occur in a well behaved plugin
- }
- }
_houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2,
plugin.getDelay(), plugin.getTimeUnit());
@@ -600,9 +544,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost
return _authenticationManager;
}
- public ACLManager getAccessManager()
+ public SecurityManager getSecurityManager()
{
- return _accessManager;
+ return _securityManager;
}
public void close()
diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java
index 59ab7ec673..26eb5bbd7f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.virtualhost.plugins;
+import java.util.concurrent.TimeUnit;
+
import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -39,5 +41,5 @@ public interface VirtualHostPlugin extends Runnable, Plugin
* @see java.util.concurrent.TimeUnit for valid value.
* @return
*/
- public String getTimeUnit();
+ public TimeUnit getTimeUnit();
}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java
index fe35cfa3aa..8bced58b7b 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java
@@ -19,24 +19,20 @@
*
*/
-package org.apache.qpid.server.security.access.management;
+package org.apache.qpid.server.management;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
+import junit.framework.TestCase;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
-
-import junit.framework.TestCase;
+import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean;
/* Note: The main purpose is to test the jmx access rights file manipulation
* within AMQUserManagementMBean. The Principal Databases are tested by their own tests,
diff --git a/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
new file mode 100644
index 0000000000..325a4e6464
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.plugins;
+
+import junit.framework.TestCase;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.ExchangeType;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+
+import java.util.Map;
+
+public class PluginTest extends TestCase
+{
+ private static final String TEST_EXCHANGE_CLASS = "org.apache.qpid.extras.exchanges.example.TestExchangeType";
+
+ private static final String PLUGIN_DIRECTORY = System.getProperty("example.plugin.target");
+ private static final String CACHE_DIRECTORY = System.getProperty("example.cache.target");
+
+ IApplicationRegistry _registry;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ PropertiesConfiguration properties = new PropertiesConfiguration();
+ properties.addProperty("plugin-directory", PLUGIN_DIRECTORY);
+ properties.addProperty("cache-directory", CACHE_DIRECTORY);
+ ServerConfiguration config = new ServerConfiguration(properties);
+
+ // This Test requries an application Registry
+ ApplicationRegistry.initialise(new TestApplicationRegistry(config));
+ _registry = ApplicationRegistry.getInstance();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ ApplicationRegistry.remove();
+ }
+
+ public void disabled_testLoadExchanges() throws Exception
+ {
+ PluginManager manager = _registry.getPluginManager();
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertNotNull("No exchanges found in " + PLUGIN_DIRECTORY, exchanges);
+ assertEquals("Wrong number of exchanges found in " + PLUGIN_DIRECTORY, 2, exchanges.size());
+ assertNotNull("Wrong exchange found in " + PLUGIN_DIRECTORY, exchanges.get(TEST_EXCHANGE_CLASS));
+ }
+
+ public void testNoExchanges() throws Exception
+ {
+ PluginManager manager = new PluginManager("/path/to/nowhere", "/tmp");
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertTrue("Exchanges found", exchanges.isEmpty());
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
index 3d3d8f93a8..393ffdeaac 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
@@ -49,7 +49,7 @@ public class AMQQueueFactoryTest extends TestCase
}
- public void testPriorityQueueRegistration()
+ public void testPriorityQueueRegistration() throws Exception
{
FieldTable fieldTable = new FieldTable();
fieldTable.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), 5);
@@ -62,7 +62,7 @@ public class AMQQueueFactoryTest extends TestCase
}
- public void testSimpleQueueRegistration()
+ public void testSimpleQueueRegistration() throws Exception
{
AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false,
false, _virtualHost, null);
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
index fe45be3f0e..e1852a0a22 100644
--- a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -25,6 +25,7 @@ import junit.framework.TestCase;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.framing.BasicContentHeaderProperties;
import org.apache.qpid.framing.ContentHeaderBody;
@@ -144,7 +145,7 @@ public class SimpleAMQQueueTest extends TestCase
assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost());
}
- public void testBinding()
+ public void testBinding() throws AMQSecurityException
{
_virtualHost.getBindingFactory().addBinding(String.valueOf(_routingKey), _queue, _exchange, Collections.EMPTY_MAP);
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
deleted file mode 100644
index 44f9861e8d..0000000000
--- a/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-
-import junit.framework.TestCase;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.commons.configuration.XMLConfiguration;
-import org.apache.qpid.server.configuration.SecurityConfiguration;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.plugins.MockPluginManager;
-import org.apache.qpid.server.plugins.PluginManager;
-import org.apache.qpid.server.protocol.AMQProtocolSession;
-import org.apache.qpid.server.protocol.InternalTestProtocolSession;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.MockAMQQueue;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-public class ACLManagerTest extends TestCase
-{
-
- private ACLManager _authzManager;
- private AMQProtocolSession _session;
- private SecurityConfiguration _conf;
- private PluginManager _pluginManager;
-
- @Override
- public void setUp() throws Exception
- {
- File tmpFile = File.createTempFile(getClass().getName(), "testconfig");
- tmpFile.deleteOnExit();
- BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile));
- out.write("<security><queueDenier>notyet</queueDenier><exchangeDenier>yes</exchangeDenier></security>");
- out.close();
-
- _conf = new SecurityConfiguration(new XMLConfiguration(tmpFile));
-
- // Create ACLManager
-
- _pluginManager = new MockPluginManager("");
- _authzManager = new ACLManager(_conf, _pluginManager);
-
-
- VirtualHost virtualHost = ApplicationRegistry.getInstance().
- getVirtualHostRegistry().getVirtualHosts().iterator().next();
-
- // Create a single session for this test.
- _session = new InternalTestProtocolSession(virtualHost);
- }
-
- @Override
- public void tearDown() throws Exception
- {
- // Correctly Close the AR we created
- ApplicationRegistry.remove();
- super.tearDown();
- }
-
- public void testACLManagerConfigurationPluginManager() throws Exception
- {
- AMQQueue queue = new MockAMQQueue("notyet");
- AMQQueue otherQueue = new MockAMQQueue("other");
-
- assertFalse(_authzManager.authoriseDelete(_session, queue));
-
- // This should only be denied if the config hasn't been correctly passed in
- assertTrue(_authzManager.authoriseDelete(_session, otherQueue));
- assertTrue(_authzManager.authorisePurge(_session, queue));
- }
-
- public void testACLManagerConfigurationPluginManagerACLPlugin() throws ConfigurationException
- {
- _authzManager = new ACLManager(_conf, _pluginManager, ExchangeDenier.FACTORY);
-
- Exchange exchange = null;
- assertFalse(_authzManager.authoriseDelete(_session, exchange));
- }
-
- public void testConfigurePlugins() throws ConfigurationException
- {
- Configuration hostConfig = new PropertiesConfiguration();
- hostConfig.setProperty("queueDenier", "thisoneneither");
- _authzManager.configureHostPlugins(new SecurityConfiguration(hostConfig));
- AMQQueue queue = new MockAMQQueue("thisoneneither");
- assertFalse(_authzManager.authoriseDelete(_session, queue));
- }
-}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
deleted file mode 100644
index 3f9c776aa2..0000000000
--- a/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- *
- */
-package org.apache.qpid.server.security.access;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.security.access.plugins.AllowAll;
-import org.apache.qpid.server.security.PrincipalHolder;
-
-public class QueueDenier extends AllowAll
-{
-
- public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
- {
- public boolean supportsTag(String name)
- {
- return name.equals("queueDenier");
- }
-
- public ACLPlugin newInstance(Configuration config)
- {
- QueueDenier plugin = new QueueDenier();
- plugin.setConfiguration(config);
- return plugin;
- }
- };
-
- private String _queueName = "";
-
-
- @Override
- public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue)
- {
- if (!(queue.getNameShortString().toString().equals(_queueName)))
- {
- return AuthzResult.ALLOWED;
- }
- else
- {
- return AuthzResult.DENIED;
- }
- }
-
- @Override
- public void setConfiguration(Configuration config)
- {
- _queueName = config.getString("queueDenier");
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/AMQSecurityException.java b/java/common/src/main/java/org/apache/qpid/AMQSecurityException.java
new file mode 100644
index 0000000000..d145d2c21d
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/AMQSecurityException.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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;
+
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * SecurityException encapsulates error code 403, or {@link AMQConstant#ACCESS_REFUSED} exceptions relating to the
+ * AMQ protocol. It is used to report authorisation failures and security errors.
+ */
+public class AMQSecurityException extends AMQException
+{
+ /** serialVersionUID */
+ private static final long serialVersionUID = 8862069852716968394L;
+
+ /**
+ * Creates an exception with an optional message and optional underlying cause.
+ *
+ * @param msg The exception message. May be null if not to be set.
+ * @param cause The underlying cause of the exception. May be null if not to be set.
+ */
+ public AMQSecurityException(String msg, Throwable cause)
+ {
+ super(AMQConstant.ACCESS_REFUSED, ((msg == null) ? "Permission denied" : msg), cause);
+ }
+
+ public AMQSecurityException(String msg)
+ {
+ this(msg, null);
+ }
+
+ public AMQSecurityException()
+ {
+ this(null);
+ }
+}
diff --git a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
index d02b9b89f4..c0e7293611 100644
--- a/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
+++ b/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedBroker.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.util.List;
import javax.management.JMException;
+import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute;
@@ -71,55 +72,63 @@ public interface ManagedBroker
/**
* Creates a new Exchange.
+ *
* @param name
* @param type
* @param durable
* @throws IOException
* @throws JMException
+ * @throws MBeanException
*/
@MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION)
void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name,
@MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type,
@MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable)
- throws IOException, JMException;
+ throws IOException, JMException, MBeanException;
/**
* unregisters all the channels, queuebindings etc and unregisters
* this exchange from managed objects.
+ *
* @param exchange
* @throws IOException
* @throws JMException
+ * @throws MBeanException
*/
@MBeanOperation(name="unregisterExchange",
description="Unregisters all the related channels and queuebindings of this exchange",
impact= MBeanOperationInfo.ACTION)
void unregisterExchange(@MBeanOperationParameter(name= ManagedExchange.TYPE, description="Exchange Name")String exchange)
- throws IOException, JMException;
+ throws IOException, JMException, MBeanException;
/**
- * Create a new Queue on the Broker server
+ * Create a new Queue on the Broker server.
+ *
* @param queueName
* @param durable
* @param owner
* @throws IOException
* @throws JMException
+ * @throws MBeanException
*/
@MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION)
void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName,
@MBeanOperationParameter(name="owner", description="Owner name")String owner,
@MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable)
- throws IOException, JMException;
+ throws IOException, JMException, MBeanException;
/**
* Unregisters the Queue bindings, removes the subscriptions and unregisters
* from the managed objects.
+ *
* @param queueName
* @throws IOException
* @throws JMException
+ * @throws MBeanException
*/
@MBeanOperation(name="deleteQueue",
description="Unregisters the Queue bindings, removes the subscriptions and deletes the queue",
impact= MBeanOperationInfo.ACTION)
void deleteQueue(@MBeanOperationParameter(name= ManagedQueue.TYPE, description="Queue Name")String queueName)
- throws IOException, JMException;
+ throws IOException, JMException, MBeanException;
}
diff --git a/java/systests/etc/config-systests-aclv2-settings.xml b/java/systests/etc/config-systests-aclv2-settings.xml
new file mode 100644
index 0000000000..a7248766db
--- /dev/null
+++ b/java/systests/etc/config-systests-aclv2-settings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - 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.
+ -
+ -->
+<broker>
+ <security>
+ <access>
+ <class>org.apache.qpid.server.security.access.plugins.AccessControl</class>
+ </access>
+ <aclv2>${QPID_HOME}/etc/global-default.txt</aclv2>
+ </security>
+
+ <virtualhosts>${QPID_HOME}/etc/virtualhosts-systests-aclv2.xml</virtualhosts>
+</broker>
+
+
diff --git a/java/systests/etc/config-systests-aclv2.xml b/java/systests/etc/config-systests-aclv2.xml
new file mode 100644
index 0000000000..33563e7891
--- /dev/null
+++ b/java/systests/etc/config-systests-aclv2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - 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.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.config}" optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-aclv2-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config-systests-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/config.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/global-default.txt b/java/systests/etc/global-default.txt
new file mode 100644
index 0000000000..01b2c41809
--- /dev/null
+++ b/java/systests/etc/global-default.txt
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+CONFIG expand=true
+
+# This section grants the admin user access to all management methods
+ACL ALLOW admin ALL METHOD
+
+# This section grants the client user access to all management methods except logging
+ACL DENY client ALL METHOD component="LoggingManagement"
+ACL ALLOW client ALL METHOD
+
+# This section grants the server user access to all management methods except configuration
+ACL DENY server ALL METHOD component="ConfigurationManagement"
+ACL ALLOW server ALL METHOD
diff --git a/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt b/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt
new file mode 100644
index 0000000000..a59b3176cb
--- /dev/null
+++ b/java/systests/etc/global-externaladminacl-changeloggerleveldenied.txt
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+# This section denies the admin user access to logging
+ACL DENY admin UPDATE METHOD component="LoggingManagement" name="setRuntimeRootLoggerLevel"
+
+# This section grants the admin user access to management methods
+ACL ALLOW admin ALL METHOD
diff --git a/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt b/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt
new file mode 100644
index 0000000000..ff024b5ee8
--- /dev/null
+++ b/java/systests/etc/global-externaladminacl-getallloggerlevelsdenied.txt
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+# This section denies the admin user access to logging methods
+ACL DENY admin ACCESS METHOD component="LoggingManagement" name="getAvailableLoggerLevels"
+
+# This section grants the admin user access to all management methods
+ACL ALLOW admin ALL METHOD
+
diff --git a/java/systests/etc/test-default.txt b/java/systests/etc/test-default.txt
new file mode 100644
index 0000000000..95e733d077
--- /dev/null
+++ b/java/systests/etc/test-default.txt
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+
+# This section grants virtualhost access rights
+ACL ALLOW client ACCESS VIRTUALHOST
+ACL ALLOW server ACCESS VIRTUALHOST
+
+# This section grants publish rights to an exchange + routing key pair
+
+# Allow clients to publish requests
+ACL ALLOW client PUBLISH EXCHANGE name="amq.direct" routingKey="example.RequestQueue"
+
+# Allow the processor to respond to a client on their Temporary Topic
+ACL ALLOW server PUBLISH EXCHANGE name="amq.direct" routingKey="tmp_*"
+ACL ALLOW server PUBLISH EXCHANGE name="amq.direct" routingKey="TempQueue*"
+
+# This section grants users the ability to consume from the broker
+
+# Allow client to consume from temporary queues
+ACL ALLOW client CONSUME QUEUE temporary=true
+
+# Only allow the server to consume from the Request Queue
+ACL ALLOW server CONSUME QUEUE name="example.RequestQueue"
+
+# Allow client and server to consume from kipper queues
+ACL ALLOW client CONSUME QUEUE name="clientid:kipper"
+ACL ALLOW server CONSUME QUEUE name="clientid:kipper"
+
+# This section grants users the ability to create/delete queues and exchanges
+
+# Allow clients to create and delete temporary and kipper queue on this exchange
+ACL ALLOW client CREATE QUEUE temporary=true
+ACL ALLOW client DELETE QUEUE temporary=true
+ACL ALLOW client CREATE QUEUE durable="true"
+ACL ALLOW client DELETE QUEUE durable="true"
+
+# Allow the server to create the Request Queue and kipper queue
+ACL ALLOW server CREATE QUEUE name="example.RequestQueue"
+ACL ALLOW server CREATE QUEUE name="clientid:kipper"
+
+## Allow client and server exchange access for the relevant queues
+ACL ALLOW client BIND EXCHANGE name="amq.direct" temporary=true
+ACL ALLOW client UNBIND EXCHANGE name="amq.direct" temporary=true
+ACL ALLOW client BIND EXCHANGE name="amq.direct" durable=true
+ACL ALLOW client UNBIND EXCHANGE name="amq.direct" durable=true
+ACL ALLOW server BIND EXCHANGE name="amq.direct" queueName="example.RequestQueue"
+
+## Allow client and server exchange access for the relevant topics
+ACL ALLOW client BIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
+ACL ALLOW client UNBIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
+ACL ALLOW server BIND EXCHANGE name="amq.topic" durable=true routingKey=kipper
+
+# Action[operation=BIND,objectType=EXCHANGE,properties={OWNER=client, DURABLE=true, QUEUE_NAME=IllegalQueue, AUTO_DELETE=false, ROUTING_KEY=IllegalQueue, NAME=amq.direct, TEMPORARY=false, EXCLUSIVE=false}]
+
+
+ACL ALLOW client CREATE EXCHANGE
+ACL ALLOW server CREATE EXCHANGE
diff --git a/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt b/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt
new file mode 100644
index 0000000000..197fe9dabe
--- /dev/null
+++ b/java/systests/etc/test-externalacljmx-deleteexchangefailure.txt
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+# This section grants virtualhost management rights
+ACL ALLOW admin ALL METHOD
+
+# testDeleteExchangeFailure()
+ACL ALLOW admin CREATE EXCHANGE name="amq.kipper.delete"
+ACL DENY admin DELETE EXCHANGE name="amq.kipper.delete"
+
diff --git a/java/systests/etc/test-externalacljmx.txt b/java/systests/etc/test-externalacljmx.txt
new file mode 100644
index 0000000000..f8a94bd44a
--- /dev/null
+++ b/java/systests/etc/test-externalacljmx.txt
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+# This section grants management access to the virtualhost
+ACL ALLOW admin ALL METHOD
+ACL ALLOW client ALL METHOD
+ACL ALLOW server ALL METHOD
+
+# Allow create kipper queue
+ACL ALLOW admin CREATE QUEUE name="kipper" owner = client # kipper
+ACL ALLOW admin BIND EXCHANGE name="amq.direct"
+
+# testCreateExchangeSuccess(), testDeleteExchangeSuccess()
+ACL ALLOW admin CREATE EXCHANGE name="amq.kipper.success"
+ACL ALLOW admin DELETE EXCHANGE name="amq.kipper.success"
+
+# testCreateExchangeFailure()
+ACL DENY admin CREATE EXCHANGE name="amq.kipper.failure"
+
diff --git a/java/systests/etc/test2-default.txt b/java/systests/etc/test2-default.txt
new file mode 100644
index 0000000000..0855e631d7
--- /dev/null
+++ b/java/systests/etc/test2-default.txt
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# This section grants all access rights
+ACL ALLOW guest ALL ALL \ No newline at end of file
diff --git a/java/systests/etc/virtualhosts-systests-acl-settings.xml b/java/systests/etc/virtualhosts-systests-acl-settings.xml
index 50fda4e999..ffbace569f 100644
--- a/java/systests/etc/virtualhosts-systests-acl-settings.xml
+++ b/java/systests/etc/virtualhosts-systests-acl-settings.xml
@@ -35,9 +35,6 @@
<security>
- <access>
- <class>org.apache.qpid.server.security.access.plugins.SimpleXML</class>
- </access>
<access_control_list>
<!-- This section grants pubish rights to an exchange + routing key pair -->
<publish>
@@ -45,7 +42,6 @@
<exchange>
<name>amq.direct</name>
<routing_keys>
-
<!-- Allow clients to publish requests -->
<routing_key>
<value>example.RequestQueue</value>
@@ -68,7 +64,6 @@
</users>
</routing_key>
</routing_keys>
-
</exchange>
</exchanges>
</publish>
@@ -90,7 +85,14 @@
</users>
</queue>
-
+ <!-- Allow client and server to consume from the kipper Queue-->
+ <queue>
+ <name>clientid:kipper</name>
+ <users>
+ <user>client</user>
+ <user>server</user>
+ </users>
+ </queue>
</queues>
</consume>
@@ -110,10 +112,28 @@
<name>amq.direct</name>
<users>
<user>client</user>
+ <user>server</user>
+ </users>
+ </exchange>
+ <exchange>
+ <name>amq.topic</name>
+ <users>
+ <user>client</user>
+ <user>server</user>
</users>
</exchange>
</exchanges>
</queue>
+
+ <!-- everyone can create the kipper queue -->
+ <queue>
+ <name>clientid:kipper</name>
+ <users>
+ <user>client</user>
+ <user>server</user>
+ </users>
+ </queue>
+
<!-- Allow the server to create the Request Queue-->
<queue>
<name>example.RequestQueue</name>
@@ -121,13 +141,21 @@
<user>server</user>
</users>
</queue>
-
</queues>
</create>
-
+ <delete>
+ <queues>
+ <!-- only client can delete the kipper queue -->
+ <queue>
+ <name>clientid:kipper</name>
+ <users>
+ <user>client</user>
+ </users>
+ </queue>
+ </queues>
+ </delete>
</access_control_list>
-
</security>
</test>
</virtualhost>
@@ -136,10 +164,6 @@
<name>test2</name>
<test2>
<security>
- <access>
- <class>org.apache.qpid.server.security.access.plugins.SimpleXML</class>
- </access>
-
<access_control_list>
<!-- This section grants specific users full permissions to all artifacts in this virtualhost -->
<access>
diff --git a/java/systests/etc/virtualhosts-systests-aclv2-settings.xml b/java/systests/etc/virtualhosts-systests-aclv2-settings.xml
new file mode 100644
index 0000000000..db1ad33a39
--- /dev/null
+++ b/java/systests/etc/virtualhosts-systests-aclv2-settings.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - 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.
+ -
+ -->
+<virtualhosts>
+ <virtualhost>
+ <name>test</name>
+ <test>
+ <queues>
+ <exchange>amq.direct</exchange>
+ <!-- 4Mb -->
+ <maximumQueueDepth>4235264</maximumQueueDepth>
+ <!-- 2Mb -->
+ <maximumMessageSize>2117632</maximumMessageSize>
+ <!-- 10 mins -->
+ <maximumMessageAge>600000</maximumMessageAge>
+ </queues>
+
+ <security>
+ <aclv2>${QPID_HOME}/etc/test-default.txt</aclv2>
+ </security>
+ </test>
+ </virtualhost>
+
+ <virtualhost>
+ <name>test2</name>
+ <test2 />
+ </virtualhost>
+</virtualhosts>
+
+
diff --git a/java/systests/etc/virtualhosts-systests-aclv2.xml b/java/systests/etc/virtualhosts-systests-aclv2.xml
new file mode 100644
index 0000000000..eb96577487
--- /dev/null
+++ b/java/systests/etc/virtualhosts-systests-aclv2.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ -
+ - 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.
+ -
+ -->
+<configuration>
+ <system/>
+ <override>
+ <xml fileName="${test.virtualhosts}" optional="true"/>
+ <xml fileName="${QPID_HOME}/etc/virtualhosts-systests-aclv2-settings.xml"/>
+ <xml fileName="${QPID_HOME}/etc/virtualhosts.xml"/>
+ </override>
+</configuration>
diff --git a/java/systests/etc/virtualhosts-systests-firewall-2.xml b/java/systests/etc/virtualhosts-systests-firewall-2.xml
index b85ab83676..7990483348 100644
--- a/java/systests/etc/virtualhosts-systests-firewall-2.xml
+++ b/java/systests/etc/virtualhosts-systests-firewall-2.xml
@@ -26,8 +26,7 @@
<name>test</name>
<test>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore
- </class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore</class>
</store>
<security>
<firewall default-action="allow"/>
@@ -39,8 +38,7 @@
<name>test2</name>
<test2>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore
- </class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore</class>
</store>
</test2>
</virtualhost>
diff --git a/java/systests/etc/virtualhosts-systests-firewall-3.xml b/java/systests/etc/virtualhosts-systests-firewall-3.xml
index ebfc2bad20..45a2ae5ef4 100644
--- a/java/systests/etc/virtualhosts-systests-firewall-3.xml
+++ b/java/systests/etc/virtualhosts-systests-firewall-3.xml
@@ -26,8 +26,7 @@
<name>test</name>
<test>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore
- </class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore</class>
</store>
</test>
</virtualhost>
@@ -36,8 +35,7 @@
<name>test2</name>
<test2>
<store>
- <class>org.apache.qpid.server.store.MemoryMessageStore
- </class>
+ <class>org.apache.qpid.server.store.MemoryMessageStore</class>
</store>
<security>
<firewall default-action="deny"/>
diff --git a/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java b/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
index 863aa43d22..4050637bb2 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/failover/MessageDisappearWithIOExceptionTest.java
@@ -263,7 +263,7 @@ public class MessageDisappearWithIOExceptionTest extends FailoverBaseCase implem
throws Exception
{
//Create Connection using the default connection URL. i.e. not the Failover URL that would be used by default
- _connection = (AMQConnection) getConnection(getConnectionFactory("default").getConnectionURL());
+ _connection = (AMQConnection) getConnectionFactory("default").createConnection("guest", "guest");
// The default connection does not have any retries configured so
// Allow this connection to retry so that we can block on the failover.
// The alternative would be to use the getConnection() default. However,
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
new file mode 100644
index 0000000000..21c121ff2c
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.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.server.security.acl;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.jms.ConnectionListener;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.url.URLSyntaxException;
+
+/**
+ * Abstract test case for ACLs.
+ *
+ * This base class contains convenience methods to mange ACL files and implements a mechanism that allows each
+ * test method to run its own setup code before the broker starts.
+ *
+ * TODO move the pre broker-startup setup method invocation code to {@link QpidTestCase}
+ *
+ * @see SimpleACLTest
+ * @see ExternalACLTest
+ * @see ExternalACLFileTest
+ * @see ExternalACLJMXTest
+ * @see ExternalAdminACLTest
+ * @see ExhaustiveACLTest
+ */
+public abstract class AbstractACLTestCase extends QpidTestCase implements ConnectionListener
+{
+ /** Used to synchronise {@link #tearDown()} when exceptions are thrown */
+ protected CountDownLatch _exceptionReceived;
+
+ /** Override this to return the name of the configuration XML file. */
+ public String getConfig()
+ {
+ return "config-systests-acl.xml";
+ }
+
+ /** Override this to setup external ACL files for virtual hosts. */
+ public List<String> getHostList()
+ {
+ return Collections.emptyList();
+ }
+
+ /**
+ * This setup method checks {@link #getConfig()} and {@link #getHostList()} to initialise the broker with specific
+ * ACL configurations and then runs an optional per-test setup method, which is simply a method with the same name
+ * as the test, but starting with {@code setUp} rather than {@code test}.
+ *
+ * @see #setUpACLFile(String)
+ * @see org.apache.qpid.test.utils.QpidTestCase#setUp()
+ */
+ @Override
+ public void setUp() throws Exception
+ {
+ if (QpidHome == null)
+ {
+ fail("QPID_HOME not set");
+ }
+
+ // Initialise ACLs.
+ _configFile = new File(QpidHome, "etc" + File.separator + getConfig());
+
+ // Initialise ACL files
+ for (String virtualHost : getHostList())
+ {
+ setUpACLFile(virtualHost);
+ }
+
+ // run test specific setup
+ String testSetup = StringUtils.replace(getName(), "test", "setUp");
+ try
+ {
+ Method setup = getClass().getDeclaredMethod(testSetup);
+ setup.invoke(this);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // Ignore
+ }
+ catch (InvocationTargetException e)
+ {
+ throw (Exception) e.getTargetException();
+ }
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ catch (JMSException e)
+ {
+ //we're throwing this away as it can happen in this test as the state manager remembers exceptions
+ //that we provoked with authentication failures, where the test passes - we can ignore on con close
+ }
+ }
+
+ /**
+ * Configures specific ACL files for a virtual host.
+ *
+ * This method checks for ACL files that exist on the filesystem. If dynamically generatyed ACL files are required in a test,
+ * then it is easier to use the {@code setUp} prefix on a method to generate the ACL file. In order, this method looks
+ * for three files:
+ * <ol>
+ * <li><em>virtualhost</em>-<em>class</em>-<em>test</em>.txt
+ * <li><em>virtualhost</em>-<em>class</em>.txt
+ * <li><em>virtualhost</em>-default.txt
+ * </ol>
+ * The <em>class</em> and <em>test</em> parts are the test class and method names respectively, with the word {@code test}
+ * removed and the rest of the text converted to lowercase. For example, the test class and method named
+ * {@code org.apache.qpid.test.AccessExampleTest#testExampleMethod} on the {@code testhost} virtualhost would use
+ * one of the following files:
+ * <ol>
+ * <li>testhost-accessexample-examplemethod.txt
+ * <li>testhost-accessexample.txt
+ * <li>testhost-default.txt
+ * </ol>
+ * These files should be copied to the <em>${QPID_HOME}/etc</em> directory when the test is run.
+ *
+ * @see #writeACLFile(String, String...)
+ */
+ public void setUpACLFile(String virtualHost) throws IOException, ConfigurationException
+ {
+ String path = QpidHome + File.separator + "etc";
+ String className = StringUtils.substringBeforeLast(getClass().getSimpleName().toLowerCase(), "test");
+ String testName = StringUtils.substringAfter(getName(), "test").toLowerCase();
+
+ File aclFile = new File(path, virtualHost + "-" + className + "-" + testName + ".txt");
+ if (!aclFile.exists())
+ {
+ aclFile = new File(path, virtualHost + "-" + className + ".txt");
+ if (!aclFile.exists())
+ {
+ aclFile = new File(path, virtualHost + "-" + "default.txt");
+ }
+ }
+
+ // Set the ACL file configuration property
+ if (virtualHost.equals("global"))
+ {
+ setConfigurationProperty("security.aclv2", aclFile.getAbsolutePath());
+ }
+ else
+ {
+ setConfigurationProperty("virtualhosts.virtualhost." + virtualHost + ".security.aclv2", aclFile.getAbsolutePath());
+ }
+ }
+
+ public void writeACLFile(String vhost, String...rules) throws ConfigurationException, IOException
+ {
+ File aclFile = File.createTempFile(getClass().getSimpleName(), getName());
+ aclFile.deleteOnExit();
+
+ if ("global".equals(vhost))
+ {
+ setConfigurationProperty("security.aclv2", aclFile.getAbsolutePath());
+ }
+ else
+ {
+ setConfigurationProperty("virtualhosts.virtualhost." + vhost + ".security.aclv2", aclFile.getAbsolutePath());
+ }
+
+ PrintWriter out = new PrintWriter(new FileWriter(aclFile));
+ out.println(String.format("# %s", _testName));
+ for (String line : rules)
+ {
+ out.println(line);
+ }
+ out.close();
+ }
+
+ /**
+ * Creates a connection to the broker, and sets a connection listener to prevent failover and an exception listener
+ * with a {@link CountDownLatch} to synchronise in the {@link #check403Exception(Throwable)} method and allow the
+ * {@link #tearDown()} method to complete properly.
+ */
+ public Connection getConnection(String vhost, String username, String password) throws NamingException, JMSException, URLSyntaxException
+ {
+ AMQConnection connection = (AMQConnection) getConnection(createConnectionURL(vhost, username, password));
+
+ //Prevent Failover
+ connection.setConnectionListener(this);
+
+ //QPID-2081: use a latch to sync on exception causing connection close, to work
+ //around the connection close race during tearDown() causing sporadic failures
+ _exceptionReceived = new CountDownLatch(1);
+
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ _exceptionReceived.countDown();
+ }
+ });
+
+ return (Connection) connection;
+ }
+
+ // Connection Listener Interface - Used here to block failover
+
+ public void bytesSent(long count)
+ {
+ }
+
+ public void bytesReceived(long count)
+ {
+ }
+
+ public boolean preFailover(boolean redirect)
+ {
+ //Prevent failover.
+ return false;
+ }
+
+ public boolean preResubscribe()
+ {
+ return false;
+ }
+
+ public void failoverComplete()
+ {
+ }
+
+ /**
+ * Convenience method to build an {@link AMQConnectionURL} with the right parameters.
+ */
+ public AMQConnectionURL createConnectionURL(String vhost, String username, String password) throws URLSyntaxException
+ {
+ String url = "amqp://" + username + ":" + password + "@clientid/" + vhost + "?brokerlist='" + getBroker() + "?retries='0''";
+ return new AMQConnectionURL(url);
+ }
+
+ /**
+ * Convenience method to validate a JMS exception with a linked {@link AMQConstant#ACCESS_REFUSED} 403 error code exception.
+ */
+ public void check403Exception(Throwable t) throws Exception
+ {
+ assertNotNull("There was no linked exception", t);
+ assertTrue("Wrong linked exception type", t instanceof AMQException);
+ assertEquals("Incorrect error code received", 403, ((AMQException) t).getErrorCode().getCode());
+
+ //use the latch to ensure the control thread waits long enough for the exception thread
+ //to have done enough to mark the connection closed before teardown commences
+ assertTrue("Timed out waiting for conneciton to report close", _exceptionReceived.await(2, TimeUnit.SECONDS));
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java
new file mode 100644
index 0000000000..1b2c98d30a
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.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.server.security.acl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.protocol.AMQConstant;
+
+/**
+ * ACL version 2/3 file testing to verify that ACL entries control queue creation with specific properties.
+ *
+ * Tests have their own ACL files that setup specific permissions, and then try to create queues with every possible combination
+ * of properties to show that rule matching works correctly. For example, a rule that specified {@code autodelete="true"} for
+ * queues with {@link name="temp.true.*"} as well should not affect queues that have names that do not match, or queues that
+ * are not autodelete, or both. Also checks that ACL entries only affect the specified users and virtual hosts.
+ */
+public class ExhaustiveACLTest extends AbstractACLTestCase
+{
+ @Override
+ public String getConfig()
+ {
+ return "config-systests-aclv2.xml";
+ }
+
+ @Override
+ public List<String> getHostList()
+ {
+ return Arrays.asList("test", "test2");
+ }
+
+ /**
+ * Creates a queue.
+ *
+ * Connects to the broker as a particular user and create the named queue on a virtual host, with the provided
+ * parameters. Uses a new {@link Connection} and {@link Session} and closes them afterwards.
+ */
+ private void createQueue(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception
+ {
+ Connection conn = getConnection(vhost, user, "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString(name), autoDelete, durable, false);
+ sess.commit();
+ conn.close();
+ }
+
+ /**
+ * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that
+ * no exceptions were thrown.
+ */
+ private void createQueueSuccess(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception
+ {
+ try
+ {
+ createQueue(vhost, user, name, autoDelete, durable);
+ }
+ catch (AMQException e)
+ {
+ fail(String.format("Create queue should have worked for \"%s\" for user %s@%s, autoDelete=%s, durable=%s",
+ name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable)));
+ }
+ }
+
+ /**
+ * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that
+ * the exception thrown was an {@link AMQConstant#ACCESS_REFUSED} or 403 error code.
+ */
+ private void createQueueFailure(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception
+ {
+ try
+ {
+ createQueue(vhost, user, name, autoDelete, durable);
+ fail(String.format("Create queue should have failed for \"%s\" for user %s@%s, autoDelete=%s, durable=%s",
+ name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable)));
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Should be an ACCESS_REFUSED error", 403, e.getErrorCode().getCode());
+ }
+ }
+
+ public void setUpAuthoriseCreateQueueAutodelete() throws Exception
+ {
+ writeACLFile("test",
+ "acl allow client access virtualhost",
+ "acl allow server access virtualhost",
+ "acl allow client create queue name=\"temp.true.*\" autodelete=true",
+ "acl allow client create queue name=\"temp.false.*\" autodelete=false",
+ "acl deny client create queue",
+ "acl allow client delete queue",
+ "acl deny all create queue"
+ );
+ }
+
+ /**
+ * Test creation of temporary queues, with the autodelete property set to true.
+ */
+ public void testAuthoriseCreateQueueAutodelete() throws Exception
+ {
+ createQueueSuccess("test", "client", "temp.true.00", true, false);
+ createQueueSuccess("test", "client", "temp.true.01", true, false);
+ createQueueSuccess("test", "client", "temp.true.02", true, true);
+ createQueueSuccess("test", "client", "temp.false.03", false, false);
+ createQueueSuccess("test", "client", "temp.false.04", false, false);
+ createQueueSuccess("test", "client", "temp.false.05", false, true);
+ createQueueFailure("test", "client", "temp.true.06", false, false);
+ createQueueFailure("test", "client", "temp.false.07", true, false);
+ createQueueFailure("test", "server", "temp.true.08", true, false);
+ createQueueFailure("test", "client", "temp.other.09", false, false);
+ createQueueSuccess("test2", "guest", "temp.true.01", false, false);
+ createQueueSuccess("test2", "guest", "temp.false.02", true, false);
+ createQueueSuccess("test2", "guest", "temp.true.03", true, false);
+ createQueueSuccess("test2", "guest", "temp.false.04", false, false);
+ createQueueSuccess("test2", "guest", "temp.other.05", false, false);
+ }
+
+ public void setUpAuthoriseCreateQueue() throws Exception
+ {
+ writeACLFile("test",
+ "acl allow client access virtualhost",
+ "acl allow server access virtualhost",
+ "acl allow client create queue name=\"create.*\""
+ );
+ }
+
+ /**
+ * Tests creation of named queues.
+ *
+ * If a named queue is specified
+ */
+ public void testAuthoriseCreateQueue() throws Exception
+ {
+ createQueueSuccess("test", "client", "create.00", true, true);
+ createQueueSuccess("test", "client", "create.01", true, false);
+ createQueueSuccess("test", "client", "create.02", false, true);
+ createQueueSuccess("test", "client", "create.03", true, false);
+ createQueueFailure("test", "server", "create.04", true, true);
+ createQueueFailure("test", "server", "create.05", true, false);
+ createQueueFailure("test", "server", "create.06", false, true);
+ createQueueFailure("test", "server", "create.07", true, false);
+ createQueueSuccess("test2", "guest", "create.00", true, true);
+ createQueueSuccess("test2", "guest", "create.01", true, false);
+ createQueueSuccess("test2", "guest", "create.02", false, true);
+ createQueueSuccess("test2", "guest", "create.03", true, false);
+ }
+
+ public void setUpAuthoriseCreateQueueBoth() throws Exception
+ {
+ writeACLFile("test",
+ "acl allow all access virtualhost",
+ "acl allow client create queue name=\"create.*\"",
+ "acl allow all create queue temporary=true"
+ );
+ }
+
+ /**
+ * Tests creation of named queues.
+ *
+ * If a named queue is specified
+ */
+ public void testAuthoriseCreateQueueBoth() throws Exception
+ {
+ createQueueSuccess("test", "client", "create.00", true, false);
+ createQueueSuccess("test", "client", "create.01", false, false);
+ createQueueFailure("test", "server", "create.02", false, false);
+ createQueueFailure("test", "guest", "create.03", false, false);
+ createQueueSuccess("test", "client", "tmp.00", true, false);
+ createQueueSuccess("test", "server", "tmp.01", true, false);
+ createQueueSuccess("test", "guest", "tmp.02", true, false);
+ createQueueSuccess("test2", "guest", "create.02", false, false);
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java
new file mode 100644
index 0000000000..1d08015669
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLFileTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.security.acl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+
+/**
+ * Tests that ACL version 2/3 files following the specification work correctly.
+ *
+ * ACL lines that are identical in meaning apart from differences allowed by the specification, such as whitespace or case
+ * of tokens are set up for numbered queues and the queues are then created to show that the meaning is correctly parsed by
+ * the plugin.
+ *
+ * TODO move this to the access-control plugin unit tests instead
+ */
+public class ExternalACLFileTest extends AbstractACLTestCase
+{
+ @Override
+ public String getConfig()
+ {
+ return "config-systests-aclv2.xml";
+ }
+
+ @Override
+ public List<String> getHostList()
+ {
+ return Arrays.asList("test");
+ }
+
+ private void createQueuePrefixList(String prefix, int count)
+ {
+ try
+ {
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
+
+ //Create n queues
+ for (int n = 0; n < count; n++)
+ {
+ AMQShortString queueName = new AMQShortString(String.format("%s.%03d", prefix, n));
+ ((AMQSession<?, ?>) sess).createQueue(queueName, false, false, false);
+ }
+
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Test failed due to:" + e.getMessage());
+ }
+ }
+
+ private void createQueueNameList(String...queueNames)
+ {
+ try
+ {
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ conn.start();
+
+ //Create all queues
+ for (String queueName : queueNames)
+ {
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString(queueName), false, false, false);
+ }
+
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Test failed due to:" + e.getMessage());
+ }
+ }
+
+ public void setUpCreateQueueMixedCase() throws Exception
+ {
+ writeACLFile(
+ "test",
+ "acl allow client create queue name=mixed.000",
+ "ACL ALLOW client CREATE QUEUE NAME=mixed.001",
+ "Acl Allow client Create Queue Name=mixed.002",
+ "aCL aLLOW client cREATE qUEUE nAME=mixed.003",
+ "aCl AlLoW client cReAtE qUeUe NaMe=mixed.004"
+ );
+ }
+
+ public void testCreateQueueMixedCase()
+ {
+ createQueuePrefixList("mixed", 5);
+ }
+
+ public void setUpCreateQueueContinuation() throws Exception
+ {
+ writeACLFile(
+ "test",
+ "acl allow client create queue name=continuation.000",
+ "acl allow client create queue \\",
+ " name=continuation.001",
+ "acl allow client \\",
+ " create queue \\",
+ " name=continuation.002",
+ "acl allow \\",
+ " client \\",
+ " create queue \\",
+ " name=continuation.003",
+ "acl \\",
+ " allow \\",
+ " client \\",
+ " create queue \\",
+ " name=continuation.004"
+ );
+ }
+
+ public void testCreateQueueContinuation()
+ {
+ createQueuePrefixList("continuation", 5);
+ }
+
+ public void setUpCreateQueueWhitespace() throws Exception
+ {
+ writeACLFile(
+ "test",
+ "acl allow client create queue name=whitespace.000",
+ "acl\tallow\tclient\tcreate\tqueue\tname=whitespace.001",
+ "acl allow client create queue name = whitespace.002",
+ "acl\tallow\tclient\tcreate\tqueue\tname\t=\twhitespace.003",
+ "acl allow\t\tclient\t \tcreate\t\t queue\t \t name \t =\t \twhitespace.004"
+ );
+ }
+
+ public void testCreateQueueWhitespace()
+ {
+ createQueuePrefixList("whitespace", 5);
+ }
+
+ public void setUpCreateQueueQuoting() throws Exception
+ {
+ writeACLFile(
+ "test",
+ "acl allow client create queue name='quoting.ABC.000'",
+ "acl allow client create queue name='quoting.*.000'",
+ "acl allow client create queue name='quoting.#.000'",
+ "acl allow client create queue name='quoting. .000'",
+ "acl allow client create queue name='quoting.!@$%.000'"
+ );
+ }
+
+ public void testCreateQueueQuoting()
+ {
+ createQueueNameList(
+ "quoting.ABC.000",
+ "quoting.*.000",
+ "quoting.#.000",
+ "quoting. .000",
+ "quoting.!@$%.000"
+ );
+ }
+}
+
+
+
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java
new file mode 100644
index 0000000000..b823690002
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.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.server.security.acl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.qpid.AMQConnectionClosedException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.test.utils.JMXTestUtils;
+
+/**
+ * Tests that ACL entries that apply to AMQP objects also apply when those objects are accessed via JMX.
+ */
+public class ExternalACLJMXTest extends AbstractACLTestCase
+{
+ private JMXTestUtils _jmx;
+
+ private static final String QUEUE_NAME = "kipper";
+ private static final String EXCHANGE_NAME = "amq.kipper";
+
+ @Override
+ public String getConfig()
+ {
+ return "config-systests-aclv2.xml";
+ }
+
+ @Override
+ public List<String> getHostList()
+ {
+ return Arrays.asList("test");
+ }
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _jmx = new JMXTestUtils(this, "admin", "admin");
+ _jmx.setUp();
+ super.setUp();
+ _jmx.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmx.close();
+ super.tearDown();
+ }
+
+ // test-externalacljmx.txt
+ // create queue owner=client # success
+ public void testCreateClientQueueSuccess() throws Exception
+ {
+ //Queue Parameters
+ String queueOwner = "client";
+
+ _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
+ }
+
+ // test-externalacljmx.txt
+ // create queue owner=client # failure
+ public void testCreateServerQueueFailure() throws Exception
+ {
+ //Queue Parameters
+ String queueOwner = "server";
+
+ try
+ {
+ _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
+
+ fail("Queue create should fail");
+ }
+ catch (Exception e)
+ {
+ assertNotNull("Cause is not set", e.getCause());
+ assertEquals("Cause message incorrect",
+ "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ }
+ }
+
+ // no create queue acl in file # failure
+ public void testCreateQueueFailure() throws Exception
+ {
+ //Queue Parameters
+ String queueOwner = "guest";
+
+ try
+ {
+ _jmx.createQueue("test", QUEUE_NAME, queueOwner, true);
+
+ fail("Queue create should fail");
+ }
+ catch (Exception e)
+ {
+ assertNotNull("Cause is not set", e.getCause());
+ assertEquals("Cause message incorrect",
+ "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ }
+ }
+
+ // test-externalacljmx.txt
+ // allow create exchange name=amq.kipper.success
+ public void testCreateExchangeSuccess() throws Exception
+ {
+ _jmx.createExchange("test", EXCHANGE_NAME + ".success", "direct", true);
+ }
+
+ // test-externalacljmx.txt
+ // deny create exchange name=amq.kipper.failure
+ public void testCreateExchangeFailure() throws Exception
+ {
+ try
+ {
+ _jmx.createExchange("test", EXCHANGE_NAME + ".failure", "direct", true);
+
+ fail("Exchange create should fail");
+ }
+ catch (Exception e)
+ {
+ assertNotNull("Cause is not set", e.getCause());
+ assertEquals("Cause message incorrect",
+ "org.apache.qpid.AMQSecurityException: Permission denied: exchange-name 'amq.kipper.failure' [error code 403: access refused]", e.getCause().getMessage());
+ }
+ }
+
+ // test-externalacljmx.txt
+ // allow create exchange name=amq.kipper.success
+ // allow delete exchange name=amq.kipper.success
+ public void testDeleteExchangeSuccess() throws Exception
+ {
+ _jmx.createExchange("test", EXCHANGE_NAME + ".success", "direct", true);
+ _jmx.unregisterExchange("test", EXCHANGE_NAME + ".success");
+ }
+
+ // test-externalacljmx-deleteexchangefailure.txt
+ // allow create exchange name=amq.kipper.delete
+ // deny delete exchange name=amq.kipper.delete
+ public void testDeleteExchangeFailure() throws Exception
+ {
+ _jmx.createExchange("test", EXCHANGE_NAME + ".delete", "direct", true);
+ try
+ {
+ _jmx.unregisterExchange("test", EXCHANGE_NAME + ".delete");
+
+ fail("Exchange delete should fail");
+ }
+ catch (Exception e)
+ {
+ assertNotNull("Cause is not set", e.getCause());
+ assertEquals("Cause message incorrect",
+ "org.apache.qpid.AMQSecurityException: Permission denied [error code 403: access refused]", e.getCause().getMessage());
+ }
+ }
+
+ /**
+ * admin user has JMX right but not AMQP
+ */
+ public void setUpCreateQueueJMXRights() throws Exception
+ {
+ writeACLFile("test",
+ "ACL ALLOW admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
+ "ACL DENY admin CREATE QUEUE");
+ }
+
+ public void testCreateQueueJMXRights() throws Exception
+ {
+ try
+ {
+ _jmx.createQueue("test", QUEUE_NAME, "admin", true);
+
+ fail("Queue create should fail");
+ }
+ catch (Exception e)
+ {
+ assertNotNull("Cause is not set", e.getCause());
+ assertEquals("Cause message incorrect",
+ "org.apache.qpid.AMQSecurityException: Permission denied: queue-name 'kipper' [error code 403: access refused]", e.getCause().getMessage());
+ }
+ }
+
+ /**
+ * admin user has AMQP right but not JMX
+ */
+ public void setUpCreateQueueAMQPRights() throws Exception
+ {
+ writeACLFile("test",
+ "ACL DENY admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
+ "ACL ALLOW admin CREATE QUEUE");
+ }
+
+ public void testCreateQueueAMQPRights() throws Exception
+ {
+ try
+ {
+ _jmx.createQueue("test", QUEUE_NAME, "admin", true);
+
+ fail("Queue create should fail");
+ }
+ catch (Exception e)
+ {
+ assertEquals("Cause message incorrect", "Permission denied: Execute createNewQueue", e.getMessage());
+ }
+ }
+
+ /**
+ * admin has both JMX and AMQP rights
+ */
+ public void setUpCreateQueueJMXAMQPRights() throws Exception
+ {
+ writeACLFile("test",
+ "ACL ALLOW admin EXECUTE METHOD component=\"VirtualHost.VirtualHostManager\" name=\"createNewQueue\"",
+ "ACL ALLOW admin CREATE QUEUE");
+ }
+
+ public void testCreateQueueJMXAMQPRights() throws Exception
+ {
+ try
+ {
+ _jmx.createQueue("test", QUEUE_NAME, "admin", true);
+ }
+ catch (Exception e)
+ {
+ fail("Queue create should succeed: " + e.getCause().getMessage());
+ }
+ }
+}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
index f51cf24caa..4603cc1862 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
@@ -4,7 +4,7 @@
* 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
+* "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
@@ -14,14 +14,24 @@
* "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.
- *
- *
+ * under the License.
*/
-package org.apache.qpid.server.security.access;
+package org.apache.qpid.server.security.acl;
+
+import java.util.Arrays;
+import java.util.List;
-public interface Accessable
+public class ExternalACLTest extends SimpleACLTest
{
- void setAccessableName(String name);
- String getAccessableName();
+ @Override
+ public String getConfig()
+ {
+ return "config-systests-aclv2.xml";
+ }
+
+ @Override
+ public List<String> getHostList()
+ {
+ return Arrays.asList("test", "test2");
+ }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java
new file mode 100644
index 0000000000..290cbfdc14
--- /dev/null
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalAdminACLTest.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.acl;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.qpid.server.logging.management.LoggingManagementMBean;
+import org.apache.qpid.test.utils.JMXTestUtils;
+
+/**
+ * Tests that ACLs can be applied to mangement operations that do not correspond to a specific AMQP object.
+ *
+ * Theses tests use the logging component, exposed as the {@link LoggingManagementMBean}, to get and set properties.
+ */
+public class ExternalAdminACLTest extends AbstractACLTestCase
+{
+ private static final String CATEGORY_PRIORITY = "LogManMBeanTest.category.priority";
+ private static final String CATEGORY_LEVEL = "LogManMBeanTest.category.level";
+ private static final String LOGGER_LEVEL = "LogManMBeanTest.logger.level";
+
+ private static final String NEWLINE = System.getProperty("line.separator");
+
+ private JMXTestUtils _jmx;
+ private File _testConfigFile;
+
+ @Override
+ public String getConfig()
+ {
+ return "config-systests-aclv2.xml";
+ }
+
+ @Override
+ public List<String> getHostList()
+ {
+ return Arrays.asList("global");
+ }
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _testConfigFile = createTempTestLog4JConfig();
+
+ _jmx = new JMXTestUtils(this, "admin", "admin");
+ _jmx.setUp();
+ super.setUp();
+ _jmx.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmx.close();
+ super.tearDown();
+ }
+
+ private File createTempTestLog4JConfig()
+ {
+ File tmpFile = null;
+ try
+ {
+ tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp");
+ tmpFile.deleteOnExit();
+
+ FileWriter fstream = new FileWriter(tmpFile);
+ BufferedWriter writer = new BufferedWriter(fstream);
+
+ writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE);
+ writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE);
+
+ writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " +
+ "threshold=\"null\">"+NEWLINE);
+
+ writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE);
+ writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE);
+ writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE);
+ writer.write(" </layout>"+NEWLINE);
+ writer.write(" </appender>"+NEWLINE);
+
+ //Example of a 'category' with a 'priority'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_PRIORITY +"\">"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'category' with a 'level'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_LEVEL +"\">"+NEWLINE);
+ writer.write(" <level value=\"warn\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'logger' with a 'level'
+ writer.write(" <logger additivity=\"true\" name=\"" + LOGGER_LEVEL + "\">"+NEWLINE);
+ writer.write(" <level value=\"error\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </logger>"+NEWLINE);
+
+ //'root' logger
+ writer.write(" <root>"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </root>"+NEWLINE);
+
+ writer.write("</log4j:configuration>"+NEWLINE);
+
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test log4j configuration");
+ }
+
+ return tmpFile;
+ }
+
+ public void testGetAllLoggerLevels() throws Exception
+ {
+ String[] levels = _jmx.getAvailableLoggerLevels();
+ for (int i = 0; i < levels.length; i++)
+ {
+ System.out.println(levels[i]);
+ }
+ assertEquals("Got incorrect number of log levels", 9, levels.length);
+ }
+
+ public void testGetAllLoggerLevelsDenied() throws Exception
+ {
+ try
+ {
+ _jmx.getAvailableLoggerLevels();
+ fail("Got list of log levels");
+ }
+ catch (Exception e)
+ {
+ // Exception throws
+ e.printStackTrace();
+ assertEquals("Permission denied: Access getAvailableLoggerLevels", e.getMessage());
+ }
+ }
+
+ public void testChangeLoggerLevel() throws Exception
+ {
+ String oldLevel = _jmx.getRuntimeRootLoggerLevel();
+ System.out.println("old level = " + oldLevel);
+ _jmx.setRuntimeRootLoggerLevel("DEBUG");
+ String newLevel = _jmx.getRuntimeRootLoggerLevel();
+ System.out.println("new level = " + newLevel);
+ assertEquals("Logging level was not changed", "DEBUG", newLevel);
+ }
+
+ public void testChangeLoggerLevelDenied() throws Exception
+ {
+ try
+ {
+ _jmx.setRuntimeRootLoggerLevel("DEBUG");
+ fail("Logging level was changed");
+ }
+ catch (Exception e)
+ {
+ assertEquals("Permission denied: Update setRuntimeRootLoggerLevel", e.getMessage());
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
index 08fc047533..fc9b07eadd 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/acl/SimpleACLTest.java
@@ -4,7 +4,7 @@
* 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
+ * "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
@@ -15,28 +15,13 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
- *
*/
-
package org.apache.qpid.server.security.acl;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQConnectionFailureException;
-import org.apache.qpid.client.AMQAuthenticationException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.jms.ConnectionListener;
-import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.url.URLSyntaxException;
+import java.io.IOException;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
-import javax.jms.ExceptionListener;
import javax.jms.IllegalStateException;
import javax.jms.JMSException;
import javax.jms.Message;
@@ -45,71 +30,45 @@ import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
import javax.naming.NamingException;
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class SimpleACLTest extends QpidTestCase implements ConnectionListener
-{
- public void setUp() throws Exception
- {
- //Performing setUp here would result in a broker with the default ACL test config
-
- //Each test now calls the private setUpACLTest to allow them to make
- //individual customisations to the base ACL settings
- }
-
- public void tearDown() throws Exception
- {
- try
- {
- super.tearDown();
- }
- catch (JMSException e)
- {
- //we're throwing this away as it can happen in this test as the state manager remembers exceptions
- //that we provoked with authentication failures, where the test passes - we can ignore on con close
- }
- }
-
- private void setUpACLTest() throws Exception
- {
- final String QPID_HOME = System.getProperty("QPID_HOME");
-
- if (QPID_HOME == null)
- {
- fail("QPID_HOME not set");
- }
-
- // Initialise ACLs.
- _configFile = new File(QPID_HOME, "etc/config-systests-acl.xml");
-
- super.setUp();
- }
-
- public String createConnectionString(String username, String password)
- {
-
- return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + getBroker() + "?retries='0''";
- }
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.url.URLSyntaxException;
+/**
+ * Basic access control list tests.
+ *
+ * These tests require an access control security plugin to be configured in the broker, and carry out various broker
+ * operations that will succeed or fail depending on the user and virtual host. See the {@code config-systests-acl-setup.xml}
+ * configuration file for the {@link SimpleXML} version of the ACLs used by the Java broker only, or the various {@code .txt}
+ * files in the system tests directory for the external version 3 ACL files used by both the Java and C++ brokers.
+ * <p>
+ * This class can be extended and the {@link #getConfig()} method overridden to run the same tests with a different type
+ * of access control mechanism. Extension classes should differ only in the configuration file used, but extra tests can be
+ * added that are specific to a particular configuration.
+ * <p>
+ * The tests perform basic AMQP operations like creating queues or excahnges and publishing and consuming messages, using
+ * JMS to contact the broker.
+ *
+ * @see ExternalACLTest
+ */
+public class SimpleACLTest extends AbstractACLTestCase
+{
public void testAccessAuthorized() throws AMQException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("client", "guest");
-
- Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
-
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
conn.start();
//Do something to show connection is active.
- sesh.rollback();
+ sess.rollback();
conn.close();
}
@@ -125,8 +84,6 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
//is unable to perform actions such as connecting (and by extension, creating a queue, and consuming
//from a queue etc). In order to test the vhost-wide 'access' ACL right, the 'guest' user has been given
//this right in the 'test2' vhost.
-
- setUpACLTest();
try
{
@@ -141,16 +98,16 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
conn.start();
//create Queues and consumers for each
- Queue namedQueue = sesh.createQueue("vhostAccessCreatedQueue" + getTestQueueName());
- Queue tempQueue = sesh.createTemporaryQueue();
- MessageConsumer consumer = sesh.createConsumer(namedQueue);
- MessageConsumer tempConsumer = sesh.createConsumer(tempQueue);
+ Queue namedQueue = sess.createQueue("vhostAccessCreatedQueue" + getTestQueueName());
+ Queue tempQueue = sess.createTemporaryQueue();
+ MessageConsumer consumer = sess.createConsumer(namedQueue);
+ MessageConsumer tempConsumer = sess.createConsumer(tempQueue);
//send a message to each queue (also causing an exchange declare)
- MessageProducer sender = ((AMQSession)sesh).createProducer(null);
- ((org.apache.qpid.jms.MessageProducer) sender).send(namedQueue, sesh.createTextMessage("test"),
+ MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null);
+ ((org.apache.qpid.jms.MessageProducer) sender).send(namedQueue, sess.createTextMessage("test"),
DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true);
- ((org.apache.qpid.jms.MessageProducer) sender).send(tempQueue, sesh.createTextMessage("test"),
+ ((org.apache.qpid.jms.MessageProducer) sender).send(tempQueue, sess.createTextMessage("test"),
DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true);
//consume the messages from the queues
@@ -165,47 +122,93 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
}
+ // XXX one
public void testAccessNoRights() throws Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("guest", "guest");
-
- //Attempt to do do things to test connection.
- Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
+ Connection conn = getConnection("test", "guest", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
conn.start();
- sesh.rollback();
-
+ sess.rollback();
+
fail("Connection was created.");
}
- catch (JMSException jmse)
+ catch (JMSException e)
{
- Throwable linkedException = jmse.getLinkedException();
- assertNotNull("Cause was null", linkedException);
+ // XXX JMSException -> linkedException -> cause = AMQException.403
+ Exception linkedException = e.getLinkedException();
+ assertNotNull("There was no linked exception", linkedException);
+ Throwable cause = linkedException.getCause();
+ assertNotNull("Cause was null", cause);
+ assertTrue("Wrong linked exception type",cause instanceof AMQException);
+ assertEquals("Incorrect error code received", 403, ((AMQException) cause).getErrorCode().getCode());
+ }
+ }
+
+ public void testClientDeleteQueueSuccess() throws Exception
+ {
+ try
+ {
+ Connection conn = getConnection("test", "client", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
- assertEquals("Linked Exception was wrong type", AMQConnectionFailureException.class, linkedException.getClass());
+ // create kipper
+ Topic kipper = sess.createTopic("kipper");
+ TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
- Throwable cause = linkedException.getCause();
- assertEquals("Cause was wrong type", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
+ subscriber.close();
+ sess.unsubscribe("kipper");
+
+ //Do something to show connection is active.
+ sess.rollback();
+ conn.close();
+ }
+ catch (Exception e)
+ {
+ fail("Test failed due to:" + e.getMessage());
+ }
+ }
+
+ // XXX two
+ public void testServerDeleteQueueFailure() throws Exception
+ {
+ try
+ {
+ Connection conn = getConnection("test", "server", "guest");
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
+ conn.start();
+
+ // create kipper
+ Topic kipper = sess.createTopic("kipper");
+ TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
+
+ subscriber.close();
+ sess.unsubscribe("kipper");
+
+ //Do something to show connection is active.
+ sess.rollback();
+ conn.close();
+ }
+ catch (JMSException e)
+ {
+ // XXX JMSException -> linedException = AMQException.403
+ check403Exception(e.getLinkedException());
}
}
public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- sesh.createConsumer(sesh.createTemporaryQueue());
+ sess.createConsumer(sess.createTemporaryQueue());
conn.close();
}
@@ -217,64 +220,38 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testClientConsumeFromNamedQueueInvalid() throws NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("client", "guest");
-
- //Prevent Failover
- ((AMQConnection) conn).setConnectionListener(this);
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- sesh.createConsumer(sesh.createQueue("IllegalQueue"));
+ sess.createConsumer(sess.createQueue("IllegalQueue"));
+
+ conn.close();
+
fail("Test failed as consumer was created.");
- //conn will be automatically closed
}
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- assertNotNull("There was no liked exception", cause);
- assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e.getLinkedException());
}
}
public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
//Create Temporary Queue - can't use the createTempQueue as QueueName is null.
- ((AMQSession) sesh).createQueue(new AMQShortString("doesnt_matter_as_autodelete_means_tmp"),
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("doesnt_matter_as_autodelete_means_tmp"),
true, false, false);
conn.close();
@@ -287,66 +264,43 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testClientCreateNamedQueue() throws NamingException, JMSException, AMQException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
//Create a Named Queue
- ((AMQSession) sesh).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
-
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
+
fail("Test failed as Queue creation succeded.");
//conn will be automatically closed
}
- catch (AMQAuthenticationException amqe)
+ catch (AMQException e)
{
- amqe.printStackTrace();
- assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) amqe).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ // XXX AMQException.403
+ check403Exception(e);
}
}
public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("client", "guest");
-
- ((AMQConnection) conn).setConnectionListener(this);
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
+ Session sess = conn.createSession(true, Session.SESSION_TRANSACTED);
conn.start();
- MessageProducer sender = sesh.createProducer(sesh.createQueue("example.RequestQueue"));
+ MessageProducer sender = sess.createProducer(sess.createQueue("example.RequestQueue"));
- sender.send(sesh.createTextMessage("test"));
+ sender.send(sess.createTextMessage("test"));
//Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
- sesh.commit();
+ sess.commit();
conn.close();
}
@@ -358,26 +312,22 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("client", "guest");
+ Connection conn = getConnection("test", "client", "guest");
- ((AMQConnection) conn).setConnectionListener(this);
-
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- MessageProducer sender = ((AMQSession) sesh).createProducer(null);
+ MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null);
- Queue queue = sesh.createQueue("example.RequestQueue");
+ Queue queue = sess.createQueue("example.RequestQueue");
// Send a message that we will wait to be sent, this should give the broker time to process the msg
// before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
// queue existence.
- ((org.apache.qpid.jms.MessageProducer) sender).send(queue, sesh.createTextMessage("test"),
+ ((org.apache.qpid.jms.MessageProducer) sender).send(queue, sess.createTextMessage("test"),
DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true);
conn.close();
@@ -390,31 +340,15 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("client", "guest");
-
- ((AMQConnection) conn).setConnectionListener(this);
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "client", "guest");
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- MessageProducer sender = ((AMQSession) session).createProducer(null);
+ MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null);
Queue queue = session.createQueue("Invalid");
@@ -435,53 +369,27 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
fail("Close is not expected to succeed.");
}
+ catch (IllegalStateException e)
+ {
+ _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error.");
+ }
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- if (cause == null)
- {
- e.printStackTrace(System.out);
- if (e instanceof IllegalStateException)
- {
- System.out.println("QPID-2345: Session became closed and we got that error rather than the authentication error.");
- }
- else
- {
- fail("JMS Exception of did not have cause.:" + e.getMessage());
- }
- }
- else
- {
- if (!(cause instanceof AMQAuthenticationException))
- {
- e.printStackTrace();
- }
- assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for connection to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
- }
-
+ check403Exception(e.getLinkedException());
}
}
public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("server", "guest");
+ Connection conn = getConnection("test", "server", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- sesh.createConsumer(sesh.createQueue("example.RequestQueue"));
+ sess.createConsumer(sess.createQueue("example.RequestQueue"));
conn.close();
}
@@ -493,116 +401,58 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("client", "guest");
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "client", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- sesh.createConsumer(sesh.createQueue("Invalid"));
+ sess.createConsumer(sess.createQueue("Invalid"));
+
+ conn.close();
fail("Test failed as consumer was created.");
- //conn will be automatically closed
}
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- assertNotNull("There was no liked exception", cause);
- assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e.getLinkedException());
}
}
public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("server", "guest");
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "server", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
- sesh.createConsumer(sesh.createTemporaryQueue());
+ sess.createConsumer(sess.createTemporaryQueue());
+
fail("Test failed as consumer was created.");
- //conn will be automatically closed
}
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- assertNotNull("There was no liked exception", cause);
- assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e.getLinkedException());
}
}
- @Override
- public Connection getConnection(String username, String password) throws NamingException, JMSException
- {
- AMQConnection connection = (AMQConnection) super.getConnection(username, password);
-
- //Prevent Failover
- connection.setConnectionListener(this);
-
- return (Connection) connection;
- }
-
public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException, Exception
{
- setUpACLTest();
-
try
{
- Connection conn = getConnection("server", "guest");
+ Connection conn = getConnection("test", "server", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
//Create Temporary Queue
- ((AMQSession) sesh).createQueue(new AMQShortString("example.RequestQueue"), false, false, false);
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("example.RequestQueue"), false, false, false);
conn.close();
}
@@ -614,65 +464,30 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("server", "guest");
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "server", "guest");
- Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
//Create a Named Queue
- ((AMQSession) sesh).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
+ ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
fail("Test failed as creation succeded.");
- //conn will be automatically closed
}
- catch (AMQAuthenticationException amqe)
+ catch (Exception e)
{
- assertEquals("Incorrect error code thrown", 403, amqe.getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e);
}
}
public void testServerCreateTemporaryQueueInvalid() throws NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
- Connection conn = getConnection("server", "guest");
try
{
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
-
+ Connection conn = getConnection("test", "server", "guest");
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
@@ -683,69 +498,28 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
}
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- assertNotNull("There was no liked exception", cause);
- assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code received", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
- }
- finally
- {
- try
- {
- conn.close();
- }
- catch (Exception e)
- {
- // This normally fails because we are denied
- }
+ check403Exception(e.getLinkedException());
}
}
-
+
public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
- Connection connection = null;
try
{
- connection = getConnection("server", "guest");
-
- connection.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection connection = getConnection("test", "server", "guest");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
- ((AMQSession) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
+ ((AMQSession<?, ?>) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
true, false, false);
fail("Test failed as creation succeded.");
- //connection will be automatically closed
}
- catch (AMQAuthenticationException amqe)
+ catch (Exception e)
{
- assertEquals("Incorrect error code thrown", 403, amqe.getErrorCode().getCode());
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e);
}
}
@@ -759,12 +533,8 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
*/
public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
- setUpACLTest();
-
//Set up the Server
- Connection serverConnection = getConnection("server", "guest");
-
- ((AMQConnection) serverConnection).setConnectionListener(this);
+ Connection serverConnection = getConnection("test", "server", "guest");
Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED);
@@ -775,7 +545,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
serverConnection.start();
//Set up the consumer
- Connection clientConnection = getConnection("client", "guest");
+ Connection clientConnection = getConnection("test", "client", "guest");
//Send a test mesage
Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
@@ -841,23 +611,9 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception
{
- setUpACLTest();
-
- //QPID-2081: use a latch to sync on exception causing connection close, to work
- //around the connection close race during tearDown() causing sporadic failures
- final CountDownLatch exceptionReceived = new CountDownLatch(1);
-
try
{
- Connection conn = getConnection("server", "guest");
-
- conn.setExceptionListener(new ExceptionListener()
- {
- public void onException(JMSException e)
- {
- exceptionReceived.countDown();
- }
- });
+ Connection conn = getConnection("test", "server", "guest");
((AMQConnection) conn).setConnectionListener(this);
@@ -865,7 +621,7 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
conn.start();
- MessageProducer sender = ((AMQSession) session).createProducer(null);
+ MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null);
Queue queue = session.createQueue("Invalid");
@@ -886,63 +642,13 @@ public class SimpleACLTest extends QpidTestCase implements ConnectionListener
fail("Close is not expected to succeed.");
}
+ catch (IllegalStateException e)
+ {
+ _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error.");
+ }
catch (JMSException e)
{
- Throwable cause = e.getLinkedException();
-
- if (cause == null)
- {
- e.printStackTrace(System.out);
- if (e instanceof IllegalStateException)
- {
- System.out.println("QPID-2345: Session became closed and we got that error rather than the authentication error.");
- }
- else
- {
- fail("JMS Exception of did not have cause.:" + e.getMessage());
- }
- }
- else if (!(cause instanceof AMQAuthenticationException))
- {
- cause.printStackTrace(System.out);
- assertEquals("Incorrect exception", IllegalStateException.class, cause.getClass());
- System.out.println("QPID-2345: Session became closed and we got that error rather than the authentication error.");
- }
- else
- {
- assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
- assertEquals("Incorrect error code thrown", 403, ((AMQAuthenticationException) cause).getErrorCode().getCode());
- }
-
- //use the latch to ensure the control thread waits long enough for the exception thread
- //to have done enough to mark the connection closed before teardown commences
- assertTrue("Timed out waiting for conneciton to report close",
- exceptionReceived.await(2, TimeUnit.SECONDS));
+ check403Exception(e.getLinkedException());
}
}
-
- // Connection Listener Interface - Used here to block failover
-
- public void bytesSent(long count)
- {
- }
-
- public void bytesReceived(long count)
- {
- }
-
- public boolean preFailover(boolean redirect)
- {
- //Prevent failover.
- return false;
- }
-
- public boolean preResubscribe()
- {
- return false;
- }
-
- public void failoverComplete()
- {
- }
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java b/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java
index ec9a297047..874a0c37e2 100644
--- a/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/server/security/firewall/FirewallConfigTest.java
@@ -1,6 +1,4 @@
-package org.apache.qpid.server.security.firewall;
/*
- *
* 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
@@ -17,9 +15,8 @@ package org.apache.qpid.server.security.firewall;
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
*/
-
+package org.apache.qpid.server.security.firewall;
import java.io.File;
import java.io.FileWriter;
@@ -85,7 +82,7 @@ public class FirewallConfigTest extends QpidTestCase
}
out.close();
}
-
+
public void testVhostAllowBrokerDeny() throws Exception
{
if (_broker.equals(VM))
@@ -104,8 +101,7 @@ public class FirewallConfigTest extends QpidTestCase
{
//Try to get a connection to the 'test2' vhost
//This is expected to fail as it is denied at the broker level
- conn = getConnection(new AMQConnectionURL(
- "amqp://username:password@clientid/test2?brokerlist='" + getBroker() + "'"));
+ conn = getConnection(new AMQConnectionURL("amqp://username:password@clientid/test2?brokerlist='" + getBroker() + "'"));
fail("We expected the connection to fail");
}
catch (JMSException e)
@@ -235,7 +231,7 @@ public class FirewallConfigTest extends QpidTestCase
}
);
}
-
+
public void testDenyOnReloadInVhost() throws Exception
{
testDeny(true, new Runnable() {
@@ -259,7 +255,7 @@ public class FirewallConfigTest extends QpidTestCase
{
testFirewall(true, inVhost, restartOrReload);
}
-
+
/*
* Check we can get a connection
*/
@@ -278,7 +274,7 @@ public class FirewallConfigTest extends QpidTestCase
return conn != null;
}
-
+
private void testFirewall(boolean initial, boolean inVhost, Runnable restartOrReload) throws Exception
{
if (_broker.equals(VM))
diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
index b0484e20d7..a6b7e20a42 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java
@@ -147,13 +147,13 @@ public class TopicSessionTest extends QpidTestCase
public void testUnsubscriptionAfterConnectionClose() throws Exception
{
- AMQConnection con1 = (AMQConnection) getConnection("guest", "guest", "clientid");
+ AMQConnection con1 = (AMQConnection) getClientConnection("guest", "guest", "clientid");
AMQTopic topic = new AMQTopic(con1, "MyTopic3");
TopicSession session1 = con1.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session1.createPublisher(topic);
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "clientid");
+ AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid");
TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0");
@@ -167,7 +167,7 @@ public class TopicSessionTest extends QpidTestCase
con2.close();
publisher.publish(session1.createTextMessage("Hello2"));
session1.commit();
- con2 = (AMQConnection) getConnection("guest", "guest", "clientid");
+ con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid");
session2 = con2.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE);
sub = session2.createDurableSubscriber(topic, "subscription0");
con2.start();
@@ -367,7 +367,7 @@ public class TopicSessionTest extends QpidTestCase
m = (TextMessage) noLocal.receive(100);
assertNull(m);
- AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "foo");
+ AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "foo");
TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE);
TopicPublisher publisher2 = session2.createPublisher(topic);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
index 9b786a5c62..18e373b8d7 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -20,23 +20,28 @@
*/
package org.apache.qpid.test.utils;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.qpid.commands.objects.AllObjects;
-import org.apache.qpid.management.common.JMXConnnectionFactory;
-import org.apache.qpid.management.common.mbeans.ManagedBroker;
-import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import java.io.IOException;
+import java.util.Set;
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
+import javax.management.MalformedObjectNameException;
import javax.management.remote.JMXConnector;
-import java.io.IOException;
-import java.util.Set;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.commands.objects.AllObjects;
+import org.apache.qpid.management.common.JMXConnnectionFactory;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
+import org.apache.qpid.management.common.mbeans.UserManagement;
/**
- *
+ * JMX access for tests.
*/
public class JMXTestUtils
{
@@ -61,9 +66,8 @@ public class JMXTestUtils
public void open() throws Exception
{
- _jmxc = JMXConnnectionFactory.getJMXConnection(
- 5000, "127.0.0.1",
- _test.getManagementPort(_test.getPort()), USER, PASSWORD);
+ _jmxc = JMXConnnectionFactory.getJMXConnection(5000, "127.0.0.1",
+ _test.getManagementPort(_test.getPort()), USER, PASSWORD);
_mbsc = _jmxc.getMBeanServerConnection();
}
@@ -77,12 +81,11 @@ public class JMXTestUtils
}
/**
- * Create a non-durable test exchange with the current test name
+ * Create a non-durable exchange with the requested name
*
- * @throws javax.management.JMException - is thrown if a exchange with this testName already exists
- * @throws java.io.IOException - if there is a problem with the JMX Connection
- * @throws javax.management.MBeanException
- * - if there is another problem creating the exchange
+ * @throws JMException if a exchange with this name already exists
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException if there is another problem creating the exchange
*/
public void createExchange(String virtualHostName, String name, String type, boolean durable)
throws JMException, IOException, MBeanException
@@ -96,24 +99,134 @@ public class JMXTestUtils
* Create a non-durable queue (with no owner) that is named after the
* creating test.
*
- * @throws JMException - is thrown if a queue with this testName already exists
- * @throws IOException - if there is a problem with the JMX Connection
+ * @throws JMException if a queue with this name already exists
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException if there is another problem creating the exchange
*/
public void createQueue(String virtualHostName, String name, String owner, boolean durable)
- throws JMException, IOException
+ throws JMException, MBeanException, IOException
{
ManagedBroker managedBroker = getManagedBroker(virtualHostName);
managedBroker.createNewQueue(name, owner, durable);
}
+
+ /**
+ * Unregisters all the channels, queuebindings etc and unregisters
+ * this exchange from managed objects.
+ *
+ * @throws JMException if an exchange with this name does not exist
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException if there is another problem creating the exchange
+ */
+ public void unregisterExchange(String virtualHostName, String exchange)
+ throws IOException, JMException, MBeanException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+
+ managedBroker.unregisterExchange(exchange);
+ }
+
+ /**
+ * Unregisters the Queue bindings, removes the subscriptions and unregisters
+ * from the managed objects.
+ *
+ * @throws JMException if a queue with this name does not exist
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException if there is another problem creating the exchange
+ */
+ public void deleteQueue(String virtualHostName, String queueName)
+ throws IOException, JMException, MBeanException
+ {
+ ManagedBroker managedBroker = getManagedBroker(virtualHostName);
+ managedBroker.deleteQueue(queueName);
+ }
+
+ /**
+ * Sets the logging level.
+ *
+ * @throws JMException
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException
+ */
+ public void setRuntimeLoggerLevel(String logger, String level)
+ throws IOException, JMException, MBeanException
+ {
+ LoggingManagement loggingManagement = getLoggingManagement();
+
+ loggingManagement.setRuntimeLoggerLevel(logger, level);
+ }
+
+ /**
+ * Reload logging config file.
+ *
+ * @throws JMException
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException
+ */
+ public void reloadConfigFile()
+ throws IOException, JMException, MBeanException
+ {
+ LoggingManagement loggingManagement = getLoggingManagement();
+
+ loggingManagement.reloadConfigFile();
+ }
+
+ /**
+ * Get list of available logger levels.
+ *
+ * @throws JMException
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException
+ */
+ public String[] getAvailableLoggerLevels()
+ throws IOException, JMException, MBeanException
+ {
+ LoggingManagement loggingManagement = getLoggingManagement();
+
+ return loggingManagement.getAvailableLoggerLevels();
+ }
+
+ /**
+ * Set root logger level.
+ *
+ * @throws JMException
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException
+ */
+ public void setRuntimeRootLoggerLevel(String level)
+ throws IOException, JMException, MBeanException
+ {
+ LoggingManagement loggingManagement = getLoggingManagement();
+
+ loggingManagement.setRuntimeRootLoggerLevel(level);
+ }
+
+ /**
+ * Get root logger level.
+ *
+ * @throws JMException
+ * @throws IOException if there is a problem with the JMX Connection
+ * @throws MBeanException
+ */
+ public String getRuntimeRootLoggerLevel()
+ throws IOException, JMException, MBeanException
+ {
+ LoggingManagement loggingManagement = getLoggingManagement();
+
+ return loggingManagement.getRuntimeRootLoggerLevel();
+ }
+
/**
- * Retrive the ObjectName for the test Virtualhost.
+ * Retrive the ObjectName for a Virtualhost.
*
- * This is then use to create aproxy to the ManagedBroker MBean.
+ * This is then used to create a proxy to the ManagedBroker MBean.
*
- * @return the ObjectName for the 'test' VirtualHost.
+ * @param virtualHostName the VirtualHost to retrieve
+ * @return the ObjectName for the VirtualHost
*/
+ @SuppressWarnings("static-access")
public ObjectName getVirtualHostManagerObjectName(String vhostName)
{
// Get the name of the test manager
@@ -126,18 +239,21 @@ public class JMXTestUtils
_test.assertEquals("Incorrect number test vhosts returned", 1, objectNames.size());
// We have verified we have only one value in objectNames so return it
- return objectNames.iterator().next();
+ ObjectName objectName = objectNames.iterator().next();
+ _test.getLogger().info("Loading: " + objectName);
+ return objectName;
}
/**
- * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ * Retrive the ObjectName for the given Queue on a Virtualhost.
*
- * This is then use to create aproxy to the ManagedExchange MBean.
+ * This is then used to create a proxy to the ManagedQueue MBean.
*
- * @param queue The exchange to retireve e.g. 'direct'
- *
- * @return the ObjectName for the given exchange on the test VirtualHost.
+ * @param virtualHostName the VirtualHost the Queue is on
+ * @param queue The Queue to retireve
+ * @return the ObjectName for the given queue on the VirtualHost
*/
+ @SuppressWarnings("static-access")
public ObjectName getQueueObjectName(String virtualHostName, String queue)
{
// Get the name of the test manager
@@ -151,19 +267,21 @@ public class JMXTestUtils
"' returned", 1, objectNames.size());
// We have verified we have only one value in objectNames so return it
- return objectNames.iterator().next();
+ ObjectName objectName = objectNames.iterator().next();
+ _test.getLogger().info("Loading: " + objectName);
+ return objectName;
}
/**
- * Retrive the ObjectName for the given Exchange on the test Virtualhost.
+ * Retrive the ObjectName for the given Exchange on a VirtualHost.
*
- * This is then use to create aproxy to the ManagedExchange MBean.
+ * This is then used to create a proxy to the ManagedExchange MBean.
*
- * @param virtualHostName
- * @param exchange The exchange to retireve e.g. 'direct'
- *
- * @return the ObjectName for the given exchange on the test VirtualHost.
+ * @param virtualHostName the VirtualHost the Exchange is on
+ * @param exchange the Exchange to retireve e.g. 'direct'
+ * @return the ObjectName for the given Exchange on the VirtualHost
*/
+ @SuppressWarnings("static-access")
public ObjectName getExchangeObjectName(String virtualHostName, String exchange)
{
// Get the name of the test manager
@@ -173,13 +291,15 @@ public class JMXTestUtils
Set<ObjectName> objectNames = allObject.returnObjects();
_test.assertNotNull("Null ObjectName Set returned", objectNames);
- _test.assertEquals("Incorrect number of exchange with name '" + exchange +
- "' returned", 1, objectNames.size());
+ _test.assertEquals("Incorrect number of exchange with name '" + exchange + "' returned", 1, objectNames.size());
// We have verified we have only one value in objectNames so return it
- return objectNames.iterator().next();
+ ObjectName objectName = objectNames.iterator().next();
+ _test.getLogger().info("Loading: " + objectName);
+ return objectName;
}
+ @SuppressWarnings("static-access")
public <T> T getManagedObject(Class<T> managedClass, String queryString)
{
AllObjects allObject = new AllObjects(_mbsc);
@@ -191,25 +311,41 @@ public class JMXTestUtils
_test.assertEquals("More than one " + managedClass + " returned", 1, objectNames.size());
ObjectName objectName = objectNames.iterator().next();
-
+ _test.getLogger().info("Loading: " + objectName);
return getManagedObject(managedClass, objectName);
}
public <T> T getManagedObject(Class<T> managedClass, ObjectName objectName)
{
- return MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, objectName, managedClass, false);
+ return MBeanServerInvocationHandler.newProxyInstance(_mbsc, objectName, managedClass, false);
}
public ManagedBroker getManagedBroker(String virtualHost)
{
- return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost).toString());
+ return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost));
}
-
+
public ManagedExchange getManagedExchange(String exchangeName)
{
- return MBeanServerInvocationHandler.
- newProxyInstance(_mbsc, getExchangeObjectName("test", exchangeName),
- ManagedExchange.class, false);
+ ObjectName objectName = getExchangeObjectName("test", exchangeName);
+ return MBeanServerInvocationHandler.newProxyInstance(_mbsc, objectName, ManagedExchange.class, false);
+ }
+
+ public LoggingManagement getLoggingManagement() throws MalformedObjectNameException
+ {
+ ObjectName objectName = new ObjectName("org.apache.qpid:type=LoggingManagement,name=LoggingManagement");
+ return getManagedObject(LoggingManagement.class, objectName);
+ }
+
+ public ConfigurationManagement getConfigurationManagement() throws MalformedObjectNameException
+ {
+ ObjectName objectName = new ObjectName("org.apache.qpid:type=ConfigurationManagement,name=ConfigurationManagement");
+ return getManagedObject(ConfigurationManagement.class, objectName);
+ }
+
+ public UserManagement getUserManagement() throws MalformedObjectNameException
+ {
+ ObjectName objectName = new ObjectName("org.apache.qpid:type=UserManagement,name=UserManagement");
+ return getManagedObject(UserManagement.class, objectName);
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
index 5b7670eaa3..57a7659782 100644
--- a/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -56,6 +56,7 @@ import junit.framework.TestResult;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
@@ -71,26 +72,23 @@ import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
import org.apache.qpid.server.store.DerbyMessageStore;
import org.apache.qpid.url.URLSyntaxException;
import org.apache.qpid.util.LogMonitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
- *
- *
+ * Qpid base class for system testing test cases.
*/
public class QpidTestCase extends TestCase
{
protected final String QpidHome = System.getProperty("QPID_HOME");
protected File _configFile = new File(System.getProperty("broker.config"));
- protected static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class);
+ protected static final Logger _logger = Logger.getLogger(QpidTestCase.class);
protected static final int LOGMONITOR_TIMEOUT = 5000;
protected long RECEIVE_TIMEOUT = 1000l;
private Map<String, String> _propertiesSetForTestOnly = new HashMap<String, String>();
private Map<String, String> _propertiesSetForBroker = new HashMap<String, String>();
- private Map<org.apache.log4j.Logger, Level> _loggerLevelSetForTest = new HashMap<org.apache.log4j.Logger, Level>();
+ private Map<Logger, Level> _loggerLevelSetForTest = new HashMap<Logger, Level>();
private XMLConfiguration _testConfiguration = new XMLConfiguration();
private XMLConfiguration _testVirtualhosts = new XMLConfiguration();
@@ -98,7 +96,6 @@ public class QpidTestCase extends TestCase
protected static final String INDEX = "index";
protected static final String CONTENT = "content";
-
/**
* Some tests are excluded when the property test.excludes is set to true.
* An exclusion list is either a file (prop test.excludesfile) which contains one test name
@@ -198,10 +195,10 @@ public class QpidTestCase extends TestCase
private String _brokerClean = System.getProperty(BROKER_CLEAN, null);
private Boolean _brokerCleanBetweenTests = Boolean.getBoolean(BROKER_CLEAN_BETWEEN_TESTS);
private String _brokerVersion = System.getProperty(BROKER_VERSION, VERSION_08);
- private String _output = System.getProperty(TEST_OUTPUT);
+ protected String _output = System.getProperty(TEST_OUTPUT);
protected Boolean _brokerPersistent = Boolean.getBoolean(BROKER_PERSITENT);
- private static String _brokerLogPrefix = System.getProperty(BROKER_LOG_PREFIX,"BROKER: ");
+ protected static String _brokerLogPrefix = System.getProperty(BROKER_LOG_PREFIX,"BROKER: ");
protected static boolean _interleaveBrokerLog = Boolean.getBoolean(BROKER_LOG_INTERLEAVE);
protected File _outputFile;
@@ -210,10 +207,10 @@ public class QpidTestCase extends TestCase
protected Map<Integer, Process> _brokers = new HashMap<Integer, Process>();
- private InitialContext _initialContext;
+ protected InitialContext _initialContext;
protected AMQConnectionFactory _connectionFactory;
- private String _testName;
+ protected String _testName;
// the connections created for a given test
protected List<Connection> _connections = new ArrayList<Connection>();
@@ -248,6 +245,11 @@ public class QpidTestCase extends TestCase
{
this("QpidTestCase");
}
+
+ public Logger getLogger()
+ {
+ return QpidTestCase._logger;
+ }
public void runBare() throws Throwable
{
@@ -287,6 +289,11 @@ public class QpidTestCase extends TestCase
{
super.runBare();
}
+ catch (Exception e)
+ {
+ _logger.error("exception", e);
+ throw e;
+ }
finally
{
try
@@ -935,7 +942,7 @@ public class QpidTestCase extends TestCase
* @param logger the logger to change
* @param level the level to set
*/
- protected void setLoggerLevel(org.apache.log4j.Logger logger, Level level)
+ protected void setLoggerLevel(Logger logger, Level level)
{
assertNotNull("Cannot set level of null logger", logger);
assertNotNull("Cannot set Logger("+logger.getName()+") to null level.",level);
@@ -954,7 +961,7 @@ public class QpidTestCase extends TestCase
*/
protected void revertLoggingLevels()
{
- for (org.apache.log4j.Logger logger : _loggerLevelSetForTest.keySet())
+ for (Logger logger : _loggerLevelSetForTest.keySet())
{
logger.setLevel(_loggerLevelSetForTest.get(logger));
}
@@ -1079,7 +1086,8 @@ public class QpidTestCase extends TestCase
public Connection getConnection(ConnectionURL url) throws JMSException
{
- Connection connection = new AMQConnectionFactory(url).createConnection("guest", "guest");
+ _logger.info(url.getURL());
+ Connection connection = new AMQConnectionFactory(url).createConnection(url.getUsername(), url.getPassword());
_connections.add(connection);
@@ -1098,14 +1106,14 @@ public class QpidTestCase extends TestCase
*/
public Connection getConnection(String username, String password) throws JMSException, NamingException
{
- _logger.info("get Connection");
+ _logger.info("get connection");
Connection con = getConnectionFactory().createConnection(username, password);
//add the connection in the lis of connections
_connections.add(con);
return con;
}
- public Connection getConnection(String username, String password, String id) throws JMSException, URLSyntaxException, AMQException, NamingException
+ public Connection getClientConnection(String username, String password, String id) throws JMSException, URLSyntaxException, AMQException, NamingException
{
_logger.info("get Connection");
Connection con;
@@ -1382,10 +1390,19 @@ public class QpidTestCase extends TestCase
/*
* Sigh, this is going to get messy. grep for BRKR and the port number
*/
-
- Process p = Runtime.getRuntime().exec("/usr/bin/pgrep -f " + getPort(port));
+ String osName = System.getProperty("os.name");
+ boolean osx = osName.equals("Mac OS X");
+
+ String cmd = osx ? "/usr/sbin/lsof -i TCP:%d -Fp" : "/usr/bin/pgrep -f %d";
+ Process p = Runtime.getRuntime().exec(String.format(cmd, getPort(port)));
BufferedReader reader = new BufferedReader (new InputStreamReader(p.getInputStream()));
- String cmd = "/bin/kill -SIGHUP " + reader.readLine();
+ String pid = reader.readLine();
+ while (reader.ready())
+ {
+ pid = reader.readLine();
+ }
+
+ cmd = "/bin/kill -SIGHUP " + (osx ? pid.substring(1) : pid);
p = Runtime.getRuntime().exec(cmd);
LogMonitor _monitor = new LogMonitor(_outputFile);
diff --git a/java/test-profiles/CPPExcludes b/java/test-profiles/CPPExcludes
index c2983d8675..255c52c94d 100755
--- a/java/test-profiles/CPPExcludes
+++ b/java/test-profiles/CPPExcludes
@@ -1,9 +1,14 @@
org.apache.qpid.test.unit.client.channelclose.ChannelCloseTest#*
org.apache.qpid.client.ResetMessageListenerTest#*
+//These tests will not work until 0-10 exception halding is fixed
+org.apache.qpid.server.security.acl.*
+
//These tests are for the java broker
-org.apache.qpid.server.security.acl.SimpleACLTest#*
+org.apache.qpid.server.security.access.plugins.*
+org.apache.qpid.server.security.access.*
org.apache.qpid.server.security.firewall.FirewallConfigTest#*
+org.apache.qpid.server.security.firewall.FirewallConfigurationTest#*
org.apache.qpid.server.plugins.PluginTest#*
org.apache.qpid.server.BrokerStartupTest#*
diff --git a/java/test-profiles/JavaInVMExcludes b/java/test-profiles/JavaInVMExcludes
index 8d36ed6773..b81df15f1a 100644
--- a/java/test-profiles/JavaInVMExcludes
+++ b/java/test-profiles/JavaInVMExcludes
@@ -16,3 +16,6 @@ org.apache.qpid.test.unit.ack.RecoverTest#testAcknowledgePerConsumer
// related to QPID-2471. These are new test cases and fail with the Java broker.
org.apache.qpid.test.unit.ack.RecoverTest#testOderingWithAsyncConsumer
org.apache.qpid.test.unit.ack.RecoverTest#testOderingWithSyncConsumer
+
+//The VM broker does not export the logging management JMX MBean
+org.apache.qpid.server.security.acl.ExternalAdminACLTest#*