| /* |
| * |
| * 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/acl/AclData.h" |
| #include "qpid/acl/AclValidator.h" |
| #include "qpid/log/Statement.h" |
| #include "qpid/sys/IntegerTypes.h" |
| #include <boost/lexical_cast.hpp> |
| #include <boost/shared_ptr.hpp> |
| #include <sstream> |
| #include <iomanip> |
| |
| 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"), |
| connectionDecisionMode(qpid::acl::ALLOW), |
| connQuotaRuleSettings(new quotaRuleSet), |
| queueQuotaRuleSettings(new quotaRuleSet), |
| connBWHostsGlobalRules(new bwHostRuleSet), |
| connBWHostsUserRules(new bwHostUserRuleMap) |
| { |
| 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]; |
| } |
| } |
| delete[] actionList[cnt]; |
| } |
| transferAcl = false; |
| connectionDecisionMode = qpid::acl::ALLOW; |
| connQuotaRuleSettings->clear(); |
| queueQuotaRuleSettings->clear(); |
| connBWHostsGlobalRules->clear(); |
| connBWHostsUserRules->clear(); |
| } |
| |
| void AclData::printDecisionRules(int userFieldWidth) { |
| AclValidator validator; |
| QPID_LOG(trace, "ACL: Decision rule cross reference"); |
| for (int act=0; act<acl::ACTIONSIZE; act++) { |
| acl::Action action = acl::Action(act); |
| for (int obj=0; obj<acl::OBJECTSIZE; obj++) { |
| acl::ObjectType object = acl::ObjectType(obj); |
| if (actionList[act] != NULL && actionList[act][obj] != NULL) { |
| for (actObjItr aoitr = actionList[act][obj]->begin(); |
| aoitr != actionList[act][obj]->end(); |
| aoitr++) { |
| std::string user = (*aoitr).first; |
| ruleSetItr rsitr = (*aoitr).second.end(); |
| for (size_t rCnt=0; rCnt < (*aoitr).second.size(); rCnt++) { |
| rsitr--; |
| std::vector<int> candidates; |
| validator.findPossibleLookupMatch( |
| action, object, rsitr->props, candidates); |
| std::stringstream ss; |
| std::string sep(""); |
| for (std::vector<int>::const_iterator |
| itr = candidates.begin(); itr != candidates.end(); itr++) { |
| ss << sep << *itr; |
| sep = ","; |
| } |
| QPID_LOG(trace, "ACL: User: " |
| << std::setfill(' ') << std::setw(userFieldWidth +1) << std::left |
| << user << " " |
| << std::setfill(' ') << std::setw(acl::ACTION_STR_WIDTH +1) << std::left |
| << AclHelper::getActionStr(action) |
| << std::setfill(' ') << std::setw(acl::OBJECTTYPE_STR_WIDTH) << std::left |
| << AclHelper::getObjectTypeStr(object) |
| << " Rule: " |
| << rsitr->toString() << " may match Lookups : (" |
| << ss.str() << ")"); |
| } |
| } |
| } else { |
| // no rules for action/object |
| } |
| } |
| } |
| } |
| |
| // |
| // 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; |
| } |
| } |
| |
| |
| // |
| // 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) |
| { |
| // 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_MAXPAGESLOWERLIMIT: |
| case acl::SPECPROP_MAXPAGESUPPERLIMIT: |
| lookupParamItr = params->find(PROP_MAXPAGES); |
| break; |
| |
| case acl::SPECPROP_MAXPAGEFACTORLOWERLIMIT: |
| case acl::SPECPROP_MAXPAGEFACTORUPPERLIMIT: |
| lookupParamItr = params->find(PROP_MAXPAGEFACTOR); |
| break; |
| |
| 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: |
| case acl::SPECPROP_MAXPAGESUPPERLIMIT: |
| case acl::SPECPROP_MAXPAGEFACTORUPPERLIMIT: |
| 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: |
| case acl::SPECPROP_MAXPAGESLOWERLIMIT: |
| case acl::SPECPROP_MAXPAGEFACTORLOWERLIMIT: |
| 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)); |
| } else { |
| // This rule did not match the requested lookup and |
| // does not contribute to an ACL decision. |
| } |
| 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 { |
| // The Action-Object list has entries but not for this actorId |
| // nor for *. |
| } |
| } 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; |
| } |
| |
| |
| // |
| // 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); |
| } |
| |
| 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 (match) { |
| aclresult = rsItr->ruleMode; |
| QPID_LOG(debug,"ACL: Rule: " << rsItr->rawRuleNum << " Successful match, the decision is:" |
| << AclHelper::getAclResultStr(aclresult)); |
| } |
| 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); |
| } |
| 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; |
| } |
| } |
| } |
| } |
| QPID_LOG(debug,"ACL: No successful match, defaulting to the decision mode " |
| << AclHelper::getAclResultStr(aclresult)); |
| return aclresult; |
| |
| } |
| |
| |
| |
| // |
| // |
| // |
| void AclData::setConnQuotaRuleSettings ( |
| boost::shared_ptr<quotaRuleSet> quotaPtr) |
| { |
| 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 (this->enforcingConnectionQuotas()) { |
| // 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; |
| } |
| } |
| } 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 this->enforcingConnectionQuotas(); |
| } |
| |
| // |
| // |
| // |
| void AclData::setQueueQuotaRuleSettings ( |
| boost::shared_ptr<quotaRuleSet> quotaPtr) |
| { |
| 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 (this->enforcingQueueQuotas()) { |
| // 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 this->enforcingQueueQuotas(); |
| } |
| |
| void AclData::setConnGlobalRules (boost::shared_ptr<bwHostRuleSet> cgr) { |
| connBWHostsGlobalRules = cgr; |
| } |
| |
| void AclData::setConnUserRules (boost::shared_ptr<bwHostUserRuleMap> hurm) { |
| connBWHostsUserRules = hurm; |
| } |
| |
| AclResult AclData::isAllowedConnection(const std::string& userName, |
| const std::string& hostName, |
| std::string& logText) { |
| bool decisionMade(false); |
| AclResult result(ALLOW); |
| for (bwHostRuleSetItr it=connBWHostsGlobalRules->begin(); |
| it!=connBWHostsGlobalRules->end(); it++) { |
| if (it->getAclHost().match(hostName)) { |
| // This host matches a global spec and controls the |
| // allow/deny decision for this connection. |
| result = it->getAclResult(); |
| logText = QPID_MSG("global rule " << it->toString() |
| << (AclHelper::resultAllows(result) ? " allows" : " denies") |
| << " connection for host " << hostName << ", user " |
| << userName); |
| decisionMade = true; |
| break; |
| } else { |
| // This rule in the global spec doesn't match and |
| // does not control the allow/deny decision. |
| } |
| } |
| |
| // Run user deny/allow list check |
| if (!decisionMade) { |
| bwHostUserRuleMapItr itrRule = connBWHostsUserRules->find(userName); |
| if (itrRule != connBWHostsUserRules->end()) { |
| for (bwHostRuleSetItr it=(*itrRule).second.begin(); |
| it!=(*itrRule).second.end(); it++) { |
| if (it->getAclHost().match(hostName)) { |
| // This host matches a user spec and controls the |
| // allow/deny decision for this connection. |
| result = it->getAclResult(); |
| logText = QPID_MSG("global rule " << it->toString() |
| << (AclHelper::resultAllows(result) ? " allows" : " denies") |
| << " connection for host " << hostName << ", user " |
| << userName); |
| decisionMade = true; |
| break; |
| } else { |
| // This rule in the user's spec doesn't match and |
| // does not control the allow/deny decision. |
| } |
| } |
| } |
| } |
| |
| // Apply global connection mode |
| if (!decisionMade) { |
| result = connectionDecisionMode; |
| logText = QPID_MSG("default connection policy " |
| << (AclHelper::resultAllows(result) ? "allows" : "denies") |
| << " connection for host " << hostName << ", user " |
| << userName); |
| } |
| return result; |
| } |
| |
| // |
| // |
| // |
| 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; |
| } |
| |
| try { |
| lookupValue = boost::lexical_cast<uint64_t>(theLookupValue); |
| } |
| catch(const boost::bad_lexical_cast&) { |
| QPID_LOG(error,"ACL: Illegal value given in lookup for property '" |
| << AclHelper::getPropertyStr(theProperty) |
| << "' : " << theLookupValue); |
| return false; |
| } |
| |
| 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)); |
| } |
| |
| 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); |
| } |
| }} |