This is an automated email from the ASF dual-hosted git repository.

vavrtom pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git


The following commit(s) were added to refs/heads/main by this push:
     new 75b1fc6  QPID-8487: [Broker-J] Enhance ACL rule evaluation
75b1fc6 is described below

commit 75b1fc6e053ef0061ab6514d90b503d87bc7aa63
Author: Marek Laca <mkl...@users.noreply.github.com>
AuthorDate: Wed Feb 23 07:58:14 2022 +0100

    QPID-8487: [Broker-J] Enhance ACL rule evaluation
    
    This closes #115
---
 .../security/access/config/LegacyOperation.java    |  13 +-
 .../server/security/access/config/ObjectType.java  |  43 +-
 .../qpid/server/security/access/config/Rule.java   |  29 +-
 .../security/access/config/RuleCollector.java      |   2 +-
 .../security/access/config/RuleInspector.java      |  64 ++
 .../security/access/config/RulePredicate.java      |  11 +
 .../server/security/access/config/RuleSet.java     | 279 +-------
 .../security/access/config/RuleSetBuilder.java     | 204 ++++++
 .../server/security/access/config/RuleSetImpl.java | 419 +++++++++++
 ...stractCommonRuleBasedAccessControlProvider.java |   4 +-
 .../security/access/plugins/RuleOutcome.java       |  61 +-
 .../security/access/config/AclFileParserTest.java  |  68 +-
 .../access/config/AclRulePredicatesTest.java       |   4 -
 .../access/config/LegacyOperationTest.java         |  43 ++
 .../security/access/config/ObjectTypeTest.java     |  65 ++
 .../security/access/config/RuleCollectorTest.java  |  14 +-
 .../server/security/access/config/RuleSetTest.java | 767 ++++++++++++++++++++-
 .../server/security/access/config/RuleTest.java    |  62 +-
 .../config/predicates/RulePredicateTest.java       |  15 +
 .../security/access/plugins/RuleOutcomeTest.java   |  62 ++
 .../jms_1_1/extensions/acl/MessagingACLTest.java   |   7 +-
 21 files changed, 1866 insertions(+), 370 deletions(-)

diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/LegacyOperation.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/LegacyOperation.java
index 56ca67c..2270864 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/LegacyOperation.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/LegacyOperation.java
@@ -18,6 +18,8 @@
  */
 package org.apache.qpid.server.security.access.config;
 
+import java.util.Locale;
+
 /**
  * An enumeration of all possible actions that can form part of an access 
control v2 rule.
  */
@@ -38,10 +40,17 @@ public enum LegacyOperation
     SHUTDOWN,
     INVOKE;
 
+    private final String _description;
+
+    LegacyOperation()
+    {
+        final String name = name();
+        _description = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + 
name.substring(1).toLowerCase(Locale.ENGLISH);
+    }
+
     @Override
     public String toString()
     {
-        String name = name();
-        return name.charAt(0) + name.substring(1).toLowerCase();
+        return _description;
     }
 }
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectType.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectType.java
index b2b4246..860ab5e 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectType.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ObjectType.java
@@ -18,6 +18,11 @@
  */
 package org.apache.qpid.server.security.access.config;
 
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Locale;
+import java.util.Set;
+
 import static 
org.apache.qpid.server.security.access.config.LegacyOperation.ACCESS;
 import static 
org.apache.qpid.server.security.access.config.LegacyOperation.ACCESS_LOGS;
 import static 
org.apache.qpid.server.security.access.config.LegacyOperation.BIND;
@@ -32,18 +37,15 @@ import static 
org.apache.qpid.server.security.access.config.LegacyOperation.SHUT
 import static 
org.apache.qpid.server.security.access.config.LegacyOperation.UNBIND;
 import static 
org.apache.qpid.server.security.access.config.LegacyOperation.UPDATE;
 
-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.
- * 
+ * <p>
  * Each object type is valid only for a certain set of {@link 
LegacyOperation}s, which are passed as a list to
  * the constructor, and can be checked using the {@link 
#isSupported(LegacyOperation)} method.
  */
 public enum ObjectType
 {
-    ALL(EnumSet.allOf(LegacyOperation.class)),
+    ALL,
     VIRTUALHOSTNODE(LegacyOperation.ALL, CREATE, DELETE, UPDATE, INVOKE),
     VIRTUALHOST(LegacyOperation.ALL, ACCESS, CREATE, DELETE, UPDATE, 
ACCESS_LOGS, INVOKE),
     MANAGEMENT(LegacyOperation.ALL, ACCESS),
@@ -54,34 +56,41 @@ public enum ObjectType
     GROUP(LegacyOperation.ALL, CREATE, DELETE, UPDATE, INVOKE),
     BROKER(LegacyOperation.ALL, CONFIGURE, ACCESS_LOGS, SHUTDOWN, INVOKE);
 
-    private EnumSet<LegacyOperation> _operations;
+    private final EnumSet<LegacyOperation> _operations;
 
+    private final String _description;
 
-    ObjectType(LegacyOperation first, LegacyOperation... rest)
+    ObjectType(LegacyOperation... rest)
     {
-        this(EnumSet.of(first, rest));
+        _operations = EnumSet.of(LegacyOperation.ALL, rest);
+        _description = description();
     }
 
-    ObjectType(EnumSet<LegacyOperation> operations)
+    ObjectType()
     {
-        _operations = operations;
+        _operations = EnumSet.allOf(LegacyOperation.class);
+        _description = description();
     }
-    
+
+    private String description()
+    {
+        final String name = name();
+        return name.substring(0, 1).toUpperCase(Locale.ENGLISH) + 
name.substring(1).toLowerCase(Locale.ENGLISH);
+    }
+
     public Set<LegacyOperation> getOperations()
     {
-        return _operations;
+        return Collections.unmodifiableSet(_operations);
     }
-    
+
     public boolean isSupported(LegacyOperation operation)
     {
         return _operations.contains(operation);
     }
-    
+
     @Override
     public String toString()
     {
-        String name = name();
-        return name.charAt(0) + name.substring(1).toLowerCase();
+        return _description;
     }
-
 }
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
index 1bf4213..13c9874 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
@@ -47,6 +47,8 @@ public class Rule
     private final AclRulePredicates _predicates;
     private final RuleOutcome _ruleOutcome;
     private final RulePredicate _rulePredicate;
+    private final boolean _isOwner;
+    private final boolean _isAll;
 
     public Rule(AclRule rule)
     {
@@ -64,16 +66,24 @@ public class Rule
         _ruleOutcome = Objects.requireNonNull(ruleOutcome);
         _predicates = Objects.requireNonNull(predicates);
         _rulePredicate = 
Objects.requireNonNull(predicates.asSinglePredicate());
+
+        _isOwner = OWNER.equalsIgnoreCase(identity);
+        _isAll = ALL.equalsIgnoreCase(identity);
+    }
+
+    public boolean isForAll()
+    {
+        return _isAll;
     }
 
-    public static boolean isAll(String identity)
+    public boolean isForOwner()
     {
-        return ALL.equalsIgnoreCase(identity);
+        return _isOwner;
     }
 
-    public static boolean isOwner(String identity)
+    public boolean isForOwnerOrAll()
     {
-        return OWNER.equalsIgnoreCase(identity);
+        return _isOwner || _isAll;
     }
 
     public String getIdentity()
@@ -96,14 +106,18 @@ public class Rule
     {
         return operationsMatch(actionOperation) &&
                 objectTypesMatch(actionObjectType) &&
-                propertiesAttributesMatch(actionOperation, 
actionObjectProperties, subject);
+                predicatesMatch(actionOperation, actionObjectProperties, 
subject);
     }
 
-    private boolean propertiesAttributesMatch(LegacyOperation operation, 
ObjectProperties objectProperties, Subject subject)
+    public boolean predicatesMatch(LegacyOperation operation, ObjectProperties 
objectProperties, Subject subject)
     {
         return _rulePredicate.matches(operation, objectProperties, subject);
     }
 
+    public boolean anyPropertiesMatch() {
+        return _rulePredicate.matchesAny();
+    }
+
     private boolean operationsMatch(LegacyOperation actionOperation)
     {
         return LegacyOperation.ALL == getOperation() || getOperation() == 
actionOperation;
@@ -170,12 +184,13 @@ public class Rule
                 ", permission=" + _ruleOutcome + ']';
     }
 
-    private static class AclRuleImpl implements AclRule
+    private static final class AclRuleImpl implements AclRule
     {
         private final Rule _rule;
 
         AclRuleImpl(Rule rule)
         {
+            super();
             _rule = Objects.requireNonNull(rule);
         }
 
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleCollector.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleCollector.java
index 561b683..bf653a2 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleCollector.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleCollector.java
@@ -96,7 +96,7 @@ final class RuleCollector
 
     RuleSet createRuleSet(EventLoggerProvider eventLoggerProvider)
     {
-        return new RuleSet(eventLoggerProvider, _rules.values(), 
_defaultResult);
+        return RuleSet.newInstance(eventLoggerProvider, _rules.values(), 
_defaultResult);
     }
 
     private static final class RuleKey
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleInspector.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleInspector.java
new file mode 100644
index 0000000..efee96d
--- /dev/null
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleInspector.java
@@ -0,0 +1,64 @@
+/*
+ *  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.config;
+
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.Result;
+
+/**
+ * Checks the rule collection based on a subject, operation and objectType.
+ * <p>
+ * Checks only enabled rules with identity equal to all, owner, the same, or a 
group with identity as a member,
+ * and operation is either all or the same operation,
+ * and object type is either all or the same object.
+ * </p>
+ */
+@FunctionalInterface
+public interface RuleInspector
+{
+    /**
+     * Check the authorisation granted to a particular identity for an 
operation on an object type with
+     * specific properties.
+     * <p>
+     * Looks up the entire rule set, which may be cached, for the user and 
operation and goes through the rules
+     * in order to find the first one that matches. Either defers if there are 
no rules, returns the result of
+     * the first match found, or denies access if there are no matching rules. 
Normally, it would be expected
+     * to have a default deny or allow rule at the end of an access 
configuration however.
+     * </p>
+     */
+    Result check(Subject subject,
+                 LegacyOperation operation,
+                 ObjectType objectType,
+                 ObjectProperties properties);
+
+    interface RuleInspectorFactory
+    {
+        RuleInspector newInspector(Set<String> relevantPrincipals);
+
+        Set<String> allRuleIdentities();
+
+        default boolean isConstant()
+        {
+            return allRuleIdentities().isEmpty();
+        }
+    }
+}
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RulePredicate.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RulePredicate.java
index 76a3022..685370f 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RulePredicate.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RulePredicate.java
@@ -59,6 +59,11 @@ public interface RulePredicate
                 || other.matches(operation, objectProperties, subject);
     }
 
+    default boolean matchesAny()
+    {
+        return false;
+    }
+
     static RulePredicate any()
     {
         return Any.INSTANCE;
@@ -95,6 +100,12 @@ public interface RulePredicate
         {
             return this;
         }
+
+        @Override
+        public boolean matchesAny()
+        {
+            return true;
+        }
     }
 
     final class None implements RulePredicate
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
index 0466118..434be50 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
@@ -1,274 +1,71 @@
 /*
- *  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
+ * 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.
  *
- *  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.config;
 
-import java.security.Principal;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
 
 import javax.security.auth.Subject;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.EventLoggerProvider;
-import org.apache.qpid.server.logging.messages.AccessControlMessages;
 import org.apache.qpid.server.security.Result;
-import org.apache.qpid.server.security.access.plugins.RuleOutcome;
-import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
 
 /**
  * Models the rule configuration for the access control plugin.
+ * RuleSet checks the rule list based on a subject, operation and objectType.
+ * <p>
+ * Allows only enabled rules with identity equal to all, owner, the same, or a 
group with identity as a member,
+ * and operation is either all or the same operation,
+ * and object type is either all or the same object.
+ * </p>
  */
-public class RuleSet implements EventLoggerProvider
+public interface RuleSet extends EventLoggerProvider, List<Rule>, RuleInspector
 {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(RuleSet.class);
-
-    private final List<Rule> _rules;
-    private final Map<Subject, Map<LegacyOperation, Map<ObjectType, 
List<Rule>>>> _cache =
-                        Collections.synchronizedMap(new WeakHashMap<Subject, 
Map<LegacyOperation, Map<ObjectType, List<Rule>>>>());
-
-    private final EventLoggerProvider _eventLogger;
-    private Result _defaultResult = Result.DENIED;
-
-    public RuleSet(final EventLoggerProvider eventLogger,
-                   final Collection<Rule> rules,
-                   final Result defaultResult)
-    {
-        _eventLogger = eventLogger;
-        _rules = new ArrayList<>(rules);
-        _defaultResult = defaultResult;
-    }
-
-    int getRuleCount()
-    {
-        return _rules.size();
-    }
-
-    /**
-     * Filtered rules list based on a subject and operation.
-     *
-     * Allows only enabled rules with identity equal to all, the same, or a 
group with identity as a member,
-     * and operation is either all or the same operation.
-     */
-    private List<Rule> getRules(final Subject subject, final LegacyOperation 
operation, final ObjectType objectType)
-    {
-        final Map<ObjectType, List<Rule>> objects = 
getObjectToRuleCache(subject, operation);
-
-        // Lookup object type rules for the operation
-        if (!objects.containsKey(objectType))
-        {
-            final Set<Principal> principals = subject.getPrincipals();
-            boolean controlled = false;
-            List<Rule> filtered = new LinkedList<>();
-            for (Rule rule : _rules)
-            {
-                if ((rule.getOperation() == LegacyOperation.ALL || 
rule.getOperation() == operation)
-                    && (rule.getObjectType() == ObjectType.ALL || 
rule.getObjectType() == objectType))
-                {
-                    controlled = true;
-
-                    if (isRelevant(principals,rule))
-                    {
-                        filtered.add(rule);
-                    }
-                }
-            }
-
-            // Return null if there are no rules at all for this operation and 
object type
-            if (filtered.isEmpty() && !controlled)
-            {
-                filtered = null;
-            }
-
-            // Save the rules we selected
-            objects.put(objectType, filtered == null ? null : 
Collections.unmodifiableList(filtered));
-
-            LOGGER.debug("Cached {} RulesList: {}", objectType, filtered);
-        }
-
-        // Return the cached rules
-        List<Rule> rules = objects.get(objectType);
-
-        LOGGER.debug("Returning RuleList: {}", rules);
-
-        return rules;
-    }
+    @Override
+    Result check(Subject subject,
+                 LegacyOperation operation,
+                 ObjectType objectType,
+                 ObjectProperties properties);
 
-    /**
-     * Check the authorisation granted to a particular identity for an 
operation on an object type with
-     * specific properties.
-     *
-     * Looks up the entire ruleset, which may be cached, for the user and 
operation and goes through the rules
-     * in order to find the first one that matches. Either defers if there are 
no rules, returns the result of
-     * the first match found, or denies access if there are no matching rules. 
Normally, it would be expected
-     * to have a default deny or allow rule at the end of an access 
configuration however.
-     */
-    public Result check(Subject subject,
-                        LegacyOperation operation,
-                        ObjectType objectType,
-                        ObjectProperties properties)
+    default Result getDefault()
     {
-        LOGGER.debug("Checking action: operation={}, object={}, 
properties={}", operation, objectType, properties);
-
-        // get the list of rules relevant for this request
-        List<Rule> rules = getRules(subject, operation, objectType);
-        if (rules == null)
-        {
-
-            LOGGER.debug("No rules found, returning default result");
-
-            return getDefault();
-        }
-
-        final boolean ownerRules = rules.stream()
-                                        .anyMatch(rule -> 
rule.getIdentity().equalsIgnoreCase(Rule.OWNER));
-
-        if (ownerRules)
-        {
-            rules = new LinkedList<>(rules);
-
-            if (operation == LegacyOperation.CREATE)
-            {
-                rules.removeIf(rule -> 
rule.getIdentity().equalsIgnoreCase(Rule.OWNER));
-            }
-            else
-            {
-                // Discard OWNER rules if the object wasn't created by the 
subject
-                final String objectCreator = (String) 
properties.get(Property.CREATED_BY);
-                final Principal principal =
-                        
AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subject);
-                if (principal == null || 
!principal.getName().equalsIgnoreCase(objectCreator))
-                {
-                    rules.removeIf(rule -> 
rule.getIdentity().equalsIgnoreCase(Rule.OWNER));
-                }
-            }
-        }
-
-        // Iterate through a filtered set of rules dealing with this identity 
and operation
-        for (Rule rule : rules)
-        {
-            LOGGER.debug("Checking against rule: {}", rule);
-
-            if (rule.matches(operation, objectType, properties, subject))
-            {
-                RuleOutcome ruleOutcome = rule.getOutcome();
-                LOGGER.debug("Action matches.  Result: {}", ruleOutcome);
-                boolean allowed = ruleOutcome.isAllowed();
-                if(ruleOutcome.isLogged())
-                {
-                    if(allowed)
-                    {
-                        getEventLogger().message(AccessControlMessages.ALLOWED(
-                                operation.toString(),
-                                objectType.toString(),
-                                properties.toString()));
-                    }
-                    else
-                    {
-                        getEventLogger().message(AccessControlMessages.DENIED(
-                                operation.toString(),
-                                objectType.toString(),
-                                properties.toString()));
-                    }
-                }
-
-
-                return allowed ? Result.ALLOWED : Result.DENIED;
-            }
-        }
-        LOGGER.debug("Deferring result of ACL check");
-        // Defer to the next plugin of this type, if it exists
-        return Result.DEFER;
+        return Result.DENIED;
     }
 
-    /** Default deny. */
-    public Result getDefault()
+    static Builder newBuilder(EventLoggerProvider eventLogger)
     {
-        return _defaultResult;
-
+        return new RuleSetBuilder(eventLogger);
     }
 
-    /**
-      * Returns all rules in the {@link RuleSet}.   Primarily intended to 
support unit-testing.
-      * @return map of rules
-      */
-    public List<Rule> getAllRules()
-     {
-         return Collections.unmodifiableList(_rules);
-     }
-
-    private boolean isRelevant(final Set<Principal> principals, final Rule 
rule)
+    static RuleSet newInstance(EventLoggerProvider eventLogger, Collection<? 
extends Rule> rules, Result defaultResult)
     {
-        if (rule.getIdentity().equalsIgnoreCase(Rule.ALL) ||
-            rule.getIdentity().equalsIgnoreCase(Rule.OWNER))
-        {
-            return true;
-        }
-        else
-        {
-            for (Iterator<Principal> iterator = principals.iterator(); 
iterator.hasNext();)
-            {
-                final Principal principal = iterator.next();
-
-                if (rule.getIdentity().equalsIgnoreCase(principal.getName()))
-                {
-                    return true;
-                }
-            }
-        }
-
-        return false;
+        return 
newBuilder(eventLogger).addAllRules(rules).setDefaultResult(defaultResult).build();
     }
 
-    private Map<ObjectType, List<Rule>> getObjectToRuleCache(final Subject 
subject, final LegacyOperation operation)
+    interface Builder
     {
-        // Lookup identity in cache and create empty operation map if required
-        Map<LegacyOperation, Map<ObjectType, List<Rule>>> operations = 
_cache.get(subject);
-        if (operations == null)
-        {
-            operations = Collections.synchronizedMap(new 
EnumMap<LegacyOperation, Map<ObjectType, List<Rule>>>(LegacyOperation.class));
-            _cache.put(subject, operations);
-        }
+        Builder setDefaultResult(Result result);
 
-        // Lookup operation and create empty object type map if required
-        Map<ObjectType, List<Rule>> objects = operations.get(operation);
-        if (objects == null)
-        {
-            objects = Collections.synchronizedMap(new EnumMap<ObjectType, 
List<Rule>>(ObjectType.class));
-            operations.put(operation, objects);
-        }
-        return objects;
-    }
+        Builder addAllRules(Collection<? extends Rule> rules);
 
-    @Override
-    public EventLogger getEventLogger()
-    {
-        return _eventLogger.getEventLogger();
+        RuleSet build();
     }
 }
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetBuilder.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetBuilder.java
new file mode 100644
index 0000000..539821c
--- /dev/null
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetBuilder.java
@@ -0,0 +1,204 @@
+/*
+ *  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.config;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.logging.EventLoggerProvider;
+import org.apache.qpid.server.security.Result;
+import 
org.apache.qpid.server.security.access.config.RuleInspector.RuleInspectorFactory;
+import org.apache.qpid.server.security.access.config.RuleSet.Builder;
+import 
org.apache.qpid.server.security.access.config.RuleSetImpl.CachedInspector;
+import 
org.apache.qpid.server.security.access.config.RuleSetImpl.DefaultResultInspector;
+import 
org.apache.qpid.server.security.access.config.RuleSetImpl.RuleBasedInspectorFactory;
+import 
org.apache.qpid.server.security.access.config.RuleSetImpl.RuleBasedInspectorWithOwnerFilteringFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class RuleSetBuilder extends AbstractList<Rule> implements Builder
+{
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(RuleSetBuilder.class);
+
+    private final Map<LegacyOperation, Map<ObjectType, List<Rule>>> _ruleMap =
+            new EnumMap<>(LegacyOperation.class);
+
+    private final List<Rule> _ruleList = new ArrayList<>();
+
+    private final EventLoggerProvider _eventLogger;
+
+    private DefaultResultInspector _defaultInspector = new 
DefaultResultInspector(Result.DENIED);
+
+    RuleSetBuilder(EventLoggerProvider eventLogger)
+    {
+        super();
+        _eventLogger = eventLogger;
+    }
+
+    @Override
+    public Builder setDefaultResult(Result result)
+    {
+        _defaultInspector = new DefaultResultInspector(result);
+        return this;
+    }
+
+    @Override
+    public Builder addAllRules(Collection<? extends Rule> rules)
+    {
+        addAll(rules);
+        return this;
+    }
+
+    @Override
+    public RuleSet build()
+    {
+        return new RuleSetImpl(this);
+    }
+
+    @Override
+    public Rule get(int index)
+    {
+        return _ruleList.get(index);
+    }
+
+    @Override
+    public int size()
+    {
+        return _ruleList.size();
+    }
+
+    @Override
+    public boolean add(Rule rule)
+    {
+        if (validate(rule))
+        {
+            addRuleToOperationMap(rule);
+            return _ruleList.add(rule);
+        }
+        return false;
+    }
+
+    private boolean validate(Rule rule)
+    {
+        // Owner identity does not have any meaning in case of create 
operation.
+        if (rule.getOperation() == LegacyOperation.CREATE && rule.isForOwner())
+        {
+            LOGGER.warn("Invalid rule with create operation for owner '{}'", 
rule);
+            return false;
+        }
+        return true;
+    }
+
+    EventLoggerProvider getEventLogger()
+    {
+        return _eventLogger;
+    }
+
+    DefaultResultInspector getDefaultInspector()
+    {
+        return _defaultInspector;
+    }
+
+    Map<LegacyOperation, Map<ObjectType, RuleInspector>> buildCache()
+    {
+        final Map<LegacyOperation, Map<ObjectType, RuleInspector>> 
operationMap =
+                new EnumMap<>(LegacyOperation.class);
+
+        for (final LegacyOperation operation : LegacyOperation.values())
+        {
+            final Map<ObjectType, RuleInspector> objectMap = new 
EnumMap<>(ObjectType.class);
+            for (final ObjectType object : ObjectType.values())
+            {
+                final List<Rule> rules = groupBy(operation, object);
+                objectMap.put(object, convertToInspector(rules));
+            }
+            operationMap.put(operation, 
Collections.unmodifiableMap(objectMap));
+        }
+        return Collections.unmodifiableMap(operationMap);
+    }
+
+    private RuleInspector convertToInspector(List<? extends Rule> rules)
+    {
+        // Return fixed result if there are no rules at all for given 
operation and object type.
+        if (rules.isEmpty())
+        {
+            return _defaultInspector;
+        }
+        // In case of any rule with 'owner' identity the special 'owner' logic 
is needed.
+        if (rules.stream().anyMatch(Rule::isForOwner))
+        {
+            return 
newInspector(RuleBasedInspectorWithOwnerFilteringFactory.newInstance(rules, 
_eventLogger));
+        }
+        return newInspector(RuleBasedInspectorFactory.newInstance(rules, 
_eventLogger));
+    }
+
+    private RuleInspector newInspector(RuleInspectorFactory factory)
+    {
+        // The constant factory provides the same inspector for any input. 
Hence, caching is not needed.
+        if (factory.isConstant())
+        {
+            return factory.newInspector(Collections.emptySet());
+        }
+        return new CachedInspector(factory).init();
+    }
+
+    private List<Rule> groupBy(LegacyOperation operation, ObjectType 
objectType)
+    {
+        return Collections.unmodifiableList(_ruleMap.getOrDefault(operation, 
Collections.emptyMap())
+                .getOrDefault(objectType, Collections.emptyList()));
+    }
+
+    private void addRuleToOperationMap(Rule rule)
+    {
+        if (LegacyOperation.ALL == rule.getOperation())
+        {
+            for (final LegacyOperation operation : LegacyOperation.values())
+            {
+                addRuleToObjectTypeMap(_ruleMap.computeIfAbsent(operation,
+                        opera -> new EnumMap<>(ObjectType.class)), rule);
+            }
+        }
+        else
+        {
+            
addRuleToObjectTypeMap(_ruleMap.computeIfAbsent(rule.getOperation(),
+                    opera -> new EnumMap<>(ObjectType.class)), rule);
+        }
+    }
+
+    private void addRuleToObjectTypeMap(Map<ObjectType, List<Rule>> 
objectTypeMap, Rule rule)
+    {
+        if (ObjectType.ALL == rule.getObjectType())
+        {
+            for (final ObjectType object : ObjectType.values())
+            {
+                objectTypeMap.computeIfAbsent(object, obj -> new 
ArrayList<>()).add(rule);
+            }
+        }
+        else
+        {
+            objectTypeMap.computeIfAbsent(rule.getObjectType(), obj -> new 
ArrayList<>()).add(rule);
+        }
+    }
+}
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetImpl.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetImpl.java
new file mode 100644
index 0000000..09bcb4b
--- /dev/null
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSetImpl.java
@@ -0,0 +1,419 @@
+/*
+ *  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.config;
+
+import org.apache.qpid.server.logging.EventLogger;
+import org.apache.qpid.server.logging.EventLoggerProvider;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * Composite inspector that delegates the rule check to specialized inspector 
for given operation and object type.
+ * Rule inspector is a 'smart' ordered list of rules.
+ */
+final class RuleSetImpl extends AbstractList<Rule> implements RuleSet
+{
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(RuleSet.class);
+
+    private static final String CHECKING_AGAINST_RULE = "Checking against 
rule: {}";
+    private static final String CHECKING_ACTION_OPERATION_OBJECT_PROPERTIES =
+            "Checking action: operation={}, object={}, properties={}";
+
+    private final List<Rule> _rules;
+
+    private final Map<LegacyOperation, Map<ObjectType, RuleInspector>> _cache;
+
+    private final EventLoggerProvider _eventLogger;
+
+    private final DefaultResultInspector _defaultInspector;
+
+    RuleSetImpl(RuleSetBuilder builder)
+    {
+        super();
+        _rules = new ArrayList<>(builder);
+        _eventLogger = builder.getEventLogger();
+
+        _defaultInspector = builder.getDefaultInspector();
+        _cache = builder.buildCache();
+    }
+
+    @Override
+    public Result getDefault()
+    {
+        return _defaultInspector.getDefaultResult();
+    }
+
+    @Override
+    public Result check(Subject subject,
+                        LegacyOperation operation,
+                        ObjectType objectType,
+                        ObjectProperties properties)
+    {
+        return _cache.get(operation)
+                .get(objectType)
+                .check(subject, operation, objectType, properties);
+    }
+
+    @Override
+    public EventLogger getEventLogger()
+    {
+        return _eventLogger.getEventLogger();
+    }
+
+    @Override
+    public Rule get(int index)
+    {
+        return _rules.get(index);
+    }
+
+    @Override
+    public int size()
+    {
+        return _rules.size();
+    }
+
+    /**
+     * Inspector for given operation and object type and so it contains only 
rules that match operation and object type.
+     * The inspector caches the specialized inspectors for given principals of 
the subject in a map.
+     */
+    static final class CachedInspector implements RuleInspector
+    {
+        private final Map<Set<String>, RuleInspector> _cache = new 
ConcurrentHashMap<>();
+
+        private final Set<String> _ruleIdentities;
+
+        private final RuleInspectorFactory _factory;
+
+        CachedInspector(RuleInspectorFactory factory)
+        {
+            super();
+            _ruleIdentities = new HashSet<>(factory.allRuleIdentities());
+            _factory = factory;
+        }
+
+        /**
+         * Populates the cache with basic cases, the set of principals without 
any relevant principal or
+         * the set with only one relevant principal. If the rules don't 
utilize groups than all possible cases will be
+         * cached at the beginning.
+         * @return Cached inspector with populated cache
+         */
+        public CachedInspector init()
+        {
+            final Set<String> empty = Collections.emptySet();
+            _cache.put(empty, _factory.newInspector(empty));
+
+            for (final String ruleIdentity : _ruleIdentities)
+            {
+                final Set<String> identities = 
Collections.singleton(ruleIdentity);
+                _cache.put(identities, _factory.newInspector(identities));
+            }
+            return this;
+        }
+
+        @Override
+        public Result check(Subject subject, LegacyOperation operation,
+                            ObjectType objectType, ObjectProperties properties)
+        {
+            final Set<String> relevantPrincipals = 
collectPrincipalNames(subject);
+            relevantPrincipals.retainAll(_ruleIdentities);
+
+            return _cache.computeIfAbsent(relevantPrincipals, 
_factory::newInspector)
+                    .check(subject, operation, objectType, properties);
+        }
+
+        private Set<String> collectPrincipalNames(Subject subject)
+        {
+            final Set<Principal> principals = subject.getPrincipals();
+            final Set<String> principalNames = new 
HashSet<>(principals.size());
+            for (final Principal principal : principals)
+            {
+                principalNames.add(principal.getName());
+            }
+            return principalNames;
+        }
+    }
+
+    /**
+     * If there is no rule for given operation and object type then the 
default result has to be returned.
+     * The default result is DENIED.
+     */
+    static final class DefaultResultInspector implements RuleInspector
+    {
+        private final Result _defaultResult;
+
+        DefaultResultInspector(Result defaultResult)
+        {
+            super();
+            _defaultResult = 
Optional.ofNullable(defaultResult).orElse(Result.DENIED);
+        }
+
+        @Override
+        public Result check(Subject subject, LegacyOperation operation,
+                            ObjectType objectType, ObjectProperties properties)
+        {
+            LOGGER.debug("No rules found, returning default result");
+            return _defaultResult;
+        }
+
+        public Result getDefaultResult()
+        {
+            return _defaultResult;
+        }
+    }
+
+    /**
+     * Rule inspector is a 'smart' ordered list of rules for given operation 
and object type that match subject
+     * principals. Hence, the rule list has been already filtered based on the 
subject principals and so it contains
+     * only rules that match the operation, object type and subject principals.
+     */
+    private static final class RuleBasedInspector implements RuleInspector
+    {
+        private final EventLoggerProvider _logger;
+
+        private final Rule[] _rules;
+
+        RuleBasedInspector(Collection<? extends Rule> rules, 
EventLoggerProvider logger)
+        {
+            _logger = logger;
+            _rules = rules.toArray(new Rule[0]);
+        }
+
+        @Override
+        public Result check(Subject subject,
+                            LegacyOperation operation,
+                            ObjectType objectType,
+                            ObjectProperties properties)
+        {
+            LOGGER.debug(CHECKING_ACTION_OPERATION_OBJECT_PROPERTIES, 
operation, objectType, properties);
+            for (final Rule rule : _rules)
+            {
+                LOGGER.debug(CHECKING_AGAINST_RULE, rule);
+                if (rule.predicatesMatch(operation, properties, subject))
+                {
+                    return rule.getOutcome().logResult(_logger, operation, 
objectType, properties);
+                }
+            }
+            LOGGER.debug("Deferring result of ACL check");
+            return Result.DEFER;
+        }
+    }
+
+    /**
+     * Rule inspector with 'owner' logic.
+     */
+    private static final class RuleBasedInspectorWithOwnerFiltering implements 
RuleInspector
+    {
+        // Iteration through array is faster than using a collection.
+        private final Rule[] _rules;
+
+        private final EventLoggerProvider _logger;
+
+        RuleBasedInspectorWithOwnerFiltering(Collection<? extends Rule> rules, 
EventLoggerProvider logger)
+        {
+            super();
+            _logger = logger;
+            _rules = rules.toArray(new Rule[0]);
+        }
+
+        @Override
+        public Result check(Subject subject,
+                            LegacyOperation operation,
+                            ObjectType objectType,
+                            ObjectProperties properties)
+        {
+            LOGGER.debug(CHECKING_ACTION_OPERATION_OBJECT_PROPERTIES, 
operation, objectType, properties);
+
+            final Object objectCreator = properties.get(Property.CREATED_BY);
+            final Principal principal = 
AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subject);
+
+            // Discard OWNER rules if the object wasn't created by the subject
+            if (principal != null && principal.getName().equals(objectCreator))
+            {
+                for (final Rule rule : _rules)
+                {
+                    LOGGER.debug(CHECKING_AGAINST_RULE, rule);
+                    if (rule.predicatesMatch(operation, properties, subject))
+                    {
+                        return rule.getOutcome().logResult(_logger, operation, 
objectType, properties);
+                    }
+                }
+            }
+            else
+            {
+                for (final Rule rule : _rules)
+                {
+                    LOGGER.debug(CHECKING_AGAINST_RULE, rule);
+                    // Discarding owner rule
+                    if (!rule.isForOwner() &&
+                            rule.predicatesMatch(operation, properties, 
subject))
+                    {
+                        return rule.getOutcome().logResult(_logger, operation, 
objectType, properties);
+                    }
+                }
+            }
+            LOGGER.debug("Deferring result of ACL check");
+            return Result.DEFER;
+        }
+    }
+
+    private abstract static class AbstractInspectorFactory implements 
RuleInspectorFactory
+    {
+        private final EventLoggerProvider _logger;
+
+        // Iteration through array is faster than using a collection.
+        private final Rule[] _rules;
+
+        private final Set<String> _allRuleIdentities;
+
+        abstract boolean matchAnyIdentity(Rule rule);
+
+        abstract RuleInspector newInspector(List<? extends Rule> list, 
EventLoggerProvider logger);
+
+        AbstractInspectorFactory(List<? extends Rule> rules, 
EventLoggerProvider logger)
+        {
+            super();
+            final List<? extends Rule> filterRules = 
filterSuppressedRules(rules);
+            _rules = filterRules.toArray(new Rule[0]);
+            _logger = Objects.requireNonNull(logger);
+            _allRuleIdentities = collectRuleIdentities(filterRules);
+        }
+
+        @Override
+        public Set<String> allRuleIdentities()
+        {
+            return Collections.unmodifiableSet(_allRuleIdentities);
+        }
+
+        @Override
+        public RuleInspector newInspector(Set<String> principalNames)
+        {
+            final List<Rule> filteredRules = new ArrayList<>();
+            for (final Rule rule : _rules)
+            {
+                if (matchAnyIdentity(rule) || 
principalNames.contains(rule.getIdentity()))
+                {
+                    filteredRules.add(rule);
+                }
+            }
+            return newInspector(filteredRules, _logger);
+        }
+
+        private Set<String> collectRuleIdentities(Collection<? extends Rule> 
rules)
+        {
+            return rules.stream()
+                    .filter(rule -> !rule.isForOwnerOrAll())
+                    .map(Rule::getIdentity)
+                    .collect(Collectors.toSet());
+        }
+
+        /**
+         * The final rule always match for any principal (identity). Hence, 
any rule after the final rule is never
+         * checked and the rules suppressed by the final rule can be ignored.
+         *
+         * @param rules the list of the rules
+         * @return a filtered list of the rules. If there is any final rule 
then the final rule is the last one.
+         */
+        private List<? extends Rule> filterSuppressedRules(List<? extends 
Rule> rules)
+        {
+            final ListIterator<? extends Rule> iter = rules.listIterator();
+            while (iter.hasNext())
+            {
+                final Rule rule = iter.next();
+                if (isFinalRule(rule))
+                {
+                    return rules.subList(0, iter.nextIndex());
+                }
+            }
+            return rules;
+        }
+
+        private boolean isFinalRule(Rule rule)
+        {
+            return rule.anyPropertiesMatch() && rule.isForAll();
+        }
+    }
+
+    static final class RuleBasedInspectorFactory extends 
AbstractInspectorFactory
+    {
+        public static RuleInspectorFactory newInstance(List<? extends Rule> 
rules, EventLoggerProvider logger)
+        {
+            return new RuleBasedInspectorFactory(rules, logger);
+        }
+
+        RuleBasedInspectorFactory(List<? extends Rule> rules, 
EventLoggerProvider logger)
+        {
+            super(rules, logger);
+        }
+
+        @Override
+        boolean matchAnyIdentity(Rule rule)
+        {
+            return rule.isForAll();
+        }
+
+        @Override
+        RuleInspector newInspector(List<? extends Rule> filteredRules, 
EventLoggerProvider logger)
+        {
+            return new RuleBasedInspector(filteredRules, logger);
+        }
+    }
+
+    static final class RuleBasedInspectorWithOwnerFilteringFactory extends 
AbstractInspectorFactory
+    {
+        public static RuleInspectorFactory newInstance(List<? extends Rule> 
rules, EventLoggerProvider logger)
+        {
+            return new RuleBasedInspectorWithOwnerFilteringFactory(rules, 
logger);
+        }
+
+        RuleBasedInspectorWithOwnerFilteringFactory(List<? extends Rule> 
rules, EventLoggerProvider logger)
+        {
+            super(rules, logger);
+        }
+
+        @Override
+        boolean matchAnyIdentity(Rule rule)
+        {
+            return rule.isForOwnerOrAll();
+        }
+
+        @Override
+        RuleInspector newInspector(List<? extends Rule> filteredRules, 
EventLoggerProvider logger)
+        {
+            return new RuleBasedInspectorWithOwnerFiltering(filteredRules, 
logger);
+        }
+    }
+}
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractCommonRuleBasedAccessControlProvider.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractCommonRuleBasedAccessControlProvider.java
index 37d90a1..f5a888b 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractCommonRuleBasedAccessControlProvider.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractCommonRuleBasedAccessControlProvider.java
@@ -81,7 +81,7 @@ abstract class AbstractCommonRuleBasedAccessControlProvider<X 
extends AbstractCo
         {
             rules.add(new Rule(configuredRule));
         }
-        return new RuleBasedAccessControl(new RuleSet(this, rules, 
_defaultResult), getModel());
+        return new RuleBasedAccessControl(RuleSet.newInstance(this, rules, 
_defaultResult), getModel());
     }
 
     public Result getDefaultResult()
@@ -98,7 +98,7 @@ abstract class AbstractCommonRuleBasedAccessControlProvider<X 
extends AbstractCo
     {
         final RuleSet ruleSet = AclFileParser.parse(path, this);
         final List<AclRule> aclRules = new ArrayList<>();
-        for (final Rule rule : ruleSet.getAllRules())
+        for (final Rule rule : ruleSet)
         {
             aclRules.add(rule.asAclRule());
         }
diff --git 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/RuleOutcome.java
 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/RuleOutcome.java
index a9b2880..976776b 100644
--- 
a/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/RuleOutcome.java
+++ 
b/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/RuleOutcome.java
@@ -20,32 +20,63 @@
  */
 package org.apache.qpid.server.security.access.plugins;
 
+import org.apache.qpid.server.logging.EventLoggerProvider;
+import org.apache.qpid.server.logging.messages.AccessControlMessages;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.access.config.LegacyOperation;
+import org.apache.qpid.server.security.access.config.ObjectProperties;
+import org.apache.qpid.server.security.access.config.ObjectType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * An enumeration of all possible outcomes that can be applied to an access 
control v2 rule.
  */
 public enum RuleOutcome
 {
-    ALLOW(true, false),
-    ALLOW_LOG(true, true),
-    DENY(false, false),
-    DENY_LOG(false, true);
+    ALLOW(Result.ALLOWED),
+    ALLOW_LOG(Result.ALLOWED)
+            {
+                @Override
+                public Result logResult(EventLoggerProvider logger, 
LegacyOperation operation, ObjectType objectType, ObjectProperties 
objectProperties)
+                {
+                    LOGGER.debug(ACTION_MATCHES_RESULT, this);
+                    
logger.getEventLogger().message(AccessControlMessages.ALLOWED(
+                            operation.toString(),
+                            objectType.toString(),
+                            objectProperties.toString()));
+                    return _result;
+                }
+            },
+    DENY(Result.DENIED),
+    DENY_LOG(Result.DENIED)
+            {
+                @Override
+                public Result logResult(EventLoggerProvider logger, 
LegacyOperation operation, ObjectType objectType, ObjectProperties 
objectProperties)
+                {
+                    LOGGER.debug(ACTION_MATCHES_RESULT, this);
+                    
logger.getEventLogger().message(AccessControlMessages.DENIED(
+                            operation.toString(),
+                            objectType.toString(),
+                            objectProperties.toString()));
+                    return _result;
+                }
+            };
 
-    private final boolean _allowed;
-    private final boolean _logged;
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(RuleOutcome.class);
 
-    RuleOutcome(final boolean allowed, final boolean logged)
-    {
-        _allowed = allowed;
-        _logged = logged;
-    }
+    private static final String ACTION_MATCHES_RESULT = "Action matches. 
Result: {}";
+
+    final Result _result;
 
-    public boolean isAllowed()
+    RuleOutcome(final Result result)
     {
-        return _allowed;
+        _result = result;
     }
 
-    public boolean isLogged()
+    public Result logResult(EventLoggerProvider logger, LegacyOperation 
operation, ObjectType objectType, ObjectProperties objectProperties)
     {
-        return _logged;
+        LOGGER.debug(ACTION_MATCHES_RESULT, this);
+        return _result;
     }
 }
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclFileParserTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclFileParserTest.java
index 486ae2e..5aea03f 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclFileParserTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclFileParserTest.java
@@ -66,7 +66,7 @@ public class AclFileParserTest extends UnitTestBase
     public void testEmptyRuleSetDefaults() throws Exception
     {
         final RuleSet ruleSet = writeACLConfig();
-        assertEquals(0, ruleSet.getAllRules().size());
+        assertEquals(0, ruleSet.size());
         assertEquals(Result.DENIED, ruleSet.getDefault());
     }
 
@@ -270,19 +270,19 @@ public class AclFileParserTest extends UnitTestBase
     public void testValidConfig() throws Exception
     {
         RuleSet ruleSet = writeACLConfig("CONFIG defaultdefer=true");
-        assertEquals("Unexpected number of rules", 0, 
ruleSet.getAllRules().size());
+        assertEquals("Unexpected number of rules", 0, ruleSet.size());
         assertEquals("Unexpected default outcome", Result.DEFER, 
ruleSet.getDefault());
 
         ruleSet = writeACLConfig("CONFIG defaultdeny=true");
-        assertEquals("Unexpected number of rules", 0, 
ruleSet.getAllRules().size());
+        assertEquals("Unexpected number of rules", 0, ruleSet.size());
         assertEquals("Unexpected default outcome", Result.DENIED, 
ruleSet.getDefault());
 
         ruleSet = writeACLConfig("CONFIG defaultallow=true");
-        assertEquals("Unexpected number of rules", 0, 
ruleSet.getAllRules().size());
+        assertEquals("Unexpected number of rules", 0, ruleSet.size());
         assertEquals("Unexpected default outcome", Result.ALLOWED, 
ruleSet.getDefault());
 
         ruleSet = writeACLConfig("CONFIG defaultdefer=false defaultallow=true 
defaultdeny=false df=false");
-        assertEquals("Unexpected number of rules", 0, 
ruleSet.getAllRules().size());
+        assertEquals("Unexpected number of rules", 0, ruleSet.size());
         assertEquals("Unexpected default outcome", Result.ALLOWED, 
ruleSet.getDefault());
     }
 
@@ -293,9 +293,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testValidRule() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL DENY-LOG user1 ACCESS 
VIRTUALHOST");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "user1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", 
ObjectType.VIRTUALHOST, rule.getObjectType());
@@ -309,9 +309,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testValidRuleWithSingleQuotedProperty() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL ALLOW all CREATE EXCHANGE 
name = 'value'");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "all", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", ObjectType.EXCHANGE, 
rule.getObjectType());
@@ -330,8 +330,8 @@ public class AclFileParserTest extends UnitTestBase
     {
         final RuleSet rules = writeACLConfig("ACL ALLOW all CREATE EXCHANGE 
name = \"value\"");
 
-        assertEquals(1, rules.getAllRules().size());
-        final Rule rule = rules.getAllRules().get(0);
+        assertEquals(1, rules.size());
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "all", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", ObjectType.EXCHANGE, 
rule.getObjectType());
@@ -349,9 +349,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testValidRuleWithManyProperties() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL ALLOW admin DELETE QUEUE 
name=name1 owner = owner1");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "admin", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.DELETE, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", ObjectType.QUEUE, 
rule.getObjectType());
@@ -373,9 +373,9 @@ public class AclFileParserTest extends UnitTestBase
         final RuleSet rules = writeACLConfig("ACL ALLOW all CREATE EXCHANGE 
routingKey = 'news.#'",
                                              "ACL ALLOW all CREATE EXCHANGE 
routingKey = 'news.co.#'",
                                              "ACL ALLOW all CREATE EXCHANGE 
routingKey = *.co.medellin");
-        assertEquals(3, rules.getAllRules().size());
+        assertEquals(3, rules.size());
 
-        final Rule rule1 = rules.getAllRules().get(0);
+        final Rule rule1 = rules.get(0);
         assertEquals("Rule has unexpected identity", "all", 
rule1.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, 
rule1.getOperation());
         assertEquals("Rule has object type", ObjectType.EXCHANGE, 
rule1.getObjectType());
@@ -385,14 +385,14 @@ public class AclFileParserTest extends UnitTestBase
                         .build();
         assertEquals("Rule has unexpected predicates", expectedPredicates1, 
rule1.getPredicates());
 
-        final Rule rule2 = rules.getAllRules().get(1);
+        final Rule rule2 = rules.get(1);
         final AclRulePredicates expectedPredicates2 =
                 new AclRulePredicatesBuilder()
                         .put(Property.ROUTING_KEY, "news.co.#")
                         .build();
         assertEquals("Rule has unexpected predicates", expectedPredicates2, 
rule2.getPredicates());
 
-        final Rule rule3 = rules.getAllRules().get(2);
+        final Rule rule3 = rules.get(2);
         final AclRulePredicates expectedPredicates3 =
                 new AclRulePredicatesBuilder()
                         .put(Property.ROUTING_KEY, "*.co.medellin")
@@ -406,23 +406,23 @@ public class AclFileParserTest extends UnitTestBase
         final RuleSet rules = writeACLConfig("5 ACL DENY all CREATE EXCHANGE",
                                              "3 ACL ALLOW all CREATE EXCHANGE 
routingKey = 'news.co.#'",
                                              "1 ACL ALLOW all CREATE EXCHANGE 
routingKey = *.co.medellin");
-        assertEquals(3, rules.getAllRules().size());
+        assertEquals(3, rules.size());
 
-        final Rule rule1 = rules.getAllRules().get(0);
+        final Rule rule1 = rules.get(0);
         final AclRulePredicates expectedPredicates1 =
                 new AclRulePredicatesBuilder()
                         .put(Property.ROUTING_KEY, "*.co.medellin")
                         .build();
         assertEquals("Rule has unexpected predicates", expectedPredicates1, 
rule1.getPredicates());
 
-        final Rule rule3 = rules.getAllRules().get(1);
+        final Rule rule3 = rules.get(1);
         final AclRulePredicates expectedPredicates3 =
                 new AclRulePredicatesBuilder()
                         .put(Property.ROUTING_KEY, "news.co.#")
                         .build();
         assertEquals("Rule has unexpected predicates", expectedPredicates3, 
rule3.getPredicates());
 
-        final Rule rule5 = rules.getAllRules().get(2);
+        final Rule rule5 = rules.get(2);
         assertEquals("Rule has unexpected identity", "all", 
rule5.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, 
rule5.getOperation());
         assertEquals("Rule has unexpected object type", ObjectType.EXCHANGE, 
rule5.getObjectType());
@@ -450,7 +450,7 @@ public class AclFileParserTest extends UnitTestBase
     public void testShortValidRule() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL DENY user UPDATE");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
         validateRule(rules, "user", LegacyOperation.UPDATE, ObjectType.ALL, 
EMPTY);
     }
 
@@ -461,9 +461,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testMixedCaseRuleInterpretation() throws Exception
     {
         final RuleSet rules = writeACLConfig("AcL deny-LOG User1 BiND Exchange 
Name=AmQ.dIrect");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "User1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.BIND, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", ObjectType.EXCHANGE, 
rule.getObjectType());
@@ -485,9 +485,9 @@ public class AclFileParserTest extends UnitTestBase
         final RuleSet rules = writeACLConfig("#Comment",
                                              "ACL DENY-LOG user1 ACCESS 
VIRTUALHOST # another comment",
                                              "  # final comment with leading 
whitespace");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "user1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", 
ObjectType.VIRTUALHOST, rule.getObjectType());
@@ -501,9 +501,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testWhitespace() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL\tDENY-LOG\t\t user1\t 
\tACCESS VIRTUALHOST");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "user1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", 
ObjectType.VIRTUALHOST, rule.getObjectType());
@@ -514,9 +514,9 @@ public class AclFileParserTest extends UnitTestBase
     public void testWhitespace2() throws Exception
     {
         final RuleSet rules = writeACLConfig("ACL\u000B DENY-LOG\t\t user1\t 
\tACCESS VIRTUALHOST\u001E");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "user1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", 
ObjectType.VIRTUALHOST, rule.getObjectType());
@@ -531,9 +531,9 @@ public class AclFileParserTest extends UnitTestBase
     {
         final RuleSet rules = writeACLConfig("ACL DENY-LOG user1 \\",
                                              "ACCESS VIRTUALHOST");
-        assertEquals(1, rules.getAllRules().size());
+        assertEquals(1, rules.size());
 
-        final Rule rule = rules.getAllRules().get(0);
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", "user1", 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", 
ObjectType.VIRTUALHOST, rule.getObjectType());
@@ -704,8 +704,8 @@ public class AclFileParserTest extends UnitTestBase
                               ObjectType objectType,
                               AclRulePredicates predicates)
     {
-        assertEquals(1, rules.getAllRules().size());
-        final Rule rule = rules.getAllRules().get(0);
+        assertEquals(1, rules.size());
+        final Rule rule = rules.get(0);
         assertEquals("Rule has unexpected identity", username, 
rule.getIdentity());
         assertEquals("Rule has unexpected operation", operation, 
rule.getOperation());
         assertEquals("Rule has unexpected object type", objectType, 
rule.getObjectType());
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
index 91343fe..48b2a8e 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java
@@ -23,10 +23,6 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.qpid.server.security.access.config.AclRulePredicates;
-import org.apache.qpid.server.security.access.config.AclRulePredicatesBuilder;
-import org.apache.qpid.server.security.access.config.Property;
-import org.apache.qpid.server.security.access.config.FirewallRule;
 import 
org.apache.qpid.server.security.access.config.predicates.TestFirewallRule;
 import org.apache.qpid.server.security.access.firewall.FirewallRuleFactory;
 import org.apache.qpid.test.utils.UnitTestBase;
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/LegacyOperationTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/LegacyOperationTest.java
new file mode 100644
index 0000000..19e2aff
--- /dev/null
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/LegacyOperationTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.config;
+
+import junit.framework.TestCase;
+import org.junit.Test;
+
+public class LegacyOperationTest extends TestCase
+{
+    @Test
+    public void testToString() {
+        assertEquals("Access", LegacyOperation.ACCESS.toString());
+        assertEquals("Access_logs", LegacyOperation.ACCESS_LOGS.toString());
+        assertEquals("All", LegacyOperation.ALL.toString());
+        assertEquals("Bind", LegacyOperation.BIND.toString());
+        assertEquals("Create", LegacyOperation.CREATE.toString());
+        assertEquals("Configure", LegacyOperation.CONFIGURE.toString());
+        assertEquals("Consume", LegacyOperation.CONSUME.toString());
+        assertEquals("Delete", LegacyOperation.DELETE.toString());
+        assertEquals("Invoke", LegacyOperation.INVOKE.toString());
+        assertEquals("Publish", LegacyOperation.PUBLISH.toString());
+        assertEquals("Purge", LegacyOperation.PURGE.toString());
+        assertEquals("Shutdown", LegacyOperation.SHUTDOWN.toString());
+        assertEquals("Unbind", LegacyOperation.UNBIND.toString());
+        assertEquals("Update", LegacyOperation.UPDATE.toString());
+    }
+}
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ObjectTypeTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ObjectTypeTest.java
new file mode 100644
index 0000000..fa9bb44
--- /dev/null
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ObjectTypeTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.config;
+
+import junit.framework.TestCase;
+import org.junit.Test;
+
+import java.util.EnumSet;
+
+public class ObjectTypeTest extends TestCase
+{
+    @Test
+    public void testIsSupported()
+    {
+        for (LegacyOperation operation : LegacyOperation.values())
+        {
+            assertTrue(ObjectType.ALL.isSupported(operation));
+        }
+
+        for (ObjectType objectType : ObjectType.values())
+        {
+            for (LegacyOperation operation : objectType.getOperations())
+            {
+                assertTrue(objectType.isSupported(operation));
+            }
+            final EnumSet<LegacyOperation> legacyOperations = 
EnumSet.allOf(LegacyOperation.class);
+            legacyOperations.removeAll(objectType.getOperations());
+            for (LegacyOperation operation : legacyOperations)
+            {
+                assertFalse(objectType.isSupported(operation));
+            }
+        }
+    }
+
+    @Test
+    public void testTestToString()
+    {
+        assertEquals("All", ObjectType.ALL.toString());
+        assertEquals("Broker", ObjectType.BROKER.toString());
+        assertEquals("Exchange", ObjectType.EXCHANGE.toString());
+        assertEquals("Group", ObjectType.GROUP.toString());
+        assertEquals("Management", ObjectType.MANAGEMENT.toString());
+        assertEquals("Method", ObjectType.METHOD.toString());
+        assertEquals("Queue", ObjectType.QUEUE.toString());
+        assertEquals("User", ObjectType.USER.toString());
+        assertEquals("Virtualhost", ObjectType.VIRTUALHOST.toString());
+        assertEquals("Virtualhostnode", ObjectType.VIRTUALHOSTNODE.toString());
+    }
+}
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleCollectorTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleCollectorTest.java
index 9218caf..9ccbf45 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleCollectorTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleCollectorTest.java
@@ -44,10 +44,9 @@ public class RuleCollectorTest extends UnitTestBase
 
         RuleSet ruleSet = 
creator.createRuleSet(Mockito.mock(EventLoggerProvider.class));
         assertNotNull(ruleSet);
-        assertEquals(2, ruleSet.getAllRules().size());
-        assertEquals(newRule(RuleOutcome.ALLOW, LegacyOperation.ACCESS), 
ruleSet.getAllRules().get(1));
-        assertEquals(newRule(RuleOutcome.DENY, LegacyOperation.PUBLISH, 
ObjectType.EXCHANGE),
-                     ruleSet.getAllRules().get(0));
+        assertEquals(2, ruleSet.size());
+        assertEquals(newRule(RuleOutcome.ALLOW, LegacyOperation.ACCESS), 
ruleSet.get(1));
+        assertEquals(newRule(RuleOutcome.DENY, LegacyOperation.PUBLISH, 
ObjectType.EXCHANGE), ruleSet.get(0));
     }
 
     @Test
@@ -61,10 +60,9 @@ public class RuleCollectorTest extends UnitTestBase
 
         RuleSet ruleSet = 
creator.createRuleSet(Mockito.mock(EventLoggerProvider.class));
         assertNotNull(ruleSet);
-        assertEquals(2, ruleSet.getAllRules().size());
-        assertEquals(newRule(RuleOutcome.ALLOW, LegacyOperation.ACCESS), 
ruleSet.getAllRules().get(1));
-        assertEquals(newRule(RuleOutcome.DENY, LegacyOperation.PUBLISH, 
ObjectType.EXCHANGE),
-                     ruleSet.getAllRules().get(0));
+        assertEquals(2, ruleSet.size());
+        assertEquals(newRule(RuleOutcome.ALLOW, LegacyOperation.ACCESS), 
ruleSet.get(1));
+        assertEquals(newRule(RuleOutcome.DENY, LegacyOperation.PUBLISH, 
ObjectType.EXCHANGE), ruleSet.get(0));
     }
 
     @Test
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleSetTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleSetTest.java
index af2f643..165abfe 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleSetTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleSetTest.java
@@ -22,21 +22,31 @@
 package org.apache.qpid.server.security.access.config;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.ListIterator;
 
 import javax.security.auth.Subject;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
+import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.EventLoggerProvider;
+import org.apache.qpid.server.model.AuthenticationProvider;
 import org.apache.qpid.server.security.Result;
 import org.apache.qpid.server.security.access.config.Rule.Builder;
 import org.apache.qpid.server.security.access.plugins.RuleOutcome;
 import org.apache.qpid.server.security.auth.TestPrincipalUtils;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
 import org.apache.qpid.test.utils.UnitTestBase;
 
 /**
@@ -99,7 +109,7 @@ public class RuleSetTest extends UnitTestBase
                 .withPredicates(properties)
                 .build());
         ruleSet = createRuleSet();
-        assertEquals(1, ruleSet.getRuleCount());
+        assertEquals(1, ruleSet.size());
         assertEquals(Result.ALLOWED, ruleSet.check(subject, operation, 
objectType, properties));
     }
 
@@ -108,7 +118,7 @@ public class RuleSetTest extends UnitTestBase
     {
         final RuleSet ruleSet = createRuleSet();
         assertNotNull(ruleSet);
-        assertEquals(ruleSet.getRuleCount(), 0);
+        assertEquals(0, ruleSet.size());
         assertEquals(ruleSet.getDefault(),
                             ruleSet.check(_testSubject, 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, EMPTY));
     }
@@ -325,7 +335,7 @@ public class RuleSetTest extends UnitTestBase
     @Test
     public void testExchangeCreate()
     {
-        ObjectProperties properties = new ObjectProperties(_exchangeName);
+        final ObjectProperties properties = new 
ObjectProperties(_exchangeName);
         properties.put(Property.TYPE, _exchangeType);
 
         assertDenyGrantAllow(_testSubject, LegacyOperation.CREATE, 
ObjectType.EXCHANGE, properties);
@@ -367,7 +377,7 @@ public class RuleSetTest extends UnitTestBase
                 .withPredicates(temporary)
                 .build());
         ruleSet = createRuleSet();
-        assertEquals(1, ruleSet.getRuleCount());
+        assertEquals(1, ruleSet.size());
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CONSUME, ObjectType.QUEUE, temporary));
 
@@ -409,7 +419,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CONSUME, ObjectType.QUEUE, normal));
@@ -450,7 +460,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CONSUME, ObjectType.QUEUE, normal));
@@ -494,7 +504,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CREATE, ObjectType.QUEUE, named));
@@ -533,7 +543,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CREATE, ObjectType.QUEUE, named));
@@ -584,7 +594,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         ruleSet = createRuleSet();
-        assertEquals(3, ruleSet.getRuleCount());
+        assertEquals(3, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CREATE, ObjectType.QUEUE, named));
@@ -620,7 +630,7 @@ public class RuleSetTest extends UnitTestBase
                 .withPredicates(named)
                 .build());
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             ruleSet.check(_testSubject, 
LegacyOperation.CREATE, ObjectType.QUEUE, named));
@@ -654,7 +664,7 @@ public class RuleSetTest extends UnitTestBase
                 .withPredicates(named)
                 .build());
         ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.CREATE, ObjectType.QUEUE, named));
         assertEquals(Result.ALLOWED,
@@ -674,7 +684,7 @@ public class RuleSetTest extends UnitTestBase
                 .withObject(ObjectType.VIRTUALHOST)
                 .build());
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(1, ruleSet.getRuleCount());
+        assertEquals(1, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             
ruleSet.check(TestPrincipalUtils.createTestSubject("usera"), 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, EMPTY));
@@ -701,7 +711,7 @@ public class RuleSetTest extends UnitTestBase
                 .withObject(ObjectType.VIRTUALHOST)
                 .build());
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             
ruleSet.check(TestPrincipalUtils.createTestSubject("usera", allowGroup), 
LegacyOperation
@@ -720,8 +730,8 @@ public class RuleSetTest extends UnitTestBase
     @Test
     public void testAllowDeterminedByRuleOrder()
     {
-        String group = "group";
-        String user = "user";
+        final String group = "group";
+        final String user = "user";
 
         _ruleCollector.addRule(1, new Builder()
                 .withIdentity(user)
@@ -736,7 +746,7 @@ public class RuleSetTest extends UnitTestBase
                 .withObject(ObjectType.VIRTUALHOST)
                 .build());
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                             
ruleSet.check(TestPrincipalUtils.createTestSubject(user, group), 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, EMPTY));
@@ -749,8 +759,8 @@ public class RuleSetTest extends UnitTestBase
     @Test
     public void testDenyDeterminedByRuleOrder()
     {
-        String group = "aclgroup";
-        String user = "usera";
+        final String group = "aclgroup";
+        final String user = "usera";
 
         _ruleCollector.addRule(1, new Builder()
                 .withIdentity(group)
@@ -766,7 +776,7 @@ public class RuleSetTest extends UnitTestBase
                 .build());
 
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(2, ruleSet.getRuleCount());
+        assertEquals(2, ruleSet.size());
 
         assertEquals(Result.DENIED,
                             
ruleSet.check(TestPrincipalUtils.createTestSubject(user, group), 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, EMPTY));
@@ -847,7 +857,7 @@ public class RuleSetTest extends UnitTestBase
                 .withObject(ObjectType.QUEUE)
                 .build());
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(1, ruleSet.getRuleCount());
+        assertEquals(1, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                      ruleSet.check(_testSubject,
@@ -872,7 +882,7 @@ public class RuleSetTest extends UnitTestBase
                 .withObject(ObjectType.QUEUE)
                 .build());
         final RuleSet ruleSet = createRuleSet();
-        assertEquals(1, ruleSet.getRuleCount());
+        assertEquals(1, ruleSet.size());
 
         assertEquals(Result.ALLOWED,
                      ruleSet.check(_testSubject,
@@ -887,4 +897,719 @@ public class RuleSetTest extends UnitTestBase
                                    new ObjectProperties(Property.CREATED_BY, 
"anotherUser")));
 
     }
+
+    @Test
+    public void testSuppressedRules()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "testExchange")
+                .build());
+        _ruleCollector.addRule(2, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+        _ruleCollector.addRule(4, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(4, ruleSet.size());
+
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, new 
ObjectProperties("testExchange")));
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, new 
ObjectProperties("exchange")));
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, new ObjectProperties()));
+    }
+
+    @Test
+    public void testPublishToExchange()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "broadcast.*")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(7, new Builder()
+                .withPredicate(Property.NAME, "rs.broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(4, ruleSet.size());
+
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, new ObjectProperties()));
+
+        ObjectProperties object = new ObjectProperties("broadcast");
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "broadcast.public");
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("rs.broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "queue");
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("brs");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        // Another user
+        final Subject testSubject = 
TestPrincipalUtils.createTestSubject("Java");
+        object = new ObjectProperties("rs.broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        assertEquals(Result.DEFER, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+    }
+
+    @Test
+    public void testPublishToExchange_OwnerBased()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(11, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.QUEUE_NAME, "QQ")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(4, ruleSet.size());
+
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, new ObjectProperties()));
+
+        // User = owner
+        ObjectProperties object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "brs");
+        object.setCreatedBy(TEST_USER);
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        object.setCreatedBy(TEST_USER);
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+    }
+
+    @Test
+    public void testPublishToExchange_OwnerBased_withoutAuthPrincipal()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withPredicate(Property.NAME,"broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(11, new Builder()
+                .withPredicate(Property.NAME,"broadcast")
+                .withPredicate(Property.QUEUE_NAME, "QQ")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(4, ruleSet.size());
+
+        // User without authentication principal
+        final Subject notAuthentificated = new Subject(false,
+                Collections.singleton(new UsernamePrincipal(TEST_USER, 
Mockito.mock(AuthenticationProvider.class))),
+                Collections.emptySet(),
+                Collections.emptySet());
+
+        ObjectProperties object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        object.setCreatedBy(TEST_USER);
+        assertEquals(Result.DENIED, ruleSet.check(notAuthentificated, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.QUEUE_NAME, "QQ");
+        assertEquals(Result.ALLOWED, ruleSet.check(notAuthentificated, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+    }
+
+    @Test
+    public void testPublishToExchange_OwnerBased_byAnotherUser()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withPredicate(Property.NAME,"broadcast")
+                .withPredicate(Property.ROUTING_KEY, "broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withPredicate(Property.NAME,"broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(11, new Builder()
+                .withPredicate(Property.NAME,"broadcast")
+                .withPredicate(Property.QUEUE_NAME, "QQ")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(4, ruleSet.size());
+
+        // Created be other user
+        ObjectProperties object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "broadcast.public");
+        object.setCreatedBy("another");
+        assertEquals(Result.DENIED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.QUEUE_NAME, "QQ");
+        object.setCreatedBy("another");
+        assertEquals(Result.ALLOWED, ruleSet.check(_testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        // Action is performed by another user
+        final Subject testSubject = 
TestPrincipalUtils.createTestSubject("Java");
+        object = new ObjectProperties("broadcast");
+        assertEquals(Result.DEFER, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        // Action is performed by another user == owner
+        object = new ObjectProperties("broadcast");
+        object.setCreatedBy("Java");
+        assertEquals(Result.DEFER, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        object = new ObjectProperties("broadcast");
+        object.put(Property.ROUTING_KEY, "rs.broadcast.public");
+        object.setCreatedBy("Java");
+        assertEquals(Result.ALLOWED, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+    }
+
+    @Test
+    public void testPublishToExchange_OwnerBased_withGenericRule()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.ROUTING_KEY, "rs.broadcast.*")
+                .withOwner()
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(11, new Builder()
+                .withPredicate(Property.NAME, "broadcast")
+                .withPredicate(Property.QUEUE_NAME, "QQ")
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        _ruleCollector.addRule(27, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(5, ruleSet.size());
+
+        // Action is performed by another user
+        final Subject testSubject = 
TestPrincipalUtils.createTestSubject("Java");
+
+        ObjectProperties object = new ObjectProperties("broadcast");
+        assertEquals(Result.DENIED, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+
+        // Action is performed by another user == owner
+        object = new ObjectProperties("broadcast");
+        object.setCreatedBy("Java");
+        assertEquals(Result.DENIED, ruleSet.check(testSubject, 
LegacyOperation.PUBLISH, ObjectType.EXCHANGE, object));
+    }
+
+    @Test
+    public void testList_UnsupportedException()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "broadcast")
+                .build());
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .build());
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertEquals(3, ruleSet.size());
+
+        final Rule rule = new Builder()
+                .withIdentity(TEST_USER)
+                .withOperation(LegacyOperation.ACCESS)
+                .withOutcome(RuleOutcome.ALLOW)
+                .build();
+        try
+        {
+            ruleSet.add(rule);
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.remove(ruleSet.get(1));
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.addAll(Collections.singleton(rule));
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.removeAll(new ArrayList<>(ruleSet));
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.retainAll(Collections.singleton(rule));
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.clear();
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.addAll(1, Collections.singleton(rule));
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.set(1, rule);
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.add(1, rule);
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+
+        try
+        {
+            ruleSet.remove(1);
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            // Nothing to do
+        }
+    }
+
+    @Test
+    public void testList()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "broadcast")
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertNotNull(ruleSet);
+        assertEquals(3, ruleSet.size());
+        assertFalse(ruleSet.isEmpty());
+
+        final Rule rule = new Builder()
+                .withIdentity(TEST_USER)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .withOutcome(RuleOutcome.ALLOW)
+                .build();
+
+        final Rule all = new Builder()
+                .withIdentity(Rule.ALL)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .build();
+
+        assertTrue(ruleSet.contains(rule));
+        assertTrue(ruleSet.containsAll(Arrays.asList(rule, all)));
+        assertEquals(rule, ruleSet.get(1));
+        assertEquals(1, ruleSet.indexOf(rule));
+        assertEquals(1, ruleSet.lastIndexOf(rule));
+    }
+
+    @Test
+    public void testList_Arrays()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "broadcast")
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertNotNull(ruleSet);
+
+        Object[] array = ruleSet.toArray();
+        Rule[] ruleArray = ruleSet.toArray(new Rule[0]);
+        assertEquals(3, array.length);
+        assertEquals(3, ruleArray.length);
+
+        for (int i = 0; i < array.length; i++)
+        {
+            assertEquals(ruleSet.get(i), array[i]);
+            assertEquals(ruleSet.get(i), ruleArray[i]);
+        }
+    }
+
+    @Test
+    public void testList_Iterators()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "broadcast")
+                .build());
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .build());
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final RuleSet ruleSet = createRuleSet();
+        assertNotNull(ruleSet);
+
+        int j = 0;
+        for (Rule r : ruleSet)
+        {
+            assertEquals(ruleSet.get(j++), r);
+        }
+
+        ListIterator<Rule> iterator = ruleSet.listIterator();
+        assertNotNull(iterator);
+        while (iterator.hasNext())
+        {
+            assertEquals(ruleSet.get(iterator.nextIndex()), iterator.next());
+            try
+            {
+                iterator.remove();
+                fail("An exception is expected!");
+            }
+            catch (RuntimeException e)
+            {
+                //
+            }
+        }
+
+        iterator = ruleSet.listIterator(1);
+        assertNotNull(iterator);
+        while (iterator.hasNext())
+        {
+            assertEquals(ruleSet.get(iterator.nextIndex()), iterator.next());
+            try
+            {
+                iterator.remove();
+                fail("An exception is expected!");
+            }
+            catch (RuntimeException e)
+            {
+                //
+            }
+        }
+    }
+
+    @Test
+    public void testList_subList()
+    {
+        _ruleCollector.addRule(1, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.PUBLISH)
+                .withObject(ObjectType.EXCHANGE)
+                .withPredicate(Property.NAME, "broadcast")
+                .build());
+
+        _ruleCollector.addRule(3, new Builder()
+                .withIdentity(TEST_USER)
+                .withOutcome(RuleOutcome.ALLOW)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .build());
+
+        _ruleCollector.addRule(17, new Builder()
+                .withIdentity(Rule.ALL)
+                .withOutcome(RuleOutcome.DENY)
+                .withOperation(LegacyOperation.ALL)
+                .withObject(ObjectType.ALL)
+                .build());
+
+        final Rule rule = new Builder()
+                .withIdentity(TEST_USER)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .withOutcome(RuleOutcome.ALLOW)
+                .build();
+
+        final RuleSet ruleSet = createRuleSet();
+        assertNotNull(ruleSet);
+
+        assertNotNull(ruleSet.subList(1, 2));
+        assertEquals(rule, ruleSet.subList(1, 2).get(0));
+
+        try
+        {
+            ruleSet.subList(1, 2).add(rule);
+            fail("An exception is expected!");
+        }
+        catch (RuntimeException e)
+        {
+            //
+        }
+    }
+
+    @Test
+    public void testGetEventLogger()
+    {
+        final Rule rule = new Builder()
+                .withIdentity(TEST_USER)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .withOutcome(RuleOutcome.ALLOW)
+                .build();
+
+        final EventLogger logger = mock(EventLogger.class);
+        final RuleSet ruleSet = RuleSet.newInstance(() -> logger, 
Collections.singletonList(rule), Result.DENIED);
+        assertNotNull(ruleSet);
+        assertEquals(logger, ruleSet.getEventLogger());
+    }
+
+    @Test
+    public void testGetDefault()
+    {
+        final Rule rule = new Builder()
+                .withIdentity(TEST_USER)
+                .withOperation(LegacyOperation.ACCESS)
+                .withObject(ObjectType.VIRTUALHOST)
+                .withOutcome(RuleOutcome.ALLOW)
+                .build();
+
+        final EventLoggerProvider logger = mock(EventLoggerProvider.class);
+        final RuleSet ruleSet = RuleSet.newInstance(logger, 
Collections.singletonList(rule), Result.ALLOWED);
+        assertNotNull(ruleSet);
+        assertEquals(Result.ALLOWED, ruleSet.getDefault());
+    }
 }
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java
index f04d3ba..8697491 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java
@@ -432,22 +432,60 @@ public class RuleTest extends UnitTestBase
     @Test
     public void testIsAll()
     {
-        assertTrue(Rule.isAll("all"));
-        assertTrue(Rule.isAll("All"));
-        assertTrue(Rule.isAll("ALL"));
-        assertFalse(Rule.isAll("any"));
-        assertFalse(Rule.isAll("Any"));
-        assertFalse(Rule.isAll("ANY"));
+        Rule rule = new Rule.Builder().withIdentity("all").build();
+        assertTrue(rule.isForAll());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("All").build();
+        assertTrue(rule.isForAll());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("ALL").build();
+        assertTrue(rule.isForAll());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("any").build();
+        assertFalse(rule.isForAll());
+        assertFalse(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("Any").build();
+        assertFalse(rule.isForAll());
+        assertFalse(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("ANY").build();
+        assertFalse(rule.isForAll());
+        assertFalse(rule.isForOwnerOrAll());
     }
 
     @Test
     public void testIsOwner()
     {
-        assertTrue(Rule.isOwner("owner"));
-        assertTrue(Rule.isOwner("Owner"));
-        assertTrue(Rule.isOwner("OWNER"));
-        assertFalse(Rule.isOwner("any"));
-        assertFalse(Rule.isOwner("Any"));
-        assertFalse(Rule.isOwner("ANY"));
+        Rule rule = new Rule.Builder().withIdentity("owner").build();
+        assertTrue(rule.isForOwner());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("Owner").build();
+        assertTrue(rule.isForOwner());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("OWNER").build();
+        assertTrue(rule.isForOwner());
+        assertTrue(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("any").build();
+        assertFalse(rule.isForOwner());
+        assertFalse(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("Any").build();
+        assertFalse(rule.isForOwner());
+        assertFalse(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withIdentity("ANY").build();
+        assertFalse(rule.isForOwner());
+        assertFalse(rule.isForOwnerOrAll());
+
+        rule = new Rule.Builder().withOwner().build();
+        assertTrue(rule.isForOwner());
+        assertTrue(rule.isForOwnerOrAll());
     }
 }
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/predicates/RulePredicateTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/predicates/RulePredicateTest.java
index 4eb6630..a9baaea 100644
--- 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/predicates/RulePredicateTest.java
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/predicates/RulePredicateTest.java
@@ -77,6 +77,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertTrue(rule.matches(LegacyOperation.UPDATE, 
ObjectType.VIRTUALHOST, action, _subject));
         assertFalse(rule.matches(LegacyOperation.ACCESS, 
ObjectType.VIRTUALHOST, action, _subject));
+        assertTrue(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -97,6 +98,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertFalse(rule.matches(LegacyOperation.UPDATE, 
ObjectType.VIRTUALHOST, action, _subject));
         assertTrue(rule.matches(LegacyOperation.ACCESS, 
ObjectType.VIRTUALHOST, action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -117,6 +119,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertFalse(rule.matches(LegacyOperation.UPDATE, 
ObjectType.VIRTUALHOST, action, _subject));
         assertFalse(rule.matches(LegacyOperation.ACCESS, 
ObjectType.VIRTUALHOST, action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -137,6 +140,7 @@ public class RulePredicateTest extends UnitTestBase
         action.put(Property.METHOD_NAME, "publish");
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -157,6 +161,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
new ObjectProperties(), _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -176,6 +181,7 @@ public class RulePredicateTest extends UnitTestBase
         action.put(Property.METHOD_NAME, "publish");
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -196,6 +202,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
new ObjectProperties(), _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -215,6 +222,7 @@ public class RulePredicateTest extends UnitTestBase
         action.put(Property.METHOD_NAME, "publish");
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -235,6 +243,7 @@ public class RulePredicateTest extends UnitTestBase
 
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
new ObjectProperties(), _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -255,6 +264,7 @@ public class RulePredicateTest extends UnitTestBase
         action.put(Property.METHOD_NAME, "publish");
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -269,6 +279,7 @@ public class RulePredicateTest extends UnitTestBase
                 .withOutcome(RuleOutcome.ALLOW)
                 .build(_firewallRuleFactory);
 
+        assertFalse(rule.anyPropertiesMatch());
         ObjectProperties action = new ObjectProperties();
         action.put(Property.ROUTING_KEY, "generic.public");
         action.setName("broadcast");
@@ -315,6 +326,7 @@ public class RulePredicateTest extends UnitTestBase
         action.put(Property.DURABLE, true);
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
action, _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -331,6 +343,7 @@ public class RulePredicateTest extends UnitTestBase
                 .withOutcome(RuleOutcome.ALLOW)
                 .build(_firewallRuleFactory);
 
+        assertFalse(rule.anyPropertiesMatch());
         ObjectProperties action = new ObjectProperties();
         action.put(Property.ROUTING_KEY, "broadcast.public");
         action.setName("broadcast");
@@ -386,6 +399,7 @@ public class RulePredicateTest extends UnitTestBase
                 .build(_firewallRuleFactory);
 
         assertTrue(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
new ObjectProperties(), _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 
     @Test
@@ -400,5 +414,6 @@ public class RulePredicateTest extends UnitTestBase
                 .build(_firewallRuleFactory);
 
         assertFalse(rule.matches(LegacyOperation.PUBLISH, ObjectType.EXCHANGE, 
new ObjectProperties(), _subject));
+        assertFalse(rule.anyPropertiesMatch());
     }
 }
\ No newline at end of file
diff --git 
a/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleOutcomeTest.java
 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleOutcomeTest.java
new file mode 100644
index 0000000..03b32bd
--- /dev/null
+++ 
b/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleOutcomeTest.java
@@ -0,0 +1,62 @@
+package org.apache.qpid.server.security.access.plugins;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.logging.EventLogger;
+import org.apache.qpid.server.logging.EventLoggerProvider;
+import org.apache.qpid.server.logging.LogMessage;
+import org.apache.qpid.server.security.Result;
+import org.apache.qpid.server.security.access.config.LegacyOperation;
+import org.apache.qpid.server.security.access.config.ObjectProperties;
+import org.apache.qpid.server.security.access.config.ObjectType;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class RuleOutcomeTest extends TestCase
+{
+    private EventLogger _logger;
+    private EventLoggerProvider _provider;
+
+    @Override
+    public void setUp()
+    {
+        _logger = Mockito.mock(EventLogger.class);
+        _provider =() ->_logger;
+    }
+
+    @Test
+    public void testLogResult()
+    {
+        assertEquals(Result.ALLOWED, RuleOutcome.ALLOW.logResult(_provider, 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, new ObjectProperties()));
+        assertEquals(Result.DENIED, RuleOutcome.DENY.logResult(_provider, 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, new ObjectProperties()));
+        Mockito.verify(_logger, 
Mockito.never()).message(Mockito.any(LogMessage.class));
+    }
+
+    @Test
+    public void testLogDeniedResult() {
+        assertEquals(Result.DENIED, RuleOutcome.DENY_LOG.logResult(_provider, 
LegacyOperation.ACCESS, ObjectType.VIRTUALHOST, new ObjectProperties()));
+
+        final ArgumentCaptor<LogMessage> captor = 
ArgumentCaptor.forClass(LogMessage.class);
+        Mockito.verify(_logger, Mockito.times(1)).message(captor.capture());
+
+        final LogMessage message = captor.getValue();
+        assertNotNull(message);
+        assertTrue(message.toString().contains("Denied"));
+        
assertTrue(message.toString().contains(LegacyOperation.ACCESS.toString()));
+        
assertTrue(message.toString().contains(ObjectType.VIRTUALHOST.toString()));
+    }
+
+    @Test
+    public void testLogAllowResult() {
+        assertEquals(Result.ALLOWED, 
RuleOutcome.ALLOW_LOG.logResult(_provider, LegacyOperation.ACCESS, 
ObjectType.VIRTUALHOST, new ObjectProperties()));
+
+        final ArgumentCaptor<LogMessage> captor = 
ArgumentCaptor.forClass(LogMessage.class);
+        Mockito.verify(_logger, Mockito.times(1)).message(captor.capture());
+
+        final LogMessage message = captor.getValue();
+        assertNotNull(message);
+        assertTrue(message.toString().contains("Allowed"));
+        
assertTrue(message.toString().contains(LegacyOperation.ACCESS.toString()));
+        
assertTrue(message.toString().contains(ObjectType.VIRTUALHOST.toString()));
+    }
+}
diff --git 
a/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
 
b/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
index ba01908..e3b77f5 100644
--- 
a/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
+++ 
b/systests/qpid-systests-jms_1.1/src/test/java/org/apache/qpid/systests/jms_1_1/extensions/acl/MessagingACLTest.java
@@ -65,14 +65,10 @@ import org.apache.qpid.server.model.Group;
 import org.apache.qpid.server.model.GroupMember;
 import org.apache.qpid.server.model.Protocol;
 import org.apache.qpid.server.security.access.config.AclFileParser;
-import org.apache.qpid.server.security.access.config.LegacyOperation;
-import org.apache.qpid.server.security.access.config.ObjectProperties;
-import org.apache.qpid.server.security.access.config.ObjectType;
 import org.apache.qpid.server.security.access.config.Rule;
 import org.apache.qpid.server.security.access.config.RuleSet;
 import org.apache.qpid.server.security.access.plugins.AclRule;
 import 
org.apache.qpid.server.security.access.plugins.RuleBasedVirtualHostAccessControlProvider;
-import org.apache.qpid.server.security.access.plugins.RuleOutcome;
 import org.apache.qpid.server.security.group.GroupProviderImpl;
 import org.apache.qpid.systests.JmsTestBase;
 
@@ -852,8 +848,7 @@ public class MessagingACLTest extends JmsTestBase
         try(StringReader stringReader = new 
StringReader(Arrays.stream(rules).collect(Collectors.joining(LINE_SEPARATOR))))
         {
             RuleSet ruleSet = AclFileParser.parse(stringReader, 
eventLoggerProvider);
-            final List<Rule> parsedRules = ruleSet.getAllRules();
-            for(final Rule rule: parsedRules)
+            for (final Rule rule: ruleSet)
             {
                 aclRules.add(rule.asAclRule());
             }

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

Reply via email to