From 4733fe031d102470c81a36a99781a177cba30b68 Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Mon, 31 May 2010 16:05:55 +0000 Subject: QPID-2569: Implement the SimpleXML as an OSGi plugin Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@949784 13f79535-47bb-0310-9956-ffa450edef68 --- .../access/config/PrincipalPermissions.java | 687 +++++++++++++++++++++ .../server/security/access/plugins/SimpleXML.java | 425 +++++++++++++ .../access/plugins/SimpleXMLActivator.java | 22 + .../access/plugins/SimpleXMLConfiguration.java | 57 ++ .../security/access/PrincipalPermissionsTest.java | 240 +++++++ 5 files changed, 1431 insertions(+) create mode 100755 qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/config/PrincipalPermissions.java create mode 100644 qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java create mode 100644 qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java create mode 100644 qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java create mode 100644 qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/config/PrincipalPermissions.java b/qpid/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/qpid/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(); + } + //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/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java new file mode 100644 index 0000000000..4b3d8f02de --- /dev/null +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -0,0 +1,425 @@ +/* + * 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 _users; + + public static final SecurityPluginFactory FACTORY = new SecurityPluginFactory() + { + public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException + { + SimpleXML plugin = new SimpleXML(config); + plugin.configure(); + return plugin; + } + + public String getPluginName() + { + return SimpleXML.class.getName(); + } + + public Class getPluginClass() + { + return SimpleXML.class; + } + }; + + public SimpleXML(ConfigurationPlugin config) throws ConfigurationException + { + _config = config.getConfiguration(SimpleXMLConfiguration.class); + } + + public void configure() throws ConfigurationException + { + SimpleXMLConfiguration config = (SimpleXMLConfiguration) _config; + + if (isConfigured()) + { + _users = new ConcurrentHashMap(); + + processConfig(config.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.BROKER || 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/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java new file mode 100644 index 0000000000..e5bae0669a --- /dev/null +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java @@ -0,0 +1,22 @@ +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/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java new file mode 100644 index 0000000000..b73ab97080 --- /dev/null +++ b/qpid/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 getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "access_control_list" }; + } + + public Configuration getConfiguration() + { + return _configuration.subset("access_control_list"); + } +} diff --git a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java new file mode 100644 index 0000000000..3cbad83369 --- /dev/null +++ b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -0,0 +1,240 @@ +/* + * + * 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 junit.framework.TestCase; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.DirectExchange; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; +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.server.virtualhost.VirtualHost; + +public class PrincipalPermissionsTest extends TestCase +{ + 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 int _ticket = 1; + private FieldTable _arguments = null; + private boolean _durable = false; + private boolean _autoDelete = false; + private AMQShortString _exchangeType = new AMQShortString("direct"); + private DirectExchange _exchange; + private VirtualHost _virtualHost; + private AMQShortString _owner = new AMQShortString(this.getClass().getName() + "owner"); + private Boolean _temporary = false; + private Boolean _ownQueue = false; + + @Override + public void setUp() + { + //Highlight that this test will cause a new AR to be created + ApplicationRegistry.getInstance(); + + _perms = new PrincipalPermissions(_user); + try + { + _virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); + _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete); + AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, false, _virtualHost, _arguments); + AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, false, _virtualHost, _arguments); + } + catch (Exception e) + { + fail(e.getMessage()); + } + } + + @Override + protected void tearDown() throws Exception + { + //Ensure we close the opened Registry + ApplicationRegistry.remove(); + } + + + 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() + { + String[] authArgs = new String[]{_exchangeName.asString(), _routingKey.asString()}; + Object[] grantArgs = new Object[]{_exchange.getNameShortString(), _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)); + } +} -- cgit v1.2.1 From 45256699f28ea572791cb0b3062dba6c5dedbf39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Wed, 2 Jun 2010 16:47:34 +0000 Subject: QPID-2581 : Update Plugins to have a consistent configure(ConfigurationPlugin config) method. Further work is required to ensure that all ConfigurationPlugins perform config validation rather than leaving that to the plugin. The plugin should just use the config. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950656 13f79535-47bb-0310-9956-ffa450edef68 --- .../qpid/server/security/access/plugins/SimpleXML.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 4b3d8f02de..26a5c132f9 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -52,8 +52,8 @@ public class SimpleXML extends AbstractPlugin { public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException { - SimpleXML plugin = new SimpleXML(config); - plugin.configure(); + SimpleXML plugin = new SimpleXML(); + plugin.configure(config); return plugin; } @@ -68,20 +68,17 @@ public class SimpleXML extends AbstractPlugin } }; - public SimpleXML(ConfigurationPlugin config) throws ConfigurationException + public void configure(ConfigurationPlugin config) throws ConfigurationException { _config = config.getConfiguration(SimpleXMLConfiguration.class); - } - public void configure() throws ConfigurationException - { - SimpleXMLConfiguration config = (SimpleXMLConfiguration) _config; + SimpleXMLConfiguration configuration = (SimpleXMLConfiguration) _config; if (isConfigured()) { _users = new ConcurrentHashMap(); - processConfig(config.getConfiguration()); + processConfig(configuration.getConfiguration()); } } -- cgit v1.2.1 From c1d1a1d8336beb13838c35f37d1e7e7c12ca93cc Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Wed, 2 Jun 2010 19:58:39 +0000 Subject: Add the ASF License to various classes currently missing it git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@950740 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/plugins/SimpleXMLActivator.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java index e5bae0669a..c09a9da0d8 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLActivator.java @@ -1,3 +1,23 @@ +/* + * + * 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; -- cgit v1.2.1 From cb825b854e8f979dc8214d2315a69d01ead73782 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:26:15 +0000 Subject: QPID-2632 : Ensure additional broker unit tests extend IBBC git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951157 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissionsTest.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java index 3cbad83369..e5942c73c2 100644 --- a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java +++ b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -32,8 +32,9 @@ 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.server.virtualhost.VirtualHost; +import org.apache.qpid.server.util.InternalBrokerBaseCase; -public class PrincipalPermissionsTest extends TestCase +public class PrincipalPermissionsTest extends InternalBrokerBaseCase { private String _user = "user"; private PrincipalPermissions _perms; @@ -49,21 +50,18 @@ public class PrincipalPermissionsTest extends TestCase private boolean _autoDelete = false; private AMQShortString _exchangeType = new AMQShortString("direct"); private DirectExchange _exchange; - private VirtualHost _virtualHost; private AMQShortString _owner = new AMQShortString(this.getClass().getName() + "owner"); private Boolean _temporary = false; private Boolean _ownQueue = false; @Override - public void setUp() + public void setUp() throws Exception { - //Highlight that this test will cause a new AR to be created - ApplicationRegistry.getInstance(); + super.setUp(); _perms = new PrincipalPermissions(_user); try { - _virtualHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete); AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, false, _virtualHost, _arguments); AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, false, _virtualHost, _arguments); @@ -74,13 +72,6 @@ public class PrincipalPermissionsTest extends TestCase } } - @Override - protected void tearDown() throws Exception - { - //Ensure we close the opened Registry - ApplicationRegistry.remove(); - } - public void testPrincipalPermissions() { -- cgit v1.2.1 From 378a7020fdb911c2009fa5846f554cd8dbf14b39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:26:59 +0000 Subject: Remove Plugin.isConfigured Only configured plugins should be created git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951158 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/access/plugins/SimpleXML.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 26a5c132f9..8c38c6e76c 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -52,8 +52,16 @@ public class SimpleXML extends AbstractPlugin { public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException { + SimpleXMLConfiguration configuration = config.getConfiguration(SimpleXMLConfiguration.class); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + return null; + } + SimpleXML plugin = new SimpleXML(); - plugin.configure(config); + plugin.configure(configuration); return plugin; } @@ -70,16 +78,13 @@ public class SimpleXML extends AbstractPlugin public void configure(ConfigurationPlugin config) throws ConfigurationException { - _config = config.getConfiguration(SimpleXMLConfiguration.class); + super.configure(config); SimpleXMLConfiguration configuration = (SimpleXMLConfiguration) _config; - if (isConfigured()) - { - _users = new ConcurrentHashMap(); + _users = new ConcurrentHashMap(); - processConfig(configuration.getConfiguration()); - } + processConfig(configuration.getConfiguration()); } private void processConfig(Configuration config) -- cgit v1.2.1 From 1fcfcde8c0ecb27ccd8387857006646bebd44d39 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:27:48 +0000 Subject: QPID-2581 : Update Plugins that use configuration to only throw ConfigurationExceptions during the configuration phase of loading configuration. Creating a plugin and providing it with configuration should not throw a configuration exception. Added configuration validation to newer plugins SimpleXML still needs validation. todo Docuement Configuration mechanism. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951159 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/security/access/plugins/SimpleXML.java | 2 +- .../qpid/server/security/access/plugins/SimpleXMLConfiguration.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 8c38c6e76c..1bf8761978 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -76,7 +76,7 @@ public class SimpleXML extends AbstractPlugin } }; - public void configure(ConfigurationPlugin config) throws ConfigurationException + public void configure(ConfigurationPlugin config) { super.configure(config); diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java index b73ab97080..e95c21b590 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXMLConfiguration.java @@ -41,17 +41,17 @@ public class SimpleXMLConfiguration extends ConfigurationPlugin public List getParentPaths() { - return Arrays.asList("security", "virtualhosts.virtualhost.security"); + return Arrays.asList("security.access_control_list", "virtualhosts.virtualhost.security.access_control_list"); } }; public String[] getElementsProcessed() { - return new String[] { "access_control_list" }; + return new String[] { "" }; } public Configuration getConfiguration() { - return _configuration.subset("access_control_list"); + return _configuration; } } -- cgit v1.2.1 From 7a7693b0dd28797d4641aeeaf9b2f9cdbafa5ed3 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Thu, 3 Jun 2010 21:28:03 +0000 Subject: QPID-2632 : Encorporated changes from Andrew Kennedy, cleanup PPT and extend IBBC as this is a broker unit test. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951160 13f79535-47bb-0310-9956-ffa450edef68 --- .../security/access/PrincipalPermissionsTest.java | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java index e5942c73c2..055dee06a0 100644 --- a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java +++ b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.security.access; import junit.framework.TestCase; +import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.exchange.DirectExchange; @@ -44,13 +45,8 @@ public class PrincipalPermissionsTest extends InternalBrokerBaseCase 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 int _ticket = 1; - private FieldTable _arguments = null; - private boolean _durable = false; private boolean _autoDelete = false; private AMQShortString _exchangeType = new AMQShortString("direct"); - private DirectExchange _exchange; - private AMQShortString _owner = new AMQShortString(this.getClass().getName() + "owner"); private Boolean _temporary = false; private Boolean _ownQueue = false; @@ -60,16 +56,6 @@ public class PrincipalPermissionsTest extends InternalBrokerBaseCase super.setUp(); _perms = new PrincipalPermissions(_user); - try - { - _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete); - AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, false, _virtualHost, _arguments); - AMQQueueFactory.createAMQQueueImpl(_tempQueueName, false, _owner , true, false, _virtualHost, _arguments); - } - catch (Exception e) - { - fail(e.getMessage()); - } } @@ -132,10 +118,12 @@ public class PrincipalPermissionsTest extends InternalBrokerBaseCase assertEquals(Result.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs)); } - public void testPublish() + public void testPublish() throws AMQException { + DirectExchange exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, false, 1, _autoDelete); + String[] authArgs = new String[]{_exchangeName.asString(), _routingKey.asString()}; - Object[] grantArgs = new Object[]{_exchange.getNameShortString(), _routingKey}; + Object[] grantArgs = new Object[]{exchange.getNameShortString(), _routingKey}; assertEquals(Result.DENIED, _perms.authorise(Permission.PUBLISH, authArgs)); _perms.grant(Permission.PUBLISH, grantArgs); -- cgit v1.2.1 From 8b7d8990366ca25e267d7b93a95cae766af94323 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Fri, 4 Jun 2010 09:39:47 +0000 Subject: QPID-2632 : Applied patch from Andrew Kennedy. To convert RST and PPT to QTCs not IBBCs git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@951341 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/security/access/PrincipalPermissionsTest.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java index 055dee06a0..65ab12a095 100644 --- a/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java +++ b/qpid/java/broker-plugins/simple-xml/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java @@ -18,24 +18,16 @@ * under the License. * */ - package org.apache.qpid.server.security.access; -import junit.framework.TestCase; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.server.exchange.DirectExchange; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.registry.ApplicationRegistry; 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.server.virtualhost.VirtualHost; -import org.apache.qpid.server.util.InternalBrokerBaseCase; +import org.apache.qpid.test.utils.QpidTestCase; -public class PrincipalPermissionsTest extends InternalBrokerBaseCase +public class PrincipalPermissionsTest extends QpidTestCase { private String _user = "user"; private PrincipalPermissions _perms; @@ -120,10 +112,8 @@ public class PrincipalPermissionsTest extends InternalBrokerBaseCase public void testPublish() throws AMQException { - DirectExchange exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, false, 1, _autoDelete); - String[] authArgs = new String[]{_exchangeName.asString(), _routingKey.asString()}; - Object[] grantArgs = new Object[]{exchange.getNameShortString(), _routingKey}; + Object[] grantArgs = new Object[]{_exchangeName, _routingKey}; assertEquals(Result.DENIED, _perms.authorise(Permission.PUBLISH, authArgs)); _perms.grant(Permission.PUBLISH, grantArgs); -- cgit v1.2.1 From ed9058f6a2584b9e4aa29caed99410ce71dbe814 Mon Sep 17 00:00:00 2001 From: Martin Ritchie Date: Mon, 14 Jun 2010 12:36:56 +0000 Subject: QPID-2638 : Add initial support for Topics section in configuration file. Added getQueueConfiguration(AMQQueue) which will return a new configuration for the given queue reflecting its binding status. This will allow the queue to be reconfigured during the binding process. Full Docs on this approach to appear on wiki. AMQQueue.configure and getConfiguration() have been updated to use ConfigurationPlugin rather than QueueConfiguration, The queue may be configured by a TopicConfiguration now. Update SlowConsumerTest to be GlobalQueuesTest and add a GlobalTopicsTest to match, where the config is added to the queues or topics section respectively git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@954433 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/security/access/plugins/SimpleXML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index 1bf8761978..c9a476c5f2 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -52,7 +52,7 @@ public class SimpleXML extends AbstractPlugin { public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException { - SimpleXMLConfiguration configuration = config.getConfiguration(SimpleXMLConfiguration.class); + SimpleXMLConfiguration configuration = config.getConfiguration(SimpleXMLConfiguration.class.getName()); // If there is no configuration for this plugin then don't load it. if (configuration == null) -- cgit v1.2.1 From 8c90c1b263f429d49069cdf96e61dc25c1d80c5a Mon Sep 17 00:00:00 2001 From: Robert Gemmell Date: Thu, 17 Jun 2010 16:04:11 +0000 Subject: QPID-2665: Remove BROKER from object types for plugins Applied patch from Andrew Kennedy git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@955654 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/qpid/server/security/access/plugins/SimpleXML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/java/broker-plugins/simple-xml/src') diff --git a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java index c9a476c5f2..ab43653122 100644 --- a/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java +++ b/qpid/java/broker-plugins/simple-xml/src/main/java/org/apache/qpid/server/security/access/plugins/SimpleXML.java @@ -371,7 +371,7 @@ public class SimpleXML extends AbstractPlugin } // Authorise object access - if (objectType == ObjectType.BROKER || objectType == ObjectType.VIRTUALHOST) + if (objectType == ObjectType.VIRTUALHOST) { return principalPermissions.authorise(Permission.ACCESS); } -- cgit v1.2.1