diff options
author | Charles E. Rolke <chug@apache.org> | 2013-06-28 16:11:55 +0000 |
---|---|---|
committer | Charles E. Rolke <chug@apache.org> | 2013-06-28 16:11:55 +0000 |
commit | c11bd16a3240f05dea6618b9c572fd3cd3d417f4 (patch) | |
tree | 7b61320ebe04da415ce709a25c760f347d98a3e2 /qpid/cpp/src | |
parent | 9f4d5ee381667a129d926ddd3df5735f839f7bbc (diff) | |
download | qpid-python-c11bd16a3240f05dea6618b9c572fd3cd3d417f4.tar.gz |
NO-JIRA: Refactor AclData to extract two deeply nested functions. Fix parens.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1497827 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/src')
-rw-r--r-- | qpid/cpp/src/qpid/acl/AclData.cpp | 1401 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/acl/AclData.h | 14 |
2 files changed, 699 insertions, 716 deletions
diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp index 68fc137612..a205ddabfc 100644 --- a/qpid/cpp/src/qpid/acl/AclData.cpp +++ b/qpid/cpp/src/qpid/acl/AclData.cpp @@ -24,772 +24,741 @@ namespace qpid { namespace acl { - // - // Instantiate the keyword strings - // - const std::string AclData::ACL_KEYWORD_USER_SUBST = "${user}"; - const std::string AclData::ACL_KEYWORD_DOMAIN_SUBST = "${domain}"; - const std::string AclData::ACL_KEYWORD_USERDOMAIN_SUBST = "${userdomain}"; - const std::string AclData::ACL_KEYWORD_ALL = "all"; - const std::string AclData::ACL_KEYWORD_ACL = "acl"; - const std::string AclData::ACL_KEYWORD_GROUP = "group"; - const std::string AclData::ACL_KEYWORD_QUOTA = "quota"; - const std::string AclData::ACL_KEYWORD_QUOTA_CONNECTIONS = "connections"; - const std::string AclData::ACL_KEYWORD_QUOTA_QUEUES = "queues"; - const char AclData::ACL_SYMBOL_WILDCARD = '*'; - const std::string AclData::ACL_KEYWORD_WILDCARD = "*"; - const char AclData::ACL_SYMBOL_LINE_CONTINUATION = '\\'; - const std::string AclData::ACL_KEYWORD_DEFAULT_EXCHANGE = "amq.default"; - - // - // constructor - // - AclData::AclData(): - decisionMode(qpid::acl::DENY), - transferAcl(false), - aclSource("UNKNOWN"), - connQuotaRulesExist(false), - connQuotaRuleSettings(new quotaRuleSet), - queueQuotaRulesExist(false), - queueQuotaRuleSettings(new quotaRuleSet) - { - for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++) - { - actionList[cnt]=0; - } +// +// Instantiate the keyword strings +// +const std::string AclData::ACL_KEYWORD_USER_SUBST = "${user}"; +const std::string AclData::ACL_KEYWORD_DOMAIN_SUBST = "${domain}"; +const std::string AclData::ACL_KEYWORD_USERDOMAIN_SUBST = "${userdomain}"; +const std::string AclData::ACL_KEYWORD_ALL = "all"; +const std::string AclData::ACL_KEYWORD_ACL = "acl"; +const std::string AclData::ACL_KEYWORD_GROUP = "group"; +const std::string AclData::ACL_KEYWORD_QUOTA = "quota"; +const std::string AclData::ACL_KEYWORD_QUOTA_CONNECTIONS = "connections"; +const std::string AclData::ACL_KEYWORD_QUOTA_QUEUES = "queues"; +const char AclData::ACL_SYMBOL_WILDCARD = '*'; +const std::string AclData::ACL_KEYWORD_WILDCARD = "*"; +const char AclData::ACL_SYMBOL_LINE_CONTINUATION = '\\'; +const std::string AclData::ACL_KEYWORD_DEFAULT_EXCHANGE = "amq.default"; + +// +// constructor +// +AclData::AclData(): + decisionMode(qpid::acl::DENY), + transferAcl(false), + aclSource("UNKNOWN"), + connQuotaRulesExist(false), + connQuotaRuleSettings(new quotaRuleSet), + queueQuotaRulesExist(false), + queueQuotaRuleSettings(new quotaRuleSet) +{ + for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++) { + actionList[cnt]=0; } - - - // - // clear - // - void AclData::clear () - { - for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++) - { - if (actionList[cnt]) - { - for (unsigned int cnt1=0; cnt1< qpid::acl::OBJECTSIZE; cnt1++) - delete actionList[cnt][cnt1]; +} + + +// +// clear +// +void AclData::clear () +{ + for (unsigned int cnt=0; cnt< qpid::acl::ACTIONSIZE; cnt++) { + if (actionList[cnt]) { + for (unsigned int cnt1=0; cnt1< qpid::acl::OBJECTSIZE; cnt1++) { + delete actionList[cnt][cnt1]; } - delete[] actionList[cnt]; } - transferAcl = false; - connQuotaRulesExist = false; - connQuotaRuleSettings->clear(); - queueQuotaRulesExist = false; - queueQuotaRuleSettings->clear(); + delete[] actionList[cnt]; } - - - // - // matchProp - // - // Compare a rule's property name with a lookup name, - // The rule's name may contain a trailing '*' to specify a wildcard match. - // - bool AclData::matchProp(const std::string& ruleStr, - const std::string& lookupStr) - { - // allow wildcard on the end of rule strings... - if (ruleStr.data()[ruleStr.size()-1]==ACL_SYMBOL_WILDCARD) - { - return ruleStr.compare(0, - ruleStr.size()-1, - lookupStr, - 0, - ruleStr.size()-1 ) == 0; - } - else - { - return ruleStr.compare(lookupStr) == 0; - } + transferAcl = false; + connQuotaRulesExist = false; + connQuotaRuleSettings->clear(); + queueQuotaRulesExist = false; + queueQuotaRuleSettings->clear(); +} + + +// +// matchProp +// +// Compare a rule's property name with a lookup name, +// The rule's name may contain a trailing '*' to specify a wildcard match. +// +bool AclData::matchProp(const std::string& ruleStr, + const std::string& lookupStr) +{ + // allow wildcard on the end of rule strings... + if (ruleStr.data()[ruleStr.size()-1]==ACL_SYMBOL_WILDCARD) { + return ruleStr.compare(0, + ruleStr.size()-1, + lookupStr, + 0, + ruleStr.size()-1 ) == 0; + } else { + return ruleStr.compare(lookupStr) == 0; } - - - // - // lookup - // - // The ACL main business logic function of matching rules and declaring - // an allow or deny result. - // - AclResult AclData::lookup( - const std::string& id, - const Action& action, - const ObjectType& objType, - const std::string& name, - std::map<Property, std::string>* params) - { - QPID_LOG(debug, "ACL: Lookup for id:" << id - << " action:" << AclHelper::getActionStr((Action) action) - << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) - << " name:" << name - << " with params " << AclHelper::propertyMapToString(params)); - - // A typical log looks like: - // ACL: Lookup for id:bob@QPID action:create objectType:queue name:q2 - // with params { durable=false passive=false autodelete=false - // exclusive=false alternate= policytype= maxqueuesize=0 - // maxqueuecount=0 } - - // Default result is blanket decision mode for the entire ACL list. - AclResult aclresult = decisionMode; - - // Test for lists of rules at the intersection of the Action & Object - if (actionList[action] && actionList[action][objType]) +} + + +// +// lookupMatchRule +// +// Check a single rule and if it's a match return the decision +// +bool AclData::lookupMatchRule( + const ruleSetItr& rsItr, + const std::string& id, + const std::string& name, + const std::map<Property, std::string>* params, + AclResult& aclresult) +{ + QPID_LOG(debug, "ACL: checking rule " << rsItr->toString()); + + bool match = true; + bool limitChecked = true; + + // Iterate this rule's properties. A 'match' is true when + // all of the rule's properties are found to be satisfied + // in the lookup param list. The lookup may specify things + // (they usually do) that are not in the rule properties but + // these things don't interfere with the rule match. + + for (specPropertyMapItr rulePropMapItr = rsItr->props.begin(); + (rulePropMapItr != rsItr->props.end()) && match; + rulePropMapItr++) { + // The rule property map's NAME property is given in + // the calling args and not in the param map. + if (rulePropMapItr->first == acl::SPECPROP_NAME) { - // Find the list of rules for this actorId - AclData::actObjItr itrRule = actionList[action][objType]->find(id); - - // If individual actorId not found then find a rule set for '*'. - if (itrRule == actionList[action][objType]->end()) - itrRule = actionList[action][objType]->find(ACL_KEYWORD_WILDCARD); - - if (itrRule != actionList[action][objType]->end()) - { - // A list of rules exists for this actor/action/object tuple. - // Iterate the rule set to search for a matching rule. - ruleSetItr rsItr = itrRule->second.end(); - for (int cnt = itrRule->second.size(); cnt != 0; cnt--) - { - rsItr--; - - QPID_LOG(debug, "ACL: checking rule " << rsItr->toString()); - - bool match = true; - bool limitChecked = true; - - // Iterate this rule's properties. A 'match' is true when - // all of the rule's properties are found to be satisfied - // in the lookup param list. The lookup may specify things - // (they usually do) that are not in the rule properties but - // these things don't interfere with the rule match. - - for (specPropertyMapItr rulePropMapItr = rsItr->props.begin(); - (rulePropMapItr != rsItr->props.end()) && match; - rulePropMapItr++) - { - // The rule property map's NAME property is given in - // the calling args and not in the param map. - if (rulePropMapItr->first == acl::SPECPROP_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 '" - << rulePropMapItr->second << "'"); - } - else - { - match = false; - QPID_LOG(debug, "ACL: lookup name '" << name - << "' didn't match with rule name '" - << rulePropMapItr->second << "'"); - } - } - else - { - if (params) - { - // The rule's property map non-NAME properties - // found in the lookup's params list. - // In some cases the param's index is not the same - // as rule's index. - propertyMapItr lookupParamItr; - switch (rulePropMapItr->first) - { - case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT: - case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT: - lookupParamItr = params->find(PROP_MAXQUEUECOUNT); - break; - - case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT: - case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT: - 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; - }; - - if (lookupParamItr == params->end()) - { - // Now the rule has a specified property - // that does not exist in the caller's - // lookup params list. - // This rule does not match. - match = false; - QPID_LOG(debug, "ACL: lookup parameter map doesn't contain the rule property '" - << AclHelper::getPropertyStr(rulePropMapItr->first) << "'"); - } - else - { - // Now account for the business of rules - // whose property indexes are mismatched. - switch (rulePropMapItr->first) - { - case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT: - case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT: - case acl::SPECPROP_MAXFILECOUNTUPPERLIMIT: - case acl::SPECPROP_MAXFILESIZEUPPERLIMIT: - limitChecked &= - compareInt( - rulePropMapItr->first, - boost::lexical_cast<std::string>(rulePropMapItr->second), - boost::lexical_cast<std::string>(lookupParamItr->second), - true); - break; - - case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT: - case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT: - case acl::SPECPROP_MAXFILECOUNTLOWERLIMIT: - case acl::SPECPROP_MAXFILESIZELOWERLIMIT: - limitChecked &= - compareInt( - rulePropMapItr->first, - boost::lexical_cast<std::string>(rulePropMapItr->second), - boost::lexical_cast<std::string>(lookupParamItr->second), - false); - break; - - default: - bool result; - if ((SPECPROP_ALTERNATE == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ALTERNATE]) || - (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 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); - } - - if (result) - { - QPID_LOG(debug, "ACL: the pair(" - << AclHelper::getPropertyStr(lookupParamItr->first) - << "," << lookupParamItr->second - << ") given in lookup matched the pair(" - << AclHelper::getPropertyStr(rulePropMapItr->first) << "," - << rulePropMapItr->second - << ") given in the rule"); - } - else - { - match = false; - QPID_LOG(debug, "ACL: the pair(" - << AclHelper::getPropertyStr(lookupParamItr->first) - << "," << lookupParamItr->second - << ") given in lookup doesn't match the pair(" - << AclHelper::getPropertyStr(rulePropMapItr->first) - << "," << rulePropMapItr->second - << ") given in the rule"); - } - break; - }; - } - } - else - { - // params don't exist. - } - } - } - if (match) - { - aclresult = rsItr->ruleMode; - if (!limitChecked) - { - // Now a lookup matched all rule properties but one - // of the numeric limit checks has failed. - // Demote allow rules to corresponding deny rules. - switch (aclresult) - { - case acl::ALLOW: - aclresult = acl::DENY; - break; - case acl::ALLOWLOG: - aclresult = acl::DENYLOG; - break; - default: - break; - }; - } - QPID_LOG(debug,"ACL: Successful match, the decision is:" - << AclHelper::getAclResultStr(aclresult)); - return aclresult; - } - else - { - // This rule did not match the requested lookup and - // does not contribute to an ACL decision. - } - } - } - else - { - // The Action-Object list has entries but not for this actorId - // nor for *. + // 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); } - } - else - { - // The Action-Object list has no entries. - } - QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode " - << AclHelper::getAclResultStr(aclresult)); - return aclresult; - } - - - // - // lookup - // - // The ACL main business logic function of matching rules and declaring - // 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, - const Action& action, - const ObjectType& objType, - const std::string& /*Exchange*/ name, - const std::string& routingKey) - { - - QPID_LOG(debug, "ACL: Lookup for id:" << id - << " action:" << AclHelper::getActionStr((Action) action) - << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) - << " exchange name:" << name - << " with routing key " << routingKey); - - AclResult aclresult = decisionMode; - - if (actionList[action] && actionList[action][objType]){ - AclData::actObjItr itrRule = actionList[action][objType]->find(id); - - if (itrRule == actionList[action][objType]->end()) - itrRule = actionList[action][objType]->find(ACL_KEYWORD_WILDCARD); - - if (itrRule != actionList[action][objType]->end() ) - { - // 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--) - { - rsItr--; - - QPID_LOG(debug, "ACL: checking rule " << rsItr->toString()); - - // Search on exchange name and routing key only if specfied in rule. - bool match =true; - if (rsItr->pubExchNameInRule) - { - // substitute user name into object name + if (result) { + QPID_LOG(debug, "ACL: lookup name '" << name + << "' matched with rule name '" + << rulePropMapItr->second << "'"); + } else { + match = false; + QPID_LOG(debug, "ACL: lookup name '" << name + << "' didn't match with rule name '" + << rulePropMapItr->second << "'"); + } + } else { + if (params) { + // The rule's property map non-NAME properties + // found in the lookup's params list. + // In some cases the param's index is not the same + // as rule's index. + propertyMapItr lookupParamItr; + switch (rulePropMapItr->first) { + case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT: + case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT: + lookupParamItr = params->find(PROP_MAXQUEUECOUNT); + break; + + case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT: + case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT: + 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; + }; + + if (lookupParamItr == params->end()) { + // Now the rule has a specified property + // that does not exist in the caller's + // lookup params list. + // This rule does not match. + match = false; + QPID_LOG(debug, "ACL: lookup parameter map doesn't contain the rule property '" + << AclHelper::getPropertyStr(rulePropMapItr->first) << "'"); + } else { + // Now account for the business of rules + // whose property indexes are mismatched. + switch (rulePropMapItr->first) { + case acl::SPECPROP_MAXQUEUECOUNTUPPERLIMIT: + case acl::SPECPROP_MAXQUEUESIZEUPPERLIMIT: + case acl::SPECPROP_MAXFILECOUNTUPPERLIMIT: + case acl::SPECPROP_MAXFILESIZEUPPERLIMIT: + limitChecked &= + compareInt( + rulePropMapItr->first, + boost::lexical_cast<std::string>(rulePropMapItr->second), + boost::lexical_cast<std::string>(lookupParamItr->second), + true); + break; + + case acl::SPECPROP_MAXQUEUECOUNTLOWERLIMIT: + case acl::SPECPROP_MAXQUEUESIZELOWERLIMIT: + case acl::SPECPROP_MAXFILECOUNTLOWERLIMIT: + case acl::SPECPROP_MAXFILESIZELOWERLIMIT: + limitChecked &= + compareInt( + rulePropMapItr->first, + boost::lexical_cast<std::string>(rulePropMapItr->second), + boost::lexical_cast<std::string>(lookupParamItr->second), + false); + break; + + default: bool result; - - if (rsItr->ruleHasUserSub[PROP_NAME]) { - std::string sName(rsItr->pubExchName); + if ((SPECPROP_ALTERNATE == rulePropMapItr->first && rsItr->ruleHasUserSub[PROP_ALTERNATE]) || + (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, name); - } - else if (rsItr->pubExchNameMatchesBlank) - { - result = name.empty(); - } - else - { - result = matchProp(rsItr->pubExchName, name); - } - - if (result) - { - QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '" - << name << "' matched with rule name '" - << rsItr->pubExchName << "'"); - } - else - { - match= false; - QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '" - << name << "' did not match with rule name '" - << rsItr->pubExchName << "'"); - } - } - - if (match && rsItr->pubRoutingKeyInRule) - { - if ((routingKey.find(ACL_KEYWORD_USER_SUBST, 0) != std::string::npos) || - (routingKey.find(ACL_KEYWORD_DOMAIN_SUBST, 0) != std::string::npos) || - (routingKey.find(ACL_KEYWORD_USERDOMAIN_SUBST, 0) != std::string::npos)) - { - // 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 - { - bool result; + result = matchProp(sName, lookupParamItr->second); + } 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(routingKey); + std::string sKey(lookupParamItr->second); substituteKeywords(sKey, id); result = rsItr->matchRoutingKey(sKey); } else { - result = rsItr->matchRoutingKey(routingKey); + result = rsItr->matchRoutingKey(lookupParamItr->second); } + } else { + // Rules without substitution + result = matchProp(rulePropMapItr->second, lookupParamItr->second); + } - 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; - } + if (result) { + QPID_LOG(debug, "ACL: the pair(" + << AclHelper::getPropertyStr(lookupParamItr->first) + << "," << lookupParamItr->second + << ") given in lookup matched the pair(" + << AclHelper::getPropertyStr(rulePropMapItr->first) << "," + << rulePropMapItr->second + << ") given in the rule"); + } else { + match = false; + QPID_LOG(debug, "ACL: the pair(" + << AclHelper::getPropertyStr(lookupParamItr->first) + << "," << lookupParamItr->second + << ") given in lookup doesn't match the pair(" + << AclHelper::getPropertyStr(rulePropMapItr->first) + << "," << rulePropMapItr->second + << ") given in the rule"); } - } - - if (match){ - aclresult = rsItr->ruleMode; - QPID_LOG(debug,"ACL: Rule: " << rsItr->rawRuleNum << " Successful match, the decision is:" - << AclHelper::getAclResultStr(aclresult)); - return aclresult; - } + break; + }; } + } else { + // params don't exist. } } - QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode " - << AclHelper::getAclResultStr(aclresult)); - return aclresult; - } - - - - // - // - // - void AclData::setConnQuotaRuleSettings ( - bool rulesExist, boost::shared_ptr<quotaRuleSet> quotaPtr) - { - connQuotaRulesExist = rulesExist; - connQuotaRuleSettings = quotaPtr; + if (match) { + aclresult = rsItr->ruleMode; + if (!limitChecked) { + // Now a lookup matched all rule properties but one + // of the numeric limit checks has failed. + // Demote allow rules to corresponding deny rules. + switch (aclresult) { + case acl::ALLOW: + aclresult = acl::DENY; + break; + case acl::ALLOWLOG: + aclresult = acl::DENYLOG; + break; + default: + break; + }; + } + QPID_LOG(debug,"ACL: Successful match, the decision is:" + << AclHelper::getAclResultStr(aclresult)); + } else { + // This rule did not match the requested lookup and + // does not contribute to an ACL decision. } - - - // - // getConnQuotaForUser - // - // Return the true or false value of connQuotaRulesExist, - // indicating whether any kind of lookup was done or not. - // - // When lookups are performed return the result value of - // 1. The user's setting else - // 2. The 'all' user setting else - // 3. Zero - // When lookups are not performed then return a result value of Zero. - // - bool AclData::getConnQuotaForUser(const std::string& theUserName, - uint16_t* theResult) const { - if (connQuotaRulesExist) { - // look for this user explicitly - quotaRuleSetItr nameItr = (*connQuotaRuleSettings).find(theUserName); - if (nameItr != (*connQuotaRuleSettings).end()) { - QPID_LOG(trace, "ACL: Connection quota for user " << theUserName - << " explicitly set to : " << (*nameItr).second); - *theResult = (*nameItr).second; - } else { - // Look for the 'all' user - nameItr = (*connQuotaRuleSettings).find(ACL_KEYWORD_ALL); - if (nameItr != (*connQuotaRuleSettings).end()) { - QPID_LOG(trace, "ACL: Connection quota for user " << theUserName - << " chosen through value for 'all' : " << (*nameItr).second); - *theResult = (*nameItr).second; - } else { - // Neither userName nor "all" found. - QPID_LOG(trace, "ACL: Connection quota for user " << theUserName - << " absent in quota settings. Return value : 0"); - *theResult = 0; + return match; +} + +// +// lookup - general ACL lookup +// +// The ACL main business logic function of matching rules and declaring +// an allow or deny result. +// +AclResult AclData::lookup( + const std::string& id, + const Action& action, + const ObjectType& objType, + const std::string& name, + std::map<Property, std::string>* params) +{ + QPID_LOG(debug, "ACL: Lookup for id:" << id + << " action:" << AclHelper::getActionStr((Action) action) + << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) + << " name:" << name + << " with params " << AclHelper::propertyMapToString(params)); + + // A typical log looks like: + // ACL: Lookup for id:bob@QPID action:create objectType:queue name:q2 + // with params { durable=false passive=false autodelete=false + // exclusive=false alternate= policytype= maxqueuesize=0 + // maxqueuecount=0 } + + // Default result is blanket decision mode for the entire ACL list. + AclResult aclresult = decisionMode; + + // Test for lists of rules at the intersection of the Action & Object + if (actionList[action] && actionList[action][objType]) { + // Find the list of rules for this actorId + AclData::actObjItr itrRule = actionList[action][objType]->find(id); + + // If individual actorId not found then find a rule set for '*'. + if (itrRule == actionList[action][objType]->end()) { + itrRule = actionList[action][objType]->find(ACL_KEYWORD_WILDCARD); + } + if (itrRule != actionList[action][objType]->end()) { + // A list of rules exists for this actor/action/object tuple. + // Iterate the rule set to search for a matching rule. + ruleSetItr rsItr = itrRule->second.end(); + for (int cnt = itrRule->second.size(); cnt != 0; cnt--) { + rsItr--; + if (lookupMatchRule(rsItr, id, name, params, aclresult)) { + return aclresult; } } } else { - // Rules do not exist - QPID_LOG(trace, "ACL: Connection quota for user " << theUserName - << " unavailable; quota settings are not specified. Return value : 0"); - *theResult = 0; + // The Action-Object list has entries but not for this actorId + // nor for *. } - return connQuotaRulesExist; + } else { + // The Action-Object list has no entries. } - // - // - // - void AclData::setQueueQuotaRuleSettings ( - bool rulesExist, boost::shared_ptr<quotaRuleSet> quotaPtr) - { - queueQuotaRulesExist = rulesExist; - queueQuotaRuleSettings = quotaPtr; + QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode " + << AclHelper::getAclResultStr(aclresult)); + return aclresult; +} + + +// +// lookupMatchPublishExchangeRule +// +// check a single publish exchange rule +// +bool AclData::lookupMatchPublishExchangeRule( + const ruleSetItr& rsItr, + const std::string& id, + const std::string& name, + const std::string& routingKey, + AclResult& aclresult) +{ + QPID_LOG(debug, "ACL: checking rule " << rsItr->toString()); + + // Search on exchange name and routing key only if specfied in rule. + bool match =true; + if (rsItr->pubExchNameInRule) { + // 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 if (rsItr->pubExchNameMatchesBlank) { + result = name.empty(); + } else { + result = matchProp(rsItr->pubExchName, name); + } + + if (result) { + QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '" + << name << "' matched with rule name '" + << rsItr->pubExchName << "'"); + } else { + match= false; + QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup exchange name '" + << name << "' did not match with rule name '" + << rsItr->pubExchName << "'"); + } } + if (match && rsItr->pubRoutingKeyInRule) { + if ((routingKey.find(ACL_KEYWORD_USER_SUBST, 0) != std::string::npos) || + (routingKey.find(ACL_KEYWORD_DOMAIN_SUBST, 0) != std::string::npos) || + (routingKey.find(ACL_KEYWORD_USERDOMAIN_SUBST, 0) != std::string::npos)) { + // 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 { + bool result; + if (rsItr->ruleHasUserSub[PROP_ROUTINGKEY]) { + std::string sKey(routingKey); + substituteKeywords(sKey, id); + result = rsItr->matchRoutingKey(sKey); + } else { + result = rsItr->matchRoutingKey(routingKey); + } - // - // getQueueQuotaForUser - // - // Return the true or false value of queueQuotaRulesExist, - // indicating whether any kind of lookup was done or not. - // - // When lookups are performed return the result value of - // 1. The user's setting else - // 2. The 'all' user setting else - // 3. Zero - // When lookups are not performed then return a result value of Zero. - // - bool AclData::getQueueQuotaForUser(const std::string& theUserName, - uint16_t* theResult) const { - if (queueQuotaRulesExist) { - // look for this user explicitly - quotaRuleSetItr nameItr = (*queueQuotaRuleSettings).find(theUserName); - if (nameItr != (*queueQuotaRuleSettings).end()) { - QPID_LOG(trace, "ACL: Queue quota for user " << theUserName - << " explicitly set to : " << (*nameItr).second); - *theResult = (*nameItr).second; + if (result) { + QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '" + << routingKey << "' matched with rule routing key '" + << rsItr->pubRoutingKey << "'"); } else { - // Look for the 'all' user - nameItr = (*queueQuotaRuleSettings).find(ACL_KEYWORD_ALL); - if (nameItr != (*queueQuotaRuleSettings).end()) { - QPID_LOG(trace, "ACL: Queue quota for user " << theUserName - << " chosen through value for 'all' : " << (*nameItr).second); - *theResult = (*nameItr).second; - } else { - // Neither userName nor "all" found. - QPID_LOG(trace, "ACL: Queue quota for user " << theUserName - << " absent in quota settings. Return value : 0"); - *theResult = 0; - } + QPID_LOG(debug, "ACL: Rule: " << rsItr->rawRuleNum << " lookup key name '" + << routingKey << "' did not match with rule routing key '" + << rsItr->pubRoutingKey << "'"); + match = false; } - } else { - // Rules do not exist - QPID_LOG(trace, "ACL: Queue quota for user " << theUserName - << " unavailable; quota settings are not specified. Return value : 0"); - *theResult = 0; } - return queueQuotaRulesExist; } - - // - // - // - AclData::~AclData() - { - clear(); + if (match) { + aclresult = rsItr->ruleMode; + QPID_LOG(debug,"ACL: Rule: " << rsItr->rawRuleNum << " Successful match, the decision is:" + << AclHelper::getAclResultStr(aclresult)); } - - - // - // Limit check an int limit - // - bool AclData::compareInt(const qpid::acl::SpecProperty theProperty, - const std::string theAclValue, - const std::string theLookupValue, - bool theMaxFlag) - { - uint64_t aclRuleValue (0); - uint64_t lookupValue (0); - - QPID_LOG(debug, "ACL: " - << (theMaxFlag ? "Upper" : "Lower") << "-limit comparison for property " - << AclHelper::getPropertyStr(theProperty) - << ". Success if lookup(" << theLookupValue - << ") " - << (theMaxFlag ? "<=" : ">=") << " rule(" << theAclValue << ")"); - - try - { - aclRuleValue = boost::lexical_cast<uint64_t>(theAclValue); + return match; +} + +// +// lookup - special PUBLISH EXCHANGE lookup +// +// The ACL main business logic function of matching rules and declaring +// 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, + const Action& action, + const ObjectType& objType, + const std::string& /*Exchange*/ name, + const std::string& routingKey) +{ + + QPID_LOG(debug, "ACL: Lookup for id:" << id + << " action:" << AclHelper::getActionStr((Action) action) + << " objectType:" << AclHelper::getObjectTypeStr((ObjectType) objType) + << " exchange name:" << name + << " with routing key " << routingKey); + + AclResult aclresult = decisionMode; + + if (actionList[action] && actionList[action][objType]){ + AclData::actObjItr itrRule = actionList[action][objType]->find(id); + + if (itrRule == actionList[action][objType]->end()) { + itrRule = actionList[action][objType]->find(ACL_KEYWORD_WILDCARD); } - catch(const boost::bad_lexical_cast&) - { - assert (false); - return false; - } - - if (aclRuleValue == 0) - { - QPID_LOG(debug, "ACL: Comparison is always true when ACL rule value is zero"); - return true; - } - - try - { - lookupValue = boost::lexical_cast<uint64_t>(theLookupValue); + if (itrRule != actionList[action][objType]->end() ) { + // 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--) { + rsItr--; + + if (lookupMatchPublishExchangeRule(rsItr, id, name, routingKey, aclresult)) { + return aclresult; + } + } } - catch(const boost::bad_lexical_cast&) - { - QPID_LOG(error,"ACL: Illegal value given in lookup for property '" - << AclHelper::getPropertyStr(theProperty) - << "' : " << theLookupValue); - return false; + } + QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode " + << AclHelper::getAclResultStr(aclresult)); + return aclresult; + +} + + + +// +// +// +void AclData::setConnQuotaRuleSettings ( + bool rulesExist, boost::shared_ptr<quotaRuleSet> quotaPtr) +{ + connQuotaRulesExist = rulesExist; + connQuotaRuleSettings = quotaPtr; +} + + +// +// getConnQuotaForUser +// +// Return the true or false value of connQuotaRulesExist, +// indicating whether any kind of lookup was done or not. +// +// When lookups are performed return the result value of +// 1. The user's setting else +// 2. The 'all' user setting else +// 3. Zero +// When lookups are not performed then return a result value of Zero. +// +bool AclData::getConnQuotaForUser(const std::string& theUserName, + uint16_t* theResult) const { + if (connQuotaRulesExist) { + // look for this user explicitly + quotaRuleSetItr nameItr = (*connQuotaRuleSettings).find(theUserName); + if (nameItr != (*connQuotaRuleSettings).end()) { + QPID_LOG(trace, "ACL: Connection quota for user " << theUserName + << " explicitly set to : " << (*nameItr).second); + *theResult = (*nameItr).second; + } else { + // Look for the 'all' user + nameItr = (*connQuotaRuleSettings).find(ACL_KEYWORD_ALL); + if (nameItr != (*connQuotaRuleSettings).end()) { + QPID_LOG(trace, "ACL: Connection quota for user " << theUserName + << " chosen through value for 'all' : " << (*nameItr).second); + *theResult = (*nameItr).second; + } else { + // Neither userName nor "all" found. + QPID_LOG(trace, "ACL: Connection quota for user " << theUserName + << " absent in quota settings. Return value : 0"); + *theResult = 0; + } } - - bool result = - (theMaxFlag ? lookupValue > aclRuleValue : lookupValue < aclRuleValue); - if ( result ) - { - QPID_LOG(debug, "ACL: Limit exceeded for property '" - << AclHelper::getPropertyStr(theProperty) << "'"); - return false; + } else { + // Rules do not exist + QPID_LOG(trace, "ACL: Connection quota for user " << theUserName + << " unavailable; quota settings are not specified. Return value : 0"); + *theResult = 0; + } + return connQuotaRulesExist; +} + +// +// +// +void AclData::setQueueQuotaRuleSettings ( + bool rulesExist, boost::shared_ptr<quotaRuleSet> quotaPtr) +{ + queueQuotaRulesExist = rulesExist; + queueQuotaRuleSettings = quotaPtr; +} + + +// +// getQueueQuotaForUser +// +// Return the true or false value of queueQuotaRulesExist, +// indicating whether any kind of lookup was done or not. +// +// When lookups are performed return the result value of +// 1. The user's setting else +// 2. The 'all' user setting else +// 3. Zero +// When lookups are not performed then return a result value of Zero. +// +bool AclData::getQueueQuotaForUser(const std::string& theUserName, + uint16_t* theResult) const { + if (queueQuotaRulesExist) { + // look for this user explicitly + quotaRuleSetItr nameItr = (*queueQuotaRuleSettings).find(theUserName); + if (nameItr != (*queueQuotaRuleSettings).end()) { + QPID_LOG(trace, "ACL: Queue quota for user " << theUserName + << " explicitly set to : " << (*nameItr).second); + *theResult = (*nameItr).second; + } else { + // Look for the 'all' user + nameItr = (*queueQuotaRuleSettings).find(ACL_KEYWORD_ALL); + if (nameItr != (*queueQuotaRuleSettings).end()) { + QPID_LOG(trace, "ACL: Queue quota for user " << theUserName + << " chosen through value for 'all' : " << (*nameItr).second); + *theResult = (*nameItr).second; + } else { + // Neither userName nor "all" found. + QPID_LOG(trace, "ACL: Queue quota for user " << theUserName + << " absent in quota settings. Return value : 0"); + *theResult = 0; + } } + } else { + // Rules do not exist + QPID_LOG(trace, "ACL: Queue quota for user " << theUserName + << " unavailable; quota settings are not specified. Return value : 0"); + *theResult = 0; + } + return queueQuotaRulesExist; +} + + +// +// +// +AclData::~AclData() +{ + clear(); +} + + +// +// Limit check an int limit +// +bool AclData::compareInt(const qpid::acl::SpecProperty theProperty, + const std::string theAclValue, + const std::string theLookupValue, + bool theMaxFlag) +{ + uint64_t aclRuleValue (0); + uint64_t lookupValue (0); + + QPID_LOG(debug, "ACL: " + << (theMaxFlag ? "Upper" : "Lower") << "-limit comparison for property " + << AclHelper::getPropertyStr(theProperty) + << ". Success if lookup(" << theLookupValue + << ") " + << (theMaxFlag ? "<=" : ">=") << " rule(" << theAclValue << ")"); + + try { + aclRuleValue = boost::lexical_cast<uint64_t>(theAclValue); + } + catch(const boost::bad_lexical_cast&) { + assert (false); + return false; + } + if (aclRuleValue == 0) { + QPID_LOG(debug, "ACL: Comparison is always true when ACL rule value is zero"); 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(); - } + try { + lookupValue = boost::lexical_cast<uint64_t>(theLookupValue); } - - - // - // 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; + catch(const boost::bad_lexical_cast&) { + QPID_LOG(error,"ACL: Illegal value given in lookup for property '" + << AclHelper::getPropertyStr(theProperty) + << "' : " << theLookupValue); + return false; } - - // - // substituteUserId - // Given an Acl rule and an authenticated userId - // do the keyword substitutions on the rule. - // - void 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, ACL_KEYWORD_USER_SUBST, user); - substituteString(ruleString, ACL_KEYWORD_DOMAIN_SUBST, domain); - substituteString(ruleString, ACL_KEYWORD_USERDOMAIN_SUBST, userdomain); + bool result = + (theMaxFlag ? lookupValue > aclRuleValue : lookupValue < aclRuleValue); + if ( result ) { + QPID_LOG(debug, "ACL: Limit exceeded for property '" + << AclHelper::getPropertyStr(theProperty) << "'"); + return false; } + 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::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)); + } - // - // 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::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, ACL_KEYWORD_USERDOMAIN_SUBST); - substituteString(ruleString, user, ACL_KEYWORD_USER_SUBST); - substituteString(ruleString, domain, ACL_KEYWORD_DOMAIN_SUBST); + substituteString(ruleString, ACL_KEYWORD_USER_SUBST, user); + substituteString(ruleString, ACL_KEYWORD_DOMAIN_SUBST, domain); + substituteString(ruleString, ACL_KEYWORD_USERDOMAIN_SUBST, 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::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, ACL_KEYWORD_USERDOMAIN_SUBST); + substituteString(ruleString, user, ACL_KEYWORD_USER_SUBST); + substituteString(ruleString, domain, ACL_KEYWORD_DOMAIN_SUBST); +} }} diff --git a/qpid/cpp/src/qpid/acl/AclData.h b/qpid/cpp/src/qpid/acl/AclData.h index afc9ce7c2a..fd0eac5b13 100644 --- a/qpid/cpp/src/qpid/acl/AclData.h +++ b/qpid/cpp/src/qpid/acl/AclData.h @@ -205,6 +205,20 @@ public: private: + inline bool lookupMatchRule( + const ruleSetItr& rsItr, + const std::string& id, + const std::string& name, + const std::map<Property, std::string>* params, + AclResult& aclresult); + + inline bool lookupMatchPublishExchangeRule( + const ruleSetItr& rsItr, + const std::string& id, + const std::string& name, + const std::string& routingKey, + AclResult& aclresult); + bool compareInt(const qpid::acl::SpecProperty theProperty, const std::string theAclValue, const std::string theLookupValue, |