You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kw...@apache.org on 2014/07/04 16:40:14 UTC

svn commit: r1607868 - in /qpid/trunk/qpid/java: bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/ bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/ bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berk...

Author: kwall
Date: Fri Jul  4 14:40:13 2014
New Revision: 1607868

URL: http://svn.apache.org/r1607868
Log:
QPID-5873: [Java Broker] Allow ACL rules to be applied to VirtualHostNode objects

* ACL rules using the new operation VIRTUALHOSTNODE apply to VHN model objects.
* ACL rules using the operation VIRTUALHOST apply to VH model objects for CREATE, UPDATE and DELETE.  This
  is a change from previous version where BROKER operation permission was required.
* For HA, VIRTUALHOSTNODE permission is required to perform updates on RemoteReplicationNodes.

Added:
    qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/
    qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/
    qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeTest.java
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java
Modified:
    qpid/trunk/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeImpl.java
    qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
    qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java
    qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
    qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
    qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java
    qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
    qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java
    qpid/trunk/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
    qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java

Modified: qpid/trunk/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeImpl.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeImpl.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeImpl.java (original)
+++ qpid/trunk/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeImpl.java Fri Jul  4 14:40:13 2014
@@ -24,6 +24,7 @@ package org.apache.qpid.server.virtualho
 import static com.sleepycat.je.rep.ReplicatedEnvironment.State.MASTER;
 import static com.sleepycat.je.rep.ReplicatedEnvironment.State.REPLICA;
 
+import java.security.AccessControlException;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
@@ -33,11 +34,13 @@ import com.sleepycat.je.rep.MasterStateE
 import org.apache.log4j.Logger;
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.IllegalStateTransitionException;
 import org.apache.qpid.server.model.ManagedAttributeField;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.StateTransition;
+import org.apache.qpid.server.security.access.Operation;
 import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade;
 
 public class BDBHARemoteReplicationNodeImpl extends AbstractConfiguredObject<BDBHARemoteReplicationNodeImpl> implements BDBHARemoteReplicationNode<BDBHARemoteReplicationNodeImpl>
@@ -46,6 +49,7 @@ public class BDBHARemoteReplicationNodeI
 
     private final ReplicatedEnvironmentFacade _replicatedEnvironmentFacade;
     private final String _address;
+    private final Broker _broker;
 
     private volatile long _joinTime;
     private volatile long _lastTransactionId;
@@ -59,6 +63,7 @@ public class BDBHARemoteReplicationNodeI
     public BDBHARemoteReplicationNodeImpl(BDBHAVirtualHostNode<?> virtualHostNode, Map<String, Object> attributes, ReplicatedEnvironmentFacade replicatedEnvironmentFacade)
     {
         super(parentsMap(virtualHostNode), attributes);
+        _broker = virtualHostNode.getParent(Broker.class);
         _address = (String)attributes.get(ADDRESS);
         _replicatedEnvironmentFacade = replicatedEnvironmentFacade;
         _state = new AtomicReference<State>(State.ACTIVE);
@@ -113,6 +118,27 @@ public class BDBHARemoteReplicationNodeI
         super.deleted();
     }
 
+
+    @Override
+    protected void authoriseSetAttributes(final ConfiguredObject<?> proxyForValidation,
+                                          final Set<String> modifiedAttributes)
+    {
+        _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.UPDATE);
+    }
+
+    @Override
+    protected void authoriseSetDesiredState(State desiredState) throws AccessControlException
+    {
+        if(desiredState == State.DELETED)
+        {
+            _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.DELETE);
+        }
+        else
+        {
+            _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.UPDATE);
+        }
+    }
+
     @Override
     public String toString()
     {

Added: qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeTest.java?rev=1607868&view=auto
==============================================================================
--- qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeTest.java (added)
+++ qpid/trunk/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNodeTest.java Fri Jul  4 14:40:13 2014
@@ -0,0 +1,160 @@
+/*
+ * 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.virtualhostnode.berkeleydb;
+
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.security.AccessControlException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObjectFactory;
+import org.apache.qpid.server.model.RemoteReplicationNode;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.store.DurableConfigurationStore;
+import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade;
+import org.apache.qpid.server.util.BrokerTestHelper;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class BDBHARemoteReplicationNodeTest extends QpidTestCase
+{
+    private final org.apache.qpid.server.security.SecurityManager _mockSecurityManager = mock(SecurityManager.class);
+
+    private Broker _broker;
+    private TaskExecutor _taskExecutor;
+    private BDBHAVirtualHostNode<?> _virtualHostNode;
+    private DurableConfigurationStore _configStore;
+    private ReplicatedEnvironmentFacade _facade;
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        _facade = mock(ReplicatedEnvironmentFacade.class);
+
+        _broker = BrokerTestHelper.createBrokerMock();
+
+        _taskExecutor = new CurrentThreadTaskExecutor();
+        _taskExecutor.start();
+        when(_broker.getTaskExecutor()).thenReturn(_taskExecutor);
+
+        _virtualHostNode = mock(BDBHAVirtualHostNode.class);
+        _configStore = mock(DurableConfigurationStore.class);
+        when(_virtualHostNode.getConfigurationStore()).thenReturn(_configStore);
+
+        // Virtualhost needs the EventLogger from the SystemContext.
+        when(_virtualHostNode.getParent(Broker.class)).thenReturn(_broker);
+
+        ConfiguredObjectFactory objectFactory = _broker.getObjectFactory();
+        when(_virtualHostNode.getModel()).thenReturn(objectFactory.getModel());
+        when(_virtualHostNode.getTaskExecutor()).thenReturn(_taskExecutor);
+    }
+
+    public void testUpdateRole()
+    {
+        String remoteReplicationName = getName();
+        BDBHARemoteReplicationNode remoteReplicationNode = createRemoteReplicationNode(remoteReplicationName);
+
+        remoteReplicationNode.setAttribute(BDBHARemoteReplicationNode.ROLE, null, "MASTER");
+
+        verify(_facade).transferMasterAsynchronously(remoteReplicationName);
+    }
+
+    public void testDelete()
+    {
+        String remoteReplicationName = getName();
+        BDBHARemoteReplicationNode remoteReplicationNode = createRemoteReplicationNode(remoteReplicationName);
+
+        remoteReplicationNode.delete();
+
+        verify(_facade).removeNodeFromGroup(remoteReplicationName);
+    }
+
+    // ***************  ReplicationNode Access Control Tests  ***************
+
+    public void testUpdateDeniedByACL()
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        String remoteReplicationName = getName();
+        BDBHARemoteReplicationNode remoteReplicationNode = createRemoteReplicationNode(remoteReplicationName);
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHostNode(
+                remoteReplicationName,
+                Operation.UPDATE);
+
+        assertNull(remoteReplicationNode.getDescription());
+
+        try
+        {
+            remoteReplicationNode.setAttribute(VirtualHost.DESCRIPTION, null, "My description");
+            fail("Exception not thrown");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+    }
+
+    public void testDeleteDeniedByACL()
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        String remoteReplicationName = getName();
+        BDBHARemoteReplicationNode remoteReplicationNode = createRemoteReplicationNode(remoteReplicationName);
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHostNode(
+                remoteReplicationName,
+                Operation.DELETE);
+
+        assertNull(remoteReplicationNode.getDescription());
+
+        try
+        {
+            remoteReplicationNode.delete();
+            fail("Exception not thrown");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+    }
+
+    private BDBHARemoteReplicationNode createRemoteReplicationNode(final String replicationNodeName)
+    {
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(RemoteReplicationNode.NAME, replicationNodeName);
+
+        BDBHARemoteReplicationNodeImpl node = new BDBHARemoteReplicationNodeImpl(_virtualHostNode, attributes, _facade);
+        node.create();
+        return node;
+    }
+
+
+}
\ No newline at end of file

Modified: qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java Fri Jul  4 14:40:13 2014
@@ -895,9 +895,19 @@ public class BrokerAdapter extends Abstr
     protected <C extends ConfiguredObject> void authoriseCreateChild(Class<C> childClass, Map<String, Object> attributes,
             ConfiguredObject... otherParents) throws AccessControlException
     {
-        if (!_securityManager.authoriseConfiguringBroker(String.valueOf(attributes.get(NAME)), childClass, Operation.CREATE))
+        if (childClass == VirtualHostNode.class)
         {
-            throw new AccessControlException("Creation of new broker level entity is denied");
+            _securityManager.authoriseVirtualHostNode(String.valueOf(attributes.get(NAME)), Operation.CREATE);
+
+        }
+        else
+        {
+            if (!_securityManager.authoriseConfiguringBroker(String.valueOf(attributes.get(NAME)),
+                                                             childClass,
+                                                             Operation.CREATE))
+            {
+                throw new AccessControlException("Creation of new broker level entity is denied");
+            }
         }
     }
 

Modified: qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SecurityManager.java Fri Jul  4 14:40:13 2014
@@ -25,6 +25,7 @@ import static org.apache.qpid.server.sec
 import static org.apache.qpid.server.security.access.ObjectType.QUEUE;
 import static org.apache.qpid.server.security.access.ObjectType.USER;
 import static org.apache.qpid.server.security.access.ObjectType.VIRTUALHOST;
+import static org.apache.qpid.server.security.access.ObjectType.VIRTUALHOSTNODE;
 import static org.apache.qpid.server.security.access.Operation.*;
 
 import java.security.AccessControlException;
@@ -242,9 +243,24 @@ public class SecurityManager implements 
         }
     }
 
-    public void authoriseCreateConnection(final AMQConnectionModel connection)
+    public void authoriseVirtualHostNode(final String virtualHostNodeName, final Operation operation)
+    {
+        if(!checkAllPlugins(new AccessCheck()
+        {
+            Result allowed(AccessControl plugin)
+            {
+                ObjectProperties properties = new ObjectProperties(virtualHostNodeName);
+                return plugin.authorise(operation, VIRTUALHOSTNODE, properties);
+            }
+        }))
+        {
+            throw new AccessControlException(operation + " permission denied for " + VIRTUALHOSTNODE
+                                             + " : " + virtualHostNodeName);
+        }
+    }
+
+    public void authoriseVirtualHost(final String virtualHostName, final Operation operation)
     {
-        final String virtualHostName = connection.getVirtualHostName();
         if(!checkAllPlugins(new AccessCheck()
         {
             Result allowed(AccessControl plugin)
@@ -252,10 +268,24 @@ public class SecurityManager implements 
                 // We put the name into the properties under both name and virtualhost_name so the user may express predicates using either.
                 ObjectProperties properties = new ObjectProperties(virtualHostName);
                 properties.put(Property.VIRTUALHOST_NAME, virtualHostName);
-                return plugin.authorise(Operation.ACCESS, VIRTUALHOST, properties);
+                return plugin.authorise(operation, VIRTUALHOST, properties);
             }
         }))
         {
+            throw new AccessControlException(operation + " permission denied for " + VIRTUALHOST
+                                             + " : " + virtualHostName);
+        }
+    }
+
+    public void authoriseCreateConnection(final AMQConnectionModel connection)
+    {
+        String virtualHostName = connection.getVirtualHostName();
+        try
+        {
+            authoriseVirtualHost(virtualHostName, Operation.ACCESS);
+        }
+        catch (AccessControlException ace)
+        {
             throw new AccessControlException("Permission denied: " + virtualHostName);
         }
     }

Modified: qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/access/ObjectType.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/access/ObjectType.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/access/ObjectType.java Fri Jul  4 14:40:13 2014
@@ -42,7 +42,8 @@ import java.util.Set;
 public enum ObjectType
 {
     ALL(Operation.ALL),
-    VIRTUALHOST(Operation.ALL, ACCESS),
+    VIRTUALHOSTNODE(Operation.ALL, CREATE, DELETE, UPDATE),
+    VIRTUALHOST(Operation.ALL, ACCESS, CREATE, DELETE, UPDATE),
     MANAGEMENT(Operation.ALL, ACCESS),
     QUEUE(Operation.ALL, CREATE, DELETE, PURGE, CONSUME, UPDATE),
     EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH, UPDATE),

Modified: qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java Fri Jul  4 14:40:13 2014
@@ -318,20 +318,18 @@ public abstract class AbstractVirtualHos
     {
         if(desiredState == State.DELETED)
         {
-            if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), org.apache.qpid.server.model.VirtualHost.class, Operation.DELETE))
-            {
-                throw new AccessControlException("Deletion of virtual host is denied");
-            }
+            _broker.getSecurityManager().authoriseVirtualHost(getName(), Operation.DELETE);
+        }
+        else
+        {
+            _broker.getSecurityManager().authoriseVirtualHost(getName(), Operation.UPDATE);
         }
     }
 
     @Override
     protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException
     {
-        if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), org.apache.qpid.server.model.VirtualHost.class, Operation.UPDATE))
-        {
-            throw new AccessControlException("Setting of virtual host attributes is denied");
-        }
+        _broker.getSecurityManager().authoriseVirtualHost(getName(), Operation.UPDATE);
     }
 
     public Collection<Connection> getConnections()

Modified: qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java Fri Jul  4 14:40:13 2014
@@ -197,22 +197,38 @@ public abstract class AbstractVirtualHos
     {
         if(desiredState == State.DELETED)
         {
-            if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), VirtualHostNode.class, Operation.DELETE))
-            {
-                throw new AccessControlException("Deletion of virtual host node is denied");
-            }
+            _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.DELETE);
+        }
+        else
+        {
+            _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.UPDATE);
         }
     }
 
     @Override
-    protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException
+    protected <C extends ConfiguredObject> void authoriseCreateChild(final Class<C> childClass,
+                                                                     final Map<String, Object> attributes,
+                                                                     final ConfiguredObject... otherParents)
+            throws AccessControlException
     {
-        if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), VirtualHostNode.class, Operation.UPDATE))
+        if (childClass == VirtualHost.class)
+        {
+            _broker.getSecurityManager().authoriseVirtualHost(String.valueOf(attributes.get(VirtualHost.NAME)),
+                                                              Operation.CREATE);
+
+        }
+        else
         {
-            throw new AccessControlException("Setting of virtual host node attributes is denied");
+            super.authoriseCreateChild(childClass, attributes, otherParents);
         }
     }
 
+    @Override
+    protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException
+    {
+        _broker.getSecurityManager().authoriseVirtualHostNode(getName(), Operation.UPDATE);
+    }
+
     private void closeConfigurationStore()
     {
         DurableConfigurationStore configurationStore = getConfigurationStore();

Modified: qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java Fri Jul  4 14:40:13 2014
@@ -22,12 +22,15 @@ package org.apache.qpid.server.model;
 
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import java.security.AccessControlException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -36,6 +39,8 @@ import org.mockito.ArgumentMatcher;
 
 import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
 import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
 import org.apache.qpid.server.store.ConfiguredObjectRecord;
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.util.BrokerTestHelper;
@@ -44,6 +49,7 @@ import org.apache.qpid.test.utils.QpidTe
 
 public class VirtualHostTest extends QpidTestCase
 {
+    private final SecurityManager _mockSecurityManager = mock(SecurityManager.class);
     private Broker _broker;
     private TaskExecutor _taskExecutor;
     private VirtualHostNode<?> _virtualHostNode;
@@ -180,6 +186,82 @@ public class VirtualHostTest extends Qpi
         verify(_configStore, never()).create(matchesRecord(queue.getId(), queue.getType()));
     }
 
+    // ***************  VH Access Control Tests  ***************
+
+    public void testUpdateDeniedByACL()
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        String virtualHostName = getName();
+        VirtualHost<?,?,?> virtualHost = createVirtualHost(virtualHostName);
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHost(
+                virtualHostName,
+                Operation.UPDATE);
+
+        assertNull(virtualHost.getDescription());
+
+        try
+        {
+            virtualHost.setAttribute(VirtualHost.DESCRIPTION, null, "My description");
+            fail("Exception not thrown");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+
+        verify(_configStore, never()).update(eq(false), matchesRecord(virtualHost.getId(), virtualHost.getType()));
+    }
+
+    public void testStopDeniedByACL()
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        String virtualHostName = getName();
+        VirtualHost<?,?,?> virtualHost = createVirtualHost(virtualHostName);
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHost(
+                virtualHostName,
+                Operation.UPDATE);
+
+        try
+        {
+            virtualHost.stop();
+            fail("Exception not thrown");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+
+        verify(_configStore, never()).update(eq(false), matchesRecord(virtualHost.getId(), virtualHost.getType()));
+    }
+
+    public void testDeleteDeniedByACL()
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        String virtualHostName = getName();
+        VirtualHost<?,?,?> virtualHost = createVirtualHost(virtualHostName);
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHost(
+                virtualHostName,
+                Operation.DELETE);
+
+        try
+        {
+            virtualHost.delete();
+            fail("Exception not thrown");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+
+        verify(_configStore, never()).remove(matchesRecord(virtualHost.getId(), virtualHost.getType()));
+    }
+
     private VirtualHost<?,?,?> createVirtualHost(final String virtualHostName)
     {
         Map<String, Object> attributes = new HashMap<>();

Modified: qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java (original)
+++ qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java Fri Jul  4 14:40:13 2014
@@ -21,9 +21,11 @@
 package org.apache.qpid.server.virtualhostnode;
 
 import static org.apache.qpid.server.virtualhostnode.AbstractStandardVirtualHostNode.*;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.security.AccessControlException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -39,6 +41,8 @@ import org.apache.qpid.server.model.Stat
 import org.apache.qpid.server.model.SystemContext;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
 import org.apache.qpid.server.store.ConfiguredObjectRecord;
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.store.NullMessageStore;
@@ -53,7 +57,8 @@ public class AbstractStandardVirtualHost
     private static final String TEST_VIRTUAL_HOST_NODE_NAME = "testNode";
     private static final String TEST_VIRTUAL_HOST_NAME = "testVirtualHost";
 
-    private UUID _nodeId = UUID.randomUUID();
+    private final UUID _nodeId = UUID.randomUUID();
+    private final SecurityManager _mockSecurityManager = mock(SecurityManager.class);
     private Broker<?> _broker;
     private TaskExecutor _taskExecutor;
 
@@ -109,7 +114,6 @@ public class AbstractStandardVirtualHost
         assertEquals("Unexpected virtual host id", virtualHostId, virtualHost.getId());
     }
 
-
     /**
      *  Tests activating a virtualhostnode with a config store which does not specify
      *  a virtualhost.  Checks no virtualhost is created.
@@ -128,7 +132,6 @@ public class AbstractStandardVirtualHost
 
         VirtualHost<?, ?, ?> virtualHost = node.getVirtualHost();
         assertNull("Virtual host should not be automatically created", virtualHost);
-
     }
 
     /**
@@ -233,6 +236,125 @@ public class AbstractStandardVirtualHost
         assertEquals("Unexpected virtual host id", virtualHostId, virtualHost.getId());
     }
 
+    public void testStopStartVHN() throws Exception
+    {
+        DurableConfigurationStore configStore = configStoreThatProducesNoRecords();
+
+        Map<String, Object> nodeAttributes = new HashMap<>();
+        nodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME);
+        nodeAttributes.put(VirtualHostNode.ID, _nodeId);
+
+        VirtualHostNode<?> node = new TestVirtualHostNode(_broker, nodeAttributes, configStore);
+        node.open();
+        node.start();
+
+        assertEquals("Unexpected virtual host node state", State.ACTIVE, node.getState());
+
+        node.stop();
+        assertEquals("Unexpected virtual host node state after stop", State.STOPPED, node.getState());
+
+        node.start();
+        assertEquals("Unexpected virtual host node state after start", State.ACTIVE, node.getState());
+    }
+
+
+    // ***************  VHN Access Control Tests  ***************
+
+    public void testUpdateVHNDeniedByACL() throws Exception
+    {
+        when(_broker.getSecurityManager()).thenReturn(_mockSecurityManager);
+
+        DurableConfigurationStore configStore = configStoreThatProducesNoRecords();
+
+        Map<String, Object> nodeAttributes = new HashMap<>();
+        nodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME);
+        nodeAttributes.put(VirtualHostNode.ID, _nodeId);
+
+        VirtualHostNode<?> node = new TestVirtualHostNode(_broker, nodeAttributes, configStore);
+        node.open();
+        node.start();
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(_mockSecurityManager).authoriseVirtualHostNode(
+                TEST_VIRTUAL_HOST_NODE_NAME,
+                Operation.UPDATE);
+
+        assertNull(node.getDescription());
+        try
+        {
+            node.setAttribute(VirtualHostNode.DESCRIPTION, null, "My virtualhost node");
+            fail("Exception not throws");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+        assertNull("Description unexpected updated", node.getDescription());
+    }
+
+    public void testDeleteVHNDeniedByACL() throws Exception
+    {
+        SecurityManager mockSecurityManager = mock(SecurityManager.class);
+        when(_broker.getSecurityManager()).thenReturn(mockSecurityManager);
+
+        DurableConfigurationStore configStore = configStoreThatProducesNoRecords();
+
+        Map<String, Object> nodeAttributes = new HashMap<>();
+        nodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME);
+        nodeAttributes.put(VirtualHostNode.ID, _nodeId);
+
+        VirtualHostNode<?> node = new TestVirtualHostNode(_broker, nodeAttributes, configStore);
+        node.open();
+        node.start();
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(mockSecurityManager).authoriseVirtualHostNode(
+                TEST_VIRTUAL_HOST_NODE_NAME,
+                Operation.DELETE);
+
+        try
+        {
+            node.delete();
+            fail("Exception not throws");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+
+        assertEquals("Virtual host node state changed unexpectedly", State.ACTIVE, node.getState());
+    }
+
+    public void testStopVHNDeniedByACL() throws Exception
+    {
+        SecurityManager mockSecurityManager = mock(SecurityManager.class);
+        when(_broker.getSecurityManager()).thenReturn(mockSecurityManager);
+
+        DurableConfigurationStore configStore = configStoreThatProducesNoRecords();
+
+        Map<String, Object> nodeAttributes = new HashMap<>();
+        nodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME);
+        nodeAttributes.put(VirtualHostNode.ID, _nodeId);
+
+        VirtualHostNode<?> node = new TestVirtualHostNode(_broker, nodeAttributes, configStore);
+        node.open();
+        node.start();
+
+        doThrow(new AccessControlException("mocked ACL exception")).when(mockSecurityManager).authoriseVirtualHostNode(
+                TEST_VIRTUAL_HOST_NODE_NAME,
+                Operation.UPDATE);
+
+        try
+        {
+            node.stop();
+            fail("Exception not throws");
+        }
+        catch (AccessControlException ace)
+        {
+            // PASS
+        }
+
+        assertEquals("Virtual host node state changed unexpectedly", State.ACTIVE, node.getState());
+    }
+
     private ConfiguredObjectRecord createVirtualHostConfiguredObjectRecord(UUID virtualHostId)
     {
         Map<String, Object> virtualHostAttributes = new HashMap<>();
@@ -263,6 +385,7 @@ public class AbstractStandardVirtualHost
             }
         };
     }
+
     private NullMessageStore configStoreThatProducesNoRecords()
     {
         return configStoreThatProduces(null);

Modified: qpid/trunk/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java (original)
+++ qpid/trunk/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java Fri Jul  4 14:40:13 2014
@@ -108,6 +108,13 @@ public class RuleSetTest extends QpidTes
         assertEquals(_ruleSet.getDefault(), _ruleSet.check(_testSubject, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
     }
 
+    public void testVirtualHostNodeCreateAllowPermissionWithVirtualHostName() throws Exception
+    {
+        _ruleSet.grant(0, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.VIRTUALHOSTNODE, ObjectProperties.EMPTY);
+        assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.VIRTUALHOSTNODE, ObjectProperties.EMPTY));
+        assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.DELETE, ObjectType.VIRTUALHOSTNODE, ObjectProperties.EMPTY));
+    }
+
     public void testVirtualHostAccessAllowPermissionWithVirtualHostName() throws Exception
     {
         _ruleSet.grant(0, TEST_USER, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, new ObjectProperties(ALLOWED_VH));

Modified: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java?rev=1607868&r1=1607867&r2=1607868&view=diff
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java (original)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java Fri Jul  4 14:40:13 2014
@@ -27,7 +27,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
 import org.codehaus.jackson.JsonGenerationException;
 import org.codehaus.jackson.map.JsonMappingException;
 import org.apache.qpid.server.management.plugin.HttpManagement;
@@ -45,7 +44,6 @@ import org.apache.qpid.server.model.adap
 import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl;
 import org.apache.qpid.server.security.FileKeyStore;
 import org.apache.qpid.server.security.FileTrustStore;
-import org.apache.qpid.server.model.VirtualHostNode;
 import org.apache.qpid.server.security.access.FileAccessControlProviderConstants;
 import org.apache.qpid.server.security.acl.AbstractACLTestCase;
 import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
@@ -72,7 +70,7 @@ public class BrokerACLTest extends QpidR
                 "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER",
                 "ACL DENY-LOG ALL ALL");
 
-        _secondaryAclFileContent =
+                _secondaryAclFileContent =
                 "ACL ALLOW-LOG ALL ACCESS MANAGEMENT\n" +
                 "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" +
                 "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER\n" +
@@ -190,58 +188,6 @@ public class BrokerACLTest extends QpidR
                 provider.get(ExternalFileBasedAuthenticationManager.PATH));
     }
 
-    /* === VirtualHostNode === */
-
-    public void testCreateVirtualHostNodeAllowed() throws Exception
-    {
-        getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
-
-        String hostName = getTestName();
-
-        int responseCode = createVirtualHostNode(hostName);
-        assertEquals("Host creation should be allowed", 201, responseCode);
-
-        assertVirtualHostNodeExists(hostName);
-    }
-
-    public void testCreateVirtualHostNodeDenied() throws Exception
-    {
-        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
-
-        String hostName = getTestName();
-
-        int responseCode = createVirtualHostNode(hostName);
-        assertEquals("Virtual host node creation should be denied", 403, responseCode);
-
-        assertVirtualHostNodeDoesNotExist(hostName);
-    }
-
-    public void testDeleteVirtualHostNodeAllowed() throws Exception
-    {
-        getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
-
-        assertVirtualHostNodeExists(TEST2_VIRTUALHOST);
-
-        int responseCode = getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "DELETE");
-        assertEquals("Virtual host node deletion should be allowed", 200, responseCode);
-
-        assertVirtualHostNodeDoesNotExist(TEST2_VIRTUALHOST);
-    }
-
-    public void testDeleteVirtualHostNodeDenied() throws Exception
-    {
-        getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
-
-        assertVirtualHostNodeExists(TEST2_VIRTUALHOST);
-
-        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
-
-        int responseCode = getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "DELETE");
-        assertEquals("Virtual host node deletion should be denied", 403, responseCode);
-
-        assertVirtualHostNodeExists(TEST2_VIRTUALHOST);
-    }
-
     /* === Port === */
 
     public void testCreatePortAllowed() throws Exception
@@ -977,37 +923,6 @@ public class BrokerACLTest extends QpidR
         assertEquals("Unexpected result", exists, !trustStores.isEmpty());
     }
 
-    private int createVirtualHostNode(String virtualHostNodeName) throws Exception
-    {
-        Map<String, Object> data = new HashMap<String, Object>();
-        data.put(VirtualHostNode.NAME, virtualHostNodeName);
-        data.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
-        data.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(virtualHostNodeName));
-
-        return getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostNodeName, "PUT", data);
-    }
-
-    private void assertVirtualHostNodeDoesNotExist(String name) throws Exception
-    {
-        assertVirtualHostNodeExistence(name, false);
-    }
-
-    private void assertVirtualHostNodeExists(String name) throws Exception
-    {
-        assertVirtualHostNodeExistence(name, true);
-    }
-
-    private void assertVirtualHostNodeExistence(String name, boolean exists) throws Exception
-    {
-        List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhostnode/" + name);
-        assertEquals("Node " + name + (exists ? " does not exist" : " exists" ), exists, !hosts.isEmpty());
-    }
-
-    private String getStoreLocation(String hostName)
-    {
-        return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
-    }
-
     private int createAuthenticationProvider(String authenticationProviderName) throws Exception
     {
         Map<String, Object> attributes = new HashMap<String, Object>();

Added: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java?rev=1607868&view=auto
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java (added)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java Fri Jul  4 14:40:13 2014
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+
+public class VirtualHostACLTest extends QpidRestTestCase
+{
+    private static final String VHN_WITHOUT_VH = "myVhnWithoutVh";
+
+    private static final String ALLOWED_USER = "user1";
+    private static final String DENIED_USER = "user2";
+
+    @Override
+    protected void customizeConfiguration() throws IOException
+    {
+        super.customizeConfiguration();
+        getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+        AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+                "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOST",
+                "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOST",
+                "ACL DENY-LOG ALL ALL");
+
+        getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+                HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+
+        Map<String, Object> virtualHostNodeAttributes = new HashMap<>();
+        virtualHostNodeAttributes.put(VirtualHostNode.NAME, VHN_WITHOUT_VH);
+        virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+        // TODO need better way to determine the VHN's optional attributes
+        virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(VHN_WITHOUT_VH));
+
+        getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes);
+    }
+
+    public void testCreateVirtualHostAllowed() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+        String hostName = getTestName();
+
+        int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName);
+        assertEquals("Virtual host creation should be allowed", HttpServletResponse.SC_CREATED, responseCode);
+
+        assertVirtualHostExists(VHN_WITHOUT_VH, hostName);
+    }
+
+    public void testCreateVirtualHostDenied() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+        String hostName = getTestName();
+
+        int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName);
+        assertEquals("Virtual host creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode);
+
+        assertVirtualHostDoesNotExist(VHN_WITHOUT_VH, hostName);
+    }
+
+    public void testDeleteVirtualHostDenied() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+        getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_FORBIDDEN);
+
+        assertVirtualHostExists(TEST2_VIRTUALHOST, TEST2_VIRTUALHOST);
+    }
+
+    public void testUpdateVirtualHostDenied() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put(VirtualHost.NAME, TEST2_VIRTUALHOST);
+        attributes.put(VirtualHost.DESCRIPTION, "new description");
+
+        getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "PUT", attributes, HttpServletResponse.SC_FORBIDDEN);
+    }
+
+    /* === Utility Methods === */
+
+    private int createVirtualHost(final String testVirtualHostNode, String virtualHostName) throws Exception
+    {
+        Map<String, Object> data = new HashMap<>();
+        data.put(VirtualHost.NAME, virtualHostName);
+        data.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE);
+
+        return getRestTestHelper().submitRequest("virtualhost/" + testVirtualHostNode + "/" + virtualHostName, "PUT", data);
+    }
+
+    private void assertVirtualHostDoesNotExist(final String virtualHostNodeName, String virtualHostName) throws Exception
+    {
+        assertVirtualHostExistence(virtualHostNodeName, virtualHostName, false);
+    }
+
+    private void assertVirtualHostExists(final String virtualHostNodeName, String virtualHostName) throws Exception
+    {
+        assertVirtualHostExistence(virtualHostNodeName, virtualHostName, true);
+    }
+
+    private void assertVirtualHostExistence(final String virtualHostNodeName, String virtualHostName, boolean exists) throws Exception
+    {
+        List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + virtualHostNodeName + "/" + virtualHostName);
+        assertEquals("Node " + virtualHostName + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty());
+    }
+
+    private String getStoreLocation(String hostName)
+    {
+        return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
+    }
+
+}

Added: qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java?rev=1607868&view=auto
==============================================================================
--- qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java (added)
+++ qpid/trunk/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java Fri Jul  4 14:40:13 2014
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.rest.acl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.model.AccessControlProvider;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProvider;
+import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl;
+import org.apache.qpid.server.security.FileKeyStore;
+import org.apache.qpid.server.security.FileTrustStore;
+import org.apache.qpid.server.security.access.FileAccessControlProviderConstants;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager;
+import org.apache.qpid.server.virtualhost.memory.MemoryVirtualHost;
+import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestFileUtils;
+import org.apache.qpid.test.utils.TestSSLConstants;
+
+public class VirtualHostNodeACLTest extends QpidRestTestCase
+{
+    private static final String TEST_VIRTUAL_HOST_NODE = "myTestVirtualHostNode";
+    private static final String ALLOWED_USER = "user1";
+    private static final String DENIED_USER = "user2";
+
+    @Override
+    protected void customizeConfiguration() throws IOException
+    {
+        super.customizeConfiguration();
+        getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER);
+
+        AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+                "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOSTNODE",
+                "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOSTNODE",
+                "ACL DENY-LOG ALL ALL");
+
+        getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT,
+                HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true);
+
+        Map<String, Object> virtualHostNodeAttributes = new HashMap<>();
+        virtualHostNodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE);
+        virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+        // TODO need better way to determine the VHN's optional attributes
+        virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(TEST_VIRTUAL_HOST_NODE));
+
+
+        getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes);
+    }
+
+    public void testCreateVirtualHostNodeAllowed() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+        String hostName = getTestName();
+
+        int responseCode = createVirtualHostNode(hostName);
+        assertEquals("Virtual host node creation should be allowed", HttpServletResponse.SC_CREATED, responseCode);
+
+        assertVirtualHostNodeExists(hostName);
+    }
+
+    public void testCreateVirtualHostNodeDenied() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+        String hostName = getTestName();
+
+        int responseCode = createVirtualHostNode(hostName);
+        assertEquals("Virtual host node creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode);
+
+        assertVirtualHostNodeDoesNotExist(hostName);
+    }
+
+    public void testDeleteVirtualHostNodeDenied() throws Exception
+    {
+        getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+        getRestTestHelper().submitRequest("virtualhostnode/" + TEST_VIRTUAL_HOST_NODE, "DELETE", HttpServletResponse.SC_FORBIDDEN);
+
+        assertVirtualHostNodeExists(TEST_VIRTUAL_HOST_NODE);
+    }
+
+    /* === Utility Methods === */
+
+    private int createVirtualHostNode(String virtualHostNodeName) throws Exception
+    {
+        Map<String, Object> data = new HashMap<>();
+        data.put(VirtualHostNode.NAME, virtualHostNodeName);
+        data.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType());
+        data.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(virtualHostNodeName));
+
+        return getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostNodeName, "PUT", data);
+    }
+
+    private void assertVirtualHostNodeDoesNotExist(String name) throws Exception
+    {
+        assertVirtualHostNodeExistence(name, false);
+    }
+
+    private void assertVirtualHostNodeExists(String name) throws Exception
+    {
+        assertVirtualHostNodeExistence(name, true);
+    }
+
+    private void assertVirtualHostNodeExistence(String name, boolean exists) throws Exception
+    {
+        List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("virtualhostnode/" + name);
+        assertEquals("Node " + name + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty());
+    }
+
+    private String getStoreLocation(String hostName)
+    {
+        return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath();
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org