diff options
Diffstat (limited to 'java/broker/src/main/java')
73 files changed, 2240 insertions, 1826 deletions
diff --git a/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java index 8bb1a6b9fa..7e999a720b 100644 --- a/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java +++ b/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java @@ -1063,7 +1063,14 @@ public class QMFService implements ConfigStore.ConfigEventListener, Closeable public BrokerSchema.QueueClass.PurgeMethodResponseCommand purge(final BrokerSchema.QueueClass.PurgeMethodResponseCommandFactory factory, final Long request) { - _obj.purge(request); + try + { + _obj.purge(request); + } catch (AMQException e) + { + // TODO + throw new RuntimeException(); + } return factory.createResponseCommand(); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java index b2e43b4f0d..811e45f4ae 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ b/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java @@ -1,5 +1,4 @@ /* - * * 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 @@ -16,24 +15,6 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed 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; @@ -189,8 +170,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param type * @param durable * @throws JMException + * @throws MBeanException */ - public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException, MBeanException { CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); try @@ -216,7 +198,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex, "Error in creating exchange " + exchangeName); + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error in creating exchange " + exchangeName); } finally { @@ -229,8 +212,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * * @param exchangeName * @throws JMException + * @throws MBeanException */ - public void unregisterExchange(String exchangeName) throws JMException + public void unregisterExchange(String exchangeName) throws JMException, MBeanException { // TODO // Check if the exchange is in use. @@ -244,7 +228,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(ex, "Error in unregistering exchange " + exchangeName); + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error in unregistering exchange " + exchangeName); } finally { @@ -260,8 +245,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param durable * @param owner * @throws JMException + * @throws MBeanException */ - public void createNewQueue(String queueName, String owner, boolean durable) throws JMException + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue != null) @@ -278,8 +264,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr ownerShortString = new AMQShortString(owner); } - queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, - getVirtualHost(), null); + queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString(queueName), durable, ownerShortString, false, false, getVirtualHost(), null); if (queue.isDurable() && !queue.isAutoDelete()) { _durableConfig.createQueue(queue); @@ -289,8 +274,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); + JMException jme = new JMException(ex.toString()); throw new MBeanException(jme, "Error in creating queue " + queueName); } finally @@ -309,13 +293,14 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * * @param queueName * @throws JMException + * @throws MBeanException */ - public void deleteQueue(String queueName) throws JMException + public void deleteQueue(String queueName) throws JMException, MBeanException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue == null) { - throw new JMException("The Queue " + queueName + " is not a registerd queue."); + throw new JMException("The Queue " + queueName + " is not a registered queue."); } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); @@ -329,8 +314,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - JMException jme = new JMException(ex.getMessage()); - jme.initCause(ex); + JMException jme = new JMException(ex.toString()); throw new MBeanException(jme, "Error in deleting queue " + queueName); } finally @@ -339,14 +323,16 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } } + @Override public ManagedObject getParentObject() { return _virtualHostMBean; } // This will have a single instance for a virtual host, so not having the name property in the ObjectName + @Override public ObjectName getObjectName() throws MalformedObjectNameException { return getObjectNameForSingleInstanceMBean(); } -} // End of MBean class +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 7d0163510a..8a0e49f537 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -23,6 +23,7 @@ package org.apache.qpid.server; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -244,9 +245,12 @@ public class AMQChannel implements SessionConfig, AMQSessionModel return _channelId; } - public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQException + public void setPublishFrame(MessagePublishInfo info, final Exchange e) throws AMQSecurityException { - + if (!getVirtualHost().getSecurityManager().authorisePublish(info.isImmediate(), info.getRoutingKey().asString(), e.getName())) + { + throw new AMQSecurityException("Permission denied: " + e.getName()); + } _currentMessage = new IncomingMessage(info); _currentMessage.setExchange(e); } @@ -421,7 +425,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel { throw new AMQException("Consumer already exists with same tag: " + tag); } - + Subscription subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(_channelId, _session, tag, acks, filters, noLocal, _creditManager); diff --git a/java/broker/src/main/java/org/apache/qpid/server/Main.java b/java/broker/src/main/java/org/apache/qpid/server/Main.java index 90afd2e4ac..d52267ad57 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -25,12 +25,12 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.Properties; -import java.util.Set; +import java.util.Arrays; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; -import java.util.Collection; -import java.util.Arrays; +import java.util.Properties; +import java.util.Set; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -42,8 +42,6 @@ import org.apache.commons.cli.PosixParser; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; -import org.apache.qpid.transport.network.ConnectionBinding; -import org.apache.qpid.transport.*; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -56,21 +54,18 @@ import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AMQProtocolEngineFactory; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; +import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.transport.ServerConnection; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.ssl.SSLContextFactory; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.network.mina.MINANetworkDriver; -import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory.VERSION; /** * Main entry point for AMQPD. * */ -@SuppressWarnings({"AccessStaticViaInstance"}) public class Main { private static Logger _logger; @@ -83,7 +78,6 @@ public class Main private static final int IPV4_ADDRESS_LENGTH = 4; private static final char IPV4_LITERAL_SEPARATOR = '.'; - private static final Collection<VERSION> ALL_VERSIONS = Arrays.asList(VERSION.values()); protected static class InitException extends Exception { @@ -123,6 +117,7 @@ public class Main } } + @SuppressWarnings("static-access") protected void setOptions(Options options) { Option help = new Option("h", "help", false, "print this message"); @@ -403,7 +398,7 @@ public class Main NetworkDriver driver = new MINANetworkDriver(); - Set<VERSION> supported = new HashSet<VERSION>(ALL_VERSIONS); + Set<VERSION> supported = EnumSet.allOf(VERSION.class); if(exclude_0_10.contains(port)) { diff --git a/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java b/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java index 5423f02107..59626a7b13 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java +++ b/java/broker/src/main/java/org/apache/qpid/server/binding/BindingFactory.java @@ -20,7 +20,12 @@ */ package org.apache.qpid.server.binding; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.configuration.BindingConfig; @@ -35,13 +40,8 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class BindingFactory { - private final VirtualHost _virtualHost; private final DurableConfigurationStore.Source _configSource; private final Exchange _defaultExchange; @@ -51,14 +51,14 @@ public class BindingFactory public BindingFactory(final VirtualHost vhost) { - this(vhost,vhost.getExchangeRegistry().getDefaultExchange()); + this(vhost, vhost.getExchangeRegistry().getDefaultExchange()); } public BindingFactory(final DurableConfigurationStore.Source configSource, final Exchange defaultExchange) { _configSource = configSource; _defaultExchange = defaultExchange; - if(configSource instanceof VirtualHost) + if (configSource instanceof VirtualHost) { _virtualHost = (VirtualHost) configSource; } @@ -83,7 +83,7 @@ public class BindingFactory private BindingImpl(String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> arguments) { - super(queue.getVirtualHost().getConfigStore().createId(),bindingKey, queue, exchange, arguments); + super(queue.getVirtualHost().getConfigStore().createId(), bindingKey, queue, exchange, arguments); _logSubject = new BindingLogSubject(bindingKey,exchange,queue); } @@ -94,7 +94,7 @@ public class BindingFactory removeBinding(this); } - public void onClose(final Exchange exchange) + public void onClose(final Exchange exchange) throws AMQSecurityException { removeBinding(this); } @@ -138,7 +138,7 @@ public class BindingFactory - public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) + public boolean addBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) throws AMQSecurityException { return makeBinding(bindingKey, queue, exchange, arguments, false, false); } @@ -147,37 +147,43 @@ public class BindingFactory public boolean replaceBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, - final Map<String, Object> arguments) + final Map<String, Object> arguments) throws AMQSecurityException { return makeBinding(bindingKey, queue, exchange, arguments, false, true); } - private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments, boolean restore, boolean force) + private boolean makeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments, boolean restore, boolean force) throws AMQSecurityException { assert queue != null; - if(bindingKey == null) + if (bindingKey == null) { bindingKey = ""; } - if(exchange == null) + if (exchange == null) { exchange = _defaultExchange; } - if(arguments == null) + if (arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } - + + //Perform ACLs + if (!getVirtualHost().getSecurityManager().authoriseBind(exchange, queue, new AMQShortString(bindingKey))) + { + throw new AMQSecurityException("Permission denied: binding " + bindingKey); + } + BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); BindingImpl existingMapping = _bindings.putIfAbsent(b,b); - if(existingMapping == null || force) + if (existingMapping == null || force) { - if(existingMapping != null) + if (existingMapping != null) { removeBinding(existingMapping); } - if(b.isDurable() && !restore) + if (b.isDurable() && !restore) { try { @@ -185,7 +191,7 @@ public class BindingFactory } catch (AMQException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); // FIXME } } @@ -201,8 +207,6 @@ public class BindingFactory { return false; } - - } private ConfigStore getConfigStore() @@ -210,43 +214,49 @@ public class BindingFactory return getVirtualHost().getConfigStore(); } - public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> argumentMap) + public void restoreBinding(final String bindingKey, final AMQQueue queue, final Exchange exchange, final Map<String, Object> argumentMap) throws AMQSecurityException { makeBinding(bindingKey,queue,exchange,argumentMap,true, false); } - public void removeBinding(final Binding b) + public void removeBinding(final Binding b) throws AMQSecurityException { removeBinding(b.getBindingKey(), b.getQueue(), b.getExchange(), b.getArguments()); } - public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) + public Binding removeBinding(String bindingKey, AMQQueue queue, Exchange exchange, Map<String, Object> arguments) throws AMQSecurityException { assert queue != null; - if(bindingKey == null) + if (bindingKey == null) { bindingKey = ""; } - if(exchange == null) + if (exchange == null) { exchange = _defaultExchange; } - if(arguments == null) + if (arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } + // Check access + if (!getVirtualHost().getSecurityManager().authoriseUnbind(exchange, new AMQShortString(bindingKey), queue)) + { + throw new AMQSecurityException("Permission denied: binding " + bindingKey); + } + BindingImpl b = _bindings.remove(new BindingImpl(bindingKey,queue,exchange,arguments)); - if(b != null) + if (b != null) { exchange.removeBinding(b); queue.removeBinding(b); exchange.removeCloseTask(b); queue.removeQueueDeleteTask(b); - if(b.isDurable()) + if (b.isDurable()) { try { @@ -257,12 +267,11 @@ public class BindingFactory } catch (AMQException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + throw new RuntimeException(e); // FIXME } } b.logDestruction(); getConfigStore().removeConfiguredObject(b); - } return b; @@ -281,7 +290,7 @@ public class BindingFactory } if(arguments == null) { - arguments = Collections.EMPTY_MAP; + arguments = Collections.emptyMap(); } BindingImpl b = new BindingImpl(bindingKey,queue,exchange,arguments); diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 7fef4558c8..f62022922a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; public class QueueConfiguration extends ConfigurationPlugin @@ -109,7 +110,7 @@ public class QueueConfiguration extends ConfigurationPlugin public String getExchange() { - return getStringValue("exchange", null); + return getStringValue("exchange", ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString()); } public List getRoutingKeys() diff --git a/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 9f1a4c52f2..f8fc27e86a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -20,6 +20,15 @@ package org.apache.qpid.server.configuration; +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; + import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -27,26 +36,17 @@ import org.apache.commons.configuration.ConfigurationFactory; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.XMLConfiguration; +import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.transport.NetworkDriverConfiguration; import sun.misc.Signal; import sun.misc.SignalHandler; -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; - public class ServerConfiguration extends ConfigurationPlugin implements SignalHandler { protected static final Logger _logger = Logger.getLogger(ServerConfiguration.class); @@ -63,17 +63,22 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public static final int DEFAULT_SSL_PORT = 8672; public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public static final int DEFAULT_JMXPORT = 8999; + + public static final String QPID_HOME = "QPID_HOME"; + public static final String QPID_WORK = "QPID_WORK"; + public static final String LIB_DIR = "lib"; + public static final String PLUGIN_DIR = "plugins"; + public static final String CACHE_DIR = "cache"; private Map<String, VirtualHostConfiguration> _virtualHosts = new HashMap<String, VirtualHostConfiguration>(); private File _configFile; private File _vhostsFile; - private Logger _log = LoggerFactory.getLogger(this.getClass()); + private Logger _log = Logger.getLogger(this.getClass()); private ConfigurationManagementMBean _mbean; - // Map of environment variables to config items private static final Map<String, String> envVarMap = new HashMap<String, String>(); @@ -142,6 +147,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa } catch (IllegalArgumentException e) { + _logger.error("Signal HUP not supported for OS: " + System.getProperty("os.name")); // We're on something that doesn't handle SIGHUP, how sad, Windows. } } @@ -192,7 +198,7 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa public String[] getElementsProcessed() { - return new String[]{""}; + return new String[] { "" }; } @Override @@ -308,7 +314,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa */ public Locale getLocale() { - String localeString = getStringValue(ADVANCED_LOCALE); // Expecting locale of format langauge_country_variant @@ -432,10 +437,15 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa _logger.warn(SECURITY_CONFIG_RELOADED); } } - + public String getQpidWork() { - return System.getProperty("QPID_WORK", System.getProperty("java.io.tmpdir")); + return System.getProperty(QPID_WORK, System.getProperty("java.io.tmpdir")); + } + + public String getQpidHome() + { + return System.getProperty(QPID_HOME); } public void setJMXManagementPort(int mport) @@ -467,11 +477,16 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa { return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); } - + public String getPluginDirectory() { return getStringValue("plugin-directory"); } + + public String getCacheDirectory() + { + return getStringValue("cache-directory"); + } public VirtualHostConfiguration getVirtualHostConfig(String name) { diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java index ece8bc90fe..0dca91b7be 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.exchange; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.management.ManagedObjectRegistry; @@ -32,6 +34,7 @@ import org.apache.qpid.management.common.mbeans.ManagedExchange; import org.apache.qpid.framing.AMQShortString; import javax.management.openmbean.*; +import javax.management.MBeanException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.MalformedObjectNameException; @@ -133,7 +136,15 @@ public abstract class AbstractExchangeMBean<T extends AbstractExchange> extends } CurrentActor.set(new ManagementActor(_logActor.getRootMessageLogger())); - vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + try + { + vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); + } + catch (AMQException ex) + { + JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error creating new binding " + binding); + } CurrentActor.remove(); } -} // End of MBean class +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java index 9be8bddd28..7837a9bc38 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeFactory.java @@ -26,9 +26,12 @@ import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; +import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.AMQUnknownExchangeType; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.qmf.ManagementExchange; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -79,27 +82,26 @@ public class DefaultExchangeFactory implements ExchangeFactory public Exchange createExchange(String exchange, String type, boolean durable, boolean autoDelete) throws AMQException { - ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(new AMQShortString(type)); - if (exchType == null) - { - - throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); - } - Exchange e = exchType.newInstance(_host, (new AMQShortString(exchange)).intern(), durable, 0, autoDelete); - return e; - + return createExchange(new AMQShortString(exchange), new AMQShortString(type), durable, autoDelete, 0); } public Exchange createExchange(AMQShortString exchange, AMQShortString type, boolean durable, boolean autoDelete, int ticket) throws AMQException { + // Check access + if (!_host.getSecurityManager().authoriseCreateExchange(autoDelete, durable, exchange, null, null, null, type)) + { + String description = "Permission denied: exchange-name '" + exchange.asString() + "'"; + throw new AMQSecurityException(description); + } + ExchangeType<? extends Exchange> exchType = _exchangeClassMap.get(type); if (exchType == null) { - throw new AMQUnknownExchangeType("Unknown exchange type: " + type,null); } + Exchange e = exchType.newInstance(_host, exchange, durable, ticket, autoDelete); return e; } diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index 84444450c9..0e7459498a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -20,18 +20,18 @@ */ package org.apache.qpid.server.exchange; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.ExchangeInitialiser; import org.apache.qpid.server.queue.IncomingMessage; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - public class DefaultExchangeRegistry implements ExchangeRegistry { private static final Logger _log = Logger.getLogger(DefaultExchangeRegistry.class); @@ -87,7 +87,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry public void unregisterExchange(AMQShortString name, boolean inUse) throws AMQException { + // Check access + if (!_host.getSecurityManager().authoriseDelete(_exchangeMap.get(name))) + { + throw new AMQSecurityException(); + } + // TODO: check inUse argument + Exchange e = _exchangeMap.remove(name); _exchangeMapStr.remove(name.toString()); if (e != null) diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java index 8a31b1bab1..13fe767d3f 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.exchange; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; @@ -138,6 +139,6 @@ public interface Exchange extends ExchangeReferrer, ExchangeConfig public static interface Task { - public void onClose(Exchange exchange); + public void onClose(Exchange exchange) throws AMQSecurityException; } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java index aa4cc1ec24..92795487e4 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java +++ b/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeFactory.java @@ -22,8 +22,6 @@ package org.apache.qpid.server.exchange; import java.util.Collection; -import org.apache.commons.configuration.Configuration; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.configuration.VirtualHostConfiguration; diff --git a/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java index ae578eb196..a4974c75ff 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java +++ b/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java @@ -674,13 +674,22 @@ public class Bridge implements BridgeConfig options.put("qpid.trace.exclude", _link.getFederationTag()); options.put("qpid.trace.id",_link.getRemoteFederationTag()); - _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, + try + { + _queue = AMQQueueFactory.createAMQQueueImpl(_tmpQueueName, isDurable(), _link.getFederationTag(), false, false, - getVirtualHost(), options); - + getVirtualHost(), + options); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } + FlowCreditManager_0_10 creditManager = new WindowCreditManager(0xFFFFFFFF,getMessageWindowSize()); Subscription_0_10 sub = new Subscription_0_10((ServerSession)session, @@ -695,14 +704,13 @@ public class Bridge implements BridgeConfig try { _queue.registerSubscription(sub, true); + getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.<String, Object>emptyMap()); } catch (AMQException e) { // TODO throw new RuntimeException(e); } - - getVirtualHost().getBindingFactory().addBinding(_key, _queue, exchange, Collections.EMPTY_MAP); } public void close() diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java index 50019090d9..a5999711bc 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java @@ -51,9 +51,6 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic { AMQProtocolSession protocolConnection = stateManager.getProtocolSession(); - - - AMQChannel channel = protocolConnection.getChannel(channelId); VirtualHost vHost = protocolConnection.getVirtualHost(); @@ -93,17 +90,9 @@ public class BasicConsumeMethodHandler implements StateAwareMethodListener<Basic } else { - final AMQShortString consumerTagName; - // Check authz - if (!vHost.getAccessManager().authoriseConsume(protocolConnection, - body.getExclusive(), body.getNoAck(), - body.getNoLocal(), body.getNowait(), queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && !queue.isDurable()) + if (queue.isExclusive() && !queue.isDurable()) { AMQSessionModel session = queue.getExclusiveOwningSession(); if (session == null || session.getConnectionModel() != protocolConnection) diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java index 2ab0b04fb9..83ca526578 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicGetMethodHandler.java @@ -92,13 +92,7 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB } else { - - //Perform ACLs - if (!vHost.getAccessManager().authoriseConsume(protocolConnection, body.getNoAck(), queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive()) + if (queue.isExclusive()) { AMQSessionModel session = queue.getExclusiveOwningSession(); if (session == null || session.getConnectionModel() != protocolConnection) diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java index a7d3ad6217..8f23b1c4d4 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/BasicPublishMethodHandler.java @@ -23,14 +23,13 @@ package org.apache.qpid.server.handler; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.BasicPublishBody; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicPublishBody; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -59,18 +58,17 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic _logger.debug("Publish received on channel " + channelId); } - AMQShortString exchange = body.getExchange(); + AMQShortString exchangeName = body.getExchange(); // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? - if (exchange == null) + if (exchangeName == null) { - exchange = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; - + exchangeName = ExchangeDefaults.DEFAULT_EXCHANGE_NAME; } VirtualHost vHost = session.getVirtualHost(); - Exchange e = vHost.getExchangeRegistry().getExchange(exchange); + Exchange exch = vHost.getExchangeRegistry().getExchange(exchangeName); // if the exchange does not exist we raise a channel exception - if (e == null) + if (exch == null) { throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name"); } @@ -86,17 +84,9 @@ public class BasicPublishMethodHandler implements StateAwareMethodListener<Basic throw body.getChannelNotFoundException(channelId); } - //Access Control - if (!vHost.getAccessManager().authorisePublish(session, - body.getImmediate(), body.getMandatory(), - body.getRoutingKey(), e)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - MessagePublishInfo info = session.getMethodRegistry().getProtocolVersionMethodConverter().convertToInfo(body); - info.setExchange(exchange); - channel.setPublishFrame(info, e); + info.setExchange(exchangeName); + channel.setPublishFrame(info, exch); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java index f5c2b93f46..6d874ee971 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelOpenHandler.java @@ -20,15 +20,19 @@ */ package org.apache.qpid.server.handler; -import java.util.UUID; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.UUID; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; +import org.apache.qpid.framing.ChannelOpenBody; +import org.apache.qpid.framing.ChannelOpenOkBody; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; +import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; @@ -39,6 +43,8 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenBody> { + private static final Logger _logger = Logger.getLogger(ChannelOpenHandler.class); + private static ChannelOpenHandler _instance = new ChannelOpenHandler(); public static ChannelOpenHandler getInstance() @@ -54,19 +60,16 @@ public class ChannelOpenHandler implements StateAwareMethodListener<ChannelOpenB { AMQProtocolSession session = stateManager.getProtocolSession(); VirtualHost virtualHost = session.getVirtualHost(); - // Protect the broker against out of order frame request. if (virtualHost == null) { throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null); } + _logger.info("Connecting to: " + virtualHost.getName()); - final AMQChannel channel = new AMQChannel(session,channelId, - virtualHost.getMessageStore()); - + final AMQChannel channel = new AMQChannel(session,channelId, virtualHost.getMessageStore()); - session.addChannel(channel); ChannelOpenOkBody response; diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index b5194084f2..76d1e5378f 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -20,18 +20,18 @@ */ package org.apache.qpid.server.handler; +import org.apache.log4j.Logger; import org.apache.qpid.AMQException; -import org.apache.qpid.framing.*; -import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; -import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ConnectionOpenBody; +import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.log4j.Logger; public class ConnectionOpenMethodHandler implements StateAwareMethodListener<ConnectionOpenBody> { @@ -57,7 +57,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con { AMQProtocolSession session = stateManager.getProtocolSession(); - //ignore leading '/' String virtualHostName; if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/') @@ -77,14 +76,15 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con } else { - session.setVirtualHost(virtualHost); - - //Perform ACL - if (!virtualHost.getAccessManager().authoriseConnect(session, virtualHost)) + // Check virtualhost access + if (!virtualHost.getSecurityManager().accessVirtualhost(virtualHostName, session.getRemoteAddress().toString())) { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied: '" + virtualHost.getName() + "'"); } + session.setVirtualHost(virtualHost); + _logger.error(session.getPrincipal().getName()); + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts if (session.getContextKey() == null) { @@ -97,8 +97,6 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con stateManager.changeState(AMQState.CONNECTION_OPEN); session.writeFrame(responseBody.generateFrame(channelId)); - - } } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index a2a6faf21b..cda8cff25a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -97,7 +97,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); - disposeSaslServer(session); + disposeSaslServer(session); break; case CONTINUE: stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 6698ae888a..6512ff1a14 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -60,11 +60,11 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< public void methodReceived(AMQStateManager stateManager, ConnectionStartOkBody body, int channelId) throws AMQException { AMQProtocolSession session = stateManager.getProtocolSession(); - + _logger.info("SASL Mechanism selected: " + body.getMechanism()); _logger.info("Locale selected: " + body.getLocale()); - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); SaslServer ss = null; try @@ -73,8 +73,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< if (ss == null) { - throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism() - ); + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server:" + body.getMechanism()); } session.setSaslServer(ss); diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java index 7cfd1fc121..98a0d33487 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeclareHandler.java @@ -45,8 +45,6 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange return _instance; } - - private ExchangeDeclareHandler() { } @@ -58,28 +56,15 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); - if (!body.getPassive()) - { - // Perform ACL if request is not passive - if (!virtualHost.getAccessManager().authoriseCreateExchange(session, body.getAutoDelete(), - body.getDurable(), body.getExchange(), body.getInternal(), body.getNowait(), body.getPassive(), - body.getType())) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - - } - if (_logger.isDebugEnabled()) { _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + body.getExchange()); } + synchronized(exchangeRegistry) { Exchange exchange = exchangeRegistry.getExchange(body.getExchange()); - - if (exchange == null) { if(body.getPassive() && ((body.getType() == null) || body.getType().length() ==0)) @@ -90,7 +75,6 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange { try { - exchange = exchangeFactory.createExchange(body.getExchange() == null ? null : body.getExchange().intern(), body.getType() == null ? null : body.getType().intern(), body.getDurable(), @@ -113,14 +97,12 @@ public class ExchangeDeclareHandler implements StateAwareMethodListener<Exchange throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + body.getExchange() + " of type " + exchange.getTypeShortString() + " to " + body.getType() +".",body.getClazz(), body.getMethod(),body.getMajor(),body.getMinor(),null); } - } if(!body.getNowait()) { MethodRegistry methodRegistry = session.getMethodRegistry(); AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody(); session.writeFrame(responseBody.generateFrame(channelId)); - } } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java index 8dbd457cc9..586aaf9336 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeDeleteHandler.java @@ -27,7 +27,6 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.exchange.ExchangeInUseException; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.Permission; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -51,13 +50,6 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD VirtualHost virtualHost = session.getVirtualHost(); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(session, - exchangeRegistry.getExchange(body.getExchange()))) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - try { if(exchangeRegistry.getExchange(body.getExchange()) == null) @@ -75,6 +67,5 @@ public class ExchangeDeleteHandler implements StateAwareMethodListener<ExchangeD throw body.getChannelException(AMQConstant.IN_USE, "Exchange in use"); // TODO: sort out consistent channel close mechanism that does all clean up etc. } - } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java index 594edb090c..0eb69e4b16 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueBindHandler.java @@ -65,7 +65,6 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody> ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); - final AMQQueue queue; final AMQShortString routingKey; @@ -113,14 +112,7 @@ public class QueueBindHandler implements StateAwareMethodListener<QueueBindBody> try { - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseBind(protocolConnection, exch, - queue, routingKey)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && !queue.isDurable()) + if (queue.isExclusive() && !queue.isDurable()) { AMQSessionModel session = queue.getExclusiveOwningSession(); if (session == null || session.getConnectionModel() != protocolConnection) diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 4f7d275e71..8939cfa334 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -69,21 +69,9 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar QueueRegistry queueRegistry = virtualHost.getQueueRegistry(); DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); - - if (!body.getPassive()) - { - // Perform ACL if request is not passive - if (!virtualHost.getAccessManager().authoriseCreateQueue(protocolConnection, body.getAutoDelete(), body.getDurable(), - body.getExclusive(), body.getNowait(), body.getPassive(), body.getQueue())) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - } - final AMQShortString queueName; // if we aren't given a queue name, we create one which we return to the client - if ((body.getQueue() == null) || (body.getQueue().length() == 0)) { queueName = createName(); @@ -94,11 +82,11 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar } AMQQueue queue; + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? synchronized (queueRegistry) { - queue = queueRegistry.getQueue(queueName); AMQSessionModel owningSession = null; @@ -110,7 +98,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar if (queue == null) { - if (body.getPassive()) { String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; @@ -129,9 +116,8 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar queue.setDeleteOnNoConsumers(true); } queueRegistry.registerQueue(queue); - if(body.getExclusive()) + if (body.getExclusive()) { - queue.setExclusiveOwningSession(protocolConnection.getChannel(channelId)); queue.setPrincipalHolder(protocolConnection); @@ -153,7 +139,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar } }); } - } if (autoRegister) { @@ -239,7 +224,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), body.getExclusive(),virtualHost, body.getArguments()); - if (body.getExclusive() && !body.getDurable()) { final AMQProtocolSession.Task deleteQueueTask = @@ -263,7 +247,7 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar session.removeSessionCloseTask(deleteQueueTask); } }); - }// if exclusive and not durable + } return queue; } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java index 4a1940ee01..da52268e52 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java @@ -99,25 +99,18 @@ public class QueueDeleteHandler implements StateAwareMethodListener<QueueDeleteB { // TODO - Error code throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used."); - } else { - AMQSessionModel session = queue.getExclusiveOwningSession(); - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(protocolConnection, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && !queue.isDurable() && (session == null || session.getConnectionModel() != protocolConnection)) + if (queue.isExclusive() && !queue.isDurable() && (session == null || session.getConnectionModel() != protocolConnection)) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, "Queue " + queue.getNameShortString() + " is exclusive, but not created on this Connection."); } + int purged = queue.delete(); - if (queue.isDurable()) { store.removeQueue(queue); diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java index a465c5a20f..759eec0129 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java @@ -101,12 +101,7 @@ public class QueuePurgeHandler implements StateAwareMethodListener<QueuePurgeBod { AMQSessionModel session = queue.getExclusiveOwningSession(); - //Perform ACLs - if (!virtualHost.getAccessManager().authorisePurge(protocolConnection, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - else if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection)) + if (queue.isExclusive() && (session == null || session.getConnectionModel() != protocolConnection)) { throw body.getConnectionException(AMQConstant.NOT_ALLOWED, "Queue is exclusive, but not created on this Connection."); diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java index 29c30de9cc..8391a4b184 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java @@ -20,24 +20,23 @@ package org.apache.qpid.server.handler; * */ - import org.apache.log4j.Logger; - -import org.apache.qpid.framing.*; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.QueueUnbindBody; import org.apache.qpid.framing.amqp_0_9.MethodRegistry_0_9; -import org.apache.qpid.server.state.StateAwareMethodListener; -import org.apache.qpid.server.state.AMQStateManager; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.security.access.Permission; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQInvalidRoutingKeyException; -import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.state.AMQStateManager; +import org.apache.qpid.server.state.StateAwareMethodListener; +import org.apache.qpid.server.virtualhost.VirtualHost; public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindBody> { @@ -100,12 +99,6 @@ public class QueueUnbindHandler implements StateAwareMethodListener<QueueUnbindB throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist."); } - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseUnbind(session, exch, routingKey, queue)) - { - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, "Permission denied"); - } - if(virtualHost.getBindingFactory().getBinding(String.valueOf(routingKey), queue, exch, FieldTable.convertToMap(body.getArguments())) == null) { throw body.getChannelException(AMQConstant.NOT_FOUND,"No such binding"); diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 0ee5763d91..7e7ac94d06 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -20,34 +20,36 @@ */ package org.apache.qpid.server.management; -import org.apache.qpid.management.common.mbeans.ConfigurationManagement; -import org.apache.qpid.management.common.mbeans.LoggingManagement; -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; -import org.apache.log4j.Logger; - -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.JMXPrincipal; -import javax.management.remote.JMXConnectionNotification; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.JMException; -import javax.management.NotificationListener; -import javax.management.Notification; -import javax.security.auth.Subject; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; -import java.security.AccessControlContext; -import java.util.HashSet; -import java.util.Set; import java.util.Properties; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.JMException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.MBeanServerForwarder; +import javax.security.auth.Subject; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.security.access.Operation; /** * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements @@ -65,18 +67,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati private MBeanServer _mbs; private static Properties _userRoles = new Properties(); private static ManagementActor _logActor; - - private static HashSet<String> _adminOnlyMethods = new HashSet<String>(); - { - _adminOnlyMethods.add(UserManagement.TYPE); - _adminOnlyMethods.add(LoggingManagement.TYPE); - _adminOnlyMethods.add(ConfigurationManagement.TYPE); - } public static MBeanServerForwarder newProxyInstance() { final InvocationHandler handler = new MBeanInvocationHandlerImpl(); - final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class }; _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); @@ -87,7 +82,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - final String methodName = method.getName(); + final String methodName = getMethodName(method, args); if (methodName.equals("getMBeanServer")) { @@ -112,145 +107,165 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati AccessControlContext acc = AccessController.getContext(); Subject subject = Subject.getSubject(acc); - // Allow operations performed locally on behalf of the connector server itself - if (subject == null) - { - return method.invoke(_mbs, args); - } - - if (args == null || DELEGATE.equals(args[0])) - { - return method.invoke(_mbs, args); - } - - // Restrict access to "createMBean" and "unregisterMBean" to any user - if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) - { - _logger.debug("User trying to create or unregister an MBean"); - throw new SecurityException("Access denied"); - } - - // Retrieve JMXPrincipal from Subject - Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - throw new SecurityException("Access denied"); - } - - Principal principal = principals.iterator().next(); - String identity = principal.getName(); - - if (isAdminMethod(args)) + try { - if (isAdmin(identity)) + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(_mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) { return method.invoke(_mbs, args); } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + _logger.debug("User trying to create or unregister an MBean"); + throw new SecurityException("Access denied: " + methodName); + } + + // Allow querying available object names + if (methodName.equals("queryNames")) + { + return method.invoke(_mbs, args); + } + + // Retrieve JMXPrincipal from Subject + Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied: no principal"); + } + + // Save the principal + Principal principal = principals.iterator().next(); + SecurityManager.setThreadPrincipal(principal); + + // Get the component, type and impact, which may be null + String type = getType(method, args); + String vhost = getVirtualHost(method, args); + int impact = getImpact(method, args); + + // Get the security manager for the virtual host (if set) + SecurityManager security; + if (vhost == null) + { + security = ApplicationRegistry.getInstance().getSecurityManager(); + } else { - throw new SecurityException("Access denied"); + security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager(); } + + if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO) + { + // Check for read-only method invocation permission + if (!security.authoriseMethod(Operation.ACCESS, type, methodName)) + { + throw new SecurityException("Permission denied: Access " + methodName); + } + } + else if (isUpdateMethod(methodName)) + { + // Check for setting properties permission + if (!security.authoriseMethod(Operation.UPDATE, type, methodName)) + { + throw new SecurityException("Permission denied: Update " + methodName); + } + } + else + { + // Check for invoking/executing method action/operation permission + if (!security.authoriseMethod(Operation.EXECUTE, type, methodName)) + { + throw new SecurityException("Permission denied: Execute " + methodName); + } + } + + // Actually invoke the method + return method.invoke(_mbs, args); } - - // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAllowedToModify(identity)) - { - return method.invoke(_mbs, args); - } - - // These users can only call "getAttribute" on the MBeanServerDelegate MBean - // Here we can add other fine grained permissions like specific method for a particular mbean - if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + catch (InvocationTargetException e) { - return method.invoke(_mbs, args); + throw e.getTargetException(); } + } - throw new SecurityException("Access denied"); + private String getType(Method method, Object[] args) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + String type = object.getKeyProperty("type"); + + return type; + } + return null; } - private boolean isAdminMethod(Object[] args) - { + private String getVirtualHost(Method method, Object[] args) + { if (args[0] instanceof ObjectName) { ObjectName object = (ObjectName) args[0]; + String vhost = object.getKeyProperty("VirtualHost"); - return _adminOnlyMethods.contains(object.getKeyProperty("type")); - } - return false; - } - - // Initialises the user roles - public static void setAccessRights(Properties accessRights) - { - _userRoles = accessRights; - } - - private boolean isAdmin(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName))) - { - return true; + return vhost; } - return false; + return null; } - - private boolean isAllowedToModify(String userName) + + private String getMethodName(Method method, Object[] args) { - if (ADMIN.equals(_userRoles.getProperty(userName)) - || READWRITE.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } + String methodName = method.getName(); - private boolean isReadOnlyUser(String userName) - { - if (READONLY.equals(_userRoles.getProperty(userName))) + // if arguments are set, try and work out real method name + if (args != null && args.length >= 1 && args[0] instanceof ObjectName) { - return true; + if (methodName.equals("getAttribute")) + { + methodName = "get" + (String) args[1]; + } + else if (methodName.equals("setAttribute")) + { + methodName = "set" + ((Attribute) args[1]).getName(); + } + else if (methodName.equals("invoke")) + { + methodName = (String) args[1]; + } } - return false; + + return methodName; } - private boolean isReadOnlyMethod(Method method, Object[] args) + private int getImpact(Method method, Object[] args) { - String methodName = method.getName(); - - //handle standard get/set/query and select 'is' methods from MBeanServer - if (methodName.startsWith("query") || methodName.startsWith("get") - ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) - { - return true; - } - else if (methodName.startsWith("set")) - { - return false; - } - //handle invocation of other methods on mbeans - if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) + if ((args[0] instanceof ObjectName) && (method.getName().equals("invoke"))) { - //get invoked method name String mbeanMethod = (args.length > 1) ? (String) args[1] : null; if (mbeanMethod == null) { - return false; + return -1; } - + try { - //check if the given method is tagged with an INFO impact attribute + //Get the impact attribute MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); if (mbeanInfo != null) { MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); for (MBeanOperationInfo opInfo : opInfos) { - if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + if (opInfo.getName().equals(mbeanMethod)) { - return true; + return opInfo.getImpact(); } } } @@ -261,7 +276,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } } - return false; + return -1; + } + + private boolean isAccessMethod(String methodName) + { + //handle standard get/query/is methods from MBeanServer + return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is")); + } + + + private boolean isUpdateMethod(String methodName) + { + //handle standard set methods from MBeanServer + return methodName.startsWith("set"); } public void handleNotification(Notification notification, Object handback) diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 4260307d04..25571f1022 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -20,16 +20,52 @@ */ package org.apache.qpid.server.protocol; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import javax.management.JMException; +import javax.security.sasl.SaslServer; + import org.apache.log4j.Logger; import org.apache.mina.transport.vmpipe.VmPipeAddress; - import org.apache.qpid.AMQChannelException; import org.apache.qpid.AMQConnectionException; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.codec.AMQCodecFactory; import org.apache.qpid.codec.AMQDecoder; import org.apache.qpid.common.ClientProperties; -import org.apache.qpid.framing.*; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlock; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQMethodBody; +import org.apache.qpid.framing.AMQProtocolHeaderException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ChannelCloseBody; +import org.apache.qpid.framing.ChannelCloseOkBody; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ContentBody; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.HeartbeatBody; +import org.apache.qpid.framing.MethodDispatcher; +import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.framing.ProtocolInitiation; +import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.Job; import org.apache.qpid.pool.ReferenceCountingExecutorService; import org.apache.qpid.protocol.AMQConstant; @@ -61,25 +97,6 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.transport.NetworkDriver; import org.apache.qpid.transport.Sender; -import javax.management.JMException; -import javax.security.sasl.SaslServer; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig { private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); @@ -117,6 +134,7 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol private Object _lastSent; protected volatile boolean _closed; + // maximum number of channels this session should have private long _maxNoOfChannels = 1000; @@ -358,14 +376,12 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol public void methodFrameReceived(int channelId, AMQMethodBody methodBody) { - final AMQMethodEvent<AMQMethodBody> evt = new AMQMethodEvent<AMQMethodBody>(channelId, methodBody); try { try { - boolean wasAnyoneInterested = _stateManager.methodReceived(evt); if (!_frameListeners.isEmpty()) @@ -418,10 +434,15 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol _logger.info(e.getMessage() + " whilst processing:" + methodBody); closeConnection(channelId, e, false); } + catch (AMQSecurityException e) + { + AMQConnectionException ce = evt.getMethod().getConnectionException(AMQConstant.ACCESS_REFUSED, e.getMessage()); + _logger.info(e.getMessage() + " whilst processing:" + methodBody); + closeConnection(channelId, ce, false); + } } catch (Exception e) { - for (AMQMethodListener listener : _frameListeners) { listener.error(e); @@ -999,7 +1020,6 @@ public class AMQProtocolEngine implements ProtocolEngine, Managable, AMQProtocol { if (throwable instanceof AMQProtocolHeaderException) { - writeFrame(new ProtocolInitiation(ProtocolVersion.getLatestSupportedVersion())); _networkDriver.close(); diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 366abd3f7c..8b53257e88 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQConnectionModel; @@ -194,7 +195,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void deleteMessageFromTop(); - long clearQueue(); + long clearQueue() throws AMQException; /** * Checks the status of messages on the queue, purging expired ones, firing age related alerts etc. diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index 3340c1e20a..a547205d27 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.queue; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -29,7 +30,6 @@ import org.apache.qpid.server.configuration.QueueConfiguration; import java.util.Map; import java.util.HashMap; - public class AMQQueueFactory { public static final AMQShortString X_QPID_PRIORITIES = new AMQShortString("x-qpid-priorities"); @@ -128,22 +128,20 @@ public class AMQQueueFactory }; - + /** @see #createAMQQueueImpl(String, boolean, String, boolean, boolean, VirtualHost, Map) */ public static AMQQueue createAMQQueueImpl(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, - boolean exclusive, - VirtualHost virtualHost, - final FieldTable arguments) + boolean exclusive, + VirtualHost virtualHost, final FieldTable arguments) throws AMQException { return createAMQQueueImpl(name == null ? null : name.toString(), durable, owner == null ? null : owner.toString(), autoDelete, exclusive, - virtualHost, - FieldTable.convertToMap(arguments)); + virtualHost, FieldTable.convertToMap(arguments)); } @@ -152,8 +150,15 @@ public class AMQQueueFactory String owner, boolean autoDelete, boolean exclusive, - VirtualHost virtualHost, Map<String, Object> arguments) + VirtualHost virtualHost, Map<String, Object> arguments) throws AMQSecurityException { + // Access check + if (!virtualHost.getSecurityManager().authoriseCreateQueue(autoDelete, durable, exclusive, null, null, new AMQShortString(queueName), owner)) + { + String description = "Permission denied: queue-name '" + queueName + "'"; + throw new AMQSecurityException(description); + } + int priorities = 1; String conflationKey = null; if(arguments != null) diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java index af1f412843..806b7f3744 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java @@ -28,6 +28,7 @@ import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; @@ -39,6 +40,7 @@ import org.apache.qpid.server.txn.LocalTransaction; import org.apache.qpid.transport.MessageProperties; import javax.management.JMException; +import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.OperationsException; @@ -336,7 +338,14 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public Long clearQueue() throws JMException { - return _queue.clearQueue(); + try + { + return _queue.clearQueue(); + } + catch (AMQException ex) + { + throw new MBeanException(ex, "Error clearing queue " + _queueName); + } } /** diff --git a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index afc7fb6480..7e78fd0481 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -1,11 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.qpid.server.queue; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.pool.ReadWriteRunnable; import org.apache.qpid.pool.ReferenceCountingExecutorService; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; @@ -50,26 +70,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); @@ -386,9 +386,16 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener // ------ Manage Subscriptions - public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) throws AMQException + public synchronized void registerSubscription(final Subscription subscription, final boolean exclusive) + throws AMQSecurityException, ExistingExclusiveSubscription, ExistingSubscriptionPreventsExclusive { - + // Access control + if (!getVirtualHost().getSecurityManager().authoriseConsume(this)) + { + throw new AMQSecurityException("Permission denied"); + } + + if (hasExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); @@ -403,7 +410,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener else { _exclusiveSubscriber = subscription; - } } @@ -1212,38 +1218,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } - public void purge(final long request) + public void purge(final long request) throws AMQException { - if(request == 0l) - { - clearQueue(); - } - else if(request > 0l) - { - - QueueEntryIterator queueListIterator = _entries.iterator(); - long count = 0; - - ServerTransaction txn = new LocalTransaction(getVirtualHost().getTransactionLog()); - - while (queueListIterator.advance()) - { - QueueEntry node = queueListIterator.getNode(); - if (!node.isDeleted() && node.acquire()) - { - dequeueEntry(node, txn); - if(++count == request) - { - break; - } - } - - } - - txn.commit(); - - - } + clear(request); } public long getCreateTime() @@ -1270,9 +1247,19 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener } } - public long clearQueue() - { + public long clearQueue() throws AMQException + { + return clear(0l); + } + private long clear(final long request) throws AMQSecurityException + { + //Perform ACLs + if (!getVirtualHost().getSecurityManager().authorisePurge(this)) + { + throw new AMQSecurityException("Permission denied: queue " + getName()); + } + QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; @@ -1284,7 +1271,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener if (!node.isDeleted() && node.acquire()) { dequeueEntry(node, txn); - count++; + if(++count == request) + { + break; + } } } @@ -1292,7 +1282,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener txn.commit(); return count; - } private void dequeueEntry(final QueueEntry node) @@ -1329,12 +1318,18 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener _deleteTaskList.remove(task); } - public int delete() throws AMQException + // TODO list all thrown exceptions + public int delete() throws AMQSecurityException, AMQException { if (!_deleted.getAndSet(true)) { + // Check access + if (!_virtualHost.getSecurityManager().authoriseDelete(this)) + { + throw new AMQSecurityException("Permission denied: " + getName()); + } - for(Binding b : getBindings()) + for (Binding b : getBindings()) { _virtualHost.getBindingFactory().removeBinding(b); } @@ -1606,6 +1601,11 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener public void flushSubscription(Subscription sub) throws AMQException { + // Access control + if (!getVirtualHost().getSecurityManager().authoriseConsume(this)) + { + throw new AMQSecurityException("Permission denied: " + getName()); + } flushSubscription(sub, Long.MAX_VALUE); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 4cb3d9e209..9adab58a0c 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -124,7 +124,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry @SuppressWarnings("finally") public static void initialise(IApplicationRegistry instance, int instanceID) throws Exception { - _logger.error("initialise(IApplicationRegistry instance, int instanceID)"); if (instance != null) { _logger.info("Initialising Application Registry(" + instance + "):" + instanceID); @@ -142,7 +141,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { - _logger.error("instance.initialise(instanceID)"); instance.initialise(instanceID); } catch (Exception e) @@ -237,12 +235,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void configure() throws ConfigurationException { - _configurationManager = new ConfigurationManager(); try { - _pluginManager = new PluginManager(_configuration.getPluginDirectory()); + _pluginManager = new PluginManager(_configuration.getPluginDirectory(), _configuration.getCacheDirectory()); } catch (Exception e) { diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java new file mode 100644 index 0000000000..8c9c2050e8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -0,0 +1,69 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This is intended as the parent for all simple plugins. + */ +public abstract class AbstractPlugin implements SecurityPlugin +{ + protected final Logger _logger = Logger.getLogger(getClass()); + + public ConfigurationPlugin _config; + + public String getPluginName() + { + return getClass().getSimpleName(); + } + + public Result getDefault() + { + return Result.ABSTAIN; + } + + public abstract Result access(ObjectType object, Object instance); + + public abstract Result authorise(Operation operation, ObjectType object, ObjectProperties properties); + + public boolean isConfigured() + { + if (_config == null) + { + return false; + } + + for (String key : _config.getElementsProcessed()) + { + if (!_config.getConfig().containsKey(key) && _config.getConfig().subset(key).isEmpty()) + { + return false; + } + } + + return true; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java new file mode 100644 index 0000000000..7f3b89b46b --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java @@ -0,0 +1,139 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This {@link SecurityPlugin} proxies the authorise calls to a serries of methods, one per {@link Operation}. + * + * Plugins that extend this class should override the relevant authorise method and implement their own + * {@link #setConfiguration(Configuration)} method. + */ +public abstract class AbstractProxyPlugin extends AbstractPlugin +{ + public Result authoriseConsume(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authorisePublish(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseCreate(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseAccess(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseBind(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseUnbind(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseDelete(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authorisePurge(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseExecute(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result authoriseUpdate(ObjectType object, ObjectProperties properties) + { + return getDefault(); + } + + public Result accessBroker(Object instance) + { + return getDefault(); + } + + public Result accessVirtualhost(Object instance) + { + return getDefault(); + } + + @Override + public Result access(ObjectType objectType, Object instance) + { + switch (objectType) + { + case BROKER: + return accessBroker(instance); + case VIRTUALHOST: + return accessVirtualhost(instance); + } + + return getDefault(); + } + + @Override + public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) + { + switch (operation) + { + case CONSUME: + return authoriseConsume(objectType, properties); + case PUBLISH: + return authorisePublish(objectType, properties); + case CREATE: + return authoriseCreate(objectType, properties); + case ACCESS: + return authoriseAccess(objectType, properties); + case BIND: + return authoriseBind(objectType, properties); + case UNBIND: + return authoriseUnbind(objectType, properties); + case DELETE: + return authoriseDelete(objectType, properties); + case PURGE: + return authorisePurge(objectType, properties); + case EXECUTE: + return authoriseExecute(objectType, properties); + case UPDATE: + return authoriseUpdate(objectType, properties); + } + + return getDefault(); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/Result.java b/java/broker/src/main/java/org/apache/qpid/server/security/Result.java new file mode 100644 index 0000000000..f79721799e --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/Result.java @@ -0,0 +1,46 @@ +/* + * 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; + +/** + * The result of a security plugin decision, normally {@link #ALLOWED} or {@link #DENIED}. + */ +public enum Result +{ + /** + * The request is allowed. + */ + ALLOWED, + + /** + * The request is denied. + */ + DENIED, + + /** + * Indicates that a plugin does not handle a particular type of request. + */ + ABSTAIN, + + /** + * A plugin instance cannot make a decision on a request it is able to handle, + * and another instance of the plugin should be checked. + */ + DEFER; +}
\ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java new file mode 100755 index 0000000000..035b7fa854 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security; + +import static org.apache.qpid.server.security.access.ObjectType.*; +import static org.apache.qpid.server.security.access.Operation.*; + +import java.security.Principal; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +/** + * The security manager contains references to all loaded {@link SecurityPlugin}s and delegates security decisions to them based + * on virtual host name. The plugins can be external <em>OSGi</em> .jar files that export the required classes or just internal + * objects for simpler plugins. + * + * @see SecurityPlugin + */ +public class SecurityManager +{ + private static final Logger _logger = Logger.getLogger(SecurityManager.class); + + /** Container for the {@link Principal} that is using to this thread. */ + private static final ThreadLocal<Principal> _principal = new ThreadLocal<Principal>(); + + private PluginManager _pluginManager; + private Map<String, SecurityPluginFactory> _pluginFactories = new HashMap<String, SecurityPluginFactory>(); + private Map<String, SecurityPlugin> _globalPlugins = new HashMap<String, SecurityPlugin>(); + private Map<String, SecurityPlugin> _hostPlugins = new HashMap<String, SecurityPlugin>(); + + public SecurityManager(SecurityManager parent) throws ConfigurationException + { + _pluginManager = parent._pluginManager; + _pluginFactories = parent._pluginFactories; + + // our global plugins are the parent's host plugins + _globalPlugins = parent._hostPlugins; + } + + public SecurityManager(ConfigurationPlugin configuration, PluginManager manager) throws ConfigurationException + { + this(configuration, manager, null); + } + + public SecurityManager(ConfigurationPlugin configuration, PluginManager manager, SecurityPluginFactory plugin) throws ConfigurationException + { + _pluginManager = manager; + if (manager == null) // No plugin manager, no plugins + { + return; + } + + _pluginFactories = _pluginManager.getSecurityPlugins(); + if (plugin != null) + { + _pluginFactories.put(plugin.getPluginName(), plugin); + } + + configureHostPlugins(configuration); + } + + public static Principal getThreadPrincipal() + { + return _principal.get(); + } + + public static void setThreadPrincipal(Principal principal) + { + _principal.set(principal); + } + + public static void setThreadPrincipal(String authId) + { + setThreadPrincipal(new UsernamePrincipal(authId)); + } + + public void configureHostPlugins(ConfigurationPlugin hostConfig) throws ConfigurationException + { + _hostPlugins = configurePlugins(hostConfig); + } + + public void configureGlobalPlugins(ConfigurationPlugin configuration) throws ConfigurationException + { + _globalPlugins = configurePlugins(configuration); + } + + public Map<String, SecurityPlugin> configurePlugins(ConfigurationPlugin hostConfig) throws ConfigurationException + { + Map<String, SecurityPlugin> plugins = new HashMap<String, SecurityPlugin>(); + for (SecurityPluginFactory<?> factory : _pluginFactories.values()) + { + SecurityPlugin plugin = factory.newInstance(hostConfig); + if (plugin.isConfigured()) + { + plugins.put(factory.getPluginName(), plugin); + } + } + return plugins; + } + + public void addHostPlugin(SecurityPlugin plugin) + { + _hostPlugins.put(plugin.getClass().getName(), plugin); + } + + public static Logger getLogger() + { + return _logger; + } + + private abstract class AccessCheck + { + abstract Result allowed(SecurityPlugin plugin); + } + + private boolean checkAllPlugins(AccessCheck checker) + { + HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins); + + for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet()) + { + // Create set of global only plugins + SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey()); + if (globalPlugin != null) + { + remainingPlugins.remove(hostEntry.getKey()); + } + + Result host = checker.allowed(hostEntry.getValue()); + + if (host == Result.DENIED) + { + // Something vetoed the access, we're done + return false; + } + + // host allow overrides global allow, so only check global on abstain or defer + if (host != Result.ALLOWED) + { + if (globalPlugin == null) + { + if (host == Result.DEFER) + { + host = hostEntry.getValue().getDefault(); + } + if (host == Result.DENIED) + { + return false; + } + } + else + { + Result global = checker.allowed(globalPlugin); + if (global == Result.DEFER) + { + global = globalPlugin.getDefault(); + } + if (global == Result.ABSTAIN && host == Result.DEFER) + { + global = hostEntry.getValue().getDefault(); + } + if (global == Result.DENIED) + { + return false; + } + } + } + } + + for (SecurityPlugin plugin : remainingPlugins.values()) + { + Result remaining = checker.allowed(plugin); + if (remaining == Result.DEFER) + { + remaining = plugin.getDefault(); + } + if (remaining == Result.DENIED) + { + return false; + } + } + + // getting here means either allowed or abstained from all plugins + return true; + } + + public boolean authoriseBind(final Exchange exch, final AMQQueue queue, final AMQShortString routingKey) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(BIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey)); + } + }); + } + + // TODO not implemented yet, awaiting consensus + public boolean authoriseObject(final String packageName, final String className) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + ObjectProperties properties = new ObjectProperties(); + properties.put(ObjectProperties.Property.PACKAGE, packageName); + properties.put(ObjectProperties.Property.CLASS, className); + return plugin.authorise(ACCESS, OBJECT, properties); + } + }); + } + + public boolean authoriseMethod(final Operation operation, final String componentName, final String methodName) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + ObjectProperties properties = new ObjectProperties(); + properties.setName(methodName); + if (componentName != null) + { + // Only set the property if there is a component name + properties.put(ObjectProperties.Property.COMPONENT, componentName); + } + return plugin.authorise(operation, METHOD, properties); + } + }); + } + + // TODO not implemented yet, awaiting consensus + public boolean accessBroker(final AMQProtocolSession session) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.access(BROKER, session); + } + }); + } + + public boolean accessVirtualhost(final String vhostname, final String remoteAddress) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.access(VIRTUALHOST, remoteAddress); + } + }); + } + + public boolean authoriseConsume(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseConsume(final boolean exclusive, final boolean noAck, final boolean noLocal, final boolean nowait, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CONSUME, QUEUE, new ObjectProperties(exclusive, noAck, noLocal, nowait, queue)); + } + }); + } + + public boolean authoriseCreateExchange(final Boolean autoDelete, final Boolean durable, final AMQShortString exchangeName, + final Boolean internal, final Boolean nowait, final Boolean passive, final AMQShortString exchangeType) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CREATE, EXCHANGE, new ObjectProperties(autoDelete, durable, exchangeName, + internal, nowait, passive, exchangeType)); + } + }); + } + + public boolean authoriseCreateQueue(final Boolean autoDelete, final Boolean durable, final Boolean exclusive, + final Boolean nowait, final Boolean passive, final AMQShortString queueName, final String owner) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(CREATE, QUEUE, new ObjectProperties(autoDelete, durable, exclusive, nowait, passive, queueName, owner)); + } + }); + } + + public boolean authoriseDelete(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(DELETE, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseDelete(final Exchange exchange) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(DELETE, EXCHANGE, new ObjectProperties(exchange.getName())); + } + }); + } + + public boolean authorisePublish(final boolean immediate, final String routingKey, final String exchangeName) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(PUBLISH, EXCHANGE, new ObjectProperties(exchangeName, routingKey, immediate)); + } + }); + } + + public boolean authorisePurge(final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(PURGE, QUEUE, new ObjectProperties(queue)); + } + }); + } + + public boolean authoriseUnbind(final Exchange exch, final AMQShortString routingKey, final AMQQueue queue) + { + return checkAllPlugins(new AccessCheck() + { + Result allowed(SecurityPlugin plugin) + { + return plugin.authorise(UNBIND, EXCHANGE, new ObjectProperties(exch, queue, routingKey)); + } + }); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java new file mode 100644 index 0000000000..c3c06bf206 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPlugin.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security; + +import org.apache.qpid.server.plugins.Plugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * The two methods, {@link #access(ObjectType, Object)} and {@link #authorise(Operation, ObjectType, ObjectProperties)}, + * return the {@link Result} of the security decision, which may be to {@link Result#ABSTAIN} if no decision is made + * by this plugin. + */ +public interface SecurityPlugin extends Plugin +{ + /** + * Default result for {@link #access(ObjectType, Object)} or {@link #authorise(Operation, ObjectType, ObjectProperties)}. + */ + Result getDefault(); + + /** + * Authorise access granted to an object instance. + */ + Result access(ObjectType objectType, Object instance); + + /** + * Authorise an operation on an object defined by a set of properties. + */ + Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java new file mode 100644 index 0000000000..789bdd0073 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java @@ -0,0 +1,54 @@ +package org.apache.qpid.server.security; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * An OSGi {@link BundleActivator} that loads a {@link SecurityPluginFactory}. + */ +public abstract class SecurityPluginActivator implements BundleActivator +{ + private static final Logger _logger = Logger.getLogger(SecurityPluginActivator.class); + + private SecurityPluginFactory _factory; + private ConfigurationPluginFactory _config; + private BundleContext _ctx; + private String _bundleName; + + /** Implement this to return the factory this plugin activates. */ + public abstract SecurityPluginFactory getFactory(); + + /** Implement this to return the factory this plugin activates. */ + public abstract ConfigurationPluginFactory getConfigurationFactory(); + + /** + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext ctx) throws Exception + { + _ctx = ctx; + _factory = getFactory(); + _config = getConfigurationFactory(); + _bundleName = ctx.getBundle().getSymbolicName(); + + // register the service + _logger.info("Registering security plugin: " + _bundleName); + _ctx.registerService(SecurityPluginFactory.class.getName(), _factory, null); + _ctx.registerService(ConfigurationPluginFactory.class.getName(), _config, null); + } + + /** + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception + { + _logger.info("Stopping security plugin: " + _bundleName); + + // null object references + _factory = null; + _config = null; + _ctx = null; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java index 895ed52222..fe81cba282 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AuthorizationManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginFactory.java @@ -1,6 +1,5 @@ -package org.apache.qpid.server.security.access; /* - * + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -8,20 +7,24 @@ package org.apache.qpid.server.security.access; * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * + * */ +package org.apache.qpid.server.security; +import org.apache.qpid.server.plugins.PluginFactory; -public class AuthorizationManager +/** + * The factory that generates instances of security plugins. Usually implemented as a static member class in the plugin itself. + */ +public interface SecurityPluginFactory<S extends SecurityPlugin> extends PluginFactory<S> { - } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java deleted file mode 100644 index 7d6ae285c5..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLManager.java +++ /dev/null @@ -1,323 +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; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; - -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.SecurityConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public class ACLManager -{ - private static final Logger _logger = Logger.getLogger(ACLManager.class); - private PluginManager _pluginManager; - private Map<String, ACLPluginFactory> _allSecurityPlugins = new HashMap<String, ACLPluginFactory>(); - private Map<String, ACLPlugin> _globalPlugins = new HashMap<String, ACLPlugin>(); - private Map<String, ACLPlugin> _hostPlugins = new HashMap<String, ACLPlugin>(); - - public ACLManager(SecurityConfiguration configuration, PluginManager manager) throws ConfigurationException - { - this(configuration, manager, null); - } - - public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin) throws ConfigurationException - { - _pluginManager = manager; - - if (manager == null) // No plugin manager, no plugins - { - return; - } - - _allSecurityPlugins = _pluginManager.getSecurityPlugins(); - if (securityPlugin != null) - { - _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin); - } - - configureGlobalPlugins(configuration); - } - - public void configureHostPlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - _hostPlugins = configurePlugins(hostConfig); - } - - public void configureGlobalPlugins(SecurityConfiguration configuration) throws ConfigurationException - { - _globalPlugins = configurePlugins(configuration); - } - - public Map<String, ACLPlugin> configurePlugins(SecurityConfiguration hostConfig) throws ConfigurationException - { - Configuration securityConfig = hostConfig.getConfiguration(); - Map<String, ACLPlugin> plugins = new HashMap<String, ACLPlugin>(); - Iterator keys = securityConfig.getKeys(); - Collection<String> handledTags = new HashSet(); - while (keys.hasNext()) - { - // Splitting the string is necessary here because of the way that getKeys() returns only - // bottom level children - String tag = ((String) keys.next()).split("\\.", 2)[0]; - if (!handledTags.contains(tag)) - { - for (ACLPluginFactory plugin : _allSecurityPlugins.values()) - { - if (plugin.supportsTag(tag)) - { - _logger.info("Plugin handling security section "+tag+" is "+plugin); - handledTags.add(tag); - plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig)); - } - } - } - if (!handledTags.contains(tag)) - { - _logger.warn("No plugin handled security section "+tag); - } - } - return plugins; - } - - public static Logger getLogger() - { - return _logger; - } - - private abstract class AccessCheck - { - abstract AuthzResult allowed(ACLPlugin plugin); - } - - private boolean checkAllPlugins(AccessCheck checker) - { - AuthzResult result = AuthzResult.ABSTAIN; - HashMap<String, ACLPlugin> remainingPlugins = new HashMap<String, ACLPlugin>(); - remainingPlugins.putAll(_globalPlugins); - for (Entry<String, ACLPlugin> plugin : _hostPlugins.entrySet()) - { - result = checker.allowed(plugin.getValue()); - if (result == AuthzResult.DENIED) - { - // Something vetoed the access, we're done - return false; - } - else if (result == AuthzResult.ALLOWED) - { - // Remove plugin from global check list since - // host allow overrides global allow - remainingPlugins.remove(plugin.getKey()); - } - } - - for (ACLPlugin plugin : remainingPlugins.values()) - { - result = checker.allowed(plugin); - if (result == AuthzResult.DENIED) - { - return false; - } - } - return true; - } - - public boolean authoriseBind(final PrincipalHolder session, final Exchange exch, final AMQQueue queue, - final AMQShortString routingKey) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseBind(session, exch, queue, routingKey); - } - - }); - } - - public boolean authoriseConnect(final PrincipalHolder session, final VirtualHost virtualHost) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConnect(session, virtualHost); - } - - }); - } - - public boolean authoriseConsume(final PrincipalHolder session, final boolean noAck, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, noAck, queue); - } - - }); - } - - public boolean authoriseConsume(final PrincipalHolder session, final boolean exclusive, final boolean noAck, - final boolean noLocal, final boolean nowait, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue); - } - - }); - } - - public boolean authoriseCreateExchange(final PrincipalHolder session, final boolean autoDelete, - final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait, - final boolean passive, final AMQShortString exchangeType) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait, - passive, exchangeType); - } - - }); - } - - public boolean authoriseCreateQueue(final PrincipalHolder session, final boolean autoDelete, - final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive, - final AMQShortString queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue); - } - - }); - } - - public boolean authoriseDelete(final PrincipalHolder session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, queue); - } - - }); - } - - public boolean authoriseDelete(final PrincipalHolder session, final Exchange exchange) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseDelete(session, exchange); - } - - }); - } - - public boolean authorisePublish(final PrincipalHolder session, final boolean immediate, final boolean mandatory, - final AMQShortString routingKey, final Exchange e) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePublish(session, immediate, mandatory, routingKey, e); - } - - }); - } - - public boolean authorisePurge(final PrincipalHolder session, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authorisePurge(session, queue); - } - - }); - } - - public boolean authoriseUnbind(final PrincipalHolder session, final Exchange exch, - final AMQShortString routingKey, final AMQQueue queue) - { - return checkAllPlugins(new AccessCheck() - { - - @Override - AuthzResult allowed(ACLPlugin plugin) - { - return plugin.authoriseUnbind(session, exch, routingKey, queue); - } - - }); - } - - public void addHostPlugin(ACLPlugin aclPlugin) - { - _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin); - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java deleted file mode 100644 index cf8a3fede9..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPlugin.java +++ /dev/null @@ -1,70 +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; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.PrincipalHolder; - -public interface ACLPlugin -{ - public enum AuthzResult - { - ALLOWED, - DENIED, - ABSTAIN - } - - void setConfiguration(Configuration config) throws ConfigurationException; - - // These return true if the plugin thinks the action should be allowed, and false if not. - - AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, AMQShortString routingKey); - - AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType); - - AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue); - - AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost); - - AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue); - - AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue); - - AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue); - - AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange); - - AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e); - - AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue); - - AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, AMQQueue queue); - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java deleted file mode 100644 index 256f093477..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/ACLPluginFactory.java +++ /dev/null @@ -1,33 +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; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -public interface ACLPluginFactory -{ - - public boolean supportsTag(String name); - - public ACLPlugin newInstance(Configuration config) throws ConfigurationException; - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java deleted file mode 100644 index d722da4ae0..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java +++ /dev/null @@ -1,65 +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; - -public class AccessResult -{ - public enum AccessStatus - { - GRANTED, REFUSED - } - - private String _authorizer; - private AccessStatus _status; - - public AccessResult(ACLPlugin authorizer, AccessStatus status) - { - _status = status; - _authorizer = authorizer.getClass().getSimpleName(); - } - - public void setAuthorizer(ACLPlugin authorizer) - { - _authorizer += authorizer.getClass().getSimpleName(); - } - - public String getAuthorizer() - { - return _authorizer; - } - - public void setStatus(AccessStatus status) - { - _status = status; - } - - public AccessStatus getStatus() - { - return _status; - } - - public void addAuthorizer(ACLPlugin accessManager) - { - _authorizer = accessManager.getClass().getSimpleName() + "->" + _authorizer; - } - - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java deleted file mode 100644 index 1b79a5a0e0..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java +++ /dev/null @@ -1,63 +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; - -public class AccessRights -{ - public enum Rights - { - ANY, - READ, - WRITE, - READWRITE - } - - Rights _right; - - public AccessRights(Rights right) - { - _right = right; - } - - public boolean allows(Rights rights) - { - switch (_right) - { - case ANY: - return (rights.equals(Rights.WRITE) - || rights.equals(Rights.READ) - || rights.equals(Rights.READWRITE) - || rights.equals(Rights.ANY)); - case READ: - return rights.equals(Rights.READ) || rights.equals(Rights.ANY); - case WRITE: - return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); - case READWRITE: - return true; - } - return false; - } - - public Rights getRights() - { - return _right; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java new file mode 100644 index 0000000000..af47ed6bf9 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java @@ -0,0 +1,315 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.queue.AMQQueue; + +/** + * An set of properties for an access control v2 rule {@link ObjectType}. + * + * The {@link #matches(ObjectProperties)} method is intended to be used when determining precedence of rules, and + * {@link #equals(Object)} and {@link #hashCode()} are intended for use in maps. This is due to the wildcard matching + * described above. + */ +public class ObjectProperties extends HashMap<ObjectProperties.Property, String> +{ + /** serialVersionUID */ + private static final long serialVersionUID = -1356019341374170495L; + + public static final String STAR= "*"; + + public static final ObjectProperties EMPTY = new ObjectProperties(); + + public enum Property + { + ROUTING_KEY, + NAME, + QUEUE_NAME, + OWNER, + TYPE, + ALTERNATE, + IMMEDIATE, + INTERNAL, + NO_WAIT, + NO_LOCAL, + NO_ACK, + PASSIVE, + DURABLE, + EXCLUSIVE, + TEMPORARY, + AUTO_DELETE, + COMPONENT, + PACKAGE, + CLASS; + + public static Property parse(String text) + { + for (Property property : values()) + { + if (property.getName().equalsIgnoreCase(text)) + { + return property; + } + } + throw new IllegalArgumentException("Not a valid property: " + text); + } + + public String getName() + { + return StringUtils.remove(name(), '_').toLowerCase(); + } + + public static List<String> getPropertyNames() + { + List<String> properties = new ArrayList<String>(); + for (Property property : values()) + { + properties.add(property.getName()); + } + return properties; + } + } + + public static List<String> getAllPropertyNames() + { + List<String> properties = new ArrayList<String>(); + for (Property property : Property.values()) + { + properties.add(StringUtils.remove(property.name(), '_').toLowerCase()); + } + return properties; + } + + public ObjectProperties() + { + super(); + } + + public ObjectProperties(ObjectProperties copy) + { + super(); + + putAll(copy); + } + + public ObjectProperties(String name) + { + super(); + + setName(name); + } + + + public ObjectProperties(AMQShortString name) + { + super(); + + setName(name); + } + + public ObjectProperties(AMQQueue queue) + { + super(); + + setName(queue.getName()); + + put(Property.AUTO_DELETE, queue.isAutoDelete()); + put(Property.TEMPORARY, queue.isAutoDelete()); + put(Property.DURABLE, queue.isDurable()); + put(Property.EXCLUSIVE, queue.isExclusive()); + if (queue.getAlternateExchange() != null) + { + put(Property.ALTERNATE, queue.getAlternateExchange().getName()); + } + if (queue.getOwner() != null) + { + put(Property.OWNER, queue.getOwner()); + } + else if (queue.getPrincipalHolder() != null) + { + put(Property.OWNER, queue.getPrincipalHolder().getPrincipal().getName()); + } + } + + public ObjectProperties(Exchange exch, AMQQueue queue, AMQShortString routingKey) + { + this(queue); + + setName(exch.getName()); + + put(Property.QUEUE_NAME, queue.getName()); + put(Property.ROUTING_KEY, routingKey); + } + + public ObjectProperties(Exchange exch, AMQShortString routingKey) + { + this(exch.getName(), routingKey.asString()); + } + + public ObjectProperties(String exchangeName, String routingKey, Boolean immediate) + { + this(exchangeName, routingKey); + + put(Property.IMMEDIATE, immediate); + } + + public ObjectProperties(String exchangeName, String routingKey) + { + super(); + + setName(exchangeName); + + put(Property.ROUTING_KEY, routingKey); + } + + public ObjectProperties(Boolean autoDelete, Boolean durable, AMQShortString exchangeName, + Boolean internal, Boolean nowait, Boolean passive, AMQShortString exchangeType) + { + super(); + + setName(exchangeName); + + put(Property.AUTO_DELETE, autoDelete); + put(Property.TEMPORARY, autoDelete); + put(Property.DURABLE, durable); + put(Property.INTERNAL, internal); + put(Property.NO_WAIT, nowait); + put(Property.PASSIVE, passive); + put(Property.TYPE, exchangeType); + } + + public ObjectProperties(Boolean autoDelete, Boolean durable, Boolean exclusive, Boolean nowait, Boolean passive, + AMQShortString queueName, String owner) + { + super(); + + setName(queueName); + + put(Property.AUTO_DELETE, autoDelete); + put(Property.TEMPORARY, autoDelete); + put(Property.DURABLE, durable); + put(Property.EXCLUSIVE, exclusive); + put(Property.NO_WAIT, nowait); + put(Property.PASSIVE, passive); + put(Property.OWNER, owner); + } + + public ObjectProperties(Boolean exclusive, Boolean noAck, Boolean noLocal, Boolean nowait, AMQQueue queue) + { + this(queue); + + put(Property.NO_LOCAL, noLocal); + put(Property.NO_ACK, noAck); + put(Property.EXCLUSIVE, exclusive); + put(Property.NO_WAIT, nowait); + } + + public List<String> getPropertyNames() + { + List<String> properties = new ArrayList<String>(); + for (Property property : keySet()) + { + properties.add(property.getName()); + } + return properties; + } + + public Boolean isSet(Property key) + { + return containsKey(key) && Boolean.valueOf(get(key)); + } + + public String getName() + { + return get(Property.NAME); + } + + public void setName(String name) + { + put(Property.NAME, name); + } + + public void setName(AMQShortString name) + { + put(Property.NAME, name); + } + + public String put(Property key, AMQShortString value) + { + return put(key, value == null ? "" : value.asString()); + } + + @Override + public String put(Property key, String value) + { + return super.put(key, value == null ? "" : value.trim()); + } + + public void put(Property key, Boolean value) + { + if (value != null) + { + super.put(key, Boolean.toString(value)); + } + } + + public boolean matches(ObjectProperties properties) + { + if (properties.keySet().isEmpty()) + { + return true; + } + + if (!keySet().containsAll(properties.keySet())) + { + return false; + } + + for (Property key : properties.keySet()) + { + String ruleValue = properties.get(key); + String thisValue = get(key); + + if (!valueMatches(thisValue, ruleValue)) + { + return false; + } + } + + return true; + } + + private boolean valueMatches(String thisValue, String ruleValue) + { + return (StringUtils.isEmpty(ruleValue) + || StringUtils.equals(thisValue, ruleValue)) + || ruleValue.equals(STAR) + || (ruleValue.endsWith(STAR) + && thisValue != null + && thisValue.length() > ruleValue.length() + && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2))); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java new file mode 100644 index 0000000000..66ef388976 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access; + +import static org.apache.qpid.server.security.access.Operation.*; + +import java.util.EnumSet; +import java.util.Set; + +/** + * An enumeration of all possible object types that can form part of an access control v2 rule. + * + * Each object type is valid only for a certain set of {@link Operation}s, which are passed as a list to + * the constructor, and can be checked using the {@link #isAllowed(Operation)} method. + */ +public enum ObjectType +{ + ALL(Operation.ALL), + VIRTUALHOST(ACCESS), + QUEUE(CREATE, DELETE, PURGE, CONSUME), + TOPIC(CREATE, DELETE, PURGE, CONSUME), + EXCHANGE(ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH), + BROKER(ACCESS), + LINK, // Not allowed in the Java broker + ROUTE, // Not allowed in the Java broker + METHOD(Operation.ALL, ACCESS, UPDATE, EXECUTE), + OBJECT(ACCESS); + + private EnumSet<Operation> _actions; + + private ObjectType() + { + _actions = EnumSet.noneOf(Operation.class); + } + + private ObjectType(Operation operation) + { + if (operation == Operation.ALL) + { + _actions = EnumSet.allOf(Operation.class); + } + else + { + _actions = EnumSet.of(operation); + } + } + + private ObjectType(Operation first, Operation...rest) + { + _actions = EnumSet.of(first, rest); + } + + public Set<Operation> getActions() + { + return _actions; + } + + public boolean isAllowed(Operation operation) + { + return _actions.contains(operation); + } + + public static ObjectType parse(String text) + { + for (ObjectType object : values()) + { + if (object.name().equalsIgnoreCase(text)) + { + return object; + } + } + throw new IllegalArgumentException("Not a valid object type: " + text); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java index f51cf24caa..7077257d01 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Operation.java @@ -14,14 +14,36 @@ * "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. - * - * + * under the License. */ package org.apache.qpid.server.security.access; -public interface Accessable +/** + * An enumeration of all possible actions that can form part of an access control v2 rule. + */ +public enum Operation { - void setAccessableName(String name); - String getAccessableName(); -} + ALL, + CONSUME, + PUBLISH, + CREATE, + ACCESS, + BIND, + UNBIND, + DELETE, + PURGE, + UPDATE, + EXECUTE; + + public static Operation parse(String text) + { + for (Operation operation : values()) + { + if (operation.name().equalsIgnoreCase(text)) + { + return operation; + } + } + throw new IllegalArgumentException("Not a valid operation: " + text); + } +}
\ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java index b65b0cdc6c..49b3a331f9 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Permission.java @@ -20,19 +20,28 @@ */ package org.apache.qpid.server.security.access; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; +import org.apache.commons.lang.StringUtils; +/** + * An enumeration of all possible permissions that can be applied to an access control v2 rule. + */ public enum Permission { - CONSUME, - PUBLISH, - CREATEQUEUE, - CREATEEXCHANGE, - ACCESS, - BIND, - UNBIND, - DELETE, - PURGE -} + ALLOW, + ALLOW_LOG, + DENY, + DENY_LOG; + + public static Permission parse(String text) + { + + for (Permission permission : values()) + { + if (permission.name().equalsIgnoreCase(StringUtils.replaceChars(text, '-', '_'))) + { + return permission; + } + } + throw new IllegalArgumentException("Not a valid permission: " + text); + } +}
\ No newline at end of file diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java deleted file mode 100644 index 13151a66b8..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java +++ /dev/null @@ -1,68 +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; - -public class VirtualHostAccess -{ - private String _vhost; - private AccessRights _rights; - - public VirtualHostAccess(String vhostaccess) - { - //format <vhost>(<rights>) - int hostend = vhostaccess.indexOf('('); - - if (hostend == -1) - { - throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); - } - - _vhost = vhostaccess.substring(0, hostend); - - String rights = vhostaccess.substring(hostend); - - if (rights.indexOf('r') != -1) - { - if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.READWRITE); - } - else - { - _rights = new AccessRights(AccessRights.Rights.READ); - } - } - else if (rights.indexOf('w') != -1) - { - _rights = new AccessRights(AccessRights.Rights.WRITE); - } - } - - public AccessRights getAccessRights() - { - return _rights; - } - - public String getVirtualHost() - { - return _vhost; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java deleted file mode 100644 index f99f3a60f7..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java +++ /dev/null @@ -1,99 +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 org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.PrincipalHolder; - -/** - * This ACLPlugin abstains from all votes. Useful if your plugin only cares about a few operations. - */ -public abstract class AbstractACLPlugin implements ACLPlugin -{ - - private static final AuthzResult DEFAULT_ANSWER = AuthzResult.ABSTAIN; - - public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, AMQQueue queue, - AMQShortString routingKey) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConnect(PrincipalHolder session, VirtualHost virtualHost) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean exclusive, boolean noAck, boolean noLocal, - boolean nowait, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseCreateExchange(PrincipalHolder session, boolean autoDelete, boolean durable, - AMQShortString exchangeName, boolean internal, boolean nowait, boolean passive, AMQShortString exchangeType) - { - // TODO Auto-generated method stub - return null; - } - - public AuthzResult authoriseCreateQueue(PrincipalHolder session, boolean autoDelete, boolean durable, - boolean exclusive, boolean nowait, boolean passive, AMQShortString queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePublish(PrincipalHolder session, boolean immediate, boolean mandatory, - AMQShortString routingKey, Exchange e) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) - { - return DEFAULT_ANSWER; - } - - public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, AMQShortString routingKey, - AMQQueue queue) - { - return DEFAULT_ANSWER; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java index 4af178574b..82963bbadc 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java @@ -15,40 +15,72 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * */ package org.apache.qpid.server.security.access.plugins; +import java.util.Arrays; +import java.util.List; + import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPluginFactory; -public class AllowAll extends BasicACLPlugin +/** Always allow. */ +public class AllowAll extends BasicPlugin { + public static class AllowAllConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public List<String> getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new AllowAllConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "allow-all" }; + } + } + + public static final SecurityPluginFactory<AllowAll> FACTORY = new SecurityPluginFactory<AllowAll>() { - public boolean supportsTag(String name) + public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException { - return false; + AllowAll plugin = new AllowAll(config); + plugin.configure(); + return plugin; } - public ACLPlugin newInstance(Configuration config) + public String getPluginName() { - return new AllowAll(); + return AllowAll.class.getName(); } - }; - public String getPluginName() - { - return this.getClass().getSimpleName(); + public Class<AllowAll> getPluginClass() + { + return AllowAll.class; + } + }; + + @Override + public Result getDefault() + { + return Result.ALLOWED; } - @Override - protected AuthzResult getResult() + public AllowAll(ConfigurationPlugin config) { - // Always allow - return AuthzResult.ALLOWED; + _config = config.getConfiguration(AllowAllConfiguration.class); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java deleted file mode 100644 index d0df354d78..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicACLPlugin.java +++ /dev/null @@ -1,110 +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 org.apache.commons.configuration.Configuration; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.PrincipalHolder; -import org.apache.qpid.server.virtualhost.VirtualHost; - -public abstract class BasicACLPlugin implements ACLPlugin -{ - - // Returns true or false if the plugin should authorise or deny the request - protected abstract AuthzResult getResult(); - - public AuthzResult authoriseBind(PrincipalHolder session, Exchange exch, - AMQQueue queue, AMQShortString routingKey) - { - return getResult(); - } - - public AuthzResult authoriseConnect(PrincipalHolder session, - VirtualHost virtualHost) - { - return getResult(); - } - - public AuthzResult authoriseConsume(PrincipalHolder session, boolean noAck, - AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseConsume(PrincipalHolder session, - boolean exclusive, boolean noAck, boolean noLocal, boolean nowait, - AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseCreateExchange(PrincipalHolder session, - boolean autoDelete, boolean durable, AMQShortString exchangeName, - boolean internal, boolean nowait, boolean passive, - AMQShortString exchangeType) - { - return getResult(); - } - - public AuthzResult authoriseCreateQueue(PrincipalHolder session, - boolean autoDelete, boolean durable, boolean exclusive, - boolean nowait, boolean passive, AMQShortString queue) - { - return getResult(); - } - - public AuthzResult authoriseDelete(PrincipalHolder session, AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseDelete(PrincipalHolder session, Exchange exchange) - { - return getResult(); - } - - public AuthzResult authorisePublish(PrincipalHolder session, - boolean immediate, boolean mandatory, AMQShortString routingKey, - Exchange e) - { - return getResult(); - } - - public AuthzResult authorisePurge(PrincipalHolder session, AMQQueue queue) - { - return getResult(); - } - - public AuthzResult authoriseUnbind(PrincipalHolder session, Exchange exch, - AMQShortString routingKey, AMQQueue queue) - { - return getResult(); - } - - public void setConfiguration(Configuration config) - { - // no-op - } - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java new file mode 100644 index 0000000000..5fc1ef7795 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.security.AbstractPlugin; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPlugin; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +/** + * This {@link SecurityPlugin} simply abstains from all authorisation requests and ignores configuration. + */ +public class BasicPlugin extends AbstractPlugin +{ + public Result access(ObjectType objectType, Object instance) + { + return getDefault(); + } + + public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) + { + return getDefault(); + } + + @Override + public void configure() throws ConfigurationException + { + // Not used + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java index 77d3c4bcdf..24af215a0c 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java @@ -15,61 +15,72 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * - * */ package org.apache.qpid.server.security.access.plugins; +import java.util.Arrays; +import java.util.List; + import org.apache.commons.configuration.Configuration; -import org.apache.qpid.AMQConnectionException; -import org.apache.qpid.framing.AMQMethodBody; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; -import org.apache.qpid.server.security.access.AccessResult; -import org.apache.qpid.server.security.access.Permission; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.Result; +import org.apache.qpid.server.security.SecurityPluginFactory; -public class DenyAll extends BasicACLPlugin +/** Always Deny. */ +public class DenyAll extends BasicPlugin { - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - public boolean supportsTag(String name) + public static class DenyAllConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() { - return false; - } + public List<String> getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } - public ACLPlugin newInstance(Configuration config) + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new DenyAllConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() { - return new DenyAll(); + return new String[] { "deny-all" }; } - }; + } - public AccessResult authorise(AMQProtocolSession session, - Permission permission, AMQMethodBody body, Object... parameters) - throws AMQConnectionException + public static final SecurityPluginFactory<DenyAll> FACTORY = new SecurityPluginFactory<DenyAll>() { + public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException + { + DenyAll plugin = new DenyAll(config); + plugin.configure(); + return plugin; + } - if (ACLManager.getLogger().isInfoEnabled()) + public String getPluginName() { - ACLManager.getLogger().info( - "Denying user:" + session.getPrincipal()); + return DenyAll.class.getName(); } - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, - "DenyAll Plugin"); - } - public String getPluginName() - { - return getClass().getSimpleName(); + public Class<DenyAll> getPluginClass() + { + return DenyAll.class; + } + }; + + @Override + public Result getDefault() + { + return Result.DENIED; } - @Override - protected AuthzResult getResult() + public DenyAll(ConfigurationPlugin config) throws ConfigurationException { - // Always deny - return AuthzResult.DENIED; + _config = config.getConfiguration(DenyAllConfiguration.class); } - } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java new file mode 100644 index 0000000000..2c0994b52a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -0,0 +1,81 @@ +/* + * 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.VirtualHostConfiguration; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.SecurityPluginFactory; + +/** Always Abstain. */ +public class LegacyAccess extends BasicPlugin +{ + public static class LegacyAccessConfiguration extends ConfigurationPlugin { + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public List<String> getParentPaths() + { + return Arrays.asList("security", "virtualhosts.virtualhost.security"); + } + + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new LegacyAccessConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "principal-databases", "access", "msg-auth", "false", "jmx" }; + } + } + + public static final SecurityPluginFactory<LegacyAccess> FACTORY = new SecurityPluginFactory<LegacyAccess>() + { + public LegacyAccess newInstance(ConfigurationPlugin config) throws ConfigurationException + { + LegacyAccess plugin = new LegacyAccess(config); + plugin.configure(); + return plugin; + } + + public String getPluginName() + { + return LegacyAccess.class.getName(); + } + + public Class<LegacyAccess> getPluginClass() + { + return LegacyAccess.class; + } + }; + + public LegacyAccess(ConfigurationPlugin config) throws ConfigurationException + { + _config = config.getConfiguration(LegacyAccessConfiguration.class); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java deleted file mode 100644 index fc1bc048d4..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccessPlugin.java +++ /dev/null @@ -1,71 +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.util.Collection; -import java.util.HashSet; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.access.ACLPlugin; -import org.apache.qpid.server.security.access.ACLPluginFactory; - -/** - * - * Used to suppress warnings in legacy config files that have things in <security> which aren't handled by a plugin directly. - * - */ -public class LegacyAccessPlugin extends BasicACLPlugin -{ - public static final ACLPluginFactory FACTORY = new ACLPluginFactory() - { - private Collection maskedTags = new HashSet<String>(); - { - maskedTags.add("principal-databases"); - maskedTags.add("access"); - maskedTags.add("msg-auth"); - maskedTags.add("false"); - maskedTags.add("jmx"); - } - - public boolean supportsTag(String name) - { - return maskedTags .contains(name); - } - - public ACLPlugin newInstance(Configuration config) - { - return new LegacyAccessPlugin(); - } - }; - - public String getPluginName() - { - return getClass().getSimpleName(); - } - - @Override - protected AuthzResult getResult() - { - // Always abstain - return AuthzResult.ABSTAIN; - } - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java index 3f846b9dd0..62967ef7eb 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.security.auth; -import javax.security.sasl.SaslException; - public class AuthenticationResult { public enum AuthenticationStatus diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 889ce815f4..6ca9c8e762 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -21,7 +21,7 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 2619a69cfd..5cebb7d2d8 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -38,7 +38,7 @@ import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; -import org.apache.qpid.server.security.access.management.AMQUserManagementMBean; +import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; import org.apache.qpid.AMQException; import javax.management.JMException; @@ -51,7 +51,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configuration) throws Exception { - _logger.info("Initialising PrincipleDatabase authentication manager"); + _logger.info("Initialising PrincipalDatabase authentication manager"); _databases = initialisePrincipalDatabases(_configuration); } @@ -171,16 +171,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); List<String> principalDBs = config.getManagementPrincipalDBs(); - - if (principalDBs.size() == 0) + if (principalDBs.isEmpty()) { throw new ConfigurationException("No principal-database specified for jmx security"); } String databaseName = principalDBs.get(0); - PrincipalDatabase database = getDatabases().get(databaseName); - if (database == null) { throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); @@ -189,14 +186,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab _mbean.setPrincipalDatabase(database); List<String> jmxaccesslist = config.getManagementAccessList(); - - if (jmxaccesslist.size() == 0) + if (jmxaccesslist.isEmpty()) { throw new ConfigurationException("No access control files specified for jmx security"); } String jmxaccesssFile = null; - + try { jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); @@ -205,7 +201,7 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); } - + try { _mbean.setAccessFile(jmxaccesssFile); diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java index 5a2965cb32..153b8c25db 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBean.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -18,51 +18,50 @@ * * */ -package org.apache.qpid.server.security.access.management; +package org.apache.qpid.server.security.auth.management; -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.util.FileUtils; -import org.apache.log4j.Logger; -import org.apache.commons.configuration.ConfigurationException; - -import javax.management.JMException; -import javax.management.remote.JMXPrincipal; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.auth.Subject; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.io.FileOutputStream; -import java.util.Properties; -import java.util.List; +import java.io.IOException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Principal; import java.util.Enumeration; +import java.util.List; +import java.util.Properties; import java.util.Random; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; -import java.security.Principal; -import java.security.AccessControlContext; -import java.security.AccessController; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; +import javax.security.auth.login.AccountNotFoundException; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; /** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ @MBeanDescription("User Management Interface") public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement { - private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); private PrincipalDatabase _principalDatabase; @@ -533,6 +532,8 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana { _logger.debug("Setting Access Rights:" + accessRights); _accessRights = accessRights; - MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + + // TODO check where this is used + // MBeanInvocationHandlerImpl.setAccessRights(_accessRights); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index d34d0c4d27..bc771162fd 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.manager; -import org.apache.qpid.common.Closeable; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.security.auth.AuthenticationResult; - import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import org.apache.qpid.common.Closeable; +import org.apache.qpid.server.security.auth.AuthenticationResult; + public interface AuthenticationManager extends Closeable { String getMechanisms(); diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 98c060599a..2a967f02af 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -64,7 +64,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public PrincipalDatabaseAuthenticationManager(String name, VirtualHostConfiguration hostConfig) throws Exception { _logger.info("Initialising " + (name == null ? "Default" : "'" + name + "'") - + " PrincipleDatabase authentication manager."); + + " PrincipalDatabase authentication manager."); // Fixme This should be done per Vhost but allowing global hack isn't right but ... // required as authentication is done before Vhost selection diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java index 77040e896c..0cbbccb3b8 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -99,7 +99,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator } catch (AccountNotFoundException e) { - throw new SecurityException(INVALID_CREDENTIALS); + throw new SecurityException(INVALID_CREDENTIALS); // XXX } if (authenticated) diff --git a/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java index 6850724b10..6cc5e7b019 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java @@ -62,6 +62,7 @@ import org.apache.qpid.server.handler.TxCommitHandler; import org.apache.qpid.server.handler.TxRollbackHandler; import org.apache.qpid.server.handler.TxSelectHandler; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; /** @@ -258,6 +259,7 @@ public class AMQStateManager implements AMQMethodListener public AMQProtocolSession getProtocolSession() { + SecurityManager.setThreadPrincipal(_protocolSession.getPrincipal()); return _protocolSession; } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java index 5badbad642..1bba2529c6 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java +++ b/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionFactoryImpl.java @@ -20,25 +20,17 @@ */ package org.apache.qpid.server.subscription; -import org.apache.qpid.server.protocol.AMQProtocolSession; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactory; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.AMQException; +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.protocol.AMQProtocolSession; public class SubscriptionFactoryImpl implements SubscriptionFactory { - - /* private SubscriptionFactoryImpl() - { - - }*/ - public Subscription createSubscription(int channelId, AMQProtocolSession protocolSession, AMQShortString consumerTag, boolean acks, FieldTable filters, boolean noLocal, FlowCreditManager creditManager) throws AMQException diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index a56951cf5c..38040ecfce 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.transport; import org.apache.qpid.transport.*; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -29,16 +30,13 @@ import javax.security.sasl.SaslServer; import javax.security.sasl.SaslException; import java.util.*; - public class ServerConnectionDelegate extends ServerDelegate { - private String _localFQDN; private final IApplicationRegistry _appRegistry; - public ServerConnectionDelegate(IApplicationRegistry appRegistry, - String localFQDN) + public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN) { this(new HashMap<String,Object>(Collections.singletonMap("qpid.federation_tag",appRegistry.getBroker().getFederationTag())), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN); } @@ -50,6 +48,7 @@ public class ServerConnectionDelegate extends ServerDelegate String localFQDN) { super(properties, parseToList(appRegistry.getAuthenticationManager().getMechanisms()), locales); + _appRegistry = appRegistry; _localFQDN = localFQDN; } @@ -65,9 +64,9 @@ public class ServerConnectionDelegate extends ServerDelegate return list; } - @Override public ServerSession getSession(Connection conn, SessionAttach atc) + @Override + public ServerSession getSession(Connection conn, SessionAttach atc) { - SessionDelegate serverSessionDelegate = new ServerSessionDelegate(_appRegistry); ServerSession ssn = new ServerSession(conn, serverSessionDelegate, new Binary(atc.getName()), 0); @@ -75,9 +74,6 @@ public class ServerConnectionDelegate extends ServerDelegate return ssn; } - - - @Override protected SaslServer createSaslServer(String mechanism) throws SaslException { @@ -85,11 +81,10 @@ public class ServerConnectionDelegate extends ServerDelegate } - @Override public void connectionOpen(Connection conn, ConnectionOpen open) { ServerConnection sconn = (ServerConnection) conn; - + VirtualHost vhost; String vhostName; if(open.hasVirtualHost()) @@ -102,19 +97,27 @@ public class ServerConnectionDelegate extends ServerDelegate } vhost = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhostName); + SecurityManager.setThreadPrincipal(conn.getAuthorizationID()); + if(vhost != null) { sconn.setVirtualHost(vhost); - sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); - - sconn.setState(Connection.State.OPEN); + if (!vhost.getSecurityManager().accessVirtualhost(vhostName, sconn.getConfig().getAddress())) + { + sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, "Permission denied '"+vhostName+"'")); + sconn.setState(Connection.State.CLOSING); + } + else + { + sconn.invoke(new ConnectionOpenOk(Collections.emptyList())); + sconn.setState(Connection.State.OPEN); + } } else { - sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '" + vhostName + "'")); + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'")); sconn.setState(Connection.State.CLOSING); } - } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 8a16867ad8..bc7ba085fc 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -157,7 +157,6 @@ public class ServerSession extends Session implements PrincipalHolder, SessionCo catch (AMQException e) { // TODO - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. throw new RuntimeException(e); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 541810d2fe..73ec7f1231 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -20,31 +20,78 @@ */ package org.apache.qpid.server.transport; -import org.apache.qpid.transport.*; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.exchange.*; -import org.apache.qpid.server.queue.QueueRegistry; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.AMQUnknownExchangeType; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.exchange.ExchangeFactory; +import org.apache.qpid.server.exchange.ExchangeInUseException; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.HeadersExchange; +import org.apache.qpid.server.flow.FlowCreditManager_0_10; +import org.apache.qpid.server.flow.WindowCreditManager; +import org.apache.qpid.server.message.MessageMetaData_0_10; +import org.apache.qpid.server.message.MessageTransferMessage; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.BaseQueue; -import org.apache.qpid.server.message.MessageTransferMessage; -import org.apache.qpid.server.message.MessageMetaData_0_10; -import org.apache.qpid.server.subscription.Subscription_0_10; -import org.apache.qpid.server.flow.*; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.StoredMessage; -import org.apache.qpid.server.store.DurableConfigurationStore; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnknownExchangeType; -import org.apache.qpid.framing.*; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import java.nio.ByteBuffer; +import org.apache.qpid.server.subscription.Subscription_0_10; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.transport.Acquired; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.ExchangeBind; +import org.apache.qpid.transport.ExchangeBound; +import org.apache.qpid.transport.ExchangeBoundResult; +import org.apache.qpid.transport.ExchangeDeclare; +import org.apache.qpid.transport.ExchangeDelete; +import org.apache.qpid.transport.ExchangeQuery; +import org.apache.qpid.transport.ExchangeQueryResult; +import org.apache.qpid.transport.ExchangeUnbind; +import org.apache.qpid.transport.ExecutionErrorCode; +import org.apache.qpid.transport.ExecutionException; +import org.apache.qpid.transport.MessageAccept; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquire; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCancel; +import org.apache.qpid.transport.MessageFlow; +import org.apache.qpid.transport.MessageFlowMode; +import org.apache.qpid.transport.MessageFlush; +import org.apache.qpid.transport.MessageReject; +import org.apache.qpid.transport.MessageRejectCode; +import org.apache.qpid.transport.MessageRelease; +import org.apache.qpid.transport.MessageResume; +import org.apache.qpid.transport.MessageSetFlowMode; +import org.apache.qpid.transport.MessageStop; +import org.apache.qpid.transport.MessageSubscribe; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Method; +import org.apache.qpid.transport.QueueDeclare; +import org.apache.qpid.transport.QueueDelete; +import org.apache.qpid.transport.QueuePurge; +import org.apache.qpid.transport.QueueQuery; +import org.apache.qpid.transport.QueueQueryResult; +import org.apache.qpid.transport.RangeSet; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionDelegate; +import org.apache.qpid.transport.TxCommit; +import org.apache.qpid.transport.TxRollback; +import org.apache.qpid.transport.TxSelect; public class ServerSessionDelegate extends SessionDelegate { @@ -58,6 +105,8 @@ public class ServerSessionDelegate extends SessionDelegate @Override public void command(Session session, Method method) { + SecurityManager.setThreadPrincipal(session.getConnection().getAuthorizationID()); + super.command(session, method); if (method.isSync()) { @@ -317,7 +366,6 @@ public class ServerSessionDelegate extends SessionDelegate catch (AMQException e) { //TODO - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. throw new RuntimeException(e); } } @@ -371,19 +419,7 @@ public class ServerSessionDelegate extends SessionDelegate } else { - if (!virtualHost.getAccessManager().authoriseCreateExchange((ServerSession)session, method.getAutoDelete(), - method.getDurable(), new AMQShortString(method.getExchange()), false, false, method.getPassive(), - new AMQShortString(method.getType()))) - { - - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - String description = "permission denied: exchange-name '" + exchangeName + "'"; - - exception(session, method, errorCode, description); - - - } - else if(exchange == null) + if (exchange == null) { ExchangeRegistry exchangeRegistry = getExchangeRegistry(session); ExchangeFactory exchangeFactory = virtualHost.getExchangeFactory(); @@ -417,12 +453,18 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.NOT_FOUND, "Unknown Exchange Type: " + method.getType()); } + catch (AMQSecurityException e) + { + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + String description = "Permission denied: exchange-name '" + exchangeName + "'"; + + exception(session, method, errorCode, description); + } catch (AMQException e) { //TODO throw new RuntimeException(e); } - } else { @@ -478,47 +520,38 @@ public class ServerSessionDelegate extends SessionDelegate VirtualHost virtualHost = getVirtualHost(session); ExchangeRegistry exchangeRegistry = virtualHost.getExchangeRegistry(); - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete((ServerSession)session, - exchangeRegistry.getExchange(method.getExchange()))) - { - exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); - - } - else + try { + Exchange exchange = getExchange(session, method.getExchange()); - try + if(exchange != null && exchange.hasReferrers()) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); + } + else { - Exchange exchange = getExchange(session, method.getExchange()); + exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); - if(exchange != null && exchange.hasReferrers()) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Exchange in use as an alternate exchange"); - } - else + if (exchange.isDurable() && !exchange.isAutoDelete()) { - exchangeRegistry.unregisterExchange(method.getExchange(), method.getIfUnused()); - - if (exchange.isDurable() && !exchange.isAutoDelete()) - { - DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); - store.removeExchange(exchange); - } - + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeExchange(exchange); } } - catch (ExchangeInUseException e) - { - exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); - } - catch (AMQException e) - { - // TODO - throw new RuntimeException(e); - } } - + catch (ExchangeInUseException e) + { + exception(session, method, ExecutionErrorCode.PRECONDITION_FAILED, "Exchange in use"); + } + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + method.getExchange()); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } @Override @@ -582,13 +615,6 @@ public class ServerSessionDelegate extends SessionDelegate { exception(session, method, ExecutionErrorCode.NOT_FOUND, "Exchange: '" + method.getExchange() + "' not found"); } - else if (!virtualHost.getAccessManager().authoriseBind((ServerSession)session, exchange, - queue, new AMQShortString(method.getBindingKey()))) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() - + "' to Queue: '" + method.getQueue() - + "' not allowed"); - } else if(exchange.getTypeShortString().equals(HeadersExchange.TYPE.getName()) && (!method.hasArguments() || method.getArguments() == null || !method.getArguments().containsKey("x-match"))) { exception(session, method, ExecutionErrorCode.INTERNAL_ERROR, "Bindings to an exchange of type " + HeadersExchange.TYPE.getName() + " require an x-match header"); @@ -600,8 +626,15 @@ public class ServerSessionDelegate extends SessionDelegate if (!exchange.isBound(routingKey, fieldTable, queue)) { - virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); - + try + { + virtualHost.getBindingFactory().addBinding(method.getBindingKey(), queue, exchange, method.getArguments()); + } + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Bind Exchange: '" + method.getExchange() + + "' to Queue: '" + method.getQueue() + "' not allowed"); + } } else { @@ -649,7 +682,14 @@ public class ServerSessionDelegate extends SessionDelegate } else { - virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); + try + { + virtualHost.getBindingFactory().removeBinding(method.getBindingKey(), queue, exchange, null); + } + catch (AMQSecurityException e) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied"); + } } } @@ -768,25 +808,6 @@ public class ServerSessionDelegate extends SessionDelegate DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); String queueName = method.getQueue(); - - if (!method.getPassive()) - { - // Perform ACL if request is not passive - - if (!virtualHost.getAccessManager().authoriseCreateQueue(((ServerSession)session), method.getAutoDelete(), method.getDurable(), - method.getExclusive(), false, method.getPassive(), new AMQShortString(queueName))) - { - ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; - String description = "permission denied: queue-name '" + queueName + "'"; - - exception(session, method, errorCode, description); - - // TODO control flow - return; - } - } - - AMQQueue queue; QueueRegistry queueRegistry = getQueueRegistry(session); //TODO: do we need to check that the queue already exists with exactly the same "configuration"? @@ -879,34 +900,32 @@ public class ServerSessionDelegate extends SessionDelegate { final AMQQueue q = queue; final ServerSession.Task deleteQueueTask = new ServerSession.Task() - { - - public void doTask(ServerSession session) { - try + public void doTask(ServerSession session) { - q.delete(); + try + { + q.delete(); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } - catch (AMQException e) - { - throw new RuntimeException(e); - } - } - }; + }; final ServerSession s = (ServerSession) session; s.addSessionCloseTask(deleteQueueTask); queue.addQueueDeleteTask(new AMQQueue.Task() - { - - public void doTask(AMQQueue queue) throws AMQException { - s.removeSessionCloseTask(deleteQueueTask); - } - }); + public void doTask(AMQQueue queue) throws AMQException + { + s.removeSessionCloseTask(deleteQueueTask); + } + }); } else if(method.getExclusive()) { - { final AMQQueue q = queue; final ServerSession.Task removeExclusive = new ServerSession.Task() { @@ -928,31 +947,34 @@ public class ServerSessionDelegate extends SessionDelegate } }); } - } + } + catch (AMQSecurityException e) + { + String description = "Cannot declare queue('" + queueName + "'), permission denied"; + ExecutionErrorCode errorCode = ExecutionErrorCode.NOT_ALLOWED; + exception(session, method, errorCode, description); } catch (AMQException e) { + // TODO throw new RuntimeException(e); } } } else if (method.getExclusive() && (queue.getPrincipalHolder() != null && !queue.getPrincipalHolder().equals(session))) { - String description = "Cannot declare queue('" + queueName + "')," + " as exclusive queue with same name " + "declared on another session"; ExecutionErrorCode errorCode = ExecutionErrorCode.RESOURCE_LOCKED; - + exception(session, method, errorCode, description); - + return; } - } } - protected AMQQueue createQueue(final String queueName, QueueDeclare body, VirtualHost virtualHost, @@ -963,15 +985,14 @@ public class ServerSessionDelegate extends SessionDelegate String owner = body.getExclusive() ? session.getClientID() : null; - final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), + final AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(queueName, body.getDurable(), owner, body.getAutoDelete(), body.getExclusive(), virtualHost, body.getArguments()); - if (body.getExclusive() && !body.getDurable()) { final ServerSession.Task deleteQueueTask = new ServerSession.Task() - { + { public void doTask(ServerSession session) { if (registry.getQueue(queueName) == queue) @@ -1006,7 +1027,6 @@ public class ServerSessionDelegate extends SessionDelegate @Override public void queueDelete(Session session, QueueDelete method) { - String queueName = method.getQueue(); if(queueName == null || queueName.length()==0) { @@ -1041,36 +1061,28 @@ public class ServerSessionDelegate extends SessionDelegate else { VirtualHost virtualHost = getVirtualHost(session); - - //Perform ACLs - if (!virtualHost.getAccessManager().authoriseDelete(((ServerSession)session), queue)) - { - exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Cannot delete queue " + queueName); - } - else + + try { - try - { - int purged = queue.delete(); - if (queue.isDurable() && !queue.isAutoDelete()) - { - DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); - store.removeQueue(queue); - } - - } - catch (AMQException e) + queue.delete(); + if (queue.isDurable() && !queue.isAutoDelete()) { - //TODO - throw new RuntimeException(e); + DurableConfigurationStore store = virtualHost.getDurableConfigurationStore(); + store.removeQueue(queue); } - } - + catch (AMQSecurityException e) + { + exception(session, method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } } } - } @Override @@ -1080,24 +1092,32 @@ public class ServerSessionDelegate extends SessionDelegate if(queueName == null || queueName.length()==0) { exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "No queue name supplied"); - } else { AMQQueue queue = getQueue(session, queueName); - if (queue == null) { exception(session, method, ExecutionErrorCode.NOT_FOUND, "No queue " + queueName + " found"); } else { - //TODO - queue.clearQueue(); + try + { + queue.clearQueue(); + } + catch (AMQSecurityException e) + { + exception(session,method, ExecutionErrorCode.NOT_ALLOWED, "Permission denied: " + queueName); + } + catch (AMQException e) + { + // TODO + throw new RuntimeException(e); + } } } - } @Override diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index 675a6f6a91..98d231a7ea 100755 --- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -102,7 +102,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa if (q == null) { - q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, _virtualHost, + q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, false, _virtualHost, arguments); _virtualHost.getQueueRegistry().registerQueue(q); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 44d178602f..d104209e98 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -20,16 +20,25 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.management.NotCompliantMBeanException; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.AMQBrokerManagerMBean; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import org.apache.qpid.server.virtualhost.plugins.VirtualHostHouseKeepingPlugin; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; @@ -58,29 +67,17 @@ import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.access.ACLManager; -import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; import org.apache.qpid.server.store.ConfigurationRecoveryHandler; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TransactionLog; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; +import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import javax.management.NotCompliantMBeanException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.TimerTask; -import java.util.UUID; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.FutureTask; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class VirtualHostImpl implements Accessable, VirtualHost +public class VirtualHostImpl implements VirtualHost { private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class); @@ -102,7 +99,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost private AuthenticationManager _authenticationManager; - private ACLManager _accessManager; + private SecurityManager _securityManager; private final ScheduledThreadPoolExecutor _houseKeepingTasks; private final IApplicationRegistry _appRegistry; @@ -117,17 +114,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost private final ConcurrentHashMap<BrokerLink,BrokerLink> _links = new ConcurrentHashMap<BrokerLink, BrokerLink>(); private static final int HOUSEKEEPING_SHUTDOWN_TIMEOUT = 5; - public void setAccessableName(String name) - { - _logger.warn("Setting Accessable Name for VirualHost is not allowed. (" - + name + ") ignored remains :" + getAccessableName()); - } - - public String getAccessableName() - { - return _name; - } - public IConnectionRegistry getConnectionRegistry() { return _connectionRegistry; @@ -140,7 +126,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost public UUID getId() { - return _id; //To change body of implemented methods use File | Settings | File Templates. + return _id; } public VirtualHostConfigType getConfigType() @@ -200,12 +186,17 @@ public class VirtualHostImpl implements Accessable, VirtualHost private VirtualHostImpl(IApplicationRegistry appRegistry, VirtualHostConfiguration hostConfig, MessageStore store) throws Exception { + if (hostConfig == null) + { + throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); + } + _appRegistry = appRegistry; - _broker = appRegistry.getBroker(); + _broker = _appRegistry.getBroker(); _configuration = hostConfig; - _name = hostConfig.getName(); + _name = _configuration.getName(); - _id = appRegistry.getConfigStore().createId(); + _id = _appRegistry.getConfigStore().createId(); CurrentActor.get().message(VirtualHostMessages.VHT_CREATED(_name)); @@ -214,6 +205,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost throw new IllegalArgumentException("Illegal name (" + _name + ") for virtualhost."); } + _securityManager = new SecurityManager(_appRegistry.getSecurityManager()); + _securityManager.configureHostPlugins(_configuration); + _virtualHostMBean = new VirtualHostMBean(); _connectionRegistry = new ConnectionRegistry(); @@ -223,15 +217,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost _queueRegistry = new DefaultQueueRegistry(this); _exchangeFactory = new DefaultExchangeFactory(this); - _exchangeFactory.initialise(hostConfig); + _exchangeFactory.initialise(_configuration); _exchangeRegistry = new DefaultExchangeRegistry(this); - - //Create a temporary RT to store the durable entries from the config file - // so we can replay them in to the real _RT after it has been loaded. - /// This should be removed after the _RT has been fully split from the the TL - StartupRoutingTable configFileRT = new StartupRoutingTable(); _durableConfigurationStore = configFileRT; @@ -241,7 +230,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost _bindingFactory = new BindingFactory(this); - initialiseModel(hostConfig); + initialiseModel(_configuration); if (store != null) { @@ -250,36 +239,10 @@ public class VirtualHostImpl implements Accessable, VirtualHost } else { - if (hostConfig == null) - { - throw new IllegalAccessException("HostConfig and MessageStore cannot be null"); - } - initialiseMessageStore(hostConfig); - } - - - - //Now that the RT has been initialised loop through the persistent queues/exchanges created from the config - // file and write them in to the new routing Table. -/* for (StartupRoutingTable.CreateQueueTuple cqt : configFileRT.queue) - { - getDurableConfigurationStore().createQueue(cqt.queue, cqt.arguments); + initialiseMessageStore(hostConfig); } - - for (Exchange exchange : configFileRT.exchange) - { - getDurableConfigurationStore().createExchange(exchange); - } - - for (StartupRoutingTable.CreateBindingTuple cbt : configFileRT.bindings) - { - getDurableConfigurationStore().bindQueue(cbt.exchange, cbt.routingKey, cbt.queue, cbt.arguments); - }*/ - - _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, hostConfig); - - _accessManager = ApplicationRegistry.getInstance().getAccessManager(); - _accessManager.configureHostPlugins(hostConfig.getSecurityConfiguration()); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(_name, _configuration); _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); _brokerMBean.register(); @@ -330,8 +293,7 @@ public class VirtualHostImpl implements Accessable, VirtualHost } Map<String, VirtualHostPluginFactory> plugins = - ApplicationRegistry.getInstance(). - getPluginManager().getVirtualHostPlugins(); + ApplicationRegistry.getInstance().getPluginManager().getVirtualHostPlugins(); if (plugins != null) { @@ -340,24 +302,6 @@ public class VirtualHostImpl implements Accessable, VirtualHost try { VirtualHostPlugin plugin = plugins.get(pluginName).newInstance(this); - - TimeUnit units = TimeUnit.MILLISECONDS; - - if (plugin.getTimeUnit() != null) - { - try - { - units = TimeUnit.valueOf(plugin.getTimeUnit()); - } - catch (IllegalArgumentException iae) - { - _logger.warn("Plugin:" + pluginName + - " provided an illegal TimeUnit value:" - + plugin.getTimeUnit()); - // Warn and use default of millseconds - // Should not occur in a well behaved plugin - } - } _houseKeepingTasks.scheduleAtFixedRate(plugin, plugin.getDelay() / 2, plugin.getDelay(), plugin.getTimeUnit()); @@ -600,9 +544,9 @@ public class VirtualHostImpl implements Accessable, VirtualHost return _authenticationManager; } - public ACLManager getAccessManager() + public SecurityManager getSecurityManager() { - return _accessManager; + return _securityManager; } public void close() diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java index 59ab7ec673..26eb5bbd7f 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java +++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/plugins/VirtualHostPlugin.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.virtualhost.plugins; +import java.util.concurrent.TimeUnit; + import org.apache.qpid.server.plugins.Plugin; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -39,5 +41,5 @@ public interface VirtualHostPlugin extends Runnable, Plugin * @see java.util.concurrent.TimeUnit for valid value. * @return */ - public String getTimeUnit(); + public TimeUnit getTimeUnit(); } |