You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ro...@apache.org on 2010/05/31 18:03:44 UTC

svn commit: r949781 [2/5] - in /qpid/trunk/qpid/java: broker/etc/ broker/src/main/java/org/apache/qpid/qmf/ broker/src/main/java/org/apache/qpid/server/ broker/src/main/java/org/apache/qpid/server/binding/ broker/src/main/java/org/apache/qpid/server/co...

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java Mon May 31 16:03:41 2010
@@ -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 
     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 
 
     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 
         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 
             }
         }
 
-        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)

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java Mon May 31 16:03:41 2010
@@ -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.virtualhos
 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 implement
     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 implement
 
     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 implement
                 _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 implement
     {
         if (throwable instanceof AMQProtocolHeaderException)
         {
-
             writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion()));
             _networkDriver.close();
 

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java Mon May 31 16:03:41 2010
@@ -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 Managa
 
     void deleteMessageFromTop();
 
-    long clearQueue();
+    long clearQueue() throws AMQException;
 
     /**
      * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc.

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java Mon May 31 16:03:41 2010
@@ -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.configurat
 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)

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java Mon May 31 16:03:41 2010
@@ -28,6 +28,7 @@ import org.apache.qpid.framing.ContentHe
 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.LocalT
 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 AMQMa
      */
     public Long clearQueue() throws JMException
     {
-        return _queue.clearQueue();
+        try
+        {
+            return _queue.clearQueue();
+        }
+        catch (AMQException ex)
+        {
+            throw new MBeanException(ex, "Error clearing queue " + _queueName);
+        }
     }
 
     /**

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java Mon May 31 16:03:41 2010
@@ -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.Atomi
 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 A
 
     // ------ 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 A
             else
             {
                 _exclusiveSubscriber = subscription;
-
             }
         }
 
@@ -1212,38 +1218,9 @@ public class SimpleAMQQueue implements A
 
     }
 
-    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 A
         }
     }
 
-    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 A
             if (!node.isDeleted() && node.acquire())
             {
                 dequeueEntry(node, txn);
-                count++;
+                if(++count == request)
+                {
+                    break;
+                }
             }
 
         }
@@ -1292,7 +1282,6 @@ public class SimpleAMQQueue implements A
         txn.commit();
 
         return count;
-
     }
 
     private void dequeueEntry(final QueueEntry node)
@@ -1329,12 +1318,18 @@ public class SimpleAMQQueue implements A
         _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 A
 
     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);
     }
 

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java Mon May 31 16:03:41 2010
@@ -124,7 +124,6 @@ public abstract class ApplicationRegistr
     @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 ApplicationRegistr
 
             try
             {
-                _logger.error("instance.initialise(instanceID)");
                 instance.initialise(instanceID);
             }
             catch (Exception e)
@@ -237,12 +235,11 @@ public abstract class ApplicationRegistr
 
     public void configure() throws ConfigurationException
     {
-
         _configurationManager = new ConfigurationManager();
 
         try
         {
-            _pluginManager = new PluginManager(_configuration.getPluginDirectory());
+            _pluginManager = new PluginManager(_configuration.getPluginDirectory(), _configuration.getCacheDirectory());
         }
         catch (Exception e)
         {

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java Mon May 31 16:03:41 2010
@@ -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;
+    }
+}

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java Mon May 31 16:03:41 2010
@@ -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(); 
+    }
+}

Copied: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java (from r949780, qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java)
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java?p2=qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java&p1=qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java&r1=949780&r2=949781&rev=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Result.java Mon May 31 16:03:41 2010
@@ -15,24 +15,32 @@
  *  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;
+package org.apache.qpid.server.security;
 
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.queue.AMQQueue;
-
-public enum Permission
+/**
+ * The result of a security plugin decision, normally {@link #ALLOWED} or {@link #DENIED}.
+ */
+public enum Result
 {
-    CONSUME,
-    PUBLISH,
-    CREATEQUEUE,
-    CREATEEXCHANGE,
-    ACCESS,
-    BIND,
-    UNBIND,
-    DELETE,
-    PURGE
-}
+    /**
+     * 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

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java Mon May 31 16:03:41 2010
@@ -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));
+            }
+        });
+    }
+}

Propchange: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
------------------------------------------------------------------------------
    svn:executable = *

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java Mon May 31 16:03:41 2010
@@ -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);
+}

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java Mon May 31 16:03:41 2010
@@ -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;
+	}
+}

Copied: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java (from r949780, qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java)
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java?p2=qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java&p1=qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java&r1=949780&r2=949781&rev=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java Mon May 31 16:03:41 2010
@@ -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.
  * 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>
 {
-
 }

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java Mon May 31 16:03:41 2010
@@ -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)));
+    }
+}

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java Mon May 31 16:03:41 2010
@@ -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);
+    }
+}

Copied: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java (from r949780, qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java)
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java?p2=qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java&p1=qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java&r1=949780&r2=949781&rev=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java Mon May 31 16:03:41 2010
@@ -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)
-        {
-            return name.startsWith("exchangeDenier");
-        }
-
-        public ACLPlugin newInstance(Configuration config)
+        for (Operation operation : values())
         {
-            return new ExchangeDenier();
+            if (operation.name().equalsIgnoreCase(text))
+            {
+                return operation;
+            }
         }
-    };
-
-    @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

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java Mon May 31 16:03:41 2010
@@ -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

Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java?rev=949781&r1=949780&r2=949781&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java (original)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java Mon May 31 16:03:41 2010
@@ -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 final ACLPluginFactory FACTORY = new ACLPluginFactory()
+    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 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);
     }
 }

Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java?rev=949781&view=auto
==============================================================================
--- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java (added)
+++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java Mon May 31 16:03:41 2010
@@ -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
+    }
+}



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org