diff options
| author | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
|---|---|---|
| committer | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
| commit | ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5 (patch) | |
| tree | dcfb94e75656c6c239fc3dcb754cd2015126424d /java/broker-plugins | |
| parent | 5eb354b338bb8d8fcd35b6ac3fb33f8103e757c3 (diff) | |
| download | qpid-python-ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5.tar.gz | |
Undo bad merge from trunk - merged at wrong level.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1187150 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/broker-plugins')
21 files changed, 1979 insertions, 793 deletions
diff --git a/java/broker-plugins/access-control/MANIFEST.MF b/java/broker-plugins/access-control/MANIFEST.MF index 78072850e4..1cd285ba20 100644 --- a/java/broker-plugins/access-control/MANIFEST.MF +++ b/java/broker-plugins/access-control/MANIFEST.MF @@ -35,7 +35,6 @@ Import-Package: org.apache.qpid, org.apache.log4j;version=1.0.0, javax.management;version=1.0.0, javax.management.openmbean;version=1.0.0, - javax.security.auth;version=1.0.0, org.osgi.util.tracker;version=1.0.0, org.osgi.framework;version=1.3 Private-Package: org.apache.qpid.server.security.access.config, diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java index 78355a7501..ebc73440ed 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java @@ -18,24 +18,20 @@ */ package org.apache.qpid.server.security.access.config; -import java.security.Principal; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.WeakHashMap; -import javax.security.auth.Subject; - import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.security.Result; @@ -49,132 +45,147 @@ import org.apache.qpid.server.security.access.logging.AccessControlMessages; * Models the rule configuration for the access control plugin. * * The access control rule definitions are loaded from an external configuration file, passed in as the - * target to the {@link load(ConfigurationFile)} method. The file specified + * target to the {@link load(ConfigurationFile)} method. The file specified */ public class RuleSet { + private static final Logger _logger = Logger.getLogger(RuleSet.class); + private static final String AT = "@"; - private static final String SLASH = "/"; + private static final String SLASH = "/"; - public static final String DEFAULT_ALLOW = "defaultallow"; - public static final String DEFAULT_DENY = "defaultdeny"; - public static final String TRANSITIVE = "transitive"; - public static final String EXPAND = "expand"; + public static final String DEFAULT_ALLOW = "defaultallow"; + public static final String DEFAULT_DENY = "defaultdeny"; + public static final String TRANSITIVE = "transitive"; + public static final String EXPAND = "expand"; public static final String AUTONUMBER = "autonumber"; public static final String CONTROLLED = "controlled"; public static final String VALIDATE = "validate"; - + public static final List<String> CONFIG_PROPERTIES = Arrays.asList( DEFAULT_ALLOW, DEFAULT_DENY, TRANSITIVE, EXPAND, AUTONUMBER, CONTROLLED ); - + private static final Integer _increment = 10; - - private final Map<String, List<String>> _aclGroups = new HashMap<String, List<String>>(); + + private final Map<String, List<String>> _groups = new HashMap<String, List<String>>(); private final SortedMap<Integer, Rule> _rules = new TreeMap<Integer, Rule>(); - private final Map<Subject, Map<Operation, Map<ObjectType, List<Rule>>>> _cache = - new WeakHashMap<Subject, Map<Operation, Map<ObjectType, List<Rule>>>>(); + private final Map<String, Map<Operation, Map<ObjectType, List<Rule>>>> _cache = + new WeakHashMap<String, Map<Operation, Map<ObjectType, List<Rule>>>>(); private final Map<String, Boolean> _config = new HashMap<String, Boolean>(); - + public RuleSet() { // set some default configuration properties configure(DEFAULT_DENY, Boolean.TRUE); configure(TRANSITIVE, Boolean.TRUE); } - + /** - * Clear the contents, including acl groups, rules and configuration. + * Clear the contents, invluding groups, rules and configuration. */ public void clear() { _rules.clear(); _cache.clear(); _config.clear(); - _aclGroups.clear(); + _groups.clear(); } - + public 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. - */ - public List<Rule> getRules(final Subject subject, final Operation operation, final ObjectType objectType) - { - final Map<ObjectType, List<Rule>> objects = getObjectToRuleCache(subject, operation); + + /** + * Filtered rules list based on an identity 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. + */ + public List<Rule> getRules(String identity, Operation operation, ObjectType objectType) + { + // Lookup identity in cache and create empty operation map if required + Map<Operation, Map<ObjectType, List<Rule>>> operations = _cache.get(identity); + if (operations == null) + { + operations = new EnumMap<Operation, Map<ObjectType, List<Rule>>>(Operation.class); + _cache.put(identity, operations); + } + + // Lookup operation and create empty object type map if required + Map<ObjectType, List<Rule>> objects = operations.get(operation); + if (objects == null) + { + objects = new EnumMap<ObjectType, List<Rule>>(ObjectType.class); + operations.put(operation, objects); + } // 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<Rule>(); for (Rule rule : _rules.values()) { - final Action ruleAction = rule.getAction(); if (rule.isEnabled() - && (ruleAction.getOperation() == Operation.ALL || ruleAction.getOperation() == operation) - && (ruleAction.getObjectType() == ObjectType.ALL || ruleAction.getObjectType() == objectType)) + && (rule.getAction().getOperation() == Operation.ALL || rule.getAction().getOperation() == operation) + && (rule.getAction().getObjectType() == ObjectType.ALL || rule.getAction().getObjectType() == objectType)) { controlled = true; - if (isRelevant(principals,rule)) + if (rule.getIdentity().equalsIgnoreCase(Rule.ALL) + || rule.getIdentity().equalsIgnoreCase(identity) + || (_groups.containsKey(rule.getIdentity()) && _groups.get(rule.getIdentity()).contains(identity))) { filtered.add(rule); } } } - + // Return null if there are no rules at all for this operation and object type if (filtered.isEmpty() && controlled == false) { filtered = null; } - + // Save the rules we selected objects.put(objectType, filtered); } - + // Return the cached rules - return objects.get(objectType); - } - - + return objects.get(objectType); + } + public boolean isValidNumber(Integer number) { return !_rules.containsKey(number); } - + public void grant(Integer number, String identity, Permission permission, Operation operation) { Action action = new Action(operation); addRule(number, identity, permission, action); } - + public void grant(Integer number, String identity, Permission permission, Operation operation, ObjectType object, ObjectProperties properties) { Action action = new Action(operation, object, properties); addRule(number, identity, permission, action); } - + public boolean ruleExists(String identity, Action action) { - for (Rule rule : _rules.values()) - { - if (rule.getIdentity().equals(identity) && rule.getAction().equals(action)) - { - return true; - } - } - return false; + for (Rule rule : _rules.values()) + { + if (rule.getIdentity().equals(identity) && rule.getAction().equals(action)) + { + return true; + } + } + return false; } - + private Permission noLog(Permission permission) { switch (permission) @@ -192,17 +203,15 @@ public class RuleSet // TODO make this work when group membership is not known at file parse time public void addRule(Integer number, String identity, Permission permission, Action action) { - _cache.clear(); - - if (!action.isAllowed()) - { - throw new IllegalArgumentException("Action is not allowd: " + action); - } + if (!action.isAllowed()) + { + throw new IllegalArgumentException("Action is not allowd: " + action); + } if (ruleExists(identity, action)) { return; } - + // expand actions - possibly multiply number by if (isSet(EXPAND)) { @@ -225,8 +234,8 @@ public class RuleSet return; } } - - // transitive action dependencies + + // transitive action dependencies if (isSet(TRANSITIVE)) { if (action.getOperation() == Operation.CREATE && action.getObjectType() == ObjectType.QUEUE) @@ -235,10 +244,10 @@ public class RuleSet exchProperties.setName(ExchangeDefaults.DEFAULT_EXCHANGE_NAME); exchProperties.put(ObjectProperties.Property.ROUTING_KEY, action.getProperties().get(ObjectProperties.Property.NAME)); addRule(null, identity, noLog(permission), new Action(Operation.BIND, ObjectType.EXCHANGE, exchProperties)); - if (action.getProperties().isSet(ObjectProperties.Property.AUTO_DELETE)) - { - addRule(null, identity, noLog(permission), new Action(Operation.DELETE, ObjectType.QUEUE, action.getProperties())); - } + if (action.getProperties().isSet(ObjectProperties.Property.AUTO_DELETE)) + { + addRule(null, identity, noLog(permission), new Action(Operation.DELETE, ObjectType.QUEUE, action.getProperties())); + } } else if (action.getOperation() == Operation.DELETE && action.getObjectType() == ObjectType.QUEUE) { @@ -252,9 +261,9 @@ public class RuleSet addRule(null, identity, noLog(permission), new Action(Operation.ACCESS, ObjectType.VIRTUALHOST)); } } - + // set rule number if needed - Rule rule = new Rule(number, identity, action, permission); + Rule rule = new Rule(number, identity, action, permission); if (rule.getNumber() == null) { if (_rules.isEmpty()) @@ -266,36 +275,34 @@ public class RuleSet rule.setNumber(_rules.lastKey() + _increment); } } - + // save rule _cache.remove(identity); _rules.put(rule.getNumber(), rule); - } - + } + public void enableRule(int ruleNumber) { _rules.get(Integer.valueOf(ruleNumber)).enable(); } - + public void disableRule(int ruleNumber) { _rules.get(Integer.valueOf(ruleNumber)).disable(); } - + public boolean addGroup(String group, List<String> constituents) { - _cache.clear(); - - if (_aclGroups.containsKey(group)) + if (_groups.containsKey(group)) { // cannot redefine return false; } else { - _aclGroups.put(group, new ArrayList<String>()); + _groups.put(group, new ArrayList<String>()); } - + for (String name : constituents) { if (name.equalsIgnoreCase(group)) @@ -303,17 +310,17 @@ public class RuleSet // recursive definition return false; } - + if (!checkName(name)) { // invalid name return false; } - - if (_aclGroups.containsKey(name)) + + if (_groups.containsKey(name)) { // is a group - _aclGroups.get(group).addAll(_aclGroups.get(name)); + _groups.get(group).addAll(_groups.get(name)); } else { @@ -323,12 +330,12 @@ public class RuleSet // invalid username return false; } - _aclGroups.get(group).add(name); + _groups.get(group).add(name); } } return true; } - + /** Return true if the name is well-formed (contains legal characters). */ protected boolean checkName(String name) { @@ -342,79 +349,79 @@ public class RuleSet } return true; } - + /** Returns true if a username has the name[@domain][/realm] format */ protected boolean isvalidUserName(String name) - { - // check for '@' and '/' in namne - int atPos = name.indexOf(AT); - int slashPos = name.indexOf(SLASH); - boolean atFound = atPos != StringUtils.INDEX_NOT_FOUND && atPos == name.lastIndexOf(AT); - boolean slashFound = slashPos != StringUtils.INDEX_NOT_FOUND && slashPos == name.lastIndexOf(SLASH); - - // must be at least one character after '@' or '/' - if (atFound && atPos > name.length() - 2) - { - return false; - } - if (slashFound && slashPos > name.length() - 2) - { - return false; - } - - // must be at least one character between '@' and '/' - if (atFound && slashFound) - { - return (atPos < (slashPos - 1)); - } - - // otherwise all good - return true; + { + // check for '@' and '/' in namne + int atPos = name.indexOf(AT); + int slashPos = name.indexOf(SLASH); + boolean atFound = atPos != StringUtils.INDEX_NOT_FOUND && atPos == name.lastIndexOf(AT); + boolean slashFound = slashPos != StringUtils.INDEX_NOT_FOUND && slashPos == name.lastIndexOf(SLASH); + + // must be at least one character after '@' or '/' + if (atFound && atPos > name.length() - 2) + { + return false; + } + if (slashFound && slashPos > name.length() - 2) + { + return false; + } + + // must be at least one character between '@' and '/' + if (atFound && slashFound) + { + return (atPos < (slashPos - 1)); + } + + // otherwise all good + return true; } - // C++ broker authorise function prototype + // C++ broker authorise function prototype // virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType, - // const std::string& name, std::map<Property, std::string>* params=0); - - // Possibly add a String name paramater? + // const std::string& name, std::map<Property, std::string>* params=0); + + // Possibly add a String name paramater? /** * 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 + * Looks up the entire ruleset, whcih 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, Operation operation, ObjectType objectType, ObjectProperties properties) + public Result check(String identity, Operation operation, ObjectType objectType, ObjectProperties properties) { // Create the action to check Action action = new Action(operation, objectType, properties); - // get the list of rules relevant for this request - List<Rule> rules = getRules(subject, operation, objectType); - if (rules == null) - { - if (isSet(CONTROLLED)) - { - // Abstain if there are no rules for this operation + // get the list of rules relevant for this request + List<Rule> rules = getRules(identity, operation, objectType); + if (rules == null) + { + if (isSet(CONTROLLED)) + { + // Abstain if there are no rules for this operation return Result.ABSTAIN; - } - else - { - return getDefault(); - } - } - - // Iterate through a filtered set of rules dealing with this identity and operation + } + else + { + return getDefault(); + } + } + + // Iterate through a filtered set of rules dealing with this identity and operation for (Rule current : rules) - { - // Check if action matches + { + // Check if action matches if (action.matches(current.getAction())) { Permission permission = current.getPermission(); - + switch (permission) { case ALLOW_LOG: @@ -432,15 +439,15 @@ public class RuleSet return Result.DENIED; } } - + // Defer to the next plugin of this type, if it exists - return Result.DEFER; + return Result.DEFER; } - - /** Default deny. */ - public Result getDefault() - { - if (isSet(DEFAULT_ALLOW)) + + /** Default deny. */ + public Result getDefault() + { + if (isSet(DEFAULT_ALLOW)) { return Result.ALLOWED; } @@ -449,19 +456,19 @@ public class RuleSet return Result.DENIED; } return Result.ABSTAIN; - } - - /** - * Check if a configuration property is set. - */ - protected boolean isSet(String key) - { - return BooleanUtils.isTrue(_config.get(key)); - } + } + + /** + * Check if a configuration property is set. + */ + protected boolean isSet(String key) + { + return BooleanUtils.isTrue(_config.get(key)); + } /** * Configure properties for the plugin instance. - * + * * @param properties */ public void configure(Map<String, Boolean> properties) @@ -471,7 +478,7 @@ public class RuleSet /** * Configure a single property for the plugin instance. - * + * * @param key * @param value */ @@ -479,48 +486,4 @@ public class RuleSet { _config.put(key, value); } - - private boolean isRelevant(final Set<Principal> principals, final Rule rule) - { - if (rule.getIdentity().equalsIgnoreCase(Rule.ALL)) - { - return true; - } - else - { - for (Iterator<Principal> iterator = principals.iterator(); iterator.hasNext();) - { - final Principal principal = iterator.next(); - - if (rule.getIdentity().equalsIgnoreCase(principal.getName()) - || (_aclGroups.containsKey(rule.getIdentity()) && _aclGroups.get(rule.getIdentity()).contains(principal.getName()))) - { - return true; - } - } - } - - return false; - } - - private Map<ObjectType, List<Rule>> getObjectToRuleCache(final Subject subject, final Operation operation) - { - // Lookup identity in cache and create empty operation map if required - Map<Operation, Map<ObjectType, List<Rule>>> operations = _cache.get(subject); - if (operations == null) - { - operations = new EnumMap<Operation, Map<ObjectType, List<Rule>>>(Operation.class); - _cache.put(subject, operations); - } - - // Lookup operation and create empty object type map if required - Map<ObjectType, List<Rule>> objects = operations.get(operation); - if (objects == null) - { - objects = new EnumMap<ObjectType, List<Rule>>(ObjectType.class); - operations.put(operation, objects); - } - return objects; - } - } diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java index a7b3059262..69cfa173bd 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.security.access.plugins; -import javax.security.auth.Subject; +import java.security.Principal; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; @@ -89,19 +89,20 @@ public class AccessControl extends AbstractPlugin /** * Check if an operation is authorised by asking the configuration object about the access - * control rules granted to the current thread's {@link Subject}. If there is no current + * control rules granted to the current thread's {@link Principal}. If there is no current * user the plugin will abstain. */ public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) { - final Subject subject = SecurityManager.getThreadSubject(); - // Abstain if there is no subject/principal associated with this thread - if (subject == null || subject.getPrincipals().size() == 0) + Principal principal = SecurityManager.getThreadPrincipal(); + + // Abstain if there is no user associated with this thread + if (principal == null) { return Result.ABSTAIN; } - - return _ruleSet.check(subject, operation, objectType, properties); + + return _ruleSet.check(principal.getName(), operation, objectType, properties); } public void configure(ConfigurationPlugin config) diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java index 09d26e5451..309a3aeb2c 100644 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java @@ -1,172 +1,195 @@ /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package org.apache.qpid.server.security.access.plugins; -import java.util.Arrays; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.PrintWriter; import junit.framework.TestCase; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.logging.UnitTestMessageLogger; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.TestLogActor; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityManager; -import org.apache.qpid.server.security.access.ObjectProperties; -import org.apache.qpid.server.security.access.ObjectType; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.security.access.config.Rule; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.security.access.config.ConfigurationFile; +import org.apache.qpid.server.security.access.config.PlainConfiguration; import org.apache.qpid.server.security.access.config.RuleSet; -import org.apache.qpid.server.security.auth.sasl.TestPrincipalUtils; /** - * Unit test for ACL V2 plugin. - * - * This unit test tests the AccessControl class and it collaboration with {@link RuleSet}, - * {@link SecurityManager} and {@link CurrentActor}. The ruleset is configured programmatically, - * rather than from an external file. + * These tests check that the ACL file parsing works correctly. * - * @see RuleSetTest + * For each message that can be returned in a {@link ConfigurationException}, an ACL file is created that should trigger this + * particular message. */ public class AccessControlTest extends TestCase { - private AccessControl _plugin = null; // Class under test - private final UnitTestMessageLogger messageLogger = new UnitTestMessageLogger(); - - protected void setUp() throws Exception + public void writeACLConfig(String...aclData) throws Exception { - super.setUp(); - - final RuleSet rs = new RuleSet(); - rs.addGroup("aclGroup1", Arrays.asList(new String[] {"member1", "member2"})); - - // Rule expressed with username - rs.grant(0, "user1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - // Rule expressed with a acl group - rs.grant(1, "aclGroup1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - // Rule expressed with an external group - rs.grant(2, "extGroup1", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - // Catch all rule - rs.grant(3, Rule.ALL, Permission.DENY_LOG, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - - _plugin = (AccessControl) AccessControl.FACTORY.newInstance(createConfiguration(rs)); - - SecurityManager.setThreadSubject(null); + File acl = File.createTempFile(getClass().getName() + getName(), "acl"); + acl.deleteOnExit(); - CurrentActor.set(new TestLogActor(messageLogger)); + // Write ACL file + PrintWriter aclWriter = new PrintWriter(new FileWriter(acl)); + for (String line : aclData) + { + aclWriter.println(line); + } + aclWriter.close(); + + // Load ruleset + ConfigurationFile configFile = new PlainConfiguration(acl); + RuleSet ruleSet = configFile.load(); } - protected void tearDown() throws Exception + public void testMissingACLConfig() throws Exception { - super.tearDown(); - SecurityManager.setThreadSubject(null); + try + { + // Load ruleset + ConfigurationFile configFile = new PlainConfiguration(new File("doesnotexist")); + RuleSet ruleSet = configFile.load(); + + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.CONFIG_NOT_FOUND_MSG, "doesnotexist"), ce.getMessage()); + assertTrue(ce.getCause() instanceof FileNotFoundException); + assertEquals("doesnotexist (No such file or directory)", ce.getCause().getMessage()); + } } - /** - * ACL plugin must always abstain if there is no subject attached to the thread. - */ - public void testNoSubjectAlwaysAbstains() + public void testACLFileSyntaxContinuation() throws Exception { - SecurityManager.setThreadSubject(null); - - final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(Result.ABSTAIN, result); + try + { + writeACLConfig("ACL ALLOW ALL \\ ALL"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.PREMATURE_CONTINUATION_MSG, 1), ce.getMessage()); + } } - /** - * Tests that an allow rule expressed with a username allows an operation performed by a thread running - * with the same username. - */ - public void testUsernameAllowsOperation() + public void testACLFileSyntaxTokens() throws Exception { - SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("user1")); - - final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(Result.ALLOWED, result); + try + { + writeACLConfig("ACL unparsed ALL ALL"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.PARSE_TOKEN_FAILED_MSG, 1), ce.getMessage()); + assertTrue(ce.getCause() instanceof IllegalArgumentException); + assertEquals("Not a valid permission: unparsed", ce.getCause().getMessage()); + } } - /** - * Tests that an allow rule expressed with an <b>ACL groupname</b> allows an operation performed by a thread running - * by a user who belongs to the same group.. - */ - public void testAclGroupMembershipAllowsOperation() + public void testACLFileSyntaxNotEnoughGroup() throws Exception { - SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("member1")); + try + { + writeACLConfig("GROUP blah"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_GROUP_MSG, 1), ce.getMessage()); + } + } - final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(Result.ALLOWED, result); + public void testACLFileSyntaxNotEnoughACL() throws Exception + { + try + { + writeACLConfig("ACL ALLOW"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_ACL_MSG, 1), ce.getMessage()); + } } - /** - * Tests that a deny rule expressed with an <b>External groupname</b> denies an operation performed by a thread running - * by a user who belongs to the same group. - */ - public void testExternalGroupMembershipDeniesOperation() + public void testACLFileSyntaxNotEnoughConfig() throws Exception { - SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("user3", "extGroup1")); - - final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(Result.DENIED, result); + try + { + writeACLConfig("CONFIG"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); + } } - /** - * Tests that the catch all deny denies the operation and logs with the logging actor. - */ - public void testCatchAllRuleDeniesUnrecognisedUsername() + public void testACLFileSyntaxNotEnough() throws Exception { - SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("unknown", "unkgroup1", "unkgroup2")); - - assertEquals("Expecting zero messages before test", 0, messageLogger.getLogMessages().size()); - final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(Result.DENIED, result); - - assertEquals("Expecting one message before test", 1, messageLogger.getLogMessages().size()); - assertTrue("Logged message does not contain expected string", messageLogger.messageContains(0, "ACL-1002")); + try + { + writeACLConfig("INVALID"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); + } } - - /** - * Creates a configuration plugin for the {@link AccessControl} plugin. - */ - private ConfigurationPlugin createConfiguration(final RuleSet rs) + + public void testACLFileSyntaxPropertyKeyOnly() throws Exception { - final ConfigurationPlugin cp = new ConfigurationPlugin() - { - public AccessControlConfiguration getConfiguration(final String plugin) - { - return new AccessControlConfiguration() - { - public RuleSet getRuleSet() - { - return rs; - } - }; - } + try + { + writeACLConfig("ACL ALLOW adk CREATE QUEUE name"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.PROPERTY_KEY_ONLY_MSG, 1), ce.getMessage()); + } + } - public String[] getElementsProcessed() - { - throw new UnsupportedOperationException(); - } - }; + public void testACLFileSyntaxPropertyNoEquals() throws Exception + { + try + { + writeACLConfig("ACL ALLOW adk CREATE QUEUE name test"); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.PROPERTY_NO_EQUALS_MSG, 1), ce.getMessage()); + } + } - return cp; + public void testACLFileSyntaxPropertyNoValue() throws Exception + { + try + { + writeACLConfig("ACL ALLOW adk CREATE QUEUE name ="); + fail("fail"); + } + catch (ConfigurationException ce) + { + assertEquals(String.format(PlainConfiguration.PROPERTY_NO_VALUE_MSG, 1), ce.getMessage()); + } } } diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java deleted file mode 100644 index e16f9943ba..0000000000 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.access.plugins; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.PrintWriter; - -import junit.framework.TestCase; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.security.access.config.ConfigurationFile; -import org.apache.qpid.server.security.access.config.PlainConfiguration; - -/** - * These tests check that the ACL file parsing works correctly. - * - * For each message that can be returned in a {@link ConfigurationException}, an ACL file is created that should trigger this - * particular message. - */ -public class PlainConfigurationTest extends TestCase -{ - public void writeACLConfig(String...aclData) throws Exception - { - File acl = File.createTempFile(getClass().getName() + getName(), "acl"); - acl.deleteOnExit(); - - // Write ACL file - PrintWriter aclWriter = new PrintWriter(new FileWriter(acl)); - for (String line : aclData) - { - aclWriter.println(line); - } - aclWriter.close(); - - // Load ruleset - ConfigurationFile configFile = new PlainConfiguration(acl); - configFile.load(); - } - - public void testMissingACLConfig() throws Exception - { - try - { - // Load ruleset - ConfigurationFile configFile = new PlainConfiguration(new File("doesnotexist")); - configFile.load(); - - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.CONFIG_NOT_FOUND_MSG, "doesnotexist"), ce.getMessage()); - assertTrue(ce.getCause() instanceof FileNotFoundException); - assertEquals("doesnotexist (No such file or directory)", ce.getCause().getMessage()); - } - } - - public void testACLFileSyntaxContinuation() throws Exception - { - try - { - writeACLConfig("ACL ALLOW ALL \\ ALL"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.PREMATURE_CONTINUATION_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxTokens() throws Exception - { - try - { - writeACLConfig("ACL unparsed ALL ALL"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.PARSE_TOKEN_FAILED_MSG, 1), ce.getMessage()); - assertTrue(ce.getCause() instanceof IllegalArgumentException); - assertEquals("Not a valid permission: unparsed", ce.getCause().getMessage()); - } - } - - public void testACLFileSyntaxNotEnoughGroup() throws Exception - { - try - { - writeACLConfig("GROUP blah"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_GROUP_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxNotEnoughACL() throws Exception - { - try - { - writeACLConfig("ACL ALLOW"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_ACL_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxNotEnoughConfig() throws Exception - { - try - { - writeACLConfig("CONFIG"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxNotEnough() throws Exception - { - try - { - writeACLConfig("INVALID"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxPropertyKeyOnly() throws Exception - { - try - { - writeACLConfig("ACL ALLOW adk CREATE QUEUE name"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.PROPERTY_KEY_ONLY_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxPropertyNoEquals() throws Exception - { - try - { - writeACLConfig("ACL ALLOW adk CREATE QUEUE name test"); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.PROPERTY_NO_EQUALS_MSG, 1), ce.getMessage()); - } - } - - public void testACLFileSyntaxPropertyNoValue() throws Exception - { - try - { - writeACLConfig("ACL ALLOW adk CREATE QUEUE name ="); - fail("fail"); - } - catch (ConfigurationException ce) - { - assertEquals(String.format(PlainConfiguration.PROPERTY_NO_VALUE_MSG, 1), ce.getMessage()); - } - } -} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java index bd9deac153..aad7290557 100644 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java @@ -21,21 +21,13 @@ package org.apache.qpid.server.security.access.plugins; -import java.security.Principal; -import java.util.Arrays; - -import javax.security.auth.Subject; - import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.security.Result; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.server.security.access.config.Rule; import org.apache.qpid.server.security.access.config.RuleSet; -import org.apache.qpid.server.security.auth.sasl.TestPrincipalUtils; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.test.utils.QpidTestCase; /** @@ -44,24 +36,16 @@ import org.apache.qpid.test.utils.QpidTestCase; * The ruleset is configured directly rather than using an external file by adding rules individually, calling the * {@link RuleSet#grant(Integer, String, Permission, Operation, ObjectType, ObjectProperties)} method. Then, the * access control mechanism is validated by checking whether operations would be authorised by calling the - * {@link RuleSet#check(Principal, Operation, ObjectType, ObjectProperties)} method. - * - * It ensure that permissions can be granted correctly on users directly, ACL groups (that is those - * groups declared directly in the ACL itself), and External groups (that is a group from an External - * Authentication Provider, such as an LDAP). - + * {@link RuleSet#check(String, Operation, ObjectType, ObjectProperties)} method. */ public class RuleSetTest extends QpidTestCase { - private RuleSet _ruleSet; // Object under test - - private static final String TEST_USER = "user"; + private RuleSet _ruleSet; // Common things that are passed to frame constructors private AMQShortString _queueName = new AMQShortString(this.getClass().getName() + "queue"); private AMQShortString _exchangeName = new AMQShortString("amq.direct"); private AMQShortString _exchangeType = new AMQShortString("direct"); - private Subject _testSubject = TestPrincipalUtils.createTestSubject(TEST_USER); @Override public void setUp() throws Exception @@ -79,36 +63,34 @@ public class RuleSetTest extends QpidTestCase super.tearDown(); } - public void assertDenyGrantAllow(Subject subject, Operation operation, ObjectType objectType) + public void assertDenyGrantAllow(String identity, Operation operation, ObjectType objectType) { - assertDenyGrantAllow(subject, operation, objectType, ObjectProperties.EMPTY); + assertDenyGrantAllow(identity, operation, objectType, ObjectProperties.EMPTY); } - public void assertDenyGrantAllow(Subject subject, Operation operation, ObjectType objectType, ObjectProperties properties) + public void assertDenyGrantAllow(String identity, Operation operation, ObjectType objectType, ObjectProperties properties) { - final Principal identity = UsernamePrincipal.getUsernamePrincipalFromSubject(subject); - - assertEquals(Result.DENIED, _ruleSet.check(subject, operation, objectType, properties)); - _ruleSet.grant(0, identity.getName(), Permission.ALLOW, operation, objectType, properties); + assertEquals(Result.DENIED, _ruleSet.check(identity, operation, objectType, properties)); + _ruleSet.grant(0, identity, Permission.ALLOW, operation, objectType, properties); assertEquals(1, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(subject, operation, objectType, properties)); + assertEquals(Result.ALLOWED, _ruleSet.check(identity, operation, objectType, properties)); } public void testEmptyRuleSet() { assertNotNull(_ruleSet); assertEquals(_ruleSet.getRuleCount(), 0); - assertEquals(_ruleSet.getDefault(), _ruleSet.check(_testSubject, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); + assertEquals(_ruleSet.getDefault(), _ruleSet.check("user", Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); } public void testVirtualHostAccess() throws Exception { - assertDenyGrantAllow(_testSubject, Operation.ACCESS, ObjectType.VIRTUALHOST); + assertDenyGrantAllow("user", Operation.ACCESS, ObjectType.VIRTUALHOST); } public void testQueueCreateNamed() throws Exception { - assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.QUEUE, new ObjectProperties(_queueName)); + assertDenyGrantAllow("user", Operation.CREATE, ObjectType.QUEUE, new ObjectProperties(_queueName)); } public void testQueueCreatenamedNullRoutingKey() @@ -116,7 +98,7 @@ public class RuleSetTest extends QpidTestCase ObjectProperties properties = new ObjectProperties(_queueName); properties.put(ObjectProperties.Property.ROUTING_KEY, (String) null); - assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.QUEUE, properties); + assertDenyGrantAllow("user", Operation.CREATE, ObjectType.QUEUE, properties); } public void testExchangeCreate() @@ -124,17 +106,17 @@ public class RuleSetTest extends QpidTestCase ObjectProperties properties = new ObjectProperties(_exchangeName); properties.put(ObjectProperties.Property.TYPE, _exchangeType.asString()); - assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.EXCHANGE, properties); + assertDenyGrantAllow("user", Operation.CREATE, ObjectType.EXCHANGE, properties); } public void testConsume() { - assertDenyGrantAllow(_testSubject, Operation.CONSUME, ObjectType.QUEUE); + assertDenyGrantAllow("user", Operation.CONSUME, ObjectType.QUEUE); } public void testPublish() { - assertDenyGrantAllow(_testSubject, Operation.PUBLISH, ObjectType.EXCHANGE); + assertDenyGrantAllow("user", Operation.PUBLISH, ObjectType.EXCHANGE); } /** @@ -149,13 +131,13 @@ public class RuleSetTest extends QpidTestCase ObjectProperties normal = new ObjectProperties(); normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); - _ruleSet.grant(0, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); + _ruleSet.grant(0, "user", Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); assertEquals(1, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); // defer to global if exists, otherwise default answer - this is handled by the security manager - assertEquals(Result.DEFER, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal)); + assertEquals(Result.DEFER, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, normal)); } /** @@ -169,15 +151,15 @@ public class RuleSetTest extends QpidTestCase ObjectProperties normal = new ObjectProperties(_queueName); normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); // should not matter if the temporary permission is processed first or last - _ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal); - _ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); + _ruleSet.grant(1, "user", Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal); + _ruleSet.grant(2, "user", Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal)); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, normal)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); } /** @@ -191,15 +173,15 @@ public class RuleSetTest extends QpidTestCase ObjectProperties normal = new ObjectProperties(_queueName); normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); // should not matter if the temporary permission is processed first or last - _ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); - _ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal); + _ruleSet.grant(1, "user", Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary); + _ruleSet.grant(2, "user", Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal)); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, normal)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CONSUME, ObjectType.QUEUE, temporary)); } /* @@ -215,15 +197,15 @@ public class RuleSetTest extends QpidTestCase ObjectProperties namedTemporary = new ObjectProperties(_queueName); namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - _ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); - _ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); + _ruleSet.grant(1, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); + _ruleSet.grant(2, "user", Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); } /** @@ -235,15 +217,15 @@ public class RuleSetTest extends QpidTestCase ObjectProperties namedTemporary = new ObjectProperties(_queueName); namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - _ruleSet.grant(1, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); - _ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); + _ruleSet.grant(1, "user", Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); + _ruleSet.grant(2, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); } /** @@ -257,18 +239,18 @@ public class RuleSetTest extends QpidTestCase ObjectProperties namedDurable = new ObjectProperties(_queueName); namedDurable.put(ObjectProperties.Property.DURABLE, Boolean.TRUE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedDurable)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedDurable)); - _ruleSet.grant(1, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); - _ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedDurable); - _ruleSet.grant(3, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); + _ruleSet.grant(1, "user", Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary); + _ruleSet.grant(2, "user", Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedDurable); + _ruleSet.grant(3, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); assertEquals(3, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedDurable)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedDurable)); } public void testNamedTemporaryQueueAllowed() @@ -277,15 +259,15 @@ public class RuleSetTest extends QpidTestCase ObjectProperties namedTemporary = new ObjectProperties(_queueName); namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - _ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary); - _ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); + _ruleSet.grant(1, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary); + _ruleSet.grant(2, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); } public void testNamedTemporaryQueueDeniedAllowed() @@ -294,101 +276,14 @@ public class RuleSetTest extends QpidTestCase ObjectProperties namedTemporary = new ObjectProperties(_queueName); namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - _ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary); - _ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, named); + _ruleSet.grant(1, "user", Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary); + _ruleSet.grant(2, "user", Permission.DENY, Operation.CREATE, ObjectType.QUEUE, named); assertEquals(2, _ruleSet.getRuleCount()); - assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named)); - assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary)); - } - - /** - * Tests support for the {@link Rule#ALL} keyword. - */ - public void testAllowToAll() - { - _ruleSet.grant(1, Rule.ALL, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(1, _ruleSet.getRuleCount()); - - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - } - - /** - * Tests support for ACL groups (i.e. inline groups declared in the ACL file itself). - */ - public void testAclGroupsSupported() - { - assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera", "userb"}))); - - _ruleSet.grant(1, "aclgroup", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(1, _ruleSet.getRuleCount()); - - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - assertEquals(Result.DEFER, _ruleSet.check(TestPrincipalUtils.createTestSubject("userc"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - } - - /** - * Tests support for nested ACL groups. - */ - public void testNestedAclGroupsSupported() - { - assertTrue(_ruleSet.addGroup("aclgroup1", Arrays.asList(new String[] {"userb"}))); - assertTrue(_ruleSet.addGroup("aclgroup2", Arrays.asList(new String[] {"usera", "aclgroup1"}))); - - _ruleSet.grant(1, "aclgroup2", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(1, _ruleSet.getRuleCount()); - - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - } - - /** - * Tests support for nested External groups (i.e. those groups coming from an external source such as an LDAP). - */ - public void testExternalGroupsSupported() - { - _ruleSet.grant(1, "extgroup1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - _ruleSet.grant(2, "extgroup2", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(2, _ruleSet.getRuleCount()); - - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera", "extgroup1"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - assertEquals(Result.DENIED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb", "extgroup2"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - } - - /** - * Rule order in the ACL determines the outcome of the check. This test ensures that a user who is - * granted explicit permission on an object, is granted that access even although late a group - * to which the user belongs is later denied the permission. - */ - public void testAllowDeterminedByRuleOrder() - { - assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera"}))); - - _ruleSet.grant(1, "usera", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - _ruleSet.grant(2, "aclgroup", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - assertEquals(2, _ruleSet.getRuleCount()); - - assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); - } - - /** - * Rule order in the ACL determines the outcome of the check. This tests ensures that a user who is denied - * access by group, is denied access, despite there being a later rule granting permission to that user. - */ - public void testDenyDeterminedByRuleOrder() - { - assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera"}))); - - _ruleSet.grant(1, "aclgroup", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - _ruleSet.grant(2, "usera", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); - - assertEquals(2, _ruleSet.getRuleCount()); - - assertEquals(Result.DENIED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY)); + assertEquals(Result.DENIED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, named)); + assertEquals(Result.ALLOWED, _ruleSet.check("user", Operation.CREATE, ObjectType.QUEUE, namedTemporary)); } } diff --git a/java/broker-plugins/experimental/info/build.xml b/java/broker-plugins/experimental/info/build.xml index 8f91adc5ff..c5881aa839 100644 --- a/java/broker-plugins/experimental/info/build.xml +++ b/java/broker-plugins/experimental/info/build.xml @@ -20,14 +20,7 @@ nn - or more contributor license agreements. See the NOTICE file --> <project name="AMQ Broker Info Plugin" default="build"> - <condition property="info-plugin.optional.depends" value="bdbstore" else=""> - <and> - <contains string="${modules.opt}" substring="bdbstore"/> - <contains string="${profile}" substring="bdb"/> - </and> - </condition> - - <property name="module.depends" value="common broker broker-plugins ${info-plugin.optional.depends}"/> + <property name="module.depends" value="common broker broker-plugins"/> <property name="module.test.depends" value="test broker/test management/common client systests common/test"/> <property name="module.manifest" value="MANIFEST.MF"/> <property name="module.plugin" value="true"/> diff --git a/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java b/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java index 21e7be26c1..c7d3fd38ff 100644 --- a/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java +++ b/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/Activator.java @@ -59,14 +59,7 @@ public class Activator implements BundleActivator _ctx = ctx; _service = new InfoServiceImpl(); ctx.registerService(InfoService.class.getName(), _service, null); - - new Thread(new Runnable() - { - public void run() - { - sendInfo("STARTUP"); - } - }).start(); + sendInfo("STARTUP"); } } diff --git a/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java b/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java index c8e9805cd9..a5d267282b 100644 --- a/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java +++ b/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java @@ -70,13 +70,15 @@ public class AppInfo sc = ApplicationRegistry.getInstance().getConfiguration(); if (null != sc) { - appInfoMap.put("jmxport", sc.getJMXPortRegistryServer() + ""); + appInfoMap.put("jmxport", sc.getJMXManagementPort() + ""); appInfoMap.put("port", sc.getPorts().toString()); appInfoMap.put("version", QpidProperties.getReleaseVersion()); appInfoMap.put("vhosts", "standalone"); - appInfoMap.put("KeystorePath", sc.getConnectorKeyStorePath()); + appInfoMap.put("JMXPrincipalDatabase", sc + .getJMXPrincipalDatabase()); + appInfoMap.put("KeystorePath", sc.getKeystorePath()); appInfoMap.put("PluginDirectory", sc.getPluginDirectory()); - appInfoMap.put("CertType", sc.getConnectorCertType()); + appInfoMap.put("CertType", sc.getCertType()); appInfoMap.put("QpidWork", sc.getQpidWork()); appInfoMap.put("Bind", sc.getBind()); } diff --git a/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java b/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java index 348e860d5f..156c9eb138 100644 --- a/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java +++ b/java/broker-plugins/experimental/info/src/test/java/org/apache/qpid/info/systest/InfoPluginTest.java @@ -210,13 +210,12 @@ public class InfoPluginTest extends QpidBrokerTestCase } br.close(); System.out.println("*** Received buffer: " + buf); + System.out.println("*** Latch countdown"); + _latch.countDown(); synchronized (_recv) { _recv.add(buf); } - - System.out.println("*** Latch countdown"); - _latch.countDown(); } catch (Exception ex) { diff --git a/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd b/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd index f6ae79536d..6e005f5bdb 100755 --- a/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd +++ b/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd @@ -17,7 +17,7 @@ # under the License. # -ver: 0.13.0 +ver: 0.9.0 Bundle-SymbolicName: qpid-shutdown-plugin Bundle-Version: ${ver} diff --git a/java/broker-plugins/extras/src/test/java/org/apache/qpid/server/plugins/ExtrasTest.java b/java/broker-plugins/extras/src/test/java/org/apache/qpid/server/plugins/ExtrasTest.java index db3ebfd4e1..57b6e19b5d 100644 --- a/java/broker-plugins/extras/src/test/java/org/apache/qpid/server/plugins/ExtrasTest.java +++ b/java/broker-plugins/extras/src/test/java/org/apache/qpid/server/plugins/ExtrasTest.java @@ -67,7 +67,7 @@ public class ExtrasTest extends TestCase public void testNoExchanges() throws Exception { - PluginManager manager = new PluginManager("/path/to/nowhere", "/tmp", null); + PluginManager manager = new PluginManager("/path/to/nowhere", "/tmp"); Map<String, ExchangeType<?>> exchanges = manager.getExchanges(); assertTrue("Exchanges found", exchanges.isEmpty()); } diff --git a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java index e078675efc..ab8957e7ef 100644 --- a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java +++ b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java @@ -28,19 +28,12 @@ import java.net.InetSocketAddress; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; +import org.apache.qpid.server.util.InternalBrokerBaseCase; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.test.utils.QpidTestCase; -public class FirewallConfigurationTest extends QpidTestCase +public class FirewallConfigurationTest extends InternalBrokerBaseCase { - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - ApplicationRegistry.remove(); - } - public void testFirewallConfiguration() throws Exception { // Write out config @@ -50,11 +43,18 @@ public class FirewallConfigurationTest extends QpidTestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.1.2.3", 65535))); + // Test config + assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.1.2.3", 65535))); + } + finally + { + ApplicationRegistry.remove(1); + } } public void testCombinedConfigurationFirewall() throws Exception @@ -80,8 +80,9 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t<cache-directory>${QPID_WORK}/cache</cache-directory>\n"); out.write("\t<management><enabled>false</enabled></management>\n"); out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); + out.write("\t\t<principal-databases>\n"); out.write("\t\t\t<principal-database>\n"); + out.write("\t\t\t\t<name>passwordfile</name>\n"); out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); out.write("\t\t\t\t<attributes>\n"); out.write("\t\t\t\t\t<attribute>\n"); @@ -90,7 +91,11 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t\t\t\t\t</attribute>\n"); out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); + out.write("\t\t</principal-databases>\n"); + out.write("\t\t<jmx>\n"); + out.write("\t\t\t<access>/dev/null</access>\n"); + out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); + out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); out.write("\t\t</firewall>\n"); @@ -111,10 +116,17 @@ public class FirewallConfigurationTest extends QpidTestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + // Test config + assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + } + finally + { + ApplicationRegistry.remove(1); + } } public void testConfigurationFirewallReload() throws Exception @@ -127,17 +139,24 @@ public class FirewallConfigurationTest extends QpidTestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + // Test config + assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - // Switch to deny the connection - writeConfigFile(mainFile, true); + // Switch to deny the connection + writeConfigFile(mainFile, true); - reg.getConfiguration().reparseConfigFileSecuritySections(); + reg.getConfiguration().reparseConfigFileSecuritySections(); - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + } + finally + { + ApplicationRegistry.remove(1); + } } public void testCombinedConfigurationFirewallReload() throws Exception @@ -162,8 +181,9 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>\n"); out.write("\t<management><enabled>false</enabled></management>\n"); out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); + out.write("\t\t<principal-databases>\n"); out.write("\t\t\t<principal-database>\n"); + out.write("\t\t\t\t<name>passwordfile</name>\n"); out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); out.write("\t\t\t\t<attributes>\n"); out.write("\t\t\t\t\t<attribute>\n"); @@ -172,7 +192,11 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t\t\t\t\t</attribute>\n"); out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); + out.write("\t\t</principal-databases>\n"); + out.write("\t\t<jmx>\n"); + out.write("\t\t\t<access>/dev/null</access>\n"); + out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); + out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); out.write("\t\t</firewall>\n"); @@ -193,40 +217,47 @@ public class FirewallConfigurationTest extends QpidTestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); + try + { + ApplicationRegistry.initialise(reg, 1); - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + // Test config + assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); + RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw"); + fileBRandom.setLength(0); + fileBRandom.seek(0); + fileBRandom.close(); - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); + out = new FileWriter(fileB); + out.write("<firewall>\n"); + out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); + out.write("</firewall>\n"); + out.close(); - reg.getConfiguration().reparseConfigFileSecuritySections(); + reg.getConfiguration().reparseConfigFileSecuritySections(); - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); + fileBRandom = new RandomAccessFile(fileB, "rw"); + fileBRandom.setLength(0); + fileBRandom.seek(0); + fileBRandom.close(); - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); + out = new FileWriter(fileB); + out.write("<firewall>\n"); + out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); + out.write("</firewall>\n"); + out.close(); - reg.getConfiguration().reparseConfigFileSecuritySections(); + reg.getConfiguration().reparseConfigFileSecuritySections(); - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); + } + finally + { + ApplicationRegistry.remove(1); + } } private void writeFirewallVhostsFile(File vhostsFile, boolean allow) throws IOException @@ -260,8 +291,9 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>\n"); out.write("\t<management><enabled>false</enabled></management>\n"); out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); + out.write("\t\t<principal-databases>\n"); out.write("\t\t\t<principal-database>\n"); + out.write("\t\t\t\t<name>passwordfile</name>\n"); out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); out.write("\t\t\t\t<attributes>\n"); out.write("\t\t\t\t\t<attribute>\n"); @@ -270,7 +302,11 @@ public class FirewallConfigurationTest extends QpidTestCase out.write("\t\t\t\t\t</attribute>\n"); out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); + out.write("\t\t</principal-databases>\n"); + out.write("\t\t<jmx>\n"); + out.write("\t\t\t<access>/dev/null</access>\n"); + out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); + out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<rule access=\""+ ((allow) ? "allow" : "deny") +"\" network=\"127.0.0.1\"/>"); out.write("\t\t</firewall>\n"); @@ -310,8 +346,8 @@ public class FirewallConfigurationTest extends QpidTestCase // Load config ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - + ApplicationRegistry.initialise(reg, 1); + // Test config VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); diff --git a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java index 00077d9d9c..2b04962c89 100644 --- a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java +++ b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java @@ -27,15 +27,12 @@ import java.net.SocketAddress; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.Result; import org.apache.qpid.server.security.access.plugins.Firewall; import org.apache.qpid.server.security.access.plugins.FirewallConfiguration; -import org.apache.qpid.server.util.TestApplicationRegistry; -import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.server.util.InternalBrokerBaseCase; -public class FirewallPluginTest extends QpidTestCase +public class FirewallPluginTest extends InternalBrokerBaseCase { public class RuleInfo { @@ -76,23 +73,15 @@ public class FirewallPluginTest extends QpidTestCase // IP address private SocketAddress _address; - private ServerConfiguration _serverConfig; @Override - protected void setUp() throws Exception + public void setUp() throws Exception { super.setUp(); - _serverConfig = new ServerConfiguration(new XMLConfiguration()); - ApplicationRegistry.initialise(new TestApplicationRegistry(_serverConfig)); + _address = new InetSocketAddress("127.0.0.1", 65535); } - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - ApplicationRegistry.remove(); - } private Firewall initialisePlugin(String defaultAction, RuleInfo[] rules) throws IOException, ConfigurationException { // Create sample config file @@ -119,7 +108,7 @@ public class FirewallPluginTest extends QpidTestCase } buf.write("</firewall>"); buf.close(); - + // Configure plugin FirewallConfiguration config = new FirewallConfiguration(); config.setConfiguration("", new XMLConfiguration(confFile)); diff --git a/java/broker-plugins/simple-xml/MANIFEST.MF b/java/broker-plugins/simple-xml/MANIFEST.MF new file mode 100644 index 0000000000..04fe7518df --- /dev/null +++ b/java/broker-plugins/simple-xml/MANIFEST.MF @@ -0,0 +1,36 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Qpid Broker-Plugins Simple XML +Bundle-SymbolicName: broker-plugins-simple-xml +Bundle-Description: Simple XML ACL plugin for Qpid. +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Bundle-DocURL: http://www.apache.org/ +Bundle-Version: 1.0.0 +Bundle-Activator: org.apache.qpid.server.security.access.plugins.SimpleXMLActivator +Bundle-RequiredExecutionEnvironment: JavaSE-1.5 +Bundle-ClassPath: . +Bundle-ActivationPolicy: lazy +Import-Package: org.apache.qpid, + org.apache.qpid.framing, + org.apache.qpid.junit.extensions.util, + org.apache.qpid.protocol, + org.apache.qpid.server.configuration, + org.apache.qpid.server.configuration.plugins, + org.apache.qpid.server.exchange, + org.apache.qpid.server.management, + org.apache.qpid.server.plugins, + org.apache.qpid.server.queue, + org.apache.qpid.server.security, + org.apache.qpid.server.security.access, + org.apache.qpid.server.virtualhost, + org.apache.qpid.util, + org.apache.commons.configuration;version=1.0.0, + org.apache.commons.lang;version=1.0.0, + org.apache.commons.lang.builder;version=1.0.0, + org.apache.log4j;version=1.0.0, + javax.management;version=1.0.0, + javax.management.openmbean;version=1.0.0, + org.osgi.util.tracker;version=1.0.0, + org.osgi.framework;version=1.3 +Private-Package: org.apache.qpid.server.security.access.config +Export-Package: org.apache.qpid.server.security.access.plugins diff --git a/java/broker-plugins/simple-xml/build.xml b/java/broker-plugins/simple-xml/build.xml new file mode 100644 index 0000000000..d3cd451648 --- /dev/null +++ b/java/broker-plugins/simple-xml/build.xml @@ -0,0 +1,29 @@ +<!-- + - 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. + --> +<project name="Qpid Broker-Plugins Simple XML" default="build"> + <property name="module.depends" value="common broker broker-plugins" /> + <property name="module.test.depends" value="test broker/test common/test management/common systests" /> + + <property name="module.manifest" value="MANIFEST.MF" /> + <property name="module.plugin" value="true" /> + + <import file="../../module.xml" /> + + <target name="bundle" depends="bundle-tasks" /> +</project> diff --git a/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/config/PrincipalPermissions.java b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/config/PrincipalPermissions.java new file mode 100755 index 0000000000..d9fc292f03 --- /dev/null +++ b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/config/PrincipalPermissions.java @@ -0,0 +1,687 @@ +/* + * + * 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.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.security.Result; + +@SuppressWarnings("unchecked") +public class PrincipalPermissions +{ + public enum Permission + { + CONSUME, + PUBLISH, + CREATEQUEUE, + CREATEEXCHANGE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE + } + + private static final Logger _logger = Logger.getLogger(PrincipalPermissions.class); + + private static final Object CONSUME_QUEUES_KEY = new Object(); + private static final Object CONSUME_TEMPORARY_KEY = new Object(); + private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object(); + + private static final Object CREATE_QUEUES_KEY = new Object(); + private static final Object CREATE_EXCHANGES_KEY = new Object(); + + + private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object(); + private static final Object CREATE_QUEUE_QUEUES_KEY = new Object(); + private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object(); + + private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object(); + + private static final int PUBLISH_EXCHANGES_KEY = 0; + + private Map _permissions; + private boolean _fullVHostAccess = false; + + private String _user; + + + public PrincipalPermissions(String user) + { + _user = user; + _permissions = new ConcurrentHashMap(); + } + + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: none + * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly + * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey + * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ + public void grant(Permission permission, Object... parameters) + { + switch (permission) + { + case ACCESS:// Parameters : None + grantAccess(permission); + break; + case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly + grantConsume(permission, parameters); + break; + case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName + // , AMQShortString exchangeName , AMQShortString routingKey + grantCreateQueue(permission, parameters); + break; + case CREATEEXCHANGE: + // Parameters AMQShortString exchangeName , AMQShortString Class + grantCreateExchange(permission, parameters); + break; + case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey + grantPublish(permission, parameters); + break; + /* The other cases just fall through to no-op */ + case DELETE: + case BIND: // All the details are currently included in the create setup. + case PURGE: + case UNBIND: + break; + } + + } + + private void grantAccess(Permission permission) + { + _fullVHostAccess = true; + } + + private void grantPublish(Permission permission, Object... parameters) { + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + publishRights = new ConcurrentHashMap(); + _permissions.put(permission, publishRights); + } + + if (parameters == null || parameters.length == 0) + { + //If we have no parameters then allow publish to all destinations + // this is signified by having a null value for publish_exchanges + } + else + { + Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + if (publish_exchanges == null) + { + publish_exchanges = new ConcurrentHashMap(); + publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges); + } + + + HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]); + + // Check to see if we have a routing key + if (parameters.length == 2) + { + if (routingKeys == null) + { + routingKeys = new HashSet<AMQShortString>(); + } + //Add routing key to permitted publish destinations + routingKeys.add(parameters[1]); + } + + // Add the updated routingkey list or null if all values allowed + publish_exchanges.put(parameters[0], routingKeys); + } + } + + private void grantCreateExchange(Permission permission, Object... parameters) { + Map rights = (Map) _permissions.get(permission); + if (rights == null) + { + rights = new ConcurrentHashMap(); + _permissions.put(permission, rights); + } + + Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY); + if (create_exchanges == null) + { + create_exchanges = new ConcurrentHashMap(); + rights.put(CREATE_EXCHANGES_KEY, create_exchanges); + } + + //Should perhaps error if parameters[0] is null; + AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null; + AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct"); + + //Store the exchangeName / class mapping if the mapping is null + rights.put(name, className); + } + + private void grantCreateQueue(Permission permission, Object... parameters) + { + Map createRights = (Map) _permissions.get(permission); + + if (createRights == null) + { + createRights = new ConcurrentHashMap(); + _permissions.put(permission, createRights); + } + + //The existence of the empty map mean permission to all. + if (parameters.length == 0) + { + return; + } + + // Get the queues map + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + //Initialiase the queue permissions if not already done + if (create_queues == null) + { + create_queues = new ConcurrentHashMap(); + //initialise temp queue permission to false and overwrite below if true + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, false); + createRights.put(CREATE_QUEUES_KEY, create_queues); + } + + //Create empty list of queues + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + if (create_queues_queues == null) + { + create_queues_queues = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues); + } + + // If we are initialising and granting CREATE rights to all temporary queues, then that's all we do + Boolean temporary = false; + if (parameters.length == 1) + { + temporary = (Boolean) parameters[0]; + create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary); + return; + } + + //From here we can be permissioning a variety of things, with varying parameters + AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null; + AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null; + //Set the routingkey to the specified value or the queueName if present + AMQShortString routingKey = (parameters.length > 3 && null != parameters[3]) ? (AMQShortString) parameters[3] : queueName; + // if we have a queueName then we need to store any associated exchange / rk bindings + if (queueName != null) + { + Map queue = (Map) create_queues_queues.get(queueName); + if (queue == null) + { + queue = new ConcurrentHashMap(); + create_queues_queues.put(queueName, queue); + } + + if (exchangeName != null) + { + queue.put(exchangeName, routingKey); + } + + //If no exchange is specified then the presence of the queueName in the map says any exchange is ok + } + + // Store the exchange that we are being granted rights to. This will be used as part of binding + + //Lookup the list of exchanges + Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY); + + if (create_queues_exchanges == null) + { + create_queues_exchanges = new ConcurrentHashMap(); + create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges); + } + + //if we have an exchange + if (exchangeName != null) + { + //Retrieve the list of permitted exchanges. + Map exchanges = (Map) create_queues_exchanges.get(exchangeName); + + if (exchanges == null) + { + exchanges = new ConcurrentHashMap(); + create_queues_exchanges.put(exchangeName, exchanges); + } + + //Store the binding details of queue/rk for this exchange. + if (queueName != null) + { + //Retrieve the list of permitted routingKeys. + Map rKeys = (Map) exchanges.get(exchangeName); + + if (rKeys == null) + { + rKeys = new ConcurrentHashMap(); + exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys); + } + + rKeys.put(queueName, routingKey); + } + } + } + + /** + * Grant consume permissions + */ + private void grantConsume(Permission permission, Object... parameters) + { + Map consumeRights = (Map) _permissions.get(permission); + + if (consumeRights == null) + { + consumeRights = new ConcurrentHashMap(); + _permissions.put(permission, consumeRights); + + //initialise own and temporary rights to false to be overwritten below if set + consumeRights.put(CONSUME_TEMPORARY_KEY, false); + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false); + } + + + //if we only have one param then we're permissioning temporary queues and topics + if (parameters.length == 1) + { + Boolean temporary = (Boolean) parameters[0]; + + if (temporary) + { + consumeRights.put(CONSUME_TEMPORARY_KEY, true); + } + } + + //if we have 2 parameters - should be a contract for this, but for now we'll handle it as is + if (parameters.length == 2) + { + AMQShortString queueName = (AMQShortString) parameters[0]; + Boolean ownQueueOnly = (Boolean) parameters[1]; + + if (ownQueueOnly) + { + consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true); + } + + LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY); + if (queues == null) + { + queues = new LinkedList(); + consumeRights.put(CONSUME_QUEUES_KEY, queues); + } + + if (queueName != null) + { + queues.add(queueName); + } + } + } + + /** + * + * @param permission the type of permission to check + * + * @param parameters vararg depending on what permission was passed in + * ACCESS: none + * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey + * CONSUME: AMQQueue queue + * CREATEQUEUE: Boolean autodelete, AMQShortString name + * CREATEEXCHANGE: AMQShortString exchangeName + * DELETE: none + * PUBLISH: Exchange exchange, AMQShortString routingKey + * PURGE: none + * UNBIND: none + */ + public Result authorise(Permission permission, String... parameters) + { + + switch (permission) + { + case ACCESS://No Parameters + return Result.ALLOWED; // The existence of this user-specific PP infers some level of access is authorised + case BIND: // Parameters : QueueBindMethod , exhangeName , queueName, routingKey + return authoriseBind(parameters); + case CREATEQUEUE:// Parameters : autoDelete, queueName + return authoriseCreateQueue(permission, parameters); + case CREATEEXCHANGE: //Parameters: exchangeName + return authoriseCreateExchange(permission, parameters); + case CONSUME: // Parameters : queueName, autoDelete, owner + return authoriseConsume(permission, parameters); + case PUBLISH: // Parameters : exchangeName, routingKey + return authorisePublish(permission, parameters); + /* Fall through */ + case DELETE: + case PURGE: + case UNBIND: + default: + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + else + { + //SimpleXML ACL does not implement these permissions and should abstain + return Result.ABSTAIN; + } + } + + } + + private Result authoriseConsume(Permission permission, String... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + + if (parameters.length == 3) + { + AMQShortString queueName = new AMQShortString(parameters[0]); + Boolean autoDelete = Boolean.valueOf(parameters[1]); + AMQShortString owner = new AMQShortString(parameters[2]); + Map queuePermissions = (Map) _permissions.get(permission); + + _logger.error("auth consume on " + StringUtils.join(parameters, ", ")); + + if (queuePermissions == null) + { + //we have a problem - we've never granted this type of permission ..... + return Result.DENIED; + } + + List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY); + + Boolean temporaryQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY); + Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY); + + + // If user is allowed to consume from temporary queues and this is a temp queue then allow it. + if (temporaryQueues && autoDelete) + { + // This will allow consumption from any temporary queue including ones not owned by this user. + // Of course the exclusivity will not be broken. + { + + // if not limited to ownQueuesOnly then ok else check queue Owner. + return (!ownQueuesOnly || owner.equals(_user)) ? Result.ALLOWED : Result.DENIED; + } + } + //if this is a temporary queue and the user does not have permissions for temporary queues then deny + else if (!temporaryQueues && autoDelete) + { + return Result.DENIED; + } + + // if queues are white listed then ensure it is ok + if (queues != null) + { + // if no queues are listed then ALL are ok othereise it must be specified. + if (ownQueuesOnly) + { + if (owner.equals(_user)) + { + return (queues.size() == 0 || queues.contains(queueName)) ? Result.ALLOWED : Result.DENIED; + } + else + { + return Result.DENIED; + } + } + + // If we are + return (queues.size() == 0 || queues.contains(queueName)) ? Result.ALLOWED : Result.DENIED; + } + } + + // Can't authenticate without the right parameters + return Result.DENIED; + } + + private Result authorisePublish(Permission permission, String... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + + Map publishRights = (Map) _permissions.get(permission); + + if (publishRights == null) + { + return Result.DENIED; + } + + Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY); + + // Having no exchanges listed gives full publish rights to all exchanges + if (exchanges == null) + { + return Result.ALLOWED; + } + // Otherwise exchange must be listed in the white list + + // If the map doesn't have the exchange then it isn't allowed + AMQShortString exchangeName = new AMQShortString(parameters[0]); + if (!exchanges.containsKey(exchangeName)) + { + return Result.DENIED; + } + else + { + // Get valid routing keys + HashSet routingKeys = (HashSet) exchanges.get(exchangeName); + + // Having no routingKeys in the map then all are allowed. + if (routingKeys == null) + { + return Result.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = routingKeys.iterator(); + + AMQShortString publishRKey = new AMQShortString(parameters[1]); + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + + if (rkey.endsWith("*")) + { + matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1)); + } + else + { + matched = publishRKey.equals(rkey); + } + } + return (matched) ? Result.ALLOWED : Result.DENIED; + } + } + } + + private Result authoriseCreateExchange(Permission permission, String... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + + Map rights = (Map) _permissions.get(permission); + + AMQShortString exchangeName = new AMQShortString(parameters[0]); + + // If the exchange list is doesn't exist then all is allowed else + // check the valid exchanges + if (rights == null || rights.containsKey(exchangeName)) + { + return Result.ALLOWED; + } + else + { + return Result.DENIED; + } + } + + private Result authoriseCreateQueue(Permission permission, String... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + + Map createRights = (Map) _permissions.get(permission); + + // If there are no create rights then deny request + if (createRights == null) + { + return Result.DENIED; + } + + //Look up the Queue Creation Rights + Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY); + + //Lookup the list of queues allowed to be created + Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY); + + + Boolean autoDelete = Boolean.valueOf(parameters[0]); + AMQShortString queueName = new AMQShortString(parameters[1]); + + if (autoDelete)// we have a temporary queue + { + return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? Result.ALLOWED : Result.DENIED; + } + else + { + // If there is a white list then check + if (create_queues_queues == null || create_queues_queues.containsKey(queueName)) + { + return Result.ALLOWED; + } + else + { + return Result.DENIED; + } + + } + } + + private Result authoriseBind(String... parameters) + { + if(_fullVHostAccess) + { + //user has been granted full access to the vhost + return Result.ALLOWED; + } + + AMQShortString exchangeName = new AMQShortString(parameters[1]); + AMQShortString bind_queueName = new AMQShortString(parameters[2]); + AMQShortString routingKey = new AMQShortString(parameters[3]); + + //Get all Create Rights for this user + Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE); + + //Lookup the list of queues + Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY); + + // Check and see if we have a queue white list to check + if (bind_create_queues_queues != null) + { + //There a white list for queues + Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName); + + if (exchangeDetails == null) //Then all queue can be bound to all exchanges. + { + return Result.ALLOWED; + } + + // Check to see if we have a white list of routingkeys to check + Map rkeys = (Map) exchangeDetails.get(exchangeName); + + // if keys is null then any rkey is allowed on this exchange + if (rkeys == null) + { + // There is no routingkey white list + return Result.ALLOWED; + } + else + { + // We have routingKeys so a match must be found to allowed binding + Iterator keys = rkeys.keySet().iterator(); + + boolean matched = false; + while (keys.hasNext() && !matched) + { + AMQShortString rkey = (AMQShortString) keys.next(); + if (rkey.endsWith("*")) + { + matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString()); + } + else + { + matched = routingKey.equals(rkey); + } + } + + + return (matched) ? Result.ALLOWED : Result.DENIED; + } + + + } + else + { + //no white list so all allowed. + return Result.ALLOWED; + } + } +} diff --git a/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java new file mode 100644 index 0000000000..ab43653122 --- /dev/null +++ b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -0,0 +1,427 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.plugins; + +import static org.apache.qpid.server.security.access.ObjectProperties.Property.*; + +import java.security.Principal; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.security.AbstractPlugin; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.security.SecurityPluginFactory; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.access.config.PrincipalPermissions; +import org.apache.qpid.server.security.access.config.PrincipalPermissions.Permission; + +/** + * This uses the default + */ +public class SimpleXML extends AbstractPlugin +{ + public static final Logger _logger = Logger.getLogger(SimpleXML.class); + + private Map<String, PrincipalPermissions> _users; + + public static final SecurityPluginFactory<SimpleXML> FACTORY = new SecurityPluginFactory<SimpleXML>() + { + public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException + { + SimpleXMLConfiguration configuration = config.getConfiguration(SimpleXMLConfiguration.class.getName()); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + return null; + } + + SimpleXML plugin = new SimpleXML(); + plugin.configure(configuration); + return plugin; + } + + public String getPluginName() + { + return SimpleXML.class.getName(); + } + + public Class<SimpleXML> getPluginClass() + { + return SimpleXML.class; + } + }; + + public void configure(ConfigurationPlugin config) + { + super.configure(config); + + SimpleXMLConfiguration configuration = (SimpleXMLConfiguration) _config; + + _users = new ConcurrentHashMap<String, PrincipalPermissions>(); + + processConfig(configuration.getConfiguration()); + } + + private void processConfig(Configuration config) + { + processPublish(config); + processConsume(config); + processCreate(config); + processAccess(config); + } + + /** + * @param config XML Configuration + */ + private void processAccess(Configuration config) + { + Configuration accessConfig = config.subset("access"); + + if (accessConfig.isEmpty()) + { + //there is no access configuration to process + return; + } + + // Process users that have full access permission + String[] users = accessConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.ACCESS, user); + } + } + + /** + * Publish format takes Exchange + Routing Key Pairs + * + * @param config XML Configuration + */ + private void processPublish(Configuration config) + { + Configuration publishConfig = config.subset("publish"); + + // Process users that have full publish permission + String[] users = publishConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user); + } + + // Process exchange limited users + int exchangeCount = 0; + Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + // Get Exchange Name + AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name")); + + // Get Routing Keys + int keyCount = 0; + Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + + while (!routingkeyConfig.isEmpty()) + { + // Get RoutingKey Value + AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value")); + + // Apply Exchange + RoutingKey permissions to Users + users = routingkeyConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName, routingKeyValue); + } + + // Apply permissions to Groups + + // Check for more configs + keyCount++; + routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")"); + } + + // Apply Exchange wide permissions to Users + users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user"); + + for (String user : users) + { + grant(Permission.PUBLISH, user, exchangeName); + } + + // Apply permissions to Groups + exchangeCount++; + exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + } + + private void grant(Permission permission, String user, Object... parameters) + { + PrincipalPermissions permissions = _users.get(user); + + if (permissions == null) + { + permissions = new PrincipalPermissions(user); + } + + _users.put(user, permissions); + permissions.grant(permission, parameters); + } + + /** + * @param config XML Configuration + */ + private void processConsume(Configuration config) + { + boolean temporary = false; + Configuration tempConfig = null; + Configuration consumeConfig = config.subset("consume"); + + tempConfig = consumeConfig.subset("queues.temporary(0)"); + if (tempConfig != null) + { + temporary = true; + } + + //Permission all users who have rights to temp queues and topics + if (tempConfig != null && !tempConfig.isEmpty()) + { + String[] tempUsers = tempConfig.getStringArray("users.user"); + for (String user : tempUsers) + { + grant(Permission.CONSUME, user, temporary); + } + } + + // Process queue limited users + int queueCount = 0; + Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + // Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + // if there is no name then there may be a temporary element + + boolean ownQueues = queueConfig.containsKey("own_queues"); + + // Process permissions for this queue + String[] users = queueConfig.getStringArray("users.user"); + for (String user : users) + { + grant(Permission.CONSUME, user, queueName, ownQueues); + } + + // See if we have another config + queueCount++; + queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process users that have full consume permission + String[] users = consumeConfig.getStringArray("users.user"); + + for (String user : users) + { + //NOTE: this call does not appear to do anything inside the grant section for consume + grant(Permission.CONSUME, user); + } + } + + /** + * @param config XML Configuration + */ + private void processCreate(Configuration config) + { + boolean temporary = false; + Configuration tempConfig = null; + + Configuration createConfig = config.subset("create"); + + tempConfig = createConfig.subset("queues.temporary(0)"); + if (tempConfig != null) + { + temporary = true; + } + + //Permission all users who have rights to temp queues and topics + if (tempConfig != null && !tempConfig.isEmpty()) + { + String[] tempUsers = tempConfig.getStringArray("users.user"); + for (String user : tempUsers) + { + grant(Permission.CREATEQUEUE, user, temporary); + } + } + // Process create permissions for queue creation + int queueCount = 0; + Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + + while (!queueConfig.isEmpty()) + { + // Get queue Name + AMQShortString queueName = new AMQShortString(queueConfig.getString("name")); + + int exchangeCount = 0; + Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key")); + + // Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + //This is broken as the user name is not stored + grant(Permission.CREATEEXCHANGE, user, exchange); + + //This call could be cleaned up as temporary is now being set earlier (above) + grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange + .equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey)); + } + + // See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that are not bound to an exchange + String[] users = queueConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATEQUEUE, user, temporary, queueName); + } + + // See if we have another config + queueCount++; + queueConfig = createConfig.subset("queues.queue(" + queueCount + ")"); + } + + // Process create permissions for exchange creation + int exchangeCount = 0; + Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + + while (!exchangeConfig.isEmpty()) + { + AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name")); + AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class")); + + // Process permissions for this queue + String[] users = exchangeConfig.getStringArray("users.user"); + for (String user : users) + { + //And this is broken too + grant(Permission.CREATEEXCHANGE, user, exchange, clazz); + } + + // See if we have another config + exchangeCount++; + exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")"); + } + + // Process users that have full create permission + String[] users = createConfig.getStringArray("users.user"); + + for (String user : users) + { + grant(Permission.CREATEEXCHANGE, user); + grant(Permission.CREATEQUEUE, user); + } + } + + public Result access(ObjectType objectType, Object instance) + { + Principal principal = SecurityManager.getThreadPrincipal(); + if (principal == null) + { + return getDefault(); // Default if there is no user associated with the thread + } + PrincipalPermissions principalPermissions = _users.get(principal.getName()); + if (principalPermissions == null) + { + return Result.DENIED; + } + + // Authorise object access + if (objectType == ObjectType.VIRTUALHOST) + { + return principalPermissions.authorise(Permission.ACCESS); + } + + // Default + return getDefault(); + } + + public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) + { + Principal principal = SecurityManager.getThreadPrincipal(); + if (principal == null) + { + return getDefault(); // Default if there is no user associated with the thread + } + PrincipalPermissions principalPermissions = _users.get(principal.getName()); + if (principalPermissions == null) + { + return Result.DENIED; + } + + // Authorise operation + switch (operation) + { + case CONSUME: + return principalPermissions.authorise(Permission.CONSUME, properties.get(NAME), properties.get(AUTO_DELETE), properties.get(OWNER)); + case PUBLISH: + return principalPermissions.authorise(Permission.PUBLISH, properties.get(NAME), properties.get(ROUTING_KEY)); + case CREATE: + if (objectType == ObjectType.EXCHANGE) + { + return principalPermissions.authorise(Permission.CREATEEXCHANGE, properties.get(NAME)); + } + else if (objectType == ObjectType.QUEUE) + { + return principalPermissions.authorise(Permission.CREATEQUEUE, properties.get(AUTO_DELETE), properties.get(NAME)); + } + case ACCESS: + return principalPermissions.authorise(Permission.ACCESS); + case BIND: + return principalPermissions.authorise(Permission.BIND, null, properties.get(NAME), properties.get(QUEUE_NAME), properties.get(ROUTING_KEY)); + case UNBIND: + return principalPermissions.authorise(Permission.UNBIND); + case DELETE: + return principalPermissions.authorise(Permission.DELETE); + case PURGE: + return principalPermissions.authorise(Permission.PURGE); + } + + // Default + return getDefault(); + } +} diff --git a/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java new file mode 100644 index 0000000000..c09a9da0d8 --- /dev/null +++ b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.SecurityPluginActivator; +import org.apache.qpid.server.security.SecurityPluginFactory; +import org.osgi.framework.BundleActivator; + +/** + * The OSGi {@link BundleActivator} for {@link SimpleXML}. + */ +public class SimpleXMLActivator extends SecurityPluginActivator +{ + public SecurityPluginFactory getFactory() + { + return SimpleXML.FACTORY; + } + + public ConfigurationPluginFactory getConfigurationFactory() + { + return SimpleXMLConfiguration.FACTORY; + } +} diff --git a/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java new file mode 100644 index 0000000000..e95c21b590 --- /dev/null +++ b/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +public class SimpleXMLConfiguration extends ConfigurationPlugin +{ + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new SimpleXMLConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + + public List<String> getParentPaths() + { + return Arrays.asList("security.access_control_list", "virtualhosts.virtualhost.security.access_control_list"); + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "" }; + } + + public Configuration getConfiguration() + { + return _configuration; + } +} diff --git a/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java new file mode 100644 index 0000000000..65ab12a095 --- /dev/null +++ b/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -0,0 +1,209 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access; + +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.access.config.PrincipalPermissions; +import org.apache.qpid.server.security.access.config.PrincipalPermissions.Permission; +import org.apache.qpid.test.utils.QpidTestCase; + +public class PrincipalPermissionsTest extends QpidTestCase +{ + private String _user = "user"; + private PrincipalPermissions _perms; + + // Common things that are passed to frame constructors + private AMQShortString _queueName = new AMQShortString(this.getClass().getName() + "queue"); + private AMQShortString _tempQueueName = new AMQShortString(this.getClass().getName() + "tempqueue"); + private AMQShortString _exchangeName = new AMQShortString("amq.direct"); + private AMQShortString _routingKey = new AMQShortString(this.getClass().getName() + "route"); + private boolean _autoDelete = false; + private AMQShortString _exchangeType = new AMQShortString("direct"); + private Boolean _temporary = false; + private Boolean _ownQueue = false; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + _perms = new PrincipalPermissions(_user); + } + + + public void testPrincipalPermissions() + { + assertNotNull(_perms); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.ACCESS, (String[]) null)); + } + + // FIXME: test has been disabled since the permissions assume that the user has tried to create + // the queue first. QPID-1597 + public void disableTestBind() throws Exception + { + String[] args = new String[]{null, _exchangeName.asString(), _queueName.asString(), _routingKey.asString()}; + + assertEquals(Result.DENIED, _perms.authorise(Permission.BIND, args)); + _perms.grant(Permission.BIND, (Object[]) null); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.BIND, args)); + } + + public void testQueueCreate() + { + Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, _routingKey}; + String[] authArgs = new String[]{Boolean.toString(_autoDelete), _queueName.asString()}; + + assertEquals(Result.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); + _perms.grant(Permission.CREATEQUEUE, grantArgs); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); + } + + public void testQueueCreateWithNullRoutingKey() + { + Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, null}; + String[] authArgs = new String[]{Boolean.toString(_autoDelete), _queueName.asString()}; + + assertEquals(Result.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); + _perms.grant(Permission.CREATEQUEUE, grantArgs); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs)); + } + + // FIXME disabled, this fails due to grant putting the grant into the wrong map QPID-1598 + public void disableTestExchangeCreate() + { + String[] authArgs = new String[]{_exchangeName.asString()}; + Object[] grantArgs = new Object[]{_exchangeName, _exchangeType}; + + assertEquals(Result.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs)); + _perms.grant(Permission.CREATEEXCHANGE, grantArgs); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs)); + } + + public void testConsume() + { + String[] authArgs = new String[]{_queueName.asString(), Boolean.toString(_autoDelete), _user}; + Object[] grantArgs = new Object[]{_queueName, _ownQueue}; + + // FIXME: This throws a null pointer exception QPID-1599 + // assertFalse(_perms.authorise(Permission.CONSUME, authArgs)); + _perms.grant(Permission.CONSUME, grantArgs); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs)); + } + + public void testPublish() throws AMQException + { + String[] authArgs = new String[]{_exchangeName.asString(), _routingKey.asString()}; + Object[] grantArgs = new Object[]{_exchangeName, _routingKey}; + + assertEquals(Result.DENIED, _perms.authorise(Permission.PUBLISH, authArgs)); + _perms.grant(Permission.PUBLISH, grantArgs); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgs)); + } + + public void testVhostAccess() + { + //Tests that granting a user Virtualhost level access allows all authorisation requests + //where previously they would be denied + + //QPID-2133 createExchange rights currently allow all exchange creation unless rights for creating some + //specific exchanges are granted. Grant a specific exchange creation to cause all others to be denied. + Object[] createArgsCreateExchange = new Object[]{new AMQShortString("madeup"), _exchangeType}; + String[] authArgsCreateExchange = new String[]{_exchangeName.asString()}; + assertEquals("Exchange creation was not allowed", Result.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); + _perms.grant(Permission.CREATEEXCHANGE, createArgsCreateExchange); + + String[] authArgsPublish = new String[]{_exchangeName.asString(), _routingKey.asString()}; + String[] authArgsConsume = new String[]{_queueName.asString(), Boolean.toString(_autoDelete), _user}; + String[] authArgsCreateQueue = new String[]{Boolean.toString(_autoDelete), _queueName.asString()}; +// QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments); + String[] authArgsBind = new String[]{ null, _exchangeName.asString(), _queueName.asString(), _routingKey.asString()}; + + assertEquals("Exchange creation was not denied", Result.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); + assertEquals("Publish was not denied", Result.DENIED, _perms.authorise(Permission.PUBLISH, authArgsPublish)); + assertEquals("Consume creation was not denied", Result.DENIED, _perms.authorise(Permission.CONSUME, authArgsConsume)); + assertEquals("Queue creation was not denied", Result.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgsCreateQueue)); + //BIND pre-grant authorise check disabled due to QPID-1597 + //assertEquals("Binding creation was not denied", Result.DENIED, _perms.authorise(Permission.BIND, authArgsBind)); + + _perms.grant(Permission.ACCESS); + + assertEquals("Exchange creation was not allowed", Result.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgsCreateExchange)); + assertEquals("Publish was not allowed", Result.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgsPublish)); + assertEquals("Consume creation was not allowed", Result.ALLOWED, _perms.authorise(Permission.CONSUME, authArgsConsume)); + assertEquals("Queue creation was not allowed", Result.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgsCreateQueue)); + assertEquals("Binding creation was not allowed", Result.ALLOWED, _perms.authorise(Permission.BIND, authArgsBind)); + } + + /** + * If the consume permission for temporary queues is for an unnamed queue then is should + * be global for any temporary queue but not for any non-temporary queue + */ + public void testTemporaryUnnamedQueueConsume() + { + String[] authNonTempQArgs = new String[]{_queueName.asString(), Boolean.toString(_autoDelete), _user}; + String[] authTempQArgs = new String[]{_tempQueueName.asString(), Boolean.TRUE.toString(), _user}; + Object[] grantArgs = new Object[]{true}; + + _perms.grant(Permission.CONSUME, grantArgs); + + //Next line shows up bug - non temp queue should be denied + assertEquals(Result.DENIED, _perms.authorise(Permission.CONSUME, authNonTempQArgs)); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs)); + } + + /** + * Test that temporary queue permissions before queue perms in the ACL config work correctly + */ + public void testTemporaryQueueFirstConsume() + { + String[] authNonTempQArgs = new String[]{_queueName.asString(), Boolean.toString(_autoDelete), _user}; + String[] authTempQArgs = new String[]{_tempQueueName.asString(), Boolean.TRUE.toString(), _user}; + Object[] grantArgs = new Object[]{true}; + Object[] grantNonTempQArgs = new Object[]{_queueName, _ownQueue}; + + //should not matter if the temporary permission is processed first or last + _perms.grant(Permission.CONSUME, grantNonTempQArgs); + _perms.grant(Permission.CONSUME, grantArgs); + + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authNonTempQArgs)); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs)); + } + + /** + * Test that temporary queue permissions after queue perms in the ACL config work correctly + */ + public void testTemporaryQueueLastConsume() + { + String[] authNonTempQArgs = new String[]{_queueName.asString(), Boolean.toString(_autoDelete), _user}; + String[] authTempQArgs = new String[]{_tempQueueName.asString(), Boolean.TRUE.toString(), _user}; + Object[] grantArgs = new Object[]{true}; + Object[] grantNonTempQArgs = new Object[]{_queueName, _ownQueue}; + + //should not matter if the temporary permission is processed first or last + _perms.grant(Permission.CONSUME, grantArgs); + _perms.grant(Permission.CONSUME, grantNonTempQArgs); + + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authNonTempQArgs)); + assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authTempQArgs)); + } +} |
