awips2/rpms/awips2.qpid/0.18/SOURCES/mrg.patch
Steve Harris fd735b8ff8 13.3.1-12 baseline
Former-commit-id: 6f374b35d0 [formerly be96282207] [formerly 0be473728a] [formerly 6f374b35d0 [formerly be96282207] [formerly 0be473728a] [formerly aaac0b51e5 [formerly 0be473728a [formerly 1f109861760e5fbc9d7a13cc4f518341cbc31276]]]]
Former-commit-id: aaac0b51e5
Former-commit-id: bb30a41300 [formerly f80f98cee2] [formerly 4cfa5d11d7d7059b88534daa18142d24f3a6f481 [formerly bc439aee4f]]
Former-commit-id: 5c941816ce99cd7acc86ec8198a9c8d060f02007 [formerly f1d156779a]
Former-commit-id: 120fc26670
2013-03-25 13:27:13 -05:00

4090 lines
194 KiB
Diff

From 862f9df4e6e14995b80f8162601959a61ca765d4 Mon Sep 17 00:00:00 2001
From: Kenneth Giusti <kgiusti@redhat.com>
Date: Wed, 5 Sep 2012 13:25:51 -0400
Subject: [PATCH 01/19] BZ854004: perform header lookup while the message is locked.
---
qpid/cpp/src/qpid/broker/Message.cpp | 9 +++++++++
qpid/cpp/src/qpid/broker/Message.h | 1 +
qpid/cpp/src/qpid/broker/MessageGroupManager.cpp | 13 +++++--------
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index 4dd8a34..1a91504 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -100,6 +100,15 @@ const FieldTable* Message::getApplicationHeaders() const
return getAdapter().getApplicationHeaders(frames);
}
+const FieldTable::ValuePtr Message::getApplicationHeader(const std::string& name) const
+{
+ sys::Mutex::ScopedLock l(lock);
+
+ const FieldTable *ft = getAdapter().getApplicationHeaders(frames);
+ if (!ft) return FieldTable::ValuePtr();
+ return ft->get( name );
+}
+
std::string Message::getAppId() const
{
sys::Mutex::ScopedLock l(lock);
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index 90e4eec..f002001 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -77,6 +77,7 @@ public:
QPID_BROKER_EXTERN std::string getExchangeName() const;
bool isImmediate() const;
QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const;
+ QPID_BROKER_EXTERN const framing::FieldTable::ValuePtr getApplicationHeader(const std::string&) const;
QPID_BROKER_EXTERN std::string getAppId() const;
QPID_BROKER_EXTERN bool isPersistent() const;
bool requiresAccept();
diff --git a/qpid/cpp/src/qpid/broker/MessageGroupManager.cpp b/qpid/cpp/src/qpid/broker/MessageGroupManager.cpp
index 15cd56a..bc5d797 100644
--- a/qpid/cpp/src/qpid/broker/MessageGroupManager.cpp
+++ b/qpid/cpp/src/qpid/broker/MessageGroupManager.cpp
@@ -84,14 +84,11 @@ MessageGroupManager::GroupState& MessageGroupManager::findGroup( const QueuedMes
}
std::string group = defaultGroupId;
- const qpid::framing::FieldTable* headers = qm.payload->getApplicationHeaders();
- if (headers) {
- qpid::framing::FieldTable::ValuePtr id = headers->get( groupIdHeader );
- if (id && id->convertsTo<std::string>()) {
- std::string tmp = id->get<std::string>();
- if (!tmp.empty()) // empty group is reserved
- group = tmp;
- }
+ const qpid::framing::FieldTable::ValuePtr id = qm.payload->getApplicationHeader(groupIdHeader);
+ if (id && id->convertsTo<std::string>()) {
+ std::string tmp = id->get<std::string>();
+ if (!tmp.empty()) // empty group is reserved
+ group = tmp;
}
if (cachedGroup && group == lastGroup) {
--
1.7.1
From ccf535a5a75e413557385adcc6874d8a47af1c17 Mon Sep 17 00:00:00 2001
From: Kenneth Giusti <kgiusti@redhat.com>
Date: Thu, 6 Sep 2012 10:03:44 -0400
Subject: [PATCH 02/19] BZ854004 - remove risky use of broker::Message::getApplicationHeaders()
---
qpid/cpp/src/qpid/broker/Link.cpp | 5 +++--
qpid/cpp/src/qpid/broker/Message.cpp | 11 ++++++++---
qpid/cpp/src/qpid/broker/Message.h | 4 ++++
qpid/cpp/src/qpid/broker/MessageMap.cpp | 5 +++--
qpid/cpp/src/qpid/broker/Queue.cpp | 4 +---
qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp | 5 +++--
qpid/cpp/src/qpid/cluster/CredentialsExchange.cpp | 7 ++++---
7 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/qpid/cpp/src/qpid/broker/Link.cpp b/qpid/cpp/src/qpid/broker/Link.cpp
index 84dd163..a853240 100644
--- a/qpid/cpp/src/qpid/broker/Link.cpp
+++ b/qpid/cpp/src/qpid/broker/Link.cpp
@@ -33,6 +33,7 @@
#include "qpid/broker/AclModule.h"
#include "qpid/broker/Exchange.h"
#include "qpid/UrlArray.h"
+#include "qpid/framing/FieldValue.h"
namespace qpid {
namespace broker {
@@ -95,9 +96,9 @@ public:
void route(broker::Deliverable& msg)
{
if (!link) return;
- const framing::FieldTable* headers = msg.getMessage().getApplicationHeaders();
+ const framing::FieldTable::ValuePtr header = msg.getMessage().getApplicationHeader(FAILOVER_HEADER_KEY);
framing::Array addresses;
- if (headers && headers->getArray(FAILOVER_HEADER_KEY, addresses)) {
+ if (header && framing::getEncodedValue<framing::Array>(header, addresses)) {
// convert the Array of addresses to a single Url container for used with setUrl():
std::vector<Url> urlVec;
Url urls;
diff --git a/qpid/cpp/src/qpid/broker/Message.cpp b/qpid/cpp/src/qpid/broker/Message.cpp
index 1a91504..d8719c7 100644
--- a/qpid/cpp/src/qpid/broker/Message.cpp
+++ b/qpid/cpp/src/qpid/broker/Message.cpp
@@ -94,17 +94,22 @@ bool Message::isImmediate() const
return getAdapter().isImmediate(frames);
}
+const FieldTable* Message::getApplicationHeadersLH() const
+{
+ return getAdapter().getApplicationHeaders(frames);
+}
+
const FieldTable* Message::getApplicationHeaders() const
{
sys::Mutex::ScopedLock l(lock);
- return getAdapter().getApplicationHeaders(frames);
+ return getApplicationHeadersLH();
}
const FieldTable::ValuePtr Message::getApplicationHeader(const std::string& name) const
{
sys::Mutex::ScopedLock l(lock);
- const FieldTable *ft = getAdapter().getApplicationHeaders(frames);
+ const FieldTable *ft = getApplicationHeadersLH();
if (!ft) return FieldTable::ValuePtr();
return ft->get( name );
}
@@ -339,7 +344,7 @@ const std::string X_QPID_TRACE("x-qpid.trace");
bool Message::isExcluded(const std::vector<std::string>& excludes) const
{
sys::Mutex::ScopedLock l(lock);
- const FieldTable* headers = getApplicationHeaders();
+ const FieldTable* headers = getApplicationHeadersLH();
if (headers) {
std::string traceStr = headers->getAsString(X_QPID_TRACE);
if (traceStr.size()) {
diff --git a/qpid/cpp/src/qpid/broker/Message.h b/qpid/cpp/src/qpid/broker/Message.h
index f002001..7af2f00 100644
--- a/qpid/cpp/src/qpid/broker/Message.h
+++ b/qpid/cpp/src/qpid/broker/Message.h
@@ -76,6 +76,9 @@ public:
const boost::shared_ptr<Exchange> getExchange(ExchangeRegistry&) const;
QPID_BROKER_EXTERN std::string getExchangeName() const;
bool isImmediate() const;
+ // Note: getApplicationHeaders() cannot be used when the message is shared between queues (or threads).
+ // The returned FieldTable will be deallocated should another thread rewrite the message headers!
+ // See BZ854004. When in doubt, don't use this method - use getApplicationHeader() instead.
QPID_BROKER_EXTERN const framing::FieldTable* getApplicationHeaders() const;
QPID_BROKER_EXTERN const framing::FieldTable::ValuePtr getApplicationHeader(const std::string&) const;
QPID_BROKER_EXTERN std::string getAppId() const;
@@ -210,6 +213,7 @@ public:
return getHeaderBody()->get<T>(true);
}
qpid::framing::AMQHeaderBody* getHeaderBody();
+ const qpid::framing::FieldTable* getApplicationHeadersLH() const;
};
}}
diff --git a/qpid/cpp/src/qpid/broker/MessageMap.cpp b/qpid/cpp/src/qpid/broker/MessageMap.cpp
index 592f3fe..de0137e 100644
--- a/qpid/cpp/src/qpid/broker/MessageMap.cpp
+++ b/qpid/cpp/src/qpid/broker/MessageMap.cpp
@@ -21,6 +21,7 @@
#include "qpid/broker/MessageMap.h"
#include "qpid/broker/QueuedMessage.h"
#include "qpid/log/Statement.h"
+#include "qpid/framing/FieldValue.h"
#include <algorithm>
namespace qpid {
@@ -42,8 +43,8 @@ bool MessageMap::deleted(const QueuedMessage& message)
std::string MessageMap::getKey(const QueuedMessage& message)
{
- const framing::FieldTable* ft = message.payload->getApplicationHeaders();
- if (ft) return ft->getAsString(key);
+ const framing::FieldTable::ValuePtr val = message.payload->getApplicationHeader(key);
+ if (val && val->convertsTo<std::string>()) return val->get<std::string>();
else return EMPTY;
}
diff --git a/qpid/cpp/src/qpid/broker/Queue.cpp b/qpid/cpp/src/qpid/broker/Queue.cpp
index 3202a26..561ac99 100644
--- a/qpid/cpp/src/qpid/broker/Queue.cpp
+++ b/qpid/cpp/src/qpid/broker/Queue.cpp
@@ -688,9 +688,7 @@ namespace {
: MessageFilter (), header(_header), value(_value) {}
bool match( const QueuedMessage& msg ) const
{
- const qpid::framing::FieldTable* headers = msg.payload->getApplicationHeaders();
- if (!headers) return false;
- FieldTable::ValuePtr h = headers->get(header);
+ const FieldTable::ValuePtr h = msg.payload->getApplicationHeader(header);
if (!h || !h->convertsTo<std::string>()) return false;
return h->get<std::string>() == value;
}
diff --git a/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp b/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
index 3c9e210..c0fe733 100644
--- a/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
+++ b/qpid/cpp/src/qpid/broker/ThresholdAlerts.cpp
@@ -25,6 +25,7 @@
#include "qpid/log/Statement.h"
#include "qpid/management/ManagementAgent.h"
#include "qmf/org/apache/qpid/broker/EventQueueThresholdExceeded.h"
+#include "qpid/framing/FieldValue.h"
namespace qpid {
namespace broker {
@@ -41,8 +42,8 @@ bool isThresholdEvent(const boost::intrusive_ptr<Message> message)
if (message->getIsManagementMessage()) {
//is this a qmf event? if so is it a threshold event?
if (isQMFv2(message)) {
- const qpid::framing::FieldTable* headers = message->getApplicationHeaders();
- if (headers && headers->getAsString("qmf.content") == "_event") {
+ const qpid::framing::FieldTable::ValuePtr header = message->getApplicationHeader("qmf.content");
+ if (header && header->convertsTo<std::string>() && header->get<std::string>() == std::string("_event")) {
//decode as list
std::string content = message->getFrames().getContent();
qpid::types::Variant::List list;
diff --git a/qpid/cpp/src/qpid/cluster/CredentialsExchange.cpp b/qpid/cpp/src/qpid/cluster/CredentialsExchange.cpp
index 416a363..93488a6 100644
--- a/qpid/cpp/src/qpid/cluster/CredentialsExchange.cpp
+++ b/qpid/cpp/src/qpid/cluster/CredentialsExchange.cpp
@@ -23,6 +23,7 @@
#include "qpid/broker/ConnectionState.h"
#include "qpid/framing/reply_exceptions.h"
#include "qpid/sys/Time.h"
+#include "qpid/framing/FieldValue.h"
namespace qpid {
namespace cluster {
@@ -63,7 +64,7 @@ bool CredentialsExchange::check(MemberId member) {
}
void CredentialsExchange::route(broker::Deliverable& msg) {
- const framing::FieldTable* args = msg.getMessage().getApplicationHeaders();
+ const framing::FieldTable::ValuePtr name = msg.getMessage().getApplicationHeader(NAME);
sys::Mutex::ScopedLock l(lock);
const broker::ConnectionState* connection =
static_cast<const broker::ConnectionState*>(msg.getMessage().getPublisher());
@@ -71,10 +72,10 @@ void CredentialsExchange::route(broker::Deliverable& msg) {
throw framing::UnauthorizedAccessException(
QPID_MSG("Unauthorized user " << connection->getUserId() << " for " << NAME
<< ", should be " << username));
- if (!args || !args->isSet(NAME))
+ if (!name)
throw framing::InvalidArgumentException(
QPID_MSG("Invalid message received by " << NAME));
- MemberId member(args->getAsUInt64(NAME));
+ MemberId member(name->getIntegerValue<uint64_t>());
map[member] = sys::AbsTime::now();
}
--
1.7.1
From e4b8f2996de58d5d80a969c804973254bbf569a8 Mon Sep 17 00:00:00 2001
From: Rajith Muditha Attapattu <rajith@apache.org>
Date: Fri, 31 Aug 2012 15:30:55 +0000
Subject: [PATCH 03/19] Bug 852030, QPID-4267: Prevent multiple inclusion of ra.xml and jboss-ra.xml files in JCA jar and JCA rar
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1379478 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/java/jca/build.xml | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/qpid/java/jca/build.xml b/qpid/java/jca/build.xml
index 934514a..3f34cc9 100644
--- a/qpid/java/jca/build.xml
+++ b/qpid/java/jca/build.xml
@@ -29,9 +29,18 @@
<property name="module.resources" value="src/main/resources"/>
- <target name="rar" depends="jar">
- <!--Note we need to do this as we need to keep the ra in the name of the artificats but we can't override the module.jar property which is based on the directory name-->
+ <target name="rar" depends="jar.nomanifest">
+
+ <!--Note we need to do this as we need to keep the ra in the name of the artificats but we can't override the module.jar property which is based on the directory name. Also, we re-jar to avoid duplicate *.xml files in the jar and the rar which is causing EAP deployment issues in later versions.-->
+ <delete file="${build.lib}/${project.name}-${module.name}-${project.version}.jar"/>
+
+ <jar destfile="${module.jar}" basedir="${module.classes}">
+ <metainf dir="${module.metainf}" >
+ <exclude name="**/*.xml"/>
+ </metainf>
+ </jar>
<move file="${build.lib}/${project.name}-${module.name}-${project.version}.jar" tofile="${build.lib}/${project.name}-ra-${project.version}.jar"/>
+
<jar destfile="${module.rar}">
<fileset dir="${module.resources}">
<include name="**/*.xml"/>
--
1.7.1
From cd6505a2a66349390be44712f632d72fcaa66ed7 Mon Sep 17 00:00:00 2001
From: Rajith Muditha Attapattu <rajith@apache.org>
Date: Thu, 6 Sep 2012 14:41:29 +0000
Subject: [PATCH 04/19] Bug 851574, QPID-4288: The pid and platform info are now fetched in a static block
and the cached value is returned.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1381625 13f79535-47bb-0310-9956-ffa450edef68
---
.../qpid/properties/ConnectionStartProperties.java | 27 ++++++++++++++------
1 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
index 15c144b..59a1b6c 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java
@@ -49,7 +49,11 @@ public class ConnectionStartProperties
public static final String SESSION_FLOW = "qpid.session_flow";
- public static int getPID()
+ public static int _pid;
+
+ public static final String _platformInfo;
+
+ static
{
RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean();
String processName = rtb.getName();
@@ -57,23 +61,20 @@ public class ConnectionStartProperties
{
try
{
- return Integer.parseInt(processName.substring(0,processName.indexOf('@')));
+ _pid = Integer.parseInt(processName.substring(0,processName.indexOf('@')));
}
catch(Exception e)
{
LOGGER.warn("Unable to get the PID due to error",e);
- return -1;
+ _pid = -1;
}
}
else
{
LOGGER.warn("Unable to get the PID due to unsupported format : " + processName);
- return -1;
+ _pid = -1;
}
- }
- public static String getPlatformInfo()
- {
StringBuilder fullSystemInfo = new StringBuilder(System.getProperty("java.runtime.name"));
fullSystemInfo.append(", ");
fullSystemInfo.append(System.getProperty("java.runtime.version"));
@@ -88,6 +89,16 @@ public class ConnectionStartProperties
fullSystemInfo.append(", ");
fullSystemInfo.append(System.getProperty("sun.os.patch.level"));
- return fullSystemInfo.toString();
+ _platformInfo = fullSystemInfo.toString();
+ }
+
+ public static int getPID()
+ {
+ return _pid;
+ }
+
+ public static String getPlatformInfo()
+ {
+ return _platformInfo;
}
}
--
1.7.1
From fd604472e4dcc8b5e7042503450a9f81c572dc6a Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Sun, 15 Jul 2012 10:17:26 +0000
Subject: [PATCH 05/19] QPID-3892 C++ broker add routing key wildcard support to Acl 'publish exchange' lookups. Although this patch does not address the original issue's regex request it provides the desired functionality in a more comprehensive manner.
* Acl publish exchange rules may specify routing keys using the topic exchange syntax with '*' and '#' wildcard match tokens.
* Acl lookups hook in to the broker's topic exchange key match code to perform the wildcard match.
* Acl rules written using the old Acl wildcard syntax (with a single trailing '*') will continue to work the same as before.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1361678 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/qpid/acl/AclData.cpp | 81 ++++++++++------------
qpid/cpp/src/qpid/acl/AclData.h | 38 +++++++++--
qpid/cpp/src/qpid/acl/AclReader.cpp | 29 ++++++--
qpid/cpp/src/qpid/acl/AclReader.h | 1 +
qpid/cpp/src/qpid/acl/AclValidator.cpp | 2 +-
qpid/cpp/src/qpid/acl/AclValidator.h | 2 +-
qpid/cpp/src/tests/acl.py | 120 +++++++++++++++++++++++++++++++-
7 files changed, 215 insertions(+), 58 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index da7f240..a07176d 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -305,7 +305,9 @@ namespace acl {
// lookup
//
// The ACL main business logic function of matching rules and declaring
- // an allow or deny result.
+ // an allow or deny result. This lookup is the fastpath per-message
+ // lookup to verify if a user is allowed to publish to an exchange with
+ // a given key.
//
AclResult AclData::lookup(
const std::string& id,
@@ -331,7 +333,8 @@ namespace acl {
if (itrRule != actionList[action][objType]->end() )
{
- //loop the vector
+ // Found a rule list for this user-action-object set.
+ // Search the rule list for a matching rule.
ruleSetItr rsItr = itrRule->second.end();
for (int cnt = itrRule->second.size(); cnt != 0; cnt--)
{
@@ -339,56 +342,46 @@ namespace acl {
QPID_LOG(debug, "ACL: checking rule " << rsItr->toString());
- // loop the names looking for match
+ // Search on exchange name and routing key only if specfied in rule.
bool match =true;
- for (specPropertyMapItr pMItr = rsItr->props.begin();
- (pMItr != rsItr->props.end()) && match;
- pMItr++)
+ if (rsItr->pubExchNameInRule)
{
- //match name is exists first
- switch (pMItr->first)
+ if (matchProp(rsItr->pubExchName, name))
{
- case acl::SPECPROP_NAME:
- if (matchProp(pMItr->second, name))
- {
- QPID_LOG(debug, "ACL: lookup exchange name '"
- << name << "' matched with rule name '"
- << pMItr->second << "'");
-
- }
- else
- {
- match= false;
- QPID_LOG(debug, "ACL: lookup exchange name '"
- << name << "' did not match with rule name '"
- << pMItr->second << "'");
- }
- break;
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '"
+ << name << "' matched with rule name '"
+ << rsItr->pubExchName << "'");
- case acl::SPECPROP_ROUTINGKEY:
- if (matchProp(pMItr->second, routingKey))
- {
- QPID_LOG(debug, "ACL: lookup key name '"
- << routingKey << "' matched with rule routing key '"
- << pMItr->second << "'");
- }
- else
- {
- match= false;
- QPID_LOG(debug, "ACL: lookup key name '"
- << routingKey << "' did not match with rule routing key '"
- << pMItr->second << "'");
- }
- break;
+ }
+ else
+ {
+ match= false;
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '"
+ << name << "' did not match with rule name '"
+ << rsItr->pubExchName << "'");
+ }
+ }
- default:
- // Don't care
- break;
- };
+ if (match && rsItr->pubRoutingKeyInRule)
+ {
+ if (rsItr->matchRoutingKey(routingKey))
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' matched with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ }
+ else
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' did not match with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ match = false;
+ }
}
+
if (match){
aclresult = rsItr->ruleMode;
- QPID_LOG(debug,"ACL: Successful match, the decision is:"
+ QPID_LOG(debug,"ACL: Rule: " << rsItr->rawRuleNum << " Successful match, the decision is:"
<< AclHelper::getAclResultStr(aclresult));
return aclresult;
}
diff --git a/qpid/cpp/src/qpid/acl/AclData.h b/qpid/cpp/src/qpid/acl/AclData.h
index 1c1cb3e..ca0a676 100644
--- a/qpid/cpp/src/qpid/acl/AclData.h
+++ b/qpid/cpp/src/qpid/acl/AclData.h
@@ -21,6 +21,9 @@
*/
#include "qpid/broker/AclModule.h"
+#include "AclTopicMatch.h"
+#include "qpid/log/Statement.h"
+#include "boost/shared_ptr.hpp"
#include <vector>
#include <sstream>
@@ -48,18 +51,29 @@ public:
// A single ACL file entry may create many rule entries in
// many ruleset vectors.
//
- struct rule {
+ struct Rule {
+ typedef broker::TopicExchange::TopicExchangeTester topicTester;
int rawRuleNum; // rule number in ACL file
qpid::acl::AclResult ruleMode; // combined allow/deny log/nolog
specPropertyMap props; //
+ bool pubRoutingKeyInRule;
+ std::string pubRoutingKey;
+ boost::shared_ptr<topicTester> pTTest;
+ bool pubExchNameInRule;
+ std::string pubExchName;
-
- rule (int ruleNum, qpid::acl::AclResult res, specPropertyMap& p) :
+ Rule (int ruleNum, qpid::acl::AclResult res, specPropertyMap& p) :
rawRuleNum(ruleNum),
ruleMode(res),
- props(p)
- {};
+ props(p),
+ pubRoutingKeyInRule(false),
+ pubRoutingKey(),
+ pTTest(boost::shared_ptr<topicTester>(new topicTester())),
+ pubExchNameInRule(false),
+ pubExchName()
+ {}
+
std::string toString () const {
std::ostringstream ruleStr;
@@ -76,9 +90,21 @@ public:
ruleStr << " }]";
return ruleStr.str();
}
+
+ void addTopicTest(const std::string& pattern) {
+ pTTest->addBindingKey(broker::TopicExchange::normalize(pattern));
+ }
+
+ // Topic Exchange tester
+ // return true if any bindings match 'pattern'
+ bool matchRoutingKey(const std::string& pattern) const
+ {
+ topicTester::BindingVec bv;
+ return pTTest->findMatches(pattern, bv);
+ }
};
- typedef std::vector<rule> ruleSet;
+ typedef std::vector<Rule> ruleSet;
typedef ruleSet::const_iterator ruleSetItr;
typedef std::map<std::string, ruleSet > actionObject; // user
typedef actionObject::iterator actObjItr;
diff --git a/qpid/cpp/src/qpid/acl/AclReader.cpp b/qpid/cpp/src/qpid/acl/AclReader.cpp
index 0830f3f..f9be49b 100644
--- a/qpid/cpp/src/qpid/acl/AclReader.cpp
+++ b/qpid/cpp/src/qpid/acl/AclReader.cpp
@@ -101,7 +101,7 @@ namespace acl {
<< AclHelper::getAclResultStr(d->decisionMode));
foundmode = true;
} else {
- AclData::rule rule(cnt, (*i)->res, (*i)->props);
+ AclData::Rule rule(cnt, (*i)->res, (*i)->props);
// Action -> Object -> map<user -> set<Rule> >
std::ostringstream actionstr;
@@ -110,8 +110,27 @@ namespace acl {
(*i)->actionAll ? acnt++ : acnt = acl::ACTIONSIZE) {
if (acnt == acl::ACT_PUBLISH)
+ {
d->transferAcl = true; // we have transfer ACL
-
+ // For Publish the only object should be Exchange
+ // and the only property should be routingkey.
+ // Go through the rule properties and find the name and the key.
+ // If found then place them specially for the lookup engine.
+ for (pmCitr pItr=(*i)->props.begin(); pItr!=(*i)->props.end(); pItr++) {
+ if (acl::SPECPROP_ROUTINGKEY == pItr->first)
+ {
+ rule.pubRoutingKeyInRule = true;
+ rule.pubRoutingKey = (std::string)pItr->second;
+ rule.addTopicTest(rule.pubRoutingKey);
+ break;
+ }
+ if (acl::SPECPROP_NAME == pItr->first)
+ {
+ rule.pubExchNameInRule = true;
+ rule.pubExchName = pItr->second;
+ }
+ }
+ }
actionstr << AclHelper::getActionStr((Action) acnt) << ",";
//find the Action, create if not exist
@@ -285,7 +304,7 @@ namespace acl {
if (ws) {
ret = true;
} else {
- errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
<< ", Non-continuation line must start with \"group\" or \"acl\".";
ret = false;
}
@@ -330,7 +349,7 @@ namespace acl {
} else {
const unsigned minimumSize = (cont ? 2 : 3);
if (toksSize < minimumSize) {
- errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
+ errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
<< ", Insufficient tokens for group definition.";
return false;
}
@@ -479,7 +498,7 @@ namespace acl {
nvPair propNvp = splitNameValuePair(toks[i]);
if (propNvp.second.size() == 0) {
errorStream << ACL_FORMAT_ERR_LOG_PREFIX << "Line : " << lineNumber
- <<", Badly formed property name-value pair \""
+ <<", Badly formed property name-value pair \""
<< propNvp.first << "\". (Must be name=value)";
return false;
}
diff --git a/qpid/cpp/src/qpid/acl/AclReader.h b/qpid/cpp/src/qpid/acl/AclReader.h
index 730013f..6351c1e 100644
--- a/qpid/cpp/src/qpid/acl/AclReader.h
+++ b/qpid/cpp/src/qpid/acl/AclReader.h
@@ -26,6 +26,7 @@
#include <string>
#include <vector>
#include <sstream>
+#include <memory>
#include "qpid/acl/AclData.h"
#include "qpid/broker/AclModule.h"
diff --git a/qpid/cpp/src/qpid/acl/AclValidator.cpp b/qpid/cpp/src/qpid/acl/AclValidator.cpp
index 49bb65d..85f0f7c 100644
--- a/qpid/cpp/src/qpid/acl/AclValidator.cpp
+++ b/qpid/cpp/src/qpid/acl/AclValidator.cpp
@@ -131,7 +131,7 @@ namespace acl {
boost::bind(&AclValidator::validateRule, this, _1));
}
- void AclValidator::validateRule(qpid::acl::AclData::rule& rule){
+ void AclValidator::validateRule(qpid::acl::AclData::Rule& rule){
std::for_each(rule.props.begin(),
rule.props.end(),
boost::bind(&AclValidator::validateProperty, this, _1));
diff --git a/qpid/cpp/src/qpid/acl/AclValidator.h b/qpid/cpp/src/qpid/acl/AclValidator.h
index f85c241..76eb222 100644
--- a/qpid/cpp/src/qpid/acl/AclValidator.h
+++ b/qpid/cpp/src/qpid/acl/AclValidator.h
@@ -71,7 +71,7 @@ class AclValidator {
public:
void validateRuleSet(std::pair<const std::string, qpid::acl::AclData::ruleSet>& rules);
- void validateRule(qpid::acl::AclData::rule& rule);
+ void validateRule(qpid::acl::AclData::Rule& rule);
void validateProperty(std::pair<const qpid::acl::SpecProperty, std::string>& prop);
void validate(boost::shared_ptr<AclData> d);
AclValidator();
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 663af3e..0e096a6 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -310,7 +310,7 @@ class ACLTests(TestBase010):
self.fail("ACL should allow queue create request");
self.fail("Error during queue create request");
-
+
def test_user_realm(self):
"""
@@ -1537,6 +1537,124 @@ class ACLTests(TestBase010):
#=====================================
+ # QMF Topic Exchange tests
+ #=====================================
+
+ def test_qmf_topic_exchange_tests(self):
+ """
+ Test using QMF method hooks into ACL logic
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ aclf.write('acl allow-log uPlain1@COMPANY publish exchange name=X routingkey=ab.cd.e\n')
+ aclf.write('acl allow-log uPlain2@COMPANY publish exchange name=X routingkey=.\n')
+ aclf.write('acl allow-log uStar1@COMPANY publish exchange name=X routingkey=a.*.b\n')
+ aclf.write('acl allow-log uStar2@COMPANY publish exchange name=X routingkey=*.x\n')
+ aclf.write('acl allow-log uStar3@COMPANY publish exchange name=X routingkey=x.x.*\n')
+ aclf.write('acl allow-log uHash1@COMPANY publish exchange name=X routingkey=a.#.b\n')
+ aclf.write('acl allow-log uHash2@COMPANY publish exchange name=X routingkey=a.#\n')
+ aclf.write('acl allow-log uHash3@COMPANY publish exchange name=X routingkey=#.a\n')
+ aclf.write('acl allow-log uHash4@COMPANY publish exchange name=X routingkey=a.#.b.#.c\n')
+ aclf.write('acl allow-log uMixed1@COMPANY publish exchange name=X routingkey=*.x.#.y\n')
+ aclf.write('acl allow-log uMixed2@COMPANY publish exchange name=X routingkey=a.#.b.*\n')
+ aclf.write('acl allow-log uMixed3@COMPANY publish exchange name=X routingkey=*.*.*.#\n')
+
+ aclf.write('acl allow-log all publish exchange name=X routingkey=MN.OP.Q\n')
+ aclf.write('acl allow-log all publish exchange name=X routingkey=M.*.N\n')
+ aclf.write('acl allow-log all publish exchange name=X routingkey=M.#.N\n')
+ aclf.write('acl allow-log all publish exchange name=X routingkey=*.M.#.N\n')
+
+ aclf.write('acl deny-log all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # aclKey: "ab.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "X", "ab.cd.e", "allow-log")
+ self.LookupPublish("uPlain1@COMPANY", "X", "abx.cd.e", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "X", "ab.cd", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "X", "ab.cd..e.", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "X", "ab.cd.e.", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "X", ".ab.cd.e", "deny-log")
+ # aclKey: "."
+ self.LookupPublish("uPlain2@COMPANY", "X", ".", "allow-log")
+
+ # aclKey: "a.*.b"
+ self.LookupPublish("uStar1@COMPANY", "X", "a.xx.b", "allow-log")
+ self.LookupPublish("uStar1@COMPANY", "X", "a.b", "deny-log")
+ # aclKey: "*.x"
+ self.LookupPublish("uStar2@COMPANY", "X", "y.x", "allow-log")
+ self.LookupPublish("uStar2@COMPANY", "X", ".x", "allow-log")
+ self.LookupPublish("uStar2@COMPANY", "X", "x", "deny-log")
+ # aclKey: "x.x.*"
+ self.LookupPublish("uStar3@COMPANY", "X", "x.x.y", "allow-log")
+ self.LookupPublish("uStar3@COMPANY", "X", "x.x.", "allow-log")
+ self.LookupPublish("uStar3@COMPANY", "X", "x.x", "deny-log")
+ self.LookupPublish("uStar3@COMPANY", "X", "q.x.y", "deny-log")
+
+ # aclKey: "a.#.b"
+ self.LookupPublish("uHash1@COMPANY", "X", "a.b", "allow-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "a.x.b", "allow-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "a..x.y.zz.b", "allow-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "a.b.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "q.x.b", "deny-log")
+
+ # aclKey: "a.#"
+ self.LookupPublish("uHash2@COMPANY", "X", "a", "allow-log")
+ self.LookupPublish("uHash2@COMPANY", "X", "a.b", "allow-log")
+ self.LookupPublish("uHash2@COMPANY", "X", "a.b.c", "allow-log")
+
+ # aclKey: "#.a"
+ self.LookupPublish("uHash3@COMPANY", "X", "a", "allow-log")
+ self.LookupPublish("uHash3@COMPANY", "X", "x.y.a", "allow-log")
+
+ # aclKey: "a.#.b.#.c"
+ self.LookupPublish("uHash4@COMPANY", "X", "a.b.c", "allow-log")
+ self.LookupPublish("uHash4@COMPANY", "X", "a.x.b.y.c", "allow-log")
+ self.LookupPublish("uHash4@COMPANY", "X", "a.x.x.b.y.y.c", "allow-log")
+
+ # aclKey: "*.x.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.x.y", "allow-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.x.p.qq.y", "allow-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.a.x.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "aa.x.b.c", "deny-log")
+
+ # aclKey: "a.#.b.*"
+ self.LookupPublish("uMixed2@COMPANY", "X", "a.b.x", "allow-log")
+ self.LookupPublish("uMixed2@COMPANY", "X", "a.x.x.x.b.x", "allow-log")
+
+ # aclKey: "*.*.*.#"
+ self.LookupPublish("uMixed3@COMPANY", "X", "x.y.z", "allow-log")
+ self.LookupPublish("uMixed3@COMPANY", "X", "x.y.z.a.b.c", "allow-log")
+ self.LookupPublish("uMixed3@COMPANY", "X", "x.y", "deny-log")
+ self.LookupPublish("uMixed3@COMPANY", "X", "x", "deny-log")
+
+ # Repeat the keys with wildcard user spec
+ self.LookupPublish("uPlain1@COMPANY", "X", "MN.OP.Q", "allow-log")
+ self.LookupPublish("uStar1@COMPANY" , "X", "M.xx.N", "allow-log")
+ self.LookupPublish("uHash1@COMPANY" , "X", "M.N", "allow-log")
+ self.LookupPublish("uHash1@COMPANY" , "X", "M.x.N", "allow-log")
+ self.LookupPublish("uHash1@COMPANY" , "X", "M..x.y.zz.N", "allow-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.M.N", "allow-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.M.p.qq.N", "allow-log")
+
+ self.LookupPublish("dev@QPID", "X", "MN.OP.Q", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "M.xx.N", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "M.N", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "M.x.N", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "M..x.y.zz.N", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "a.M.N", "allow-log")
+ self.LookupPublish("dev@QPID", "X", "a.M.p.qq.N", "allow-log")
+
+ #=====================================
# Connection limits
#=====================================
--
1.7.1
From d9f282af80d57bdb01a90966178839da5cbf4021 Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Sun, 15 Jul 2012 11:52:47 -0500
Subject: [PATCH 06/19] QPID-4107 r1361334 type in file name
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1361733 13f79535-47bb-0310-9956-ffa450edef68
Conflicts:
qpid/cpp/src/ha.mk
---
qpid/cpp/src/ha.mk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/qpid/cpp/src/ha.mk b/qpid/cpp/src/ha.mk
index 96a3d87..85dd9dd 100644
--- a/qpid/cpp/src/ha.mk
+++ b/qpid/cpp/src/ha.mk
@@ -23,7 +23,7 @@
dmoduleexec_LTLIBRARIES += ha.la
ha_la_SOURCES = \
- qpid/ha/AlternateExchangeSetter.h \
+ qpid/ha/AlternateExchangeSetter.h \
qpid/ha/Backup.cpp \
qpid/ha/Backup.h \
qpid/ha/BackupConnectionExcluder.h \
--
1.7.1
From af60f8280c721dcee9b03b23bff4d89a9d61cf13 Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Mon, 16 Jul 2012 12:58:29 +0000
Subject: [PATCH 07/19] QPID-3892 add missing file
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1362014 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/qpid/acl/AclTopicMatch.h | 89 +++++++++++++++++++++++++++++++++
1 files changed, 89 insertions(+), 0 deletions(-)
create mode 100644 qpid/cpp/src/qpid/acl/AclTopicMatch.h
diff --git a/qpid/cpp/src/qpid/acl/AclTopicMatch.h b/qpid/cpp/src/qpid/acl/AclTopicMatch.h
new file mode 100644
index 0000000..486c229
--- /dev/null
+++ b/qpid/cpp/src/qpid/acl/AclTopicMatch.h
@@ -0,0 +1,89 @@
+#ifndef QPID_ACL_TOPIC_MATCH_H
+#define QPID_ACL_TOPIC_MATCH_H
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/broker/TopicKeyNode.h"
+#include "qpid/broker/TopicExchange.h"
+#include "qpid/log/Statement.h"
+#include "boost/shared_ptr.hpp"
+#include <vector>
+#include <sstream>
+
+namespace qpid {
+namespace broker {
+
+// Class for executing topic exchange routing key matching rules in
+// Acl code the allows or denies users publishing to an exchange.
+class TopicExchange::TopicExchangeTester {
+
+class boundNode;
+
+public:
+ typedef std::vector<bool> BindingVec;
+ typedef TopicKeyNode<boundNode> TestBindingNode;
+
+private:
+ // Target class to be bound into topic key tree
+ class boundNode {
+ public:
+ BindingVec bindingVector;
+ };
+
+ // Acl binding trees contain only one node each.
+ // When the iterator sees it then the node matches the caller's spec.
+ class TestFinder : public TestBindingNode::TreeIterator {
+ public:
+ TestFinder(BindingVec& m) : bv(m), found(false) {};
+ ~TestFinder() {};
+ bool visit(TestBindingNode& /*node*/) {
+ assert(!found);
+ found = true;
+ return true;
+ }
+ BindingVec& bv;
+ bool found;
+ };
+
+public:
+ TopicExchangeTester() {};
+ ~TopicExchangeTester() {};
+ bool addBindingKey(const std::string& bKey) {
+ std::string routingPattern = normalize(bKey);
+ boundNode *mbn = bindingTree.add(routingPattern);
+ if (mbn) {
+ // push a dummy binding to mark this node as "non-leaf"
+ mbn->bindingVector.push_back(true);
+ return true;
+ }
+ return false;
+ }
+
+ bool findMatches(const std::string& rKey, BindingVec& matches) {
+ TestFinder testFinder(matches);
+ bindingTree.iterateMatch( rKey, testFinder );
+ return testFinder.found;
+ }
+
+private:
+ TestBindingNode bindingTree;
+};
+}} // namespace qpid::broker
+
+#endif // QPID_ACL_TOPIC_MATCH_H
--
1.7.1
From c68822714d4da4bee808e19f4b10145b7f4bdcae Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Wed, 15 Aug 2012 14:14:57 +0000
Subject: [PATCH 08/19] NO-JIRA Initialize variable before its use.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1373429 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/tests/acl.py | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 0e096a6..23886d5 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -119,6 +119,7 @@ class ACLTests(TestBase010):
def LookupPublish(self, userName, exchName, keyName, expectedResult):
result = self.acl_lookupPublish(userName, exchName, keyName)
if (result['result'] != expectedResult):
+ suffix = ', [ERROR: Expected= ' + expectedResult
if (result['result'] is None):
suffix = suffix + ', Exception= ' + result['text'] + ']'
else:
--
1.7.1
From 1a5a36a7d839c32d2e6edfe739de379624f3b3ba Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Mon, 20 Aug 2012 20:09:43 +0000
Subject: [PATCH 09/19] QPID-4230 (review 6645) Username substition keywords in Acl file.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1375195 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/qpid/acl/AclData.cpp | 183 +++++++++++-
qpid/cpp/src/qpid/acl/AclData.h | 15 +-
qpid/cpp/src/qpid/acl/AclReader.cpp | 9 +
qpid/cpp/src/qpid/broker/AclModule.h | 4 +-
qpid/cpp/src/tests/acl.py | 540 ++++++++++++++++++++++++++++++++++
5 files changed, 738 insertions(+), 13 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index a07176d..7c14d09 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -25,6 +25,13 @@ namespace qpid {
namespace acl {
//
+ // Instantiate the substitution keyword string
+ //
+ const std::string AclData::USER_SUBSTITUTION_KEYWORD = "${user}";
+ const std::string AclData::DOMAIN_SUBSTITUTION_KEYWORD = "${domain}";
+ const std::string AclData::USERDOMAIN_SUBSTITUTION_KEYWORD = "${userdomain}";
+
+ //
// constructor
//
AclData::AclData():
@@ -147,7 +154,17 @@ namespace acl {
// the calling args and not in the param map.
if (rulePropMapItr->first == acl::SPECPROP_NAME)
{
- if (matchProp(rulePropMapItr->second, name))
+ // substitute user name into object name
+ bool result;
+ if (rsItr->ruleHasUserSub[PROP_NAME]) {
+ std::string sName(rulePropMapItr->second);
+ substituteUserId(sName, id);
+ result = matchProp(sName, name);
+ } else {
+ result = matchProp(rulePropMapItr->second, name);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: lookup name '" << name
<< "' matched with rule name '"
@@ -222,7 +239,20 @@ namespace acl {
break;
default:
- if (matchProp(rulePropMapItr->second, lookupParamItr->second))
+ bool result;
+ if ((SPECPROP_ALTERNATE == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ALTERNATE]) ||
+ (SPECPROP_ROUTINGKEY == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) ||
+ (SPECPROP_QUEUENAME == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_QUEUENAME]))
+ {
+ // These properties are allowed to have username substitution
+ std::string sName(rulePropMapItr->second);
+ substituteUserId(sName, id);
+ result = matchProp(sName, lookupParamItr->second);
+ } else {
+ result = matchProp(rulePropMapItr->second, lookupParamItr->second);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: the pair("
<< AclHelper::getPropertyStr(lookupParamItr->first)
@@ -346,7 +376,18 @@ namespace acl {
bool match =true;
if (rsItr->pubExchNameInRule)
{
- if (matchProp(rsItr->pubExchName, name))
+ // substitute user name into object name
+ bool result;
+
+ if (rsItr->ruleHasUserSub[PROP_NAME]) {
+ std::string sName(rsItr->pubExchName);
+ substituteUserId(sName, id);
+ result = matchProp(sName, name);
+ } else {
+ result = matchProp(rsItr->pubExchName, name);
+ }
+
+ if (result)
{
QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '"
<< name << "' matched with rule name '"
@@ -364,18 +405,40 @@ namespace acl {
if (match && rsItr->pubRoutingKeyInRule)
{
- if (rsItr->matchRoutingKey(routingKey))
+ if ((routingKey.find(USER_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (routingKey.find(DOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (routingKey.find(USERDOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos))
{
- QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
- << routingKey << "' matched with rule routing key '"
- << rsItr->pubRoutingKey << "'");
+ // The user is not allowed to present a routing key with the substitution key in it
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum <<
+ " User-specified routing key has substitution wildcard:" << routingKey
+ << ". Rule match prohibited.");
+ match = false;
}
else
{
- QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
- << routingKey << "' did not match with rule routing key '"
- << rsItr->pubRoutingKey << "'");
- match = false;
+ bool result;
+ if (rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) {
+ std::string sKey(routingKey);
+ substituteKeywords(sKey, id);
+ result = rsItr->matchRoutingKey(sKey);
+ } else {
+ result = rsItr->matchRoutingKey(routingKey);
+ }
+
+ if (result)
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' matched with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ }
+ else
+ {
+ QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '"
+ << routingKey << "' did not match with rule routing key '"
+ << rsItr->pubRoutingKey << "'");
+ match = false;
+ }
}
}
@@ -501,4 +564,102 @@ namespace acl {
return true;
}
+ const std::string DOMAIN_SEPARATOR("@");
+ const std::string PERIOD(".");
+ const std::string UNDERSCORE("_");
+ //
+ // substituteString
+ // Given a name string from an Acl rule, substitute the replacement into it
+ // wherever the placeholder directs.
+ //
+ void AclData::substituteString(std::string& targetString,
+ const std::string& placeholder,
+ const std::string& replacement)
+ {
+ assert (!placeholder.empty());
+ if (placeholder.empty())
+ return;
+ size_t start_pos(0);
+ while((start_pos = targetString.find(placeholder, start_pos)) != std::string::npos)
+ {
+ targetString.replace(start_pos, placeholder.length(), replacement);
+ start_pos += replacement.length();
+ }
+ }
+
+
+ //
+ // normalizeUserId
+ // Given a name string return it in a form usable as topic keys:
+ // change "@" and "." to "_".
+ //
+ std::string AclData::normalizeUserId(const std::string& userId)
+ {
+ std::string normalId(userId);
+ substituteString(normalId, DOMAIN_SEPARATOR, UNDERSCORE);
+ substituteString(normalId, PERIOD, UNDERSCORE);
+ return normalId;
+ }
+
+
+ //
+ // substituteUserId
+ // Given an Acl rule and an authenticated userId
+ // do the keyword substitutions on the rule.
+ //
+ void AclData::AclData::substituteUserId(std::string& ruleString,
+ const std::string& userId)
+ {
+ size_t locDomSeparator(0);
+ std::string user("");
+ std::string domain("");
+ std::string userdomain = normalizeUserId(userId);
+
+ locDomSeparator = userId.find(DOMAIN_SEPARATOR);
+ if (std::string::npos == locDomSeparator) {
+ // "@" not found. There's just a user name
+ user = normalizeUserId(userId);
+ } else {
+ // "@" found, split the names. Domain may be blank.
+ user = normalizeUserId(userId.substr(0,locDomSeparator));
+ domain = normalizeUserId(userId.substr(locDomSeparator+1));
+ }
+
+ substituteString(ruleString, USER_SUBSTITUTION_KEYWORD, user);
+ substituteString(ruleString, DOMAIN_SUBSTITUTION_KEYWORD, domain);
+ substituteString(ruleString, USERDOMAIN_SUBSTITUTION_KEYWORD, userdomain);
+ }
+
+
+ //
+ // substituteKeywords
+ // Given an Acl rule and an authenticated userId
+ // do reverse keyword substitutions on the rule.
+ // That is, replace the normalized name in the rule string with
+ // the keyword that represents it. This stragegy is used for
+ // topic key lookups where the keyword string proper is in the
+ // topic key search tree.
+ //
+ void AclData::AclData::substituteKeywords(std::string& ruleString,
+ const std::string& userId)
+ {
+ size_t locDomSeparator(0);
+ std::string user("");
+ std::string domain("");
+ std::string userdomain = normalizeUserId(userId);
+
+ locDomSeparator = userId.find(DOMAIN_SEPARATOR);
+ if (std::string::npos == locDomSeparator) {
+ // "@" not found. There's just a user name
+ user = normalizeUserId(userId);
+ } else {
+ // "@" found, split the names
+ user = normalizeUserId(userId.substr(0,locDomSeparator));
+ domain = normalizeUserId(userId.substr(locDomSeparator+1));
+ }
+ std::string oRule(ruleString);
+ substituteString(ruleString, userdomain, USERDOMAIN_SUBSTITUTION_KEYWORD);
+ substituteString(ruleString, user, USER_SUBSTITUTION_KEYWORD);
+ substituteString(ruleString, domain, DOMAIN_SUBSTITUTION_KEYWORD);
+ }
}}
diff --git a/qpid/cpp/src/qpid/acl/AclData.h b/qpid/cpp/src/qpid/acl/AclData.h
index ca0a676..b4b13c4 100644
--- a/qpid/cpp/src/qpid/acl/AclData.h
+++ b/qpid/cpp/src/qpid/acl/AclData.h
@@ -62,6 +62,7 @@ public:
boost::shared_ptr<topicTester> pTTest;
bool pubExchNameInRule;
std::string pubExchName;
+ std::vector<bool> ruleHasUserSub;
Rule (int ruleNum, qpid::acl::AclResult res, specPropertyMap& p) :
rawRuleNum(ruleNum),
@@ -71,7 +72,8 @@ public:
pubRoutingKey(),
pTTest(boost::shared_ptr<topicTester>(new topicTester())),
pubExchNameInRule(false),
- pubExchName()
+ pubExchName(),
+ ruleHasUserSub(PROPERTYSIZE, false)
{}
@@ -132,6 +134,17 @@ public:
bool matchProp(const std::string & src, const std::string& src1);
void clear ();
+ static const std::string USER_SUBSTITUTION_KEYWORD;
+ static const std::string DOMAIN_SUBSTITUTION_KEYWORD;
+ static const std::string USERDOMAIN_SUBSTITUTION_KEYWORD;
+ void substituteString(std::string& targetString,
+ const std::string& placeholder,
+ const std::string& replacement);
+ std::string normalizeUserId(const std::string& userId);
+ void substituteUserId(std::string& ruleString,
+ const std::string& userId);
+ void substituteKeywords(std::string& ruleString,
+ const std::string& userId);
AclData();
virtual ~AclData();
diff --git a/qpid/cpp/src/qpid/acl/AclReader.cpp b/qpid/cpp/src/qpid/acl/AclReader.cpp
index f9be49b..fae67d0 100644
--- a/qpid/cpp/src/qpid/acl/AclReader.cpp
+++ b/qpid/cpp/src/qpid/acl/AclReader.cpp
@@ -103,6 +103,15 @@ namespace acl {
} else {
AclData::Rule rule(cnt, (*i)->res, (*i)->props);
+ // Record which properties have the user substitution string
+ for (pmCitr pItr=rule.props.begin(); pItr!=rule.props.end(); pItr++) {
+ if ((pItr->second.find(AclData::USER_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (pItr->second.find(AclData::DOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos) ||
+ (pItr->second.find(AclData::USERDOMAIN_SUBSTITUTION_KEYWORD, 0) != std::string::npos)) {
+ rule.ruleHasUserSub[pItr->first] = true;
+ }
+ }
+
// Action -> Object -> map<user -> set<Rule> >
std::ostringstream actionstr;
for (int acnt = ((*i)->actionAll ? 0 : (*i)->action);
diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h
index f1eb0fc..4caf8ed 100644
--- a/qpid/cpp/src/qpid/broker/AclModule.h
+++ b/qpid/cpp/src/qpid/broker/AclModule.h
@@ -78,7 +78,9 @@ namespace acl {
PROP_SCHEMACLASS,
PROP_POLICYTYPE,
PROP_MAXQUEUESIZE,
- PROP_MAXQUEUECOUNT };
+ PROP_MAXQUEUECOUNT,
+ PROPERTYSIZE // PROPERTYSIZE must be last in list
+ };
// Property used in ACL spec file
// Note for properties common to file processing/rule storage and to
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 23886d5..102796c 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -1704,6 +1704,546 @@ class ACLTests(TestBase010):
result = None
+ #=====================================
+ # User name substitution
+ #=====================================
+
+ def test_user_name_substitution(self):
+ """
+ Test name substitution internals, limits, and edge cases.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}\n')
+ aclf.write('acl allow all create queue name=${userdomain}-tmp\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}-tmp\n')
+ aclf.write('acl allow all create queue name=tmp-${userdomain}-tmp-${userdomain}\n')
+ aclf.write('acl allow all create queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all access queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all purge queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all consume queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all delete queue name=temp0-${userdomain}\n')
+ aclf.write('acl allow all create exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all access exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all bind exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all unbind exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all delete exchange name=temp0-${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=temp0-${userdomain}\n')
+
+ aclf.write('acl allow all publish exchange name=X routingkey=${userdomain}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=a.*.${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=b.#.${userdomain}\n')
+ aclf.write('acl allow all publish exchange name=X routingkey=*.${userdomain}.#.y\n')
+
+ aclf.write('acl allow all create queue name=user-${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=${user}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=a.*.${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=b.#.${user}\n')
+ aclf.write('acl allow all publish exchange name=U routingkey=*.${user}.#.y\n')
+
+ aclf.write('acl allow all create queue name=domain-${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=${domain}.cd.e\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=a.*.${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=b.#.${domain}\n')
+ aclf.write('acl allow all publish exchange name=D routingkey=*.${domain}.#.y\n')
+
+ # Resolving ${user}_${domain} into ${userdomain} works for everything but routing keys
+ aclf.write('acl allow all create queue name=mixed-OK-${user}_${domain}\n')
+ # For routing keys ${user}_${domain} will be parsed into ${userdomain}.
+ # Routing keys not be found when the rule specifies ${user}_${domain}.
+ aclf.write('acl allow all publish exchange name=NOGO routingkey=${user}_${domain}.cd.e\n')
+ # This works since it is does not conflict with ${userdomain}
+ aclf.write('acl allow all publish exchange name=OK routingkey=${user}___${domain}.cd.e\n')
+
+ aclf.write('acl deny-log all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ self.Lookup("alice@QPID", "create", "queue", "tmp-alice_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-tmp", {}, "allow")
+ self.Lookup("charlie@QPID", "create", "queue", "tmp-charlie_QPID-tmp", {}, "allow")
+ self.Lookup("dave@QPID", "create", "queue", "tmp-dave_QPID-tmp-dave_QPID", {}, "allow")
+ self.Lookup("ed@BIG.COM", "create", "queue", "tmp-ed_BIG_COM", {}, "allow")
+ self.Lookup("c.e.r@BIG.GER.COM", "create", "queue", "tmp-c_e_r_BIG_GER_COM", {}, "allow")
+ self.Lookup("c@", "create", "queue", "tmp-c_", {}, "allow")
+ self.Lookup("someuser", "create", "queue", "tmp-someuser", {}, "allow")
+
+ self.Lookup("alice@QPID", "create", "queue", "tmp-${user}", {}, "deny-log")
+
+ self.Lookup("bob@QPID", "create", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "delete", "exchange", "temp0-bob_QPID", {}, "allow")
+ self.LookupPublish("bob@QPID", "temp0-bob_QPID", "x", "allow")
+
+ self.Lookup("bob@QPID", "create", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "access", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "purge", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "consume", "queue", "temp0-bob_QPID", {}, "allow")
+ self.Lookup("bob@QPID", "delete", "queue", "temp0-bob_QPID", {}, "allow")
+
+ self.Lookup("alice@QPID", "access", "queue", "temp0-bob_QPID", {}, "deny-log")
+
+ # aclKey: "${userdomain}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "X", "uPlain1_COMPANY.cd.e", "allow")
+ # aclKey: "a.*.${userdomain}"
+ self.LookupPublish("uStar1@COMPANY", "X", "a.xx.uStar1_COMPANY", "allow")
+ self.LookupPublish("uStar1@COMPANY", "X", "a.b", "deny-log")
+ # aclKey: "b.#.${userdomain}"
+ self.LookupPublish("uHash1@COMPANY", "X", "b.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b.x.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b..x.y.zz.uHash1_COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "X", "b.uHash1_COMPANY.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "X", "q.x.uHash1_COMPANY", "deny-log")
+ # aclKey: "*.${userdomain}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.uMixed1_COMPANY.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.uMixed1_COMPANY.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "X", "a.a.uMixed1_COMPANY.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "X", "aa.uMixed1_COMPANY.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "X", "a.uMixed1_COMPANY_COM.y", "allow")
+
+
+ self.Lookup("bob@QPID", "create", "queue", "user-bob", {}, "allow")
+ # aclKey: "${user}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "U", "uPlain1.cd.e", "allow")
+ # aclKey: "a.*.${user}"
+ self.LookupPublish("uStar1@COMPANY", "U", "a.xx.uStar1", "allow")
+ self.LookupPublish("uStar1@COMPANY", "U", "a.b", "deny-log")
+ # aclKey: "b.#.${user}"
+ self.LookupPublish("uHash1@COMPANY", "U", "b.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b.x.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b..x.y.zz.uHash1", "allow")
+ self.LookupPublish("uHash1@COMPANY", "U", "b.uHash1.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "U", "q.x.uHash1", "deny-log")
+ # aclKey: "*.${user}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.uMixed1.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.uMixed1.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "U", "a.a.uMixed1.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "U", "aa.uMixed1.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "U", "a.uMixed1.y", "allow")
+
+
+ self.Lookup("bob@QPID", "create", "queue", "domain-QPID", {}, "allow")
+ # aclKey: "${domain}.cd.e"
+ self.LookupPublish("uPlain1@COMPANY", "D", "COMPANY.cd.e", "allow")
+ # aclKey: "a.*.${domain}"
+ self.LookupPublish("uStar1@COMPANY", "D", "a.xx.COMPANY", "allow")
+ self.LookupPublish("uStar1@COMPANY", "D", "a.b", "deny-log")
+ # aclKey: "b.#.${domain}"
+ self.LookupPublish("uHash1@COMPANY", "D", "b.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b.x.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b..x.y.zz.COMPANY", "allow")
+ self.LookupPublish("uHash1@COMPANY", "D", "b.COMPANY.", "deny-log")
+ self.LookupPublish("uHash1@COMPANY", "D", "q.x.COMPANY", "deny-log")
+ # aclKey: "*.${domain}.#.y"
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.COMPANY.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.COMPANY.p.qq.y", "allow")
+ self.LookupPublish("uMixed1@COMPANY", "D", "a.a.COMPANY.y", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY", "D", "aa.COMPANY.b.c", "deny-log")
+ self.LookupPublish("uMixed1@COMPANY.COM", "D", "a.COMPANY_COM.y", "allow")
+
+ self.Lookup("uPlain1@COMPANY", "create", "queue", "mixed-OK-uPlain1_COMPANY", {}, "allow")
+ self.LookupPublish("uPlain1@COMPANY", "NOGO", "uPlain1_COMPANY.cd.e", "deny-log")
+ self.LookupPublish("uPlain1@COMPANY", "OK", "uPlain1___COMPANY.cd.e", "allow")
+
+
+ #=====================================
+ # User name substitution details
+ #=====================================
+ # User name substitution allows for three flavors of keyword in the Acl file.
+ # Given a user name of bob.user@QPID.COM the keywords are normalized and resolve as follows:
+ # ${userdomain} - bob_user_QPID_COM
+ # ${user} - bob_user
+ # ${domain} - QPID_COM
+ #
+ # The following substitution tests are very similar but differ in the flavor of keyword used
+ # in the rules. The tests results using the different keywords differ slightly in how permissive
+ # the rules become.
+ # ${userdomain} limits access to one authenticated user
+ # ${user} limits access to a user name regardless of user's domain
+ # ${domain} limits access to a domain regardless of user name
+ #
+
+ def test_user_name_substitution_userdomain(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single alternate exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange:
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${userdomain}-work alternate=${userdomain}-work2\n')
+ aclf.write('acl deny all create queue name=${userdomain}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${userdomain}-work\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work alternate=${userdomain}-work2\n')
+ aclf.write('acl deny all create exchange name=${userdomain}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${userdomain}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${userdomain}-work2\n')
+ aclf.write('acl deny all create exchange name=${userdomain}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${userdomain}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ aclf.write('acl allow all unbind exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${userdomain}-work routingkey=${userdomain} queuename=${userdomain}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${userdomain}-work2 routingkey=${userdomain} queuename=${userdomain}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${userdomain}-work routingkey=${userdomain}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${userdomain}-work2 routingkey=${userdomain}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "joe_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "joe_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {"alternate":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work", {"alternate":"joe_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob_QPID-work2", {"alternate":"someexchange"}, "deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "joe_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "joe_QPID-work2",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work", {"alternate":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob_QPID-work2",{"alternate":"someexchange"}, "deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", { "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe_QPID-work", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", { "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe_QPID-work2", {"routingkey":"bob_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"joe_QPID", "queuename":"bob_QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob_QPID-work2", {"routingkey":"bob_QPID", "queuename":"joe_QPID-work2"}, "deny")
+ # publish
+ self.LookupPublish("bob@QPID", "bob_QPID-work", "bob_QPID", "allow")
+ self.LookupPublish("bob@QPID", "bob_QPID-work2", "bob_QPID", "allow")
+ self.LookupPublish("bob@QPID", "joe_QPID-work", "bob_QPID", "deny")
+ self.LookupPublish("bob@QPID", "joe_QPID-work2", "bob_QPID", "deny")
+ self.LookupPublish("bob@QPID", "bob_QPID-work", "joe_QPID", "deny")
+ self.LookupPublish("bob@QPID", "bob_QPID-work2", "joe_QPID", "deny")
+
+
+ def test_user_name_substitution_user(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single backup exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${user}-work alternate=${user}-work2\n')
+ aclf.write('acl deny all create queue name=${user}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${user}-work\n')
+ aclf.write('acl allow all create exchange name=${user}-work alternate=${user}-work2\n')
+ aclf.write('acl deny all create exchange name=${user}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${user}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${user}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${user}-work2\n')
+ aclf.write('acl deny all create exchange name=${user}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${user}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ aclf.write('acl allow all unbind exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${user}-work routingkey=${user} queuename=${user}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${user}-work2 routingkey=${user} queuename=${user}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${user}-work routingkey=${user}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${user}-work2 routingkey=${user}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "joe-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "joe-work2", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {"alternate":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work", {"alternate":"joe-work2"}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "bob-work2", {"alternate":"someexchange"},"deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "joe-work", {}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "joe-work2",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work", {"alternate":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "bob-work2",{"alternate":"someexchange"},"deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "bind", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "unbind", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", { "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob", "queuename":"bob-work"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe-work", {"routingkey":"bob", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"joe", "queuename":"bob-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work", {"routingkey":"bob", "queuename":"joe-work"}, "deny")
+
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", { "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "allow")
+ self.Lookup("bob@QPID", "access", "exchange", "joe-work2", {"routingkey":"bob", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"joe", "queuename":"bob-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "bob-work2", {"routingkey":"bob", "queuename":"joe-work2"}, "deny")
+ # publish
+ self.LookupPublish("bob@QPID", "bob-work", "bob", "allow")
+ self.LookupPublish("bob@QPID", "bob-work2", "bob", "allow")
+ self.LookupPublish("bob@QPID", "joe-work", "bob", "deny")
+ self.LookupPublish("bob@QPID", "joe-work2", "bob", "deny")
+ self.LookupPublish("bob@QPID", "bob-work", "joe", "deny")
+ self.LookupPublish("bob@QPID", "bob-work2", "joe", "deny")
+
+
+ def test_user_name_substitution_domain(self):
+ """
+ Test a setup where users can create, bind, and publish to a main exchange and queue.
+ Allow access to a single backup exchange and queue.
+ """
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ # Create primary queue and exchange
+ # allow predefined alternate
+ # deny any other alternate
+ # allow no alternate
+ aclf.write('acl allow all create queue name=${domain}-work alternate=${domain}-work2\n')
+ aclf.write('acl deny all create queue name=${domain}-work alternate=*\n')
+ aclf.write('acl allow all create queue name=${domain}-work\n')
+ aclf.write('acl allow all create exchange name=${domain}-work alternate=${domain}-work2\n')
+ aclf.write('acl deny all create exchange name=${domain}-work alternate=*\n')
+ aclf.write('acl allow all create exchange name=${domain}-work\n')
+ # Create backup queue and exchange
+ # Deny any alternate
+ aclf.write('acl deny all create queue name=${domain}-work2 alternate=*\n')
+ aclf.write('acl allow all create queue name=${domain}-work2\n')
+ aclf.write('acl deny all create exchange name=${domain}-work2 alternate=*\n')
+ aclf.write('acl allow all create exchange name=${domain}-work2\n')
+ # Bind/unbind primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ aclf.write('acl allow all unbind exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ # Bind/unbind backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all bind exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ aclf.write('acl allow all unbind exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ # Access primary exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${domain}-work routingkey=${domain} queuename=${domain}-work\n')
+ # Access backup exchange
+ # Use only predefined routingkey and queuename
+ aclf.write('acl allow all access exchange name=${domain}-work2 routingkey=${domain} queuename=${domain}-work2\n')
+ # Publish primary exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${domain}-work routingkey=${domain}\n')
+ # Publish backup exchange
+ # Use only predefined routingkey
+ aclf.write('acl allow all publish exchange name=${domain}-work2 routingkey=${domain}\n')
+ # deny mode
+ aclf.write('acl deny all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ # create queues
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work2", {}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work3", {}, "deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"bob_QPID-work2"},"deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work", {"alternate":"joe_QPID-work2"},"deny")
+ self.Lookup("bob@QPID", "create", "queue", "QPID-work2", {"alternate":"someexchange"}, "deny")
+ # create exchanges
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work", {}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work2",{}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work3",{}, "deny")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work", {"alternate":"QPID-work2"}, "allow")
+ self.Lookup("bob@QPID", "create", "exchange", "QPID-work2",{"alternate":"someexchange"}, "deny")
+ # bind/unbind/access
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "bind", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "unbind", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", { "queuename":"QPID-work"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work", {"routingkey":"QPID", "queuename":"QPID-work"}, "allow")
+
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {"routingkey":"QPID"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", { "queuename":"QPID-work2"}, "deny")
+ self.Lookup("bob@QPID", "access", "exchange", "QPID-work2", {"routingkey":"QPID", "queuename":"QPID-work2"}, "allow")
+ # publish
+ self.LookupPublish("bob@QPID", "QPID-work", "QPID", "allow")
+ self.LookupPublish("bob@QPID", "QPID-work2", "QPID", "allow")
+ self.LookupPublish("joe@QPID", "QPID-work", "QPID", "allow")
+ self.LookupPublish("joe@QPID", "QPID-work2", "QPID", "allow")
+
+
class BrokerAdmin:
def __init__(self, broker, username=None, password=None):
self.connection = qpid.messaging.Connection(broker)
--
1.7.1
From dccba01e71e738e0e3789e062c712da7e6b9e7b3 Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Tue, 21 Aug 2012 14:42:51 +0000
Subject: [PATCH 10/19] QPID-4230 Username substitution keywords in Acl file. Repair function definitions that fail Windows compile.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1375583 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/qpid/acl/AclData.cpp | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index 7c14d09..6994de2 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -607,8 +607,8 @@ namespace acl {
// Given an Acl rule and an authenticated userId
// do the keyword substitutions on the rule.
//
- void AclData::AclData::substituteUserId(std::string& ruleString,
- const std::string& userId)
+ void AclData::substituteUserId(std::string& ruleString,
+ const std::string& userId)
{
size_t locDomSeparator(0);
std::string user("");
@@ -640,8 +640,8 @@ namespace acl {
// topic key lookups where the keyword string proper is in the
// topic key search tree.
//
- void AclData::AclData::substituteKeywords(std::string& ruleString,
- const std::string& userId)
+ void AclData::substituteKeywords(std::string& ruleString,
+ const std::string& userId)
{
size_t locDomSeparator(0);
std::string user("");
--
1.7.1
From 9133f1e58739093af5cdad674e0f2ee30c10188d Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Mon, 20 Aug 2012 15:44:34 -0400
Subject: [PATCH 11/19] This sort of works. It needs some refactoring.
---
qpid/cpp/src/qpid/acl/Acl.cpp | 14 +++-
qpid/cpp/src/qpid/acl/Acl.h | 5 +-
qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp | 116 +++++++++++++++++++++---
qpid/cpp/src/qpid/acl/AclConnectionCounter.h | 35 ++++++--
qpid/cpp/src/qpid/acl/AclPlugin.cpp | 1 +
qpid/cpp/src/qpid/broker/AclModule.h | 5 +
qpid/cpp/src/qpid/broker/Broker.cpp | 5 +
qpid/cpp/src/tests/acl.py | 50 ++++++++++
qpid/cpp/src/tests/run_acl_tests | 16 +++-
9 files changed, 220 insertions(+), 27 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/Acl.cpp b/qpid/cpp/src/qpid/acl/Acl.cpp
index 89c4b34..8116e67 100644
--- a/qpid/cpp/src/qpid/acl/Acl.cpp
+++ b/qpid/cpp/src/qpid/acl/Acl.cpp
@@ -51,7 +51,7 @@ using qpid::management::Args;
namespace _qmf = qmf::org::apache::qpid::acl;
Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), mgmtObject(0),
- connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp, aclValues.aclMaxConnectTotal))
+ connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp, aclValues.aclMaxConnectTotal, aclValues.aclMaxQueuesPerUser))
{
agent = broker->getManagementAgent();
@@ -136,6 +136,18 @@ void Acl::setUserId(const qpid::broker::Connection& connection, const std::strin
}
+bool Acl::approveCreateQueue(const std::string& userId, const std::string& queueName)
+{
+ return connectionCounter->approveCreateQueue(userId, queueName);
+}
+
+
+void Acl::recordDestroyQueue(const std::string& queueName)
+{
+ connectionCounter->recordDestroyQueue(queueName);
+}
+
+
bool Acl::result(
const AclResult& aclreslt,
const std::string& id,
diff --git a/qpid/cpp/src/qpid/acl/Acl.h b/qpid/cpp/src/qpid/acl/Acl.h
index 4787934..918b98c 100644
--- a/qpid/cpp/src/qpid/acl/Acl.h
+++ b/qpid/cpp/src/qpid/acl/Acl.h
@@ -49,6 +49,7 @@ struct AclValues {
uint16_t aclMaxConnectPerUser;
uint16_t aclMaxConnectPerIp;
uint16_t aclMaxConnectTotal;
+ uint16_t aclMaxQueuesPerUser;
};
@@ -92,9 +93,11 @@ public:
const std::string& ExchangeName,
const std::string& RoutingKey);
+ // Resource quota tracking
virtual bool approveConnection(const broker::Connection& connection);
-
virtual void setUserId(const broker::Connection& connection, const std::string& username);
+ virtual bool approveCreateQueue(const std::string& userId, const std::string& queueName);
+ virtual void recordDestroyQueue(const std::string& queueName);
virtual ~Acl();
private:
diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
index 8c6e3ee..56dbced 100644
--- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
+++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
@@ -42,8 +42,10 @@ namespace acl {
//
//
//
-ConnectionCounter::ConnectionCounter(Acl& a, uint16_t nl, uint16_t hl, uint16_t tl) :
- acl(a), nameLimit(nl), hostLimit(hl), totalLimit(tl), totalCurrentConnections(0) {}
+ConnectionCounter::ConnectionCounter(Acl& a, uint16_t nl, uint16_t hl, uint16_t tl, uint16_t ql) :
+ acl(a), nameLimit(nl), hostLimit(hl), totalLimit(tl), queueLimit(ql), totalCurrentConnections(0) {
+ QPID_LOG(critical, "ACL CONNECTION_COUNTER nameLimit:" << nameLimit << ", hostLimit:" << hostLimit << ", totalLimit:" << totalLimit << ", queueLimit:" << queueLimit);
+ }
ConnectionCounter::~ConnectionCounter() {}
@@ -55,7 +57,7 @@ ConnectionCounter::~ConnectionCounter() {}
// Called with lock held.
//
bool ConnectionCounter::limitApproveLH(
- connectCountsMap_t& theMap,
+ countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog) {
@@ -63,7 +65,7 @@ bool ConnectionCounter::limitApproveLH(
bool result(true);
if (theLimit > 0) {
uint16_t count;
- connectCountsMap_t::iterator eRef = theMap.find(theName);
+ countsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
count = (uint16_t)(*eRef).second;
result = count <= theLimit;
@@ -73,9 +75,49 @@ bool ConnectionCounter::limitApproveLH(
}
if (emitLog) {
QPID_LOG(trace, "ACL ConnectionApprover IP=" << theName
- << " limit=" << theLimit
- << " curValue=" << count
- << " result=" << (result ? "allow" : "deny"));
+ << " limit=" << theLimit
+ << " curValue=" << count
+ << " result=" << (result ? "allow" : "deny"));
+ }
+ }
+ return result;
+}
+
+
+//
+// limitApproveLH
+//
+// Resource creation approver.
+// If user is under limit increment count and return true.
+// Called with lock held.
+//
+bool ConnectionCounter::limitApproveLH(
+ const std::string& theTitle,
+ countsMap_t& theMap,
+ const std::string& theName,
+ uint16_t theLimit,
+ bool emitLog) {
+
+ bool result(true);
+ if (theLimit > 0) {
+ uint16_t count;
+ countsMap_t::iterator eRef = theMap.find(theName);
+ if (eRef != theMap.end()) {
+ count = (uint16_t)(*eRef).second;
+ result = count < theLimit;
+ if (result) {
+ count += 1;
+ (*eRef).second = count;
+ }
+ } else {
+ // Not found
+ theMap[theName] = count = 1;
+ }
+ if (emitLog) {
+ QPID_LOG(trace, theTitle << theName
+ << " limit=" << theLimit
+ << " curValue=" << count
+ << " result=" << (result ? "allow" : "deny"));
}
}
return result;
@@ -89,7 +131,7 @@ bool ConnectionCounter::limitApproveLH(
// called with dataLock already taken
//
bool ConnectionCounter::countConnectionLH(
- connectCountsMap_t& theMap,
+ countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog) {
@@ -97,7 +139,7 @@ bool ConnectionCounter::countConnectionLH(
bool result(true);
uint16_t count(0);
if (theLimit > 0) {
- connectCountsMap_t::iterator eRef = theMap.find(theName);
+ countsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
count = (uint16_t)(*eRef).second + 1;
(*eRef).second = count;
@@ -123,10 +165,10 @@ bool ConnectionCounter::countConnectionLH(
// called with dataLock already taken
//
void ConnectionCounter::releaseLH(
- connectCountsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
+ countsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
if (theLimit > 0) {
- connectCountsMap_t::iterator eRef = theMap.find(theName);
+ countsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
uint16_t count = (uint16_t) (*eRef).second;
assert (count > 0);
@@ -174,7 +216,7 @@ void ConnectionCounter::closed(broker::Connection& connection) {
Mutex::ScopedLock locker(dataLock);
- connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ countsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
if (eRef != connectProgressMap.end()) {
if ((*eRef).second == C_OPENED){
// Normal case: connection was created and opened.
@@ -306,7 +348,7 @@ void ConnectionCounter::setUserId(const broker::Connection& connection,
{
Mutex::ScopedLock locker(dataLock);
- connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ countsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
if (eRef != connectProgressMap.end()) {
if ((*eRef).second == C_OPENED){
// Connection has been opened so that current user has been counted
@@ -338,6 +380,54 @@ void ConnectionCounter::setUserId(const broker::Connection& connection,
//
+// approveCreateQueue
+// Count an attempted queue creation by this user.
+// Disapprove if over limit.
+//
+bool ConnectionCounter::approveCreateQueue(const std::string& userId, const std::string& queueName)
+{
+ Mutex::ScopedLock locker(dataLock);
+
+ QPID_LOG(critical, "approveCreateQueue ----------- userId:" << userId << ", queueName:" << queueName);
+
+ bool okByQ = limitApproveLH("ACL Queue creation approver. userId:", queuePerUserMap, userId, queueLimit, true);
+
+ if (okByQ) {
+ // Queue is owned by this userId
+ queueOwnerMap[queueName] = userId;
+
+ QPID_LOG(trace, "ACL create queue approved for user '" << userId
+ << "' queue '" << queueName << "'");
+ } else {
+
+ QPID_LOG(error, "Client max queue count limit of " << queueLimit
+ << " exceeded by '" << userId << "' creating queue '"
+ << queueName << "'. Queue creation denied.");
+ }
+ return okByQ;
+}
+
+
+//
+// recordDestroyQueue
+// Return a destroyed queue to a user's quota
+//
+void ConnectionCounter::recordDestroyQueue(const std::string& queueName)
+{
+ Mutex::ScopedLock locker(dataLock);
+
+ queueOwnerMap_t::iterator eRef = queueOwnerMap.find(queueName);
+ if (eRef != queueOwnerMap.end()) {
+ releaseLH(queuePerUserMap, (*eRef).second, queueLimit);
+
+ queueOwnerMap.erase(eRef);
+ } else {
+ QPID_LOG(notice, "ACL owner for queue '" << queueName
+ << "' not found in owner map");
+ }
+}
+
+//
// getClientIp - given a connection's mgmtId return the client host part.
//
// TODO: Ideally this would be a method of the connection itself.
diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.h b/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
index 54fa693..70c60fb 100644
--- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
+++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
@@ -44,48 +44,63 @@ class Acl;
class ConnectionCounter : public broker::ConnectionObserver
{
private:
- typedef std::map<std::string, uint32_t> connectCountsMap_t;
+ typedef std::map<std::string, uint32_t> countsMap_t;
enum CONNECTION_PROGRESS { C_CREATED=1, C_OPENED=2 };
+ typedef std::map<std::string, std::string> queueOwnerMap_t;
Acl& acl;
uint16_t nameLimit;
uint16_t hostLimit;
uint16_t totalLimit;
+ uint16_t queueLimit;
uint16_t totalCurrentConnections;
qpid::sys::Mutex dataLock;
/** Records per-connection state */
- connectCountsMap_t connectProgressMap;
+ countsMap_t connectProgressMap;
/** Records per-username counts */
- connectCountsMap_t connectByNameMap;
+ countsMap_t connectByNameMap;
/** Records per-host counts */
- connectCountsMap_t connectByHostMap;
+ countsMap_t connectByHostMap;
+
+ /** Records queueName-queueUserId */
+ queueOwnerMap_t queueOwnerMap;
+
+ /** Records queue-by-owner counts */
+ countsMap_t queuePerUserMap;
/** Given a connection's management ID, return the client host name */
std::string getClientHost(const std::string mgmtId);
/** Return approval for proposed connection */
- bool limitApproveLH(connectCountsMap_t& theMap,
+ bool limitApproveLH(countsMap_t& theMap,
+ const std::string& theName,
+ uint16_t theLimit,
+ bool emitLog);
+
+ /** Return approval for proposed resource creation */
+ bool limitApproveLH(const std::string& theTitle,
+ countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog);
/** Record a connection.
* @return indication if user/host is over its limit */
- bool countConnectionLH(connectCountsMap_t& theMap,
+ bool countConnectionLH(countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog);
/** Release a connection */
- void releaseLH(connectCountsMap_t& theMap,
+ void releaseLH(countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit);
public:
- ConnectionCounter(Acl& acl, uint16_t nl, uint16_t hl, uint16_t tl);
+ ConnectionCounter(Acl& acl, uint16_t nl, uint16_t hl, uint16_t tl, uint16_t ql);
~ConnectionCounter();
// ConnectionObserver interface
@@ -95,6 +110,10 @@ public:
// Connection counting
bool approveConnection(const broker::Connection& conn);
void setUserId(const broker::Connection& connection, const std::string& username);
+
+ // Queue counting
+ bool approveCreateQueue(const std::string& userId, const std::string& queueName);
+ void recordDestroyQueue(const std::string& queueName);
};
}} // namespace qpid::ha
diff --git a/qpid/cpp/src/qpid/acl/AclPlugin.cpp b/qpid/cpp/src/qpid/acl/AclPlugin.cpp
index ebf5e90..4aaa00a 100644
--- a/qpid/cpp/src/qpid/acl/AclPlugin.cpp
+++ b/qpid/cpp/src/qpid/acl/AclPlugin.cpp
@@ -45,6 +45,7 @@ struct AclOptions : public Options {
("max-connections" , optValue(values.aclMaxConnectTotal, "N"), "The maximum combined number of connections allowed. 0 implies no limit.")
("max-connections-per-user", optValue(values.aclMaxConnectPerUser, "N"), "The maximum number of connections allowed per user. 0 implies no limit.")
("max-connections-per-ip" , optValue(values.aclMaxConnectPerIp, "N"), "The maximum number of connections allowed per host IP address. 0 implies no limit.")
+ ("max-queues-per-user", optValue(values.aclMaxQueuesPerUser, "N"), "The maximum number of queues allowed per user. 0 implies no limit.")
;
}
};
diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h
index 4caf8ed..987d3e4 100644
--- a/qpid/cpp/src/qpid/broker/AclModule.h
+++ b/qpid/cpp/src/qpid/broker/AclModule.h
@@ -151,6 +151,11 @@ namespace broker {
*/
virtual void setUserId(const Connection& connection, const std::string& username)=0;
+ /** Approve queue creation by counting per-user.
+ */
+ virtual bool approveCreateQueue(const std::string& userId, const std::string& queueName)=0;
+ virtual void recordDestroyQueue(const std::string& queueName)=0;
+
virtual ~AclModule() {};
};
} // namespace broker
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index c202d9c..be7340a 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -1076,6 +1076,9 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << userId));
+
+ if (!acl->approveCreateQueue(userId,name) )
+ throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << userId));
}
Exchange::shared_ptr alternate;
@@ -1113,6 +1116,8 @@ void Broker::deleteQueue(const std::string& name, const std::string& userId,
Queue::shared_ptr queue = queues.find(name);
if (queue) {
if (check) check(queue);
+ if (acl)
+ acl->recordDestroyQueue(name);
queues.destroy(name);
queue->destroyed();
} else {
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 102796c..8055996 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -53,6 +53,9 @@ class ACLTests(TestBase010):
def port_u(self):
return int(self.defines["port-u"])
+ def port_q(self):
+ return int(self.defines["port-q"])
+
def get_session_by_port(self, user, passwd, byPort):
socket = connect(self.broker.host, byPort)
connection = Connection (sock=socket, username=user, password=passwd,
@@ -2243,6 +2246,53 @@ class ACLTests(TestBase010):
self.LookupPublish("joe@QPID", "QPID-work", "QPID", "allow")
self.LookupPublish("joe@QPID", "QPID-work2", "QPID", "allow")
+ #=====================================
+ # Queue limits
+ #=====================================
+
+ def test__queue_limits(self):
+ """
+ Test ACL control queue limits
+ """
+ # bob should be able to create two queues
+ session = self.get_session_by_port('bob','bob', self.port_q())
+
+ try:
+ session.queue_declare(queue="queue1")
+ session.queue_declare(queue="queue2")
+ except qpid.session.SessionException, e:
+ self.fail("Error during queue create request");
+
+ # third queue should fail
+ try:
+ session.queue_declare(queue="queue3")
+ self.fail("Should not be able to create third queue")
+ except Exception, e:
+ result = None
+ session = self.get_session_by_port('bob','bob', self.port_q())
+
+ # alice should be able to create two queues
+ session2 = self.get_session_by_port('alice','alice', self.port_q())
+
+ try:
+ session2.queue_declare(queue="queuea1")
+ session2.queue_declare(queue="queuea2")
+ except qpid.session.SessionException, e:
+ self.fail("Error during queue create request");
+
+ # third queue should fail
+ try:
+ session2.queue_declare(queue="queuea3")
+ self.fail("Should not be able to create third queue")
+ except Exception, e:
+ result = None
+
+ # bob should be able to delete a queue and create another
+ try:
+ session.queue_delete(queue="queue1")
+ session.queue_declare(queue="queue3")
+ except qpid.session.SessionException, e:
+ self.fail("Error during queue create request");
class BrokerAdmin:
def __init__(self, broker, username=None, password=None):
diff --git a/qpid/cpp/src/tests/run_acl_tests b/qpid/cpp/src/tests/run_acl_tests
index 25241ad..652684f 100755
--- a/qpid/cpp/src/tests/run_acl_tests
+++ b/qpid/cpp/src/tests/run_acl_tests
@@ -24,22 +24,26 @@ source ./test_env.sh
DATA_DIR=`pwd`/data_dir
DATA_DIRI=`pwd`/data_diri
DATA_DIRU=`pwd`/data_diru
+DATA_DIRQ=`pwd`/data_dirq
trap stop_brokers INT TERM QUIT
start_brokers() {
- ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIR --load-module $ACL_LIB --acl-file policy.acl --auth no --log-to-file local.log > qpidd.port
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIR --load-module $ACL_LIB --acl-file policy.acl --auth no --log-to-file local.log > qpidd.port
LOCAL_PORT=`cat qpidd.port`
- ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRI --load-module $ACL_LIB --acl-file policy.acl --auth no --max-connections-per-ip 2 --log-to-file locali.log > qpiddi.port
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRI --load-module $ACL_LIB --acl-file policy.acl --auth no --max-connections-per-ip 2 --log-to-file locali.log > qpiddi.port
LOCAL_PORTI=`cat qpiddi.port`
../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRU --load-module $ACL_LIB --acl-file policy.acl --auth no --max-connections-per-user 2 --log-to-file localu.log > qpiddu.port
LOCAL_PORTU=`cat qpiddu.port`
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRQ --load-module $ACL_LIB --acl-file policy.acl --auth no --max-queues-per-user 2 -t --log-to-file localq.log > qpiddq.port
+ LOCAL_PORTQ=`cat qpiddq.port`
}
stop_brokers() {
$QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORT
$QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORTI
$QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORTU
+ $QPIDD_EXEC --no-module-dir -q --port $LOCAL_PORTQ
}
test_loading_acl_from_absolute_path(){
@@ -59,20 +63,24 @@ if test -d ${PYTHON_DIR} ; then
rm -rf $DATA_DIR
rm -rf $DATA_DIRI
rm -rf $DATA_DIRU
+ rm -rf $DATA_DIRQ
mkdir -p $DATA_DIR
mkdir -p $DATA_DIRI
mkdir -p $DATA_DIRU
+ mkdir -p $DATA_DIRQ
cp $srcdir/policy.acl $DATA_DIR
cp $srcdir/policy.acl $DATA_DIRI
cp $srcdir/policy.acl $DATA_DIRU
+ cp $srcdir/policy.acl $DATA_DIRQ
start_brokers
- echo "Running acl tests using brokers on ports $LOCAL_PORT, $LOCAL_PORTI, and $LOCAL_PORTU"
- $QPID_PYTHON_TEST -b localhost:$LOCAL_PORT -m acl -Dport-i=$LOCAL_PORTI -Dport-u=$LOCAL_PORTU || EXITCODE=1
+ echo "Running acl tests using brokers on ports $LOCAL_PORT, $LOCAL_PORTI, $LOCAL_PORTU, and $LOCAL_PORTQ"
+ $QPID_PYTHON_TEST -b localhost:$LOCAL_PORT -m acl -Dport-i=$LOCAL_PORTI -Dport-u=$LOCAL_PORTU -Dport-q=$LOCAL_PORTQ || EXITCODE=1
stop_brokers || EXITCODE=1
test_loading_acl_from_absolute_path || EXITCODE=1
rm -rf $DATA_DIR
rm -rf $DATA_DIRI
rm -rf $DATA_DIRU
+ rm -rf $DATA_DIRQ
exit $EXITCODE
fi
--
1.7.1
From 423d492e38f4214a2ca1d87f0ee7347203785fef Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Tue, 21 Aug 2012 15:21:26 -0400
Subject: [PATCH 12/19] QPID-2393 Count queues per user.
Move queue counting functions out of connection counting files
and into new files.
---
qpid/cpp/src/qpid/acl/AclResourceCounter.cpp | 167 ++++++++++++++++++++++++++
qpid/cpp/src/qpid/acl/AclResourceCounter.h | 77 ++++++++++++
2 files changed, 244 insertions(+), 0 deletions(-)
create mode 100644 qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
create mode 100644 qpid/cpp/src/qpid/acl/AclResourceCounter.h
diff --git a/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
new file mode 100644
index 0000000..98bc144
--- /dev/null
+++ b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
@@ -0,0 +1,167 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "AclResourceCounter.h"
+#include "Acl.h"
+#include "qpid/log/Statement.h"
+#include "qpid/sys/Mutex.h"
+#include <assert.h>
+#include <sstream>
+
+using namespace qpid::sys;
+
+namespace qpid {
+namespace acl {
+
+//
+// This module approves various resource creation requests:
+// Queues
+//
+
+
+//
+//
+//
+ResourceCounter::ResourceCounter(Acl& a, uint16_t ql) :
+ acl(a), queueLimit(ql) {
+ QPID_LOG(critical, "ACL RESOURCE_COUNTER queueLimit:" << queueLimit);
+ }
+
+ResourceCounter::~ResourceCounter() {}
+
+
+//
+// limitApproveLH
+//
+// Resource creation approver.
+// If user is under limit increment count and return true.
+// Called with lock held.
+//
+bool ResourceCounter::limitApproveLH(
+ const std::string& theTitle,
+ countsMap_t& theMap,
+ const std::string& theName,
+ uint16_t theLimit,
+ bool emitLog) {
+
+ bool result(true);
+ if (theLimit > 0) {
+ uint16_t count;
+ countsMap_t::iterator eRef = theMap.find(theName);
+ if (eRef != theMap.end()) {
+ count = (uint16_t)(*eRef).second;
+ result = count < theLimit;
+ if (result) {
+ count += 1;
+ (*eRef).second = count;
+ }
+ } else {
+ // Not found
+ theMap[theName] = count = 1;
+ }
+ if (emitLog) {
+ QPID_LOG(trace, theTitle << theName
+ << " limit=" << theLimit
+ << " curValue=" << count
+ << " result=" << (result ? "allow" : "deny"));
+ }
+ }
+ return result;
+}
+
+
+//
+// releaseLH
+//
+// Decrement the name's count in map.
+// called with dataLock already taken
+//
+void ResourceCounter::releaseLH(
+ countsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
+
+ if (theLimit > 0) {
+ countsMap_t::iterator eRef = theMap.find(theName);
+ if (eRef != theMap.end()) {
+ uint16_t count = (uint16_t) (*eRef).second;
+ assert (count > 0);
+ if (1 == count) {
+ theMap.erase (eRef);
+ } else {
+ (*eRef).second = count - 1;
+ }
+ } else {
+ // User had no connections.
+ QPID_LOG(notice, "ACL ResourceCounter Connection for '" << theName
+ << "' not found in connection count pool");
+ }
+ }
+}
+
+
+//
+// approveCreateQueue
+// Count an attempted queue creation by this user.
+// Disapprove if over limit.
+//
+bool ResourceCounter::approveCreateQueue(const std::string& userId, const std::string& queueName)
+{
+ Mutex::ScopedLock locker(dataLock);
+
+ QPID_LOG(critical, "DEV HACK approveCreateQueue ----------- userId:" << userId << ", queueName:" << queueName);
+
+ bool okByQ = limitApproveLH("ACL Queue creation approver. userId:", queuePerUserMap, userId, queueLimit, true);
+
+ if (okByQ) {
+ // Queue is owned by this userId
+ queueOwnerMap[queueName] = userId;
+
+ QPID_LOG(trace, "ACL create queue approved for user '" << userId
+ << "' queue '" << queueName << "'");
+ } else {
+
+ QPID_LOG(error, "Client max queue count limit of " << queueLimit
+ << " exceeded by '" << userId << "' creating queue '"
+ << queueName << "'. Queue creation denied.");
+ }
+ return okByQ;
+}
+
+
+//
+// recordDestroyQueue
+// Return a destroyed queue to a user's quota
+//
+void ResourceCounter::recordDestroyQueue(const std::string& queueName)
+{
+ Mutex::ScopedLock locker(dataLock);
+
+ queueOwnerMap_t::iterator eRef = queueOwnerMap.find(queueName);
+ if (eRef != queueOwnerMap.end()) {
+ releaseLH(queuePerUserMap, (*eRef).second, queueLimit);
+
+ queueOwnerMap.erase(eRef);
+ } else {
+ QPID_LOG(notice, "ACL owner for queue '" << queueName
+ << "' not found in owner map");
+ }
+}
+
+}} // namespace qpid::acl
diff --git a/qpid/cpp/src/qpid/acl/AclResourceCounter.h b/qpid/cpp/src/qpid/acl/AclResourceCounter.h
new file mode 100644
index 0000000..061ced9
--- /dev/null
+++ b/qpid/cpp/src/qpid/acl/AclResourceCounter.h
@@ -0,0 +1,77 @@
+#ifndef QPID_ACL_RESOURCECOUNTER_H
+#define QPID_ACL_RESOURCECOUNTER_H
+
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "qpid/sys/Mutex.h"
+#include <boost/iterator/iterator_concepts.hpp>
+
+#include <map>
+
+namespace qpid {
+
+namespace acl {
+class Acl;
+
+ /**
+ * Approve or disapprove resource creation requests
+ */
+class ResourceCounter
+{
+private:
+ typedef std::map<std::string, uint32_t> countsMap_t;
+ typedef std::map<std::string, std::string> queueOwnerMap_t;
+
+ Acl& acl;
+ uint16_t queueLimit;
+ qpid::sys::Mutex dataLock;
+
+ /** Records queueName-queueUserId */
+ queueOwnerMap_t queueOwnerMap;
+
+ /** Records queue-by-owner counts */
+ countsMap_t queuePerUserMap;
+
+ /** Return approval for proposed resource creation */
+ bool limitApproveLH(const std::string& theTitle,
+ countsMap_t& theMap,
+ const std::string& theName,
+ uint16_t theLimit,
+ bool emitLog);
+
+ /** Release a connection */
+ void releaseLH(countsMap_t& theMap,
+ const std::string& theName,
+ uint16_t theLimit);
+
+public:
+ ResourceCounter(Acl& acl, uint16_t ql);
+ ~ResourceCounter();
+
+ // Queue counting
+ bool approveCreateQueue(const std::string& userId, const std::string& queueName);
+ void recordDestroyQueue(const std::string& queueName);
+};
+
+}} // namespace qpid::acl
+
+#endif /*!QPID_ACL_RESOURCECOUNTER_H*/
--
1.7.1
From 37a9e78081db4602fc9970b5649729ab021f0573 Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Tue, 21 Aug 2012 15:24:13 -0400
Subject: [PATCH 13/19] QPID-2393 Count queues per user.
Move queue counting out of connection counting files and
into new files.
---
qpid/cpp/src/CMakeLists.txt | 2 +
qpid/cpp/src/acl.mk | 2 +
qpid/cpp/src/qpid/acl/Acl.cpp | 9 +-
qpid/cpp/src/qpid/acl/Acl.h | 2 +
qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp | 116 +++---------------------
qpid/cpp/src/qpid/acl/AclConnectionCounter.h | 35 ++------
6 files changed, 32 insertions(+), 134 deletions(-)
diff --git a/qpid/cpp/src/CMakeLists.txt b/qpid/cpp/src/CMakeLists.txt
index cd1d7b7..62e6dcd 100644
--- a/qpid/cpp/src/CMakeLists.txt
+++ b/qpid/cpp/src/CMakeLists.txt
@@ -601,6 +601,8 @@ if (BUILD_ACL)
qpid/acl/AclPlugin.cpp
qpid/acl/AclReader.cpp
qpid/acl/AclReader.h
+ qpid/acl/AclResourceCounter.cpp
+ qpid/acl/AclResourceCounter.h
qpid/acl/AclValidator.cpp
qpid/acl/AclValidator.h
)
diff --git a/qpid/cpp/src/acl.mk b/qpid/cpp/src/acl.mk
index 0301f8c..74f8ef1 100644
--- a/qpid/cpp/src/acl.mk
+++ b/qpid/cpp/src/acl.mk
@@ -31,6 +31,8 @@ acl_la_SOURCES = \
qpid/acl/AclPlugin.cpp \
qpid/acl/AclReader.cpp \
qpid/acl/AclReader.h \
+ qpid/acl/AclResourceCounter.cpp \
+ qpid/acl/AclResourceCounter.h \
qpid/acl/AclValidator.cpp \
qpid/acl/AclValidator.h
diff --git a/qpid/cpp/src/qpid/acl/Acl.cpp b/qpid/cpp/src/qpid/acl/Acl.cpp
index 8116e67..b5a808f 100644
--- a/qpid/cpp/src/qpid/acl/Acl.cpp
+++ b/qpid/cpp/src/qpid/acl/Acl.cpp
@@ -18,6 +18,7 @@
#include "qpid/acl/Acl.h"
#include "qpid/acl/AclConnectionCounter.h"
+#include "qpid/acl/AclResourceCounter.h"
#include "qpid/acl/AclData.h"
#include "qpid/acl/AclValidator.h"
#include "qpid/sys/Mutex.h"
@@ -51,8 +52,8 @@ using qpid::management::Args;
namespace _qmf = qmf::org::apache::qpid::acl;
Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), mgmtObject(0),
- connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp, aclValues.aclMaxConnectTotal, aclValues.aclMaxQueuesPerUser))
-{
+ connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp, aclValues.aclMaxConnectTotal)),
+ resourceCounter(new ResourceCounter(*this, aclValues.aclMaxQueuesPerUser)){
agent = broker->getManagementAgent();
@@ -138,13 +139,13 @@ void Acl::setUserId(const qpid::broker::Connection& connection, const std::strin
bool Acl::approveCreateQueue(const std::string& userId, const std::string& queueName)
{
- return connectionCounter->approveCreateQueue(userId, queueName);
+ return resourceCounter->approveCreateQueue(userId, queueName);
}
void Acl::recordDestroyQueue(const std::string& queueName)
{
- connectionCounter->recordDestroyQueue(queueName);
+ resourceCounter->recordDestroyQueue(queueName);
}
diff --git a/qpid/cpp/src/qpid/acl/Acl.h b/qpid/cpp/src/qpid/acl/Acl.h
index 918b98c..2097f6c 100644
--- a/qpid/cpp/src/qpid/acl/Acl.h
+++ b/qpid/cpp/src/qpid/acl/Acl.h
@@ -43,6 +43,7 @@ class Connection;
namespace acl {
class ConnectionCounter;
+class ResourceCounter;
struct AclValues {
std::string aclFile;
@@ -65,6 +66,7 @@ private:
qpid::management::ManagementAgent* agent;
mutable qpid::sys::Mutex dataLock;
boost::shared_ptr<ConnectionCounter> connectionCounter;
+ boost::shared_ptr<ResourceCounter> resourceCounter;
public:
Acl (AclValues& av, broker::Broker& b);
diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
index 56dbced..8c6e3ee 100644
--- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
+++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp
@@ -42,10 +42,8 @@ namespace acl {
//
//
//
-ConnectionCounter::ConnectionCounter(Acl& a, uint16_t nl, uint16_t hl, uint16_t tl, uint16_t ql) :
- acl(a), nameLimit(nl), hostLimit(hl), totalLimit(tl), queueLimit(ql), totalCurrentConnections(0) {
- QPID_LOG(critical, "ACL CONNECTION_COUNTER nameLimit:" << nameLimit << ", hostLimit:" << hostLimit << ", totalLimit:" << totalLimit << ", queueLimit:" << queueLimit);
- }
+ConnectionCounter::ConnectionCounter(Acl& a, uint16_t nl, uint16_t hl, uint16_t tl) :
+ acl(a), nameLimit(nl), hostLimit(hl), totalLimit(tl), totalCurrentConnections(0) {}
ConnectionCounter::~ConnectionCounter() {}
@@ -57,7 +55,7 @@ ConnectionCounter::~ConnectionCounter() {}
// Called with lock held.
//
bool ConnectionCounter::limitApproveLH(
- countsMap_t& theMap,
+ connectCountsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog) {
@@ -65,7 +63,7 @@ bool ConnectionCounter::limitApproveLH(
bool result(true);
if (theLimit > 0) {
uint16_t count;
- countsMap_t::iterator eRef = theMap.find(theName);
+ connectCountsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
count = (uint16_t)(*eRef).second;
result = count <= theLimit;
@@ -75,49 +73,9 @@ bool ConnectionCounter::limitApproveLH(
}
if (emitLog) {
QPID_LOG(trace, "ACL ConnectionApprover IP=" << theName
- << " limit=" << theLimit
- << " curValue=" << count
- << " result=" << (result ? "allow" : "deny"));
- }
- }
- return result;
-}
-
-
-//
-// limitApproveLH
-//
-// Resource creation approver.
-// If user is under limit increment count and return true.
-// Called with lock held.
-//
-bool ConnectionCounter::limitApproveLH(
- const std::string& theTitle,
- countsMap_t& theMap,
- const std::string& theName,
- uint16_t theLimit,
- bool emitLog) {
-
- bool result(true);
- if (theLimit > 0) {
- uint16_t count;
- countsMap_t::iterator eRef = theMap.find(theName);
- if (eRef != theMap.end()) {
- count = (uint16_t)(*eRef).second;
- result = count < theLimit;
- if (result) {
- count += 1;
- (*eRef).second = count;
- }
- } else {
- // Not found
- theMap[theName] = count = 1;
- }
- if (emitLog) {
- QPID_LOG(trace, theTitle << theName
- << " limit=" << theLimit
- << " curValue=" << count
- << " result=" << (result ? "allow" : "deny"));
+ << " limit=" << theLimit
+ << " curValue=" << count
+ << " result=" << (result ? "allow" : "deny"));
}
}
return result;
@@ -131,7 +89,7 @@ bool ConnectionCounter::limitApproveLH(
// called with dataLock already taken
//
bool ConnectionCounter::countConnectionLH(
- countsMap_t& theMap,
+ connectCountsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog) {
@@ -139,7 +97,7 @@ bool ConnectionCounter::countConnectionLH(
bool result(true);
uint16_t count(0);
if (theLimit > 0) {
- countsMap_t::iterator eRef = theMap.find(theName);
+ connectCountsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
count = (uint16_t)(*eRef).second + 1;
(*eRef).second = count;
@@ -165,10 +123,10 @@ bool ConnectionCounter::countConnectionLH(
// called with dataLock already taken
//
void ConnectionCounter::releaseLH(
- countsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
+ connectCountsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
if (theLimit > 0) {
- countsMap_t::iterator eRef = theMap.find(theName);
+ connectCountsMap_t::iterator eRef = theMap.find(theName);
if (eRef != theMap.end()) {
uint16_t count = (uint16_t) (*eRef).second;
assert (count > 0);
@@ -216,7 +174,7 @@ void ConnectionCounter::closed(broker::Connection& connection) {
Mutex::ScopedLock locker(dataLock);
- countsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
if (eRef != connectProgressMap.end()) {
if ((*eRef).second == C_OPENED){
// Normal case: connection was created and opened.
@@ -348,7 +306,7 @@ void ConnectionCounter::setUserId(const broker::Connection& connection,
{
Mutex::ScopedLock locker(dataLock);
- countsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
+ connectCountsMap_t::iterator eRef = connectProgressMap.find(connection.getMgmtId());
if (eRef != connectProgressMap.end()) {
if ((*eRef).second == C_OPENED){
// Connection has been opened so that current user has been counted
@@ -380,54 +338,6 @@ void ConnectionCounter::setUserId(const broker::Connection& connection,
//
-// approveCreateQueue
-// Count an attempted queue creation by this user.
-// Disapprove if over limit.
-//
-bool ConnectionCounter::approveCreateQueue(const std::string& userId, const std::string& queueName)
-{
- Mutex::ScopedLock locker(dataLock);
-
- QPID_LOG(critical, "approveCreateQueue ----------- userId:" << userId << ", queueName:" << queueName);
-
- bool okByQ = limitApproveLH("ACL Queue creation approver. userId:", queuePerUserMap, userId, queueLimit, true);
-
- if (okByQ) {
- // Queue is owned by this userId
- queueOwnerMap[queueName] = userId;
-
- QPID_LOG(trace, "ACL create queue approved for user '" << userId
- << "' queue '" << queueName << "'");
- } else {
-
- QPID_LOG(error, "Client max queue count limit of " << queueLimit
- << " exceeded by '" << userId << "' creating queue '"
- << queueName << "'. Queue creation denied.");
- }
- return okByQ;
-}
-
-
-//
-// recordDestroyQueue
-// Return a destroyed queue to a user's quota
-//
-void ConnectionCounter::recordDestroyQueue(const std::string& queueName)
-{
- Mutex::ScopedLock locker(dataLock);
-
- queueOwnerMap_t::iterator eRef = queueOwnerMap.find(queueName);
- if (eRef != queueOwnerMap.end()) {
- releaseLH(queuePerUserMap, (*eRef).second, queueLimit);
-
- queueOwnerMap.erase(eRef);
- } else {
- QPID_LOG(notice, "ACL owner for queue '" << queueName
- << "' not found in owner map");
- }
-}
-
-//
// getClientIp - given a connection's mgmtId return the client host part.
//
// TODO: Ideally this would be a method of the connection itself.
diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.h b/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
index 70c60fb..54fa693 100644
--- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
+++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.h
@@ -44,63 +44,48 @@ class Acl;
class ConnectionCounter : public broker::ConnectionObserver
{
private:
- typedef std::map<std::string, uint32_t> countsMap_t;
+ typedef std::map<std::string, uint32_t> connectCountsMap_t;
enum CONNECTION_PROGRESS { C_CREATED=1, C_OPENED=2 };
- typedef std::map<std::string, std::string> queueOwnerMap_t;
Acl& acl;
uint16_t nameLimit;
uint16_t hostLimit;
uint16_t totalLimit;
- uint16_t queueLimit;
uint16_t totalCurrentConnections;
qpid::sys::Mutex dataLock;
/** Records per-connection state */
- countsMap_t connectProgressMap;
+ connectCountsMap_t connectProgressMap;
/** Records per-username counts */
- countsMap_t connectByNameMap;
+ connectCountsMap_t connectByNameMap;
/** Records per-host counts */
- countsMap_t connectByHostMap;
-
- /** Records queueName-queueUserId */
- queueOwnerMap_t queueOwnerMap;
-
- /** Records queue-by-owner counts */
- countsMap_t queuePerUserMap;
+ connectCountsMap_t connectByHostMap;
/** Given a connection's management ID, return the client host name */
std::string getClientHost(const std::string mgmtId);
/** Return approval for proposed connection */
- bool limitApproveLH(countsMap_t& theMap,
- const std::string& theName,
- uint16_t theLimit,
- bool emitLog);
-
- /** Return approval for proposed resource creation */
- bool limitApproveLH(const std::string& theTitle,
- countsMap_t& theMap,
+ bool limitApproveLH(connectCountsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog);
/** Record a connection.
* @return indication if user/host is over its limit */
- bool countConnectionLH(countsMap_t& theMap,
+ bool countConnectionLH(connectCountsMap_t& theMap,
const std::string& theName,
uint16_t theLimit,
bool emitLog);
/** Release a connection */
- void releaseLH(countsMap_t& theMap,
+ void releaseLH(connectCountsMap_t& theMap,
const std::string& theName,
uint16_t theLimit);
public:
- ConnectionCounter(Acl& acl, uint16_t nl, uint16_t hl, uint16_t tl, uint16_t ql);
+ ConnectionCounter(Acl& acl, uint16_t nl, uint16_t hl, uint16_t tl);
~ConnectionCounter();
// ConnectionObserver interface
@@ -110,10 +95,6 @@ public:
// Connection counting
bool approveConnection(const broker::Connection& conn);
void setUserId(const broker::Connection& connection, const std::string& username);
-
- // Queue counting
- bool approveCreateQueue(const std::string& userId, const std::string& queueName);
- void recordDestroyQueue(const std::string& queueName);
};
}} // namespace qpid::ha
--
1.7.1
From 47e2c4a615ff8d6b2459b0dac6ae494b99cd2f85 Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Tue, 21 Aug 2012 15:42:03 -0400
Subject: [PATCH 14/19] QPID-2393 Queue counting per user.
Clean up the self tests and error messages.
---
qpid/cpp/src/qpid/acl/AclResourceCounter.cpp | 14 ++++++--------
qpid/cpp/src/qpid/acl/AclResourceCounter.h | 3 ++-
qpid/cpp/src/tests/acl.py | 15 ++++++++++++---
qpid/cpp/src/tests/run_acl_tests | 2 +-
4 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
index 98bc144..581c860 100644
--- a/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
+++ b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
@@ -95,7 +95,7 @@ bool ResourceCounter::limitApproveLH(
// called with dataLock already taken
//
void ResourceCounter::releaseLH(
- countsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
+ const std::string& theTitle, countsMap_t& theMap, const std::string& theName, uint16_t theLimit) {
if (theLimit > 0) {
countsMap_t::iterator eRef = theMap.find(theName);
@@ -109,8 +109,8 @@ void ResourceCounter::releaseLH(
}
} else {
// User had no connections.
- QPID_LOG(notice, "ACL ResourceCounter Connection for '" << theName
- << "' not found in connection count pool");
+ QPID_LOG(notice, theTitle << theName
+ << "' not found in resource count pool");
}
}
}
@@ -125,8 +125,6 @@ bool ResourceCounter::approveCreateQueue(const std::string& userId, const std::s
{
Mutex::ScopedLock locker(dataLock);
- QPID_LOG(critical, "DEV HACK approveCreateQueue ----------- userId:" << userId << ", queueName:" << queueName);
-
bool okByQ = limitApproveLH("ACL Queue creation approver. userId:", queuePerUserMap, userId, queueLimit, true);
if (okByQ) {
@@ -155,12 +153,12 @@ void ResourceCounter::recordDestroyQueue(const std::string& queueName)
queueOwnerMap_t::iterator eRef = queueOwnerMap.find(queueName);
if (eRef != queueOwnerMap.end()) {
- releaseLH(queuePerUserMap, (*eRef).second, queueLimit);
+ releaseLH("ACL resource counter: Queue owner for queue '", queuePerUserMap, (*eRef).second, queueLimit);
queueOwnerMap.erase(eRef);
} else {
- QPID_LOG(notice, "ACL owner for queue '" << queueName
- << "' not found in owner map");
+ QPID_LOG(notice, "ACL resource counter: Queue '" << queueName
+ << "' not found in queue owner map");
}
}
diff --git a/qpid/cpp/src/qpid/acl/AclResourceCounter.h b/qpid/cpp/src/qpid/acl/AclResourceCounter.h
index 061ced9..f5995eb 100644
--- a/qpid/cpp/src/qpid/acl/AclResourceCounter.h
+++ b/qpid/cpp/src/qpid/acl/AclResourceCounter.h
@@ -59,7 +59,8 @@ private:
bool emitLog);
/** Release a connection */
- void releaseLH(countsMap_t& theMap,
+ void releaseLH(const std::string& theTitle,
+ countsMap_t& theMap,
const std::string& theName,
uint16_t theLimit);
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 8055996..180f848 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -2247,12 +2247,13 @@ class ACLTests(TestBase010):
self.LookupPublish("joe@QPID", "QPID-work2", "QPID", "allow")
#=====================================
- # Queue limits
+ # Queue per-user quota
#=====================================
- def test__queue_limits(self):
+ def test_queue_per_user_quota(self):
"""
- Test ACL control queue limits
+ Test ACL queue counting limits.
+ port_q has a limit of 2
"""
# bob should be able to create two queues
session = self.get_session_by_port('bob','bob', self.port_q())
@@ -2286,6 +2287,7 @@ class ACLTests(TestBase010):
self.fail("Should not be able to create third queue")
except Exception, e:
result = None
+ session2 = self.get_session_by_port('alice','alice', self.port_q())
# bob should be able to delete a queue and create another
try:
@@ -2294,6 +2296,13 @@ class ACLTests(TestBase010):
except qpid.session.SessionException, e:
self.fail("Error during queue create request");
+ # alice should be able to delete a queue and create another
+ try:
+ session2.queue_delete(queue="queuea1")
+ session2.queue_declare(queue="queuea3")
+ except qpid.session.SessionException, e:
+ self.fail("Error during queue create request");
+
class BrokerAdmin:
def __init__(self, broker, username=None, password=None):
self.connection = qpid.messaging.Connection(broker)
diff --git a/qpid/cpp/src/tests/run_acl_tests b/qpid/cpp/src/tests/run_acl_tests
index 652684f..d4d0d74 100755
--- a/qpid/cpp/src/tests/run_acl_tests
+++ b/qpid/cpp/src/tests/run_acl_tests
@@ -35,7 +35,7 @@ start_brokers() {
LOCAL_PORTI=`cat qpiddi.port`
../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRU --load-module $ACL_LIB --acl-file policy.acl --auth no --max-connections-per-user 2 --log-to-file localu.log > qpiddu.port
LOCAL_PORTU=`cat qpiddu.port`
- ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRQ --load-module $ACL_LIB --acl-file policy.acl --auth no --max-queues-per-user 2 -t --log-to-file localq.log > qpiddq.port
+ ../qpidd --daemon --port 0 --no-module-dir --data-dir $DATA_DIRQ --load-module $ACL_LIB --acl-file policy.acl --auth no --max-queues-per-user 2 --log-to-file localq.log > qpiddq.port
LOCAL_PORTQ=`cat qpiddq.port`
}
--
1.7.1
From ea700fa9fd73d22c0d366afa175cd9adf96504d3 Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Tue, 21 Aug 2012 16:12:57 -0400
Subject: [PATCH 15/19] QPID-2393 Count queues per user.
Add management property, statistic, and event for queues denied.
---
qpid/cpp/src/qpid/acl/Acl.cpp | 10 ++++++++++
qpid/cpp/src/qpid/acl/Acl.h | 1 +
qpid/cpp/src/qpid/acl/management-schema.xml | 4 ++++
3 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/Acl.cpp b/qpid/cpp/src/qpid/acl/Acl.cpp
index b5a808f..17afc1b 100644
--- a/qpid/cpp/src/qpid/acl/Acl.cpp
+++ b/qpid/cpp/src/qpid/acl/Acl.cpp
@@ -33,6 +33,7 @@
#include "qmf/org/apache/qpid/acl/Package.h"
#include "qmf/org/apache/qpid/acl/EventAllow.h"
#include "qmf/org/apache/qpid/acl/EventConnectionDeny.h"
+#include "qmf/org/apache/qpid/acl/EventQueueQuotaDeny.h"
#include "qmf/org/apache/qpid/acl/EventDeny.h"
#include "qmf/org/apache/qpid/acl/EventFileLoaded.h"
#include "qmf/org/apache/qpid/acl/EventFileLoadFailed.h"
@@ -85,6 +86,15 @@ void Acl::reportConnectLimit(const std::string user, const std::string addr)
}
+void Acl::reportQueueLimit(const std::string user, const std::string queueName)
+{
+ if (mgmtObject!=0)
+ mgmtObject->inc_queueQuotaDenyCount();
+
+ agent->raiseEvent(_qmf::EventQueueQuotaDeny(user, queueName));
+}
+
+
bool Acl::authorise(
const std::string& id,
const Action& action,
diff --git a/qpid/cpp/src/qpid/acl/Acl.h b/qpid/cpp/src/qpid/acl/Acl.h
index 2097f6c..e0513d5 100644
--- a/qpid/cpp/src/qpid/acl/Acl.h
+++ b/qpid/cpp/src/qpid/acl/Acl.h
@@ -75,6 +75,7 @@ public:
* issue management counts and alerts for denied connections
*/
void reportConnectLimit(const std::string user, const std::string addr);
+ void reportQueueLimit(const std::string user, const std::string queueName);
inline virtual bool doTransferAcl() {
return transferAcl;
diff --git a/qpid/cpp/src/qpid/acl/management-schema.xml b/qpid/cpp/src/qpid/acl/management-schema.xml
index f52c251..5e42e94 100644
--- a/qpid/cpp/src/qpid/acl/management-schema.xml
+++ b/qpid/cpp/src/qpid/acl/management-schema.xml
@@ -25,8 +25,10 @@
<property name="maxConnections" type="uint16" access="RO" desc="Maximum allowed connections"/>
<property name="maxConnectionsPerIp" type="uint16" access="RO" desc="Maximum allowed connections"/>
<property name="maxConnectionsPerUser" type="uint16" access="RO" desc="Maximum allowed connections"/>
+ <property name="maxQueuesPerUser" type="uint16" access="RO" desc="Maximum allowed queues"/>
<statistic name="aclDenyCount" type="count64" unit="request" desc="Number of ACL requests denied"/>
<statistic name="connectionDenyCount" type="count64" unit="connection" desc="Number of connections denied"/>
+ <statistic name="queueQuotaDenyCount" type="count64" unit="connection" desc="Number of queue creations denied"/>
<method name="reloadACLFile" desc="Reload the ACL file"/>
@@ -70,11 +72,13 @@
<arg name="reason" type="lstr"/>
<arg name="userId" type="sstr"/>
<arg name="clientAddr" type="sstr"/>
+ <arg name="queueName" type="sstr"/>
</eventArguments>
<event name="allow" sev="inform" args="userId, action, objectType, objectName, arguments"/>
<event name="deny" sev="notice" args="userId, action, objectType, objectName, arguments"/>
<event name="connectionDeny" sev="notice" args="userId, clientAddr"/>
+ <event name="queueQuotaDeny" sev="notice" args="userId, queueName"/>
<event name="fileLoaded" sev="inform" args="userId"/>
<event name="fileLoadFailed" sev="error" args="userId, reason"/>
--
1.7.1
From 64dbf3066f0096752f48e15ce364799d45595b49 Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Wed, 22 Aug 2012 14:32:02 -0400
Subject: [PATCH 16/19] QPID-2393 Count queues. On disapproving a queue creation do management event and counting.
Get rid of stray debug statement.
---
qpid/cpp/src/qpid/acl/AclResourceCounter.cpp | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
index 581c860..66dfd07 100644
--- a/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
+++ b/qpid/cpp/src/qpid/acl/AclResourceCounter.cpp
@@ -41,9 +41,7 @@ namespace acl {
//
//
ResourceCounter::ResourceCounter(Acl& a, uint16_t ql) :
- acl(a), queueLimit(ql) {
- QPID_LOG(critical, "ACL RESOURCE_COUNTER queueLimit:" << queueLimit);
- }
+ acl(a), queueLimit(ql) {}
ResourceCounter::~ResourceCounter() {}
@@ -79,9 +77,9 @@ bool ResourceCounter::limitApproveLH(
}
if (emitLog) {
QPID_LOG(trace, theTitle << theName
- << " limit=" << theLimit
- << " curValue=" << count
- << " result=" << (result ? "allow" : "deny"));
+ << " limit=" << theLimit
+ << " curValue=" << count
+ << " result=" << (result ? "allow" : "deny"));
}
}
return result;
@@ -138,6 +136,8 @@ bool ResourceCounter::approveCreateQueue(const std::string& userId, const std::s
QPID_LOG(error, "Client max queue count limit of " << queueLimit
<< " exceeded by '" << userId << "' creating queue '"
<< queueName << "'. Queue creation denied.");
+
+ acl.reportQueueLimit(userId, queueName);
}
return okByQ;
}
--
1.7.1
From 932a4a3ef623577501c42f83eb45fb1f668d18e8 Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Thu, 23 Aug 2012 13:50:29 -0400
Subject: [PATCH 17/19] QPID-2393 Count queues per user. Show queue limit in mgmt property.
---
qpid/cpp/src/qpid/acl/Acl.cpp | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/Acl.cpp b/qpid/cpp/src/qpid/acl/Acl.cpp
index 17afc1b..6eeda9f 100644
--- a/qpid/cpp/src/qpid/acl/Acl.cpp
+++ b/qpid/cpp/src/qpid/acl/Acl.cpp
@@ -65,6 +65,7 @@ Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(fals
mgmtObject->set_maxConnections(aclValues.aclMaxConnectTotal);
mgmtObject->set_maxConnectionsPerIp(aclValues.aclMaxConnectPerIp);
mgmtObject->set_maxConnectionsPerUser(aclValues.aclMaxConnectPerUser);
+ mgmtObject->set_maxQueuesPerUser(aclValues.aclMaxQueuesPerUser);
}
std::string errorString;
if (!readAclFile(errorString)){
--
1.7.1
From a1d72e1b65a1f639e248260a8bf4dcdebb3b30ac Mon Sep 17 00:00:00 2001
From: Chuck Rolke <crolke@redhat.com>
Date: Tue, 28 Aug 2012 09:57:52 -0400
Subject: [PATCH 18/19] BZ-783428 Add FILE SIZE/COUNT limit checks to Acl processor.
---
qpid/cpp/src/qpid/acl/AclData.cpp | 14 ++
qpid/cpp/src/qpid/acl/AclValidator.cpp | 16 ++
qpid/cpp/src/qpid/broker/AclModule.h | 20 ++-
qpid/cpp/src/qpid/broker/Broker.cpp | 2 +
qpid/cpp/src/tests/acl.py | 282 ++++++++++++++++++++++++++++++++
5 files changed, 333 insertions(+), 1 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index 6994de2..feb8b9d 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -199,6 +199,16 @@ namespace acl {
lookupParamItr = params->find(PROP_MAXQUEUESIZE);
break;
+ case acl::SPECPROP_MAXFILECOUNTUPPERLIMIT:
+ case acl::SPECPROP_MAXFILECOUNTLOWERLIMIT:
+ lookupParamItr = params->find(PROP_MAXFILECOUNT);
+ break;
+
+ case acl::SPECPROP_MAXFILESIZEUPPERLIMIT:
+ case acl::SPECPROP_MAXFILESIZELOWERLIMIT:
+ lookupParamItr = params->find(PROP_MAXFILESIZE);
+ break;
+
default:
lookupParamItr = params->find((Property)rulePropMapItr->first);
break;
@@ -222,6 +232,8 @@ namespace acl {
{
case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT:
case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT:
+ case acl::SPECPROP_MAXFILECOUNTUPPERLIMIT:
+ case acl::SPECPROP_MAXFILESIZEUPPERLIMIT:
limitChecked &=
compareIntMax(
rulePropMapItr->first,
@@ -231,6 +243,8 @@ namespace acl {
case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT:
case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT:
+ case acl::SPECPROP_MAXFILECOUNTLOWERLIMIT:
+ case acl::SPECPROP_MAXFILESIZELOWERLIMIT:
limitChecked &=
compareIntMin(
rulePropMapItr->first,
diff --git a/qpid/cpp/src/qpid/acl/AclValidator.cpp b/qpid/cpp/src/qpid/acl/AclValidator.cpp
index 85f0f7c..73b49b2 100644
--- a/qpid/cpp/src/qpid/acl/AclValidator.cpp
+++ b/qpid/cpp/src/qpid/acl/AclValidator.cpp
@@ -94,6 +94,22 @@ namespace acl {
boost::shared_ptr<PropertyType>(
new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+ validators.insert(Validator(acl::SPECPROP_MAXFILESIZELOWERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXFILESIZEUPPERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXFILECOUNTLOWERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
+ validators.insert(Validator(acl::SPECPROP_MAXFILECOUNTUPPERLIMIT,
+ boost::shared_ptr<PropertyType>(
+ new IntPropertyType(0,std::numeric_limits<int64_t>::max()))));
+
std::string policyTypes[] = {"ring", "ring_strict", "flow_to_disk", "reject"};
std::vector<std::string> v(policyTypes, policyTypes + sizeof(policyTypes) / sizeof(std::string));
validators.insert(Validator(acl::SPECPROP_POLICYTYPE,
diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h
index 987d3e4..4070e49 100644
--- a/qpid/cpp/src/qpid/broker/AclModule.h
+++ b/qpid/cpp/src/qpid/broker/AclModule.h
@@ -79,6 +79,8 @@ namespace acl {
PROP_POLICYTYPE,
PROP_MAXQUEUESIZE,
PROP_MAXQUEUECOUNT,
+ PROP_MAXFILESIZE,
+ PROP_MAXFILECOUNT,
PROPERTYSIZE // PROPERTYSIZE must be last in list
};
@@ -102,7 +104,11 @@ namespace acl {
SPECPROP_MAXQUEUESIZELOWERLIMIT,
SPECPROP_MAXQUEUESIZEUPPERLIMIT,
SPECPROP_MAXQUEUECOUNTLOWERLIMIT,
- SPECPROP_MAXQUEUECOUNTUPPERLIMIT };
+ SPECPROP_MAXQUEUECOUNTUPPERLIMIT,
+ SPECPROP_MAXFILESIZELOWERLIMIT,
+ SPECPROP_MAXFILESIZEUPPERLIMIT,
+ SPECPROP_MAXFILECOUNTLOWERLIMIT,
+ SPECPROP_MAXFILECOUNTUPPERLIMIT };
// AclResult shared between ACL spec and ACL authorise interface
enum AclResult {
@@ -227,6 +233,8 @@ namespace acl {
if (str.compare("policytype") == 0) return PROP_POLICYTYPE;
if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE;
if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT;
+ if (str.compare("maxfilesize") == 0) return PROP_MAXFILESIZE;
+ if (str.compare("maxfilecount") == 0) return PROP_MAXFILECOUNT;
throw qpid::Exception(str);
}
static inline std::string getPropertyStr(const Property p) {
@@ -245,6 +253,8 @@ namespace acl {
case PROP_POLICYTYPE: return "policytype";
case PROP_MAXQUEUESIZE: return "maxqueuesize";
case PROP_MAXQUEUECOUNT: return "maxqueuecount";
+ case PROP_MAXFILESIZE: return "maxfilesize";
+ case PROP_MAXFILECOUNT: return "maxfilecount";
default: assert(false); // should never get here
}
return "";
@@ -266,6 +276,10 @@ namespace acl {
if (str.compare("queuemaxsizeupperlimit") == 0) return SPECPROP_MAXQUEUESIZEUPPERLIMIT;
if (str.compare("queuemaxcountlowerlimit") == 0) return SPECPROP_MAXQUEUECOUNTLOWERLIMIT;
if (str.compare("queuemaxcountupperlimit") == 0) return SPECPROP_MAXQUEUECOUNTUPPERLIMIT;
+ if (str.compare("filemaxsizelowerlimit") == 0) return SPECPROP_MAXFILESIZELOWERLIMIT;
+ if (str.compare("filemaxsizeupperlimit") == 0) return SPECPROP_MAXFILESIZEUPPERLIMIT;
+ if (str.compare("filemaxcountlowerlimit") == 0) return SPECPROP_MAXFILECOUNTLOWERLIMIT;
+ if (str.compare("filemaxcountupperlimit") == 0) return SPECPROP_MAXFILECOUNTUPPERLIMIT;
// Allow old names in ACL file as aliases for newly-named properties
if (str.compare("maxqueuesize") == 0) return SPECPROP_MAXQUEUESIZEUPPERLIMIT;
if (str.compare("maxqueuecount") == 0) return SPECPROP_MAXQUEUECOUNTUPPERLIMIT;
@@ -289,6 +303,10 @@ namespace acl {
case SPECPROP_MAXQUEUESIZEUPPERLIMIT: return "queuemaxsizeupperlimit";
case SPECPROP_MAXQUEUECOUNTLOWERLIMIT: return "queuemaxcountlowerlimit";
case SPECPROP_MAXQUEUECOUNTUPPERLIMIT: return "queuemaxcountupperlimit";
+ case SPECPROP_MAXFILESIZELOWERLIMIT: return "filemaxsizelowerlimit";
+ case SPECPROP_MAXFILESIZEUPPERLIMIT: return "filemaxsizeupperlimit";
+ case SPECPROP_MAXFILECOUNTLOWERLIMIT: return "filemaxcountlowerlimit";
+ case SPECPROP_MAXFILECOUNTUPPERLIMIT: return "filemaxcountupperlimit";
default: assert(false); // should never get here
}
return "";
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index be7340a..06a2df8 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -1073,6 +1073,8 @@ std::pair<boost::shared_ptr<Queue>, bool> Broker::createQueue(
params.insert(make_pair(acl::PROP_POLICYTYPE, arguments.getAsString("qpid.policy_type")));
params.insert(make_pair(acl::PROP_MAXQUEUECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.max_count"))));
params.insert(make_pair(acl::PROP_MAXQUEUESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.max_size"))));
+ params.insert(make_pair(acl::PROP_MAXFILECOUNT, boost::lexical_cast<string>(arguments.getAsInt("qpid.file_count"))));
+ params.insert(make_pair(acl::PROP_MAXFILESIZE, boost::lexical_cast<string>(arguments.getAsInt64("qpid.file_size"))));
if (!acl->authorise(userId,acl::ACT_CREATE,acl::OBJ_QUEUE,name,&params) )
throw framing::UnauthorizedAccessException(QPID_MSG("ACL denied queue create request from " << userId));
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 180f848..3d138ab 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -545,6 +545,123 @@ class ACLTests(TestBase010):
self.fail(result)
+ def test_illegal_filemaxsize_upper_limit_spec(self):
+ """
+ Test illegal file policy
+ """
+ #
+ # Use filemaxsizeupperlimit
+ #
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxsizeupperlimit=-1\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "-1 is not a valid value for 'filemaxsizeupperlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxsizeupperlimit=9223372036854775808\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "9223372036854775808 is not a valid value for 'filemaxsizeupperlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+
+
+ def test_illegal_filemaxcount_upper_limit_spec(self):
+ """
+ Test illegal file policy
+ """
+ #
+ # use maxfilecountupperlimit
+ #
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxcountupperlimit=-1\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "-1 is not a valid value for 'filemaxcountupperlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxcountupperlimit=9223372036854775808\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "9223372036854775808 is not a valid value for 'filemaxcountupperlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+
+ def test_illegal_filemaxsize_lower_limit_spec(self):
+ """
+ Test illegal file policy
+ """
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxsizelowerlimit=-1\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "-1 is not a valid value for 'filemaxsizelowerlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxsizelowerlimit=9223372036854775808\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "9223372036854775808 is not a valid value for 'filemaxsizelowerlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+
+
+ def test_illegal_filemaxcount_lower_limit_spec(self):
+ """
+ Test illegal file policy
+ """
+
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxcountlowerlimit=-1\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "-1 is not a valid value for 'filemaxcountlowerlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID create queue name=q2 filemaxcountlowerlimit=9223372036854775808\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ expected = "9223372036854775808 is not a valid value for 'filemaxcountlowerlimit', " \
+ "values should be between 0 and 9223372036854775807";
+ if (result.find(expected) == -1):
+ self.fail(result)
+
+
#=====================================
# ACL queue tests
#=====================================
@@ -834,6 +951,171 @@ class ACLTests(TestBase010):
self.fail("ACL should allow queue delete request for q4");
#=====================================
+ # ACL file tests
+ #=====================================
+
+ def test_file_allow_mode(self):
+ """
+ Test cases for file acl in allow mode
+ """
+ aclf = self.get_acl_file()
+ aclf.write('acl deny bob@QPID access queue name=qf1\n')
+ aclf.write('acl deny bob@QPID create queue name=qf1 durable=true\n')
+ aclf.write('acl deny bob@QPID create queue name=qf2 exclusive=true policytype=ring\n')
+ aclf.write('acl deny bob@QPID access queue name=qf3\n')
+ aclf.write('acl deny bob@QPID purge queue name=qf3\n')
+ aclf.write('acl deny bob@QPID delete queue name=qf4\n')
+ aclf.write('acl deny bob@QPID create queue name=qf5 filemaxsizeupperlimit=1000 filemaxcountupperlimit=100\n')
+ aclf.write('acl allow all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 200
+ queue_options["qpid.file_size"] = 500
+ session.queue_declare(queue="qf5", exclusive=True, arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=qf5, qpid.file_size=500 and qpid.file_count=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 200
+ queue_options["qpid.file_size"] = 100
+ session.queue_declare(queue="qf2", exclusive=True, arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (403 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=qf2, qpid.file_size=100 and qpid.file_count=200 ");
+
+
+ def test_file_deny_mode(self):
+ """
+ Test cases for queue acl in deny mode
+ """
+ aclf = self.get_acl_file()
+ aclf.write('acl allow bob@QPID access queue name=qfd1\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd1 durable=true\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd2 exclusive=true policytype=ring\n')
+ aclf.write('acl allow bob@QPID access queue name=qfd3\n')
+ aclf.write('acl allow bob@QPID purge queue name=qfd3\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd3\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd4\n')
+ aclf.write('acl allow bob@QPID delete queue name=qfd4\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd5 filemaxsizeupperlimit=1000 filemaxcountupperlimit=100\n')
+ aclf.write('acl allow bob@QPID create queue name=qfd6 filemaxsizelowerlimit=50 filemaxsizeupperlimit=100 filemaxcountlowerlimit=50 filemaxcountupperlimit=100\n')
+ aclf.write('acl allow anonymous all all\n')
+ aclf.write('acl deny all all')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="qfd1", durable=True)
+ except qpid.session.SessionException, e:
+ if (403 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=qfd1 durable=true");
+
+ try:
+ session.queue_declare(queue="qfd1", durable=True, passive=True)
+ except qpid.session.SessionException, e:
+ if (403 == e.args[0].error_code):
+ self.fail("ACL should allow queue passive declare request with name=qfd1 durable=true passive=true");
+
+ try:
+ session.queue_declare(queue="qfd1", durable=False, passive=False)
+ self.fail("ACL should deny queue create request with name=qfd1 durable=true passive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ session.queue_declare(queue="qfd2", exclusive=False)
+ self.fail("ACL should deny queue create request with name=qfd2 exclusive=false");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 200
+ queue_options["qpid.file_size"] = 500
+ session.queue_declare(queue="qfd5", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=qfd5 filemaxsizeupperlimit=500 filemaxcountupperlimit=200");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 100
+ queue_options["qpid.file_size"] = 500
+ session.queue_declare(queue="qfd5", arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (403 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=qfd5 filemaxsizeupperlimit=500 filemaxcountupperlimit=200");
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 49
+ queue_options["qpid.file_size"] = 100
+ session.queue_declare(queue="qfd6", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=qfd6 filemaxsizeupperlimit=100 filemaxcountupperlimit=49");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 101
+ queue_options["qpid.file_size"] = 100
+ session.queue_declare(queue="qfd6", arguments=queue_options)
+ self.fail("ACL should allow queue create request with name=qfd6 filemaxsizeupperlimit=100 filemaxcountupperlimit=101");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 100
+ queue_options["qpid.file_size"] = 49
+ session.queue_declare(queue="qfd6", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=qfd6 filemaxsizeupperlimit=49 filemaxcountupperlimit=100");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 100
+ queue_options["qpid.file_size"] =101
+ session.queue_declare(queue="qfd6", arguments=queue_options)
+ self.fail("ACL should deny queue create request with name=qfd6 filemaxsizeupperlimit=101 filemaxcountupperlimit=100");
+ except qpid.session.SessionException, e:
+ self.assertEqual(403,e.args[0].error_code)
+ session = self.get_session('bob','bob')
+
+ try:
+ queue_options = {}
+ queue_options["qpid.file_count"] = 50
+ queue_options["qpid.file_size"] = 50
+ session.queue_declare(queue="qfd6", arguments=queue_options)
+ except qpid.session.SessionException, e:
+ if (403 == e.args[0].error_code):
+ self.fail("ACL should allow queue create request with name=qfd6 filemaxsizeupperlimit=50 filemaxcountupperlimit=50");
+
+
+ #=====================================
# ACL exchange tests
#=====================================
--
1.7.1
From b4dcc8feb765e60e4e189221f0c7f18d7906439c Mon Sep 17 00:00:00 2001
From: Charles E. Rolke <chug@apache.org>
Date: Fri, 24 Aug 2012 21:50:59 +0000
Subject: [PATCH 19/19] QPID-4249 TopicExchange binding lookup for all routing keys
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1377130 13f79535-47bb-0310-9956-ffa450edef68
---
qpid/cpp/src/qpid/acl/AclData.cpp | 21 +++++-
qpid/cpp/src/qpid/acl/AclReader.cpp | 17 +++--
qpid/cpp/src/tests/acl.py | 125 ++++++++++++++++++++++++++++++++++-
3 files changed, 152 insertions(+), 11 deletions(-)
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp
index feb8b9d..997fbdf 100644
--- a/qpid/cpp/src/qpid/acl/AclData.cpp
+++ b/qpid/cpp/src/qpid/acl/AclData.cpp
@@ -255,14 +255,31 @@ namespace acl {
default:
bool result;
if ((SPECPROP_ALTERNATE == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ALTERNATE]) ||
- (SPECPROP_ROUTINGKEY == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) ||
(SPECPROP_QUEUENAME == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_QUEUENAME]))
{
// These properties are allowed to have username substitution
std::string sName(rulePropMapItr->second);
substituteUserId(sName, id);
result = matchProp(sName, lookupParamItr->second);
- } else {
+ }
+ else if (SPECPROP_ROUTINGKEY == rulePropMapItr->first)
+ {
+ // Routing key is allowed to have username substitution
+ // and it gets topic exchange matching
+ if (rsItr->ruleHasUserSub[PROP_ROUTINGKEY])
+ {
+ std::string sKey(lookupParamItr->second);
+ substituteKeywords(sKey, id);
+ result = rsItr->matchRoutingKey(sKey);
+ }
+ else
+ {
+ result = rsItr->matchRoutingKey(lookupParamItr->second);
+ }
+ }
+ else
+ {
+ // Rules without substitution
result = matchProp(rulePropMapItr->second, lookupParamItr->second);
}
diff --git a/qpid/cpp/src/qpid/acl/AclReader.cpp b/qpid/cpp/src/qpid/acl/AclReader.cpp
index fae67d0..3d5a666 100644
--- a/qpid/cpp/src/qpid/acl/AclReader.cpp
+++ b/qpid/cpp/src/qpid/acl/AclReader.cpp
@@ -112,6 +112,16 @@ namespace acl {
}
}
+ // Find possible routingkey property and cache its pattern
+ for (pmCitr pItr=rule.props.begin(); pItr!=rule.props.end(); pItr++) {
+ if (acl::SPECPROP_ROUTINGKEY == pItr->first)
+ {
+ rule.pubRoutingKeyInRule = true;
+ rule.pubRoutingKey = (std::string)pItr->second;
+ rule.addTopicTest(rule.pubRoutingKey);
+ }
+ }
+
// Action -> Object -> map<user -> set<Rule> >
std::ostringstream actionstr;
for (int acnt = ((*i)->actionAll ? 0 : (*i)->action);
@@ -126,13 +136,6 @@ namespace acl {
// Go through the rule properties and find the name and the key.
// If found then place them specially for the lookup engine.
for (pmCitr pItr=(*i)->props.begin(); pItr!=(*i)->props.end(); pItr++) {
- if (acl::SPECPROP_ROUTINGKEY == pItr->first)
- {
- rule.pubRoutingKeyInRule = true;
- rule.pubRoutingKey = (std::string)pItr->second;
- rule.addTopicTest(rule.pubRoutingKey);
- break;
- }
if (acl::SPECPROP_NAME == pItr->first)
{
rule.pubExchNameInRule = true;
diff --git a/qpid/cpp/src/tests/acl.py b/qpid/cpp/src/tests/acl.py
index 3d138ab..1020a2e 100755
--- a/qpid/cpp/src/tests/acl.py
+++ b/qpid/cpp/src/tests/acl.py
@@ -1823,10 +1823,10 @@ class ACLTests(TestBase010):
#=====================================
- # QMF Topic Exchange tests
+ # Routingkey lookup using Topic Exchange tests
#=====================================
- def test_qmf_topic_exchange_tests(self):
+ def test_topic_exchange_publish_tests(self):
"""
Test using QMF method hooks into ACL logic
"""
@@ -1940,6 +1940,127 @@ class ACLTests(TestBase010):
self.LookupPublish("dev@QPID", "X", "a.M.N", "allow-log")
self.LookupPublish("dev@QPID", "X", "a.M.p.qq.N", "allow-log")
+ def test_topic_exchange_other_tests(self):
+ """
+ Test using QMF method hooks into ACL logic
+ """
+ action_list = ['access','bind','unbind']
+
+ aclf = self.get_acl_file()
+ aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n')
+ aclf.write('acl allow-log anonymous create queue\n')
+ aclf.write('acl allow-log anonymous all exchange name=qmf.*\n')
+ aclf.write('acl allow-log anonymous all exchange name=amq.direct\n')
+ aclf.write('acl allow-log anonymous all exchange name=qpid.management\n')
+ aclf.write('acl allow-log anonymous access method name=*\n')
+ aclf.write('# end hack alert\n')
+ for action in action_list:
+ aclf.write('acl allow-log uPlain1@COMPANY ' + action + ' exchange name=X routingkey=ab.cd.e\n')
+ aclf.write('acl allow-log uPlain2@COMPANY ' + action + ' exchange name=X routingkey=.\n')
+ aclf.write('acl allow-log uStar1@COMPANY ' + action + ' exchange name=X routingkey=a.*.b\n')
+ aclf.write('acl allow-log uStar2@COMPANY ' + action + ' exchange name=X routingkey=*.x\n')
+ aclf.write('acl allow-log uStar3@COMPANY ' + action + ' exchange name=X routingkey=x.x.*\n')
+ aclf.write('acl allow-log uHash1@COMPANY ' + action + ' exchange name=X routingkey=a.#.b\n')
+ aclf.write('acl allow-log uHash2@COMPANY ' + action + ' exchange name=X routingkey=a.#\n')
+ aclf.write('acl allow-log uHash3@COMPANY ' + action + ' exchange name=X routingkey=#.a\n')
+ aclf.write('acl allow-log uHash4@COMPANY ' + action + ' exchange name=X routingkey=a.#.b.#.c\n')
+ aclf.write('acl allow-log uMixed1@COMPANY ' + action + ' exchange name=X routingkey=*.x.#.y\n')
+ aclf.write('acl allow-log uMixed2@COMPANY ' + action + ' exchange name=X routingkey=a.#.b.*\n')
+ aclf.write('acl allow-log uMixed3@COMPANY ' + action + ' exchange name=X routingkey=*.*.*.#\n')
+
+ aclf.write('acl allow-log all ' + action + ' exchange name=X routingkey=MN.OP.Q\n')
+ aclf.write('acl allow-log all ' + action + ' exchange name=X routingkey=M.*.N\n')
+ aclf.write('acl allow-log all ' + action + ' exchange name=X routingkey=M.#.N\n')
+ aclf.write('acl allow-log all ' + action + ' exchange name=X routingkey=*.M.#.N\n')
+
+ aclf.write('acl deny-log all all\n')
+ aclf.close()
+
+ result = self.reload_acl()
+ if (result):
+ self.fail(result)
+
+ for action in action_list:
+ # aclKey: "ab.cd.e"
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd.e"}, "allow-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd.e"}, "allow-log")
+
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd.e"}, "allow-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"abx.cd.e"}, "deny-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd"}, "deny-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd..e."}, "deny-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"ab.cd.e."}, "deny-log")
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":".ab.cd.e"}, "deny-log")
+ # aclKey: "."
+ self.Lookup("uPlain2@COMPANY", action, "exchange", "X", {"routingkey":"."}, "allow-log")
+
+ # aclKey: "a.*.b"
+ self.Lookup("uStar1@COMPANY", action, "exchange", "X", {"routingkey":"a.xx.b"}, "allow-log")
+ self.Lookup("uStar1@COMPANY", action, "exchange", "X", {"routingkey":"a.b"}, "deny-log")
+ # aclKey: "*.x"
+ self.Lookup("uStar2@COMPANY", action, "exchange", "X", {"routingkey":"y.x"}, "allow-log")
+ self.Lookup("uStar2@COMPANY", action, "exchange", "X", {"routingkey":".x"}, "allow-log")
+ self.Lookup("uStar2@COMPANY", action, "exchange", "X", {"routingkey":"x"}, "deny-log")
+ # aclKey: "x.x.*"
+ self.Lookup("uStar3@COMPANY", action, "exchange", "X", {"routingkey":"x.x.y"}, "allow-log")
+ self.Lookup("uStar3@COMPANY", action, "exchange", "X", {"routingkey":"x.x."}, "allow-log")
+ self.Lookup("uStar3@COMPANY", action, "exchange", "X", {"routingkey":"x.x"}, "deny-log")
+ self.Lookup("uStar3@COMPANY", action, "exchange", "X", {"routingkey":"q.x.y"}, "deny-log")
+
+ # aclKey: "a.#.b"
+ self.Lookup("uHash1@COMPANY", action, "exchange", "X", {"routingkey":"a.b"}, "allow-log")
+ self.Lookup("uHash1@COMPANY", action, "exchange", "X", {"routingkey":"a.x.b"}, "allow-log")
+ self.Lookup("uHash1@COMPANY", action, "exchange", "X", {"routingkey":"a..x.y.zz.b"}, "allow-log")
+ self.Lookup("uHash1@COMPANY", action, "exchange", "X", {"routingkey":"a.b."}, "deny-log")
+ self.Lookup("uHash1@COMPANY", action, "exchange", "X", {"routingkey":"q.x.b"}, "deny-log")
+
+ # aclKey: "a.#"
+ self.Lookup("uHash2@COMPANY", action, "exchange", "X", {"routingkey":"a"}, "allow-log")
+ self.Lookup("uHash2@COMPANY", action, "exchange", "X", {"routingkey":"a.b"}, "allow-log")
+ self.Lookup("uHash2@COMPANY", action, "exchange", "X", {"routingkey":"a.b.c"}, "allow-log")
+
+ # aclKey: "#.a"
+ self.Lookup("uHash3@COMPANY", action, "exchange", "X", {"routingkey":"a"}, "allow-log")
+ self.Lookup("uHash3@COMPANY", action, "exchange", "X", {"routingkey":"x.y.a"}, "allow-log")
+
+ # aclKey: "a.#.b.#.c"
+ self.Lookup("uHash4@COMPANY", action, "exchange", "X", {"routingkey":"a.b.c"}, "allow-log")
+ self.Lookup("uHash4@COMPANY", action, "exchange", "X", {"routingkey":"a.x.b.y.c"}, "allow-log")
+ self.Lookup("uHash4@COMPANY", action, "exchange", "X", {"routingkey":"a.x.x.b.y.y.c"}, "allow-log")
+
+ # aclKey: "*.x.#.y"
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"a.x.y"}, "allow-log")
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"a.x.p.qq.y"}, "allow-log")
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"a.a.x.y"}, "deny-log")
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"aa.x.b.c"}, "deny-log")
+
+ # aclKey: "a.#.b.*"
+ self.Lookup("uMixed2@COMPANY", action, "exchange", "X", {"routingkey":"a.b.x"}, "allow-log")
+ self.Lookup("uMixed2@COMPANY", action, "exchange", "X", {"routingkey":"a.x.x.x.b.x"}, "allow-log")
+
+ # aclKey: "*.*.*.#"
+ self.Lookup("uMixed3@COMPANY", action, "exchange", "X", {"routingkey":"x.y.z"}, "allow-log")
+ self.Lookup("uMixed3@COMPANY", action, "exchange", "X", {"routingkey":"x.y.z.a.b.c"}, "allow-log")
+ self.Lookup("uMixed3@COMPANY", action, "exchange", "X", {"routingkey":"x.y"}, "deny-log")
+ self.Lookup("uMixed3@COMPANY", action, "exchange", "X", {"routingkey":"x"}, "deny-log")
+
+ # Repeat the keys with wildcard user spec
+ self.Lookup("uPlain1@COMPANY", action, "exchange", "X", {"routingkey":"MN.OP.Q"}, "allow-log")
+ self.Lookup("uStar1@COMPANY" , action, "exchange", "X", {"routingkey":"M.xx.N"}, "allow-log")
+ self.Lookup("uHash1@COMPANY" , action, "exchange", "X", {"routingkey":"M.N"}, "allow-log")
+ self.Lookup("uHash1@COMPANY" , action, "exchange", "X", {"routingkey":"M.x.N"}, "allow-log")
+ self.Lookup("uHash1@COMPANY" , action, "exchange", "X", {"routingkey":"M..x.y.zz.N"}, "allow-log")
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"a.M.N"}, "allow-log")
+ self.Lookup("uMixed1@COMPANY", action, "exchange", "X", {"routingkey":"a.M.p.qq.N"}, "allow-log")
+
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "MN.OP.Q"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "M.xx.N"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "M.N"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "M.x.N"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "M..x.y.zz.N"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "a.M.N"}, "allow-log")
+ self.Lookup("dev@QPID", action, "exchange", "X", {"routingkey": "a.M.p.qq.N"}, "allow-log")
+
#=====================================
# Connection limits
#=====================================
--
1.7.1