summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ritchie <ritchiem@apache.org>2009-04-13 11:45:24 +0000
committerMartin Ritchie <ritchiem@apache.org>2009-04-13 11:45:24 +0000
commitb5e656e4135a2c879512e4be996bc405135eb287 (patch)
tree5c5d1955eb26e422ded756a5c9fdf135c92e5969
parent74f3baec729eda36d10d1f11f4c3d14eef1a25bf (diff)
downloadqpid-python-b5e656e4135a2c879512e4be996bc405135eb287.tar.gz
Merge branch 'QPID-1583'
merged from trunk r743304 git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/0.5-fix@764418 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java99
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java44
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java146
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java267
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java3
5 files changed, 557 insertions, 2 deletions
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
new file mode 100644
index 0000000000..682135bc25
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AbstractACLPlugin.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+/**
+ * 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(AMQProtocolSession session, Exchange exch, AMQQueue queue,
+ AMQShortString routingKey)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConsume(AMQProtocolSession session, boolean noAck, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseConsume(AMQProtocolSession session, boolean exclusive, boolean noAck, boolean noLocal,
+ boolean nowait, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseCreateExchange(AMQProtocolSession 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(AMQProtocolSession session, boolean autoDelete, boolean durable,
+ boolean exclusive, boolean nowait, boolean passive, AMQShortString queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authorisePublish(AMQProtocolSession session, boolean immediate, boolean mandatory,
+ AMQShortString routingKey, Exchange e)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authorisePurge(AMQProtocolSession session, AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+
+ public AuthzResult authoriseUnbind(AMQProtocolSession session, Exchange exch, AMQShortString routingKey,
+ AMQQueue queue)
+ {
+ return DEFAULT_ANSWER;
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java
new file mode 100644
index 0000000000..7fcf4a0494
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallFactory.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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.network;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+
+public class FirewallFactory implements ACLPluginFactory
+{
+
+ @Override
+ public ACLPlugin newInstance(Configuration config)
+ {
+ FirewallPlugin plugin = new FirewallPlugin();
+ plugin.setConfiguration(config);
+ return plugin;
+ }
+
+ @Override
+ public boolean supportsTag(String name)
+ {
+ return name.equals("firewall");
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
new file mode 100644
index 0000000000..c0089d5e12
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/network/FirewallPlugin.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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.network;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.security.access.plugins.AbstractACLPlugin;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.util.NetMatcher;
+
+import sun.net.util.IPAddressUtil;
+
+public class FirewallPlugin extends AbstractACLPlugin
+{
+
+ public class FirewallRule
+ {
+
+ private AuthzResult _access;
+ private NetMatcher _network;
+ private Pattern _hostnamePattern;
+
+ public FirewallRule(String access, String network, String hostname)
+ {
+ _access = (access.equals("allow")) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
+ _network = (network != null) ? new NetMatcher(new String[]{network}) : null;
+ _hostnamePattern = (hostname != null) ? Pattern.compile(hostname) : null;
+ }
+
+ public boolean match(InetAddress remote)
+ {
+ if (_hostnamePattern != null)
+ {
+ return _hostnamePattern.matcher(remote.getCanonicalHostName()).matches();
+ }
+ else
+ {
+ return _network.matchInetNetwork(remote);
+ }
+ }
+
+ public AuthzResult getAccess()
+ {
+ return _access;
+ }
+
+ }
+
+ private AuthzResult _default = AuthzResult.ABSTAIN;
+ private FirewallRule[] _rules;
+
+ @Override
+ public AuthzResult authoriseConnect(AMQProtocolSession session, VirtualHost virtualHost)
+ {
+ if (!(session instanceof AMQMinaProtocolSession))
+ {
+ return AuthzResult.ABSTAIN; // We only deal with tcp sessions, which mean MINA right now
+ }
+
+ InetAddress addr = getInetAdressFromMinaSession((AMQMinaProtocolSession) session);
+
+ if (addr == null)
+ {
+ return AuthzResult.ABSTAIN; // Not an Inet socket on the other end
+ }
+
+ boolean match = false;
+ for (FirewallRule rule : _rules)
+ {
+ match = rule.match(addr);
+ if (match)
+ {
+ return rule.getAccess();
+ }
+ }
+ return _default;
+
+ }
+
+ private InetAddress getInetAdressFromMinaSession(AMQMinaProtocolSession session)
+ {
+ SocketAddress remote = session.getIOSession().getRemoteAddress();
+ if (remote instanceof InetSocketAddress)
+ {
+ return ((InetSocketAddress) remote).getAddress();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public void setConfiguration(Configuration config)
+ {
+ // Get default action
+ String defaultAction = config.getString("[@default-action]");
+ if (defaultAction == null) {
+ _default = AuthzResult.ABSTAIN;
+ }
+ else if (defaultAction.toLowerCase().equals("allow"))
+ {
+ _default = AuthzResult.ALLOWED;
+ }
+ else
+ {
+ _default = AuthzResult.DENIED;
+ }
+
+ int numRules = config.getList("rule[@access]").size(); // all rules must
+ // have an access
+ // attribute
+ _rules = new FirewallRule[numRules];
+ for (int i = 0; i < numRules; i++)
+ {
+ FirewallRule rule = new FirewallRule((String) config.getProperty("rule(" + i + ")[@access]"),
+ (String) config.getProperty("rule(" + i + ")[@network]"), (String) config.getProperty("rule(" + i
+ + ")[@hostname]"));
+ _rules[i] = rule;
+ }
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java
new file mode 100644
index 0000000000..5229146847
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java
@@ -0,0 +1,267 @@
+/*
+ *
+ * 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.network;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.mina.common.IoSession;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
+import org.apache.qpid.server.protocol.TestIoSession;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+
+public class FirewallPluginTest extends TestCase
+{
+
+ public class RuleInfo
+ {
+ private String _access;
+ private String _network;
+ private String _hostname;
+
+ public void setAccess(String _access)
+ {
+ this._access = _access;
+ }
+
+ public String getAccess()
+ {
+ return _access;
+ }
+
+ public void setNetwork(String _network)
+ {
+ this._network = _network;
+ }
+
+ public String getNetwork()
+ {
+ return _network;
+ }
+
+ public void setHostname(String _hostname)
+ {
+ this._hostname = _hostname;
+ }
+
+ public String getHostname()
+ {
+ return _hostname;
+ }
+ }
+
+ private TestableMemoryMessageStore _store;
+ private VirtualHost _virtualHost;
+ private AMQMinaProtocolSession _session;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _store = new TestableMemoryMessageStore();
+ _virtualHost = new VirtualHost("vhost", _store);
+ TestIoSession iosession = new TestIoSession();
+ iosession.setAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = null;
+ AMQCodecFactory codecFactory = new AMQCodecFactory(true);
+ _session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
+ }
+
+ private FirewallPlugin initialisePlugin(String defaultAction, RuleInfo[] rules) throws IOException, ConfigurationException
+ {
+ // Create sample config file
+ File confFile = File.createTempFile(getClass().getSimpleName()+"conffile", null);
+ confFile.deleteOnExit();
+ BufferedWriter buf = new BufferedWriter(new FileWriter(confFile));
+ buf.write("<firewall default-action=\""+defaultAction+"\">\n");
+ if (rules != null)
+ {
+ for (RuleInfo rule : rules)
+ {
+ buf.write("<rule");
+ buf.write(" access=\""+rule.getAccess()+"\"");
+ if (rule.getHostname() != null)
+ {
+ buf.write(" hostname=\""+rule.getHostname()+"\"");
+ }
+ if (rule.getNetwork() != null)
+ {
+ buf.write(" network=\""+rule.getNetwork()+"\"");
+ }
+ buf.write("/>\n");
+ }
+ }
+ buf.write("</firewall>");
+ buf.close();
+
+ // Configure plugin
+ FirewallPlugin plugin = new FirewallPlugin();
+ plugin.setConfiguration(new XMLConfiguration(confFile));
+ return plugin;
+ }
+
+ private FirewallPlugin initialisePlugin(String string) throws ConfigurationException, IOException
+ {
+ return initialisePlugin(string, null);
+ }
+
+ public void testDefaultAction() throws Exception
+ {
+ // Test simple deny
+ FirewallPlugin plugin = initialisePlugin("deny");
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Test simple allow
+ plugin = initialisePlugin("allow");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+
+ public void testSingleIPRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleNetworkRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.0/24");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setHostname(new InetSocketAddress("127.0.0.1", 5672).getHostName());
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostWilcardRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setHostname(".*ocal.*");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralFirstAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.23");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("deny");
+ thirdRule.setHostname("localhost");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralLastAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("deny");
+ firstRule.setHostname("localhost");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("allow");
+ thirdRule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testNetmask() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.0/24");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java b/qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
index 4ffc32c218..4c653e6ca0 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
@@ -18,9 +18,8 @@
package org.apache.qpid.util;
import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
public class NetMatcher