#include "ServiceProvider.h"
#include "attribute/Attribute.h"
#include "attribute/filtering/AttributeFilter.h"
-#include "attribute/filtering/MatchFunctor.h"
+#include "attribute/filtering/FilterPolicyContext.h"
#include "util/SPConstants.h"
#include <xmltooling/util/NDC.h>
using namespace opensaml::saml2md;
using namespace opensaml;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
namespace shibsp {
m_document = doc;
}
- void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const;
+ void filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const;
private:
MatchFunctor* buildFunctor(
- const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+ const DOMElement* e, const FilterPolicyContext& functorMap, const char* logname, bool standalone
);
- pair<string,const MatchFunctor*> buildAttributeRule(const DOMElement* e, bool standalone);
+ pair<string,const MatchFunctor*> buildAttributeRule(const DOMElement* e, const FilterPolicyContext& functorMap, bool standalone);
Category& m_log;
DOMDocument* m_document;
delete m_impl;
}
- void filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const {
+ void filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const {
m_impl->filterAttributes(context, attributes);
}
static const XMLCh PermitValueRuleReference[] = UNICODE_LITERAL_24(P,e,r,m,i,t,V,a,l,u,e,R,u,l,e,R,e,f,e,r,e,n,c,e);
static const XMLCh PolicyRequirementRule[] = UNICODE_LITERAL_21(P,o,l,i,c,y,R,e,q,u,i,r,e,m,e,n,t,R,u,l,e);
static const XMLCh PolicyRequirementRuleReference[]=UNICODE_LITERAL_30(P,o,l,i,c,y,R,e,q,u,i,r,e,m,e,n,t,R,u,l,e,R,e,f,e,r,e,n,c,e);
- static const XMLCh attributeId[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
+ static const XMLCh attributeID[] = UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D);
static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
static const XMLCh _ref[] = UNICODE_LITERAL_3(r,e,f);
};
if (!XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicyGroup))
throw ConfigurationException("XML AttributeFilter requires afp:AttributeFilterPolicyGroup at root of configuration.");
+ FilterPolicyContext reqFunctors(m_policyReqRules);
+ FilterPolicyContext valFunctors(m_permitValRules);
+
DOMElement* child = XMLHelper::getFirstChildElement(e);
while (child) {
if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
- buildFunctor(child, m_policyReqRules, "PolicyRequirementRule", true);
+ buildFunctor(child, reqFunctors, "PolicyRequirementRule", true);
}
else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
- buildFunctor(child, m_permitValRules, "PermitValueRule", true);
+ buildFunctor(child, valFunctors, "PermitValueRule", true);
}
else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
- buildAttributeRule(child, true);
+ buildAttributeRule(child, valFunctors, true);
}
else if (XMLHelper::isNodeNamed(child, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeFilterPolicy)) {
e = XMLHelper::getFirstChildElement(child);
- MatchFunctor* func;
+ MatchFunctor* func = NULL;
if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRule)) {
- func = buildFunctor(e, m_policyReqRules, "PolicyRequirementRule", false);
+ func = buildFunctor(e, reqFunctors, "PolicyRequirementRule", false);
}
else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PolicyRequirementRuleReference)) {
auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
e = XMLHelper::getNextSiblingElement(e);
while (e) {
if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRule)) {
- pair<string,const MatchFunctor*> rule = buildAttributeRule(e, false);
+ pair<string,const MatchFunctor*> rule = buildAttributeRule(e, valFunctors, false);
if (rule.second)
- m_policies.back().m_rules.insert(rule);
+ m_policies.back().m_rules.insert(Policy::rules_t::value_type(rule.first, rule.second));
}
else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, AttributeRuleReference)) {
auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
if (ref.get() && *ref.get()) {
map< string,pair<string,const MatchFunctor*> >::const_iterator ar = m_attrRules.find(ref.get());
if (ar != m_attrRules.end())
- m_policies.back().m_rules.insert(ar->second);
+ m_policies.back().m_rules.insert(Policy::rules_t::value_type(ar->second.first, ar->second.second));
else
m_log.warn("skipping invalid AttributeRuleReference (%s)", ref.get());
}
}
MatchFunctor* XMLFilterImpl::buildFunctor(
- const DOMElement* e, multimap<string,MatchFunctor*>& functorMap, const char* logname, bool standalone
+ const DOMElement* e, const FilterPolicyContext& functorMap, const char* logname, bool standalone
)
{
auto_ptr_char temp(e->getAttributeNS(NULL,_id));
m_log.warn("skipping stand-alone %s with no id", logname);
return NULL;
}
- else if (*id && functorMap.count(id)) {
+ else if (*id && functorMap.getMatchFunctors().count(id)) {
if (standalone) {
m_log.warn("skipping duplicate stand-alone %s with id (%s)", logname, id);
return NULL;
auto_ptr<QName> type(XMLHelper::getXSIType(e));
if (type.get()) {
try {
- MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), e);
- functorMap.insert(make_pair(id, func));
+ MatchFunctor* func = SPConfig::getConfig().MatchFunctorManager.newPlugin(*type.get(), make_pair(&functorMap,e));
+ functorMap.getMatchFunctors().insert(multimap<string,MatchFunctor*>::value_type(id, func));
return func;
}
catch (exception& ex) {
return NULL;
}
-pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElement* e, bool standalone)
+pair<string,const MatchFunctor*> XMLFilterImpl::buildAttributeRule(const DOMElement* e, const FilterPolicyContext& functorMap, bool standalone)
{
auto_ptr_char temp(e->getAttributeNS(NULL,_id));
const char* id = (temp.get() && *temp.get()) ? temp.get() : "";
if (standalone && !*id) {
m_log.warn("skipping stand-alone AttributeRule with no id");
- return make_pair(string(),(MatchFunctor*)NULL);
+ return make_pair(string(),(const MatchFunctor*)NULL);
}
else if (*id && m_attrRules.count(id)) {
if (standalone) {
m_log.warn("skipping duplicate stand-alone AttributeRule with id (%s)", id);
- return make_pair(string(),(MatchFunctor*)NULL);
+ return make_pair(string(),(const MatchFunctor*)NULL);
}
else
id = "";
}
- auto_ptr_char attrId(e->getAttributeNS(NULL,attributeId));
- if (!attrId.get() || !*attrId.get())
- m_log.warn("skipping AttributeRule with no attributeId");
+ auto_ptr_char attrID(e->getAttributeNS(NULL,attributeID));
+ if (!attrID.get() || !*attrID.get())
+ m_log.warn("skipping AttributeRule with no attributeID");
e = XMLHelper::getFirstChildElement(e);
MatchFunctor* func=NULL;
if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRule)) {
- func = buildFunctor(e, m_permitValRules, "PermitValueRule", false);
+ func = buildFunctor(e, functorMap, "PermitValueRule", false);
}
else if (e && XMLHelper::isNodeNamed(e, shibspconstants::SHIB2ATTRIBUTEFILTER_NS, PermitValueRuleReference)) {
auto_ptr_char ref(e->getAttributeNS(NULL, _ref));
if (func) {
if (*id)
- return m_attrRules[id] = make_pair(attrId.get(), func);
+ return m_attrRules[id] = pair<string,const MatchFunctor*>(attrID.get(), func);
else
- return make_pair(attrId.get(), func);
+ return pair<string,const MatchFunctor*>(attrID.get(), func);
}
m_log.warn("skipping AttributeRule (%s), PermitValueRule invalid or missing", id);
- return make_pair(string(),(MatchFunctor*)NULL);
+ return make_pair(string(),(const MatchFunctor*)NULL);
}
-void XMLFilterImpl::filterAttributes(const FilteringContext& context, multimap<string,Attribute*>& attributes) const
+void XMLFilterImpl::filterAttributes(const FilteringContext& context, vector<Attribute*>& attributes) const
{
- auto_ptr_char issuer(context.getAttributeIssuer());\r
-\r
- m_log.debug("filtering %lu attribute(s) from (%s)", attributes.size(), issuer.get() ? issuer.get() : "unknown source");\r
-\r
- if (m_policies.empty()) {\r
- m_log.warn("no filter policies were loaded, filtering out all attributes from (%s)", issuer.get() ? issuer.get() : "unknown source");\r
- for_each(attributes.begin(), attributes.end(), cleanup_pair<string,Attribute>());\r
- attributes.clear();\r
- return;\r
- }\r
+ auto_ptr_char issuer(context.getAttributeIssuer());
+
+ m_log.debug("filtering %lu attribute(s) from (%s)", attributes.size(), issuer.get() ? issuer.get() : "unknown source");
+
+ if (m_policies.empty()) {
+ m_log.warn("no filter policies were loaded, filtering out all attributes from (%s)", issuer.get() ? issuer.get() : "unknown source");
+ for_each(attributes.begin(), attributes.end(), xmltooling::cleanup<Attribute>());
+ attributes.clear();
+ return;
+ }
size_t count,index;
for (vector<Policy>::const_iterator p=m_policies.begin(); p!=m_policies.end(); ++p) {
if (p->m_applies->evaluatePolicyRequirement(context)) {
// Loop over the attributes and look for possible rules to run.
- for (multimap<string,Attribute*>::iterator a=attributes.begin(); a!=attributes.end();) {
- pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = p->m_rules.equal_range(a->second->getId());
- if (rules.first == rules.second) {
- // No rule found, so we're filtering it out.
- m_log.warn(\r
- "no rule found, filtering out values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source"\r
- );\r
- multimap<string,Attribute*>::iterator dead = a++;\r
- delete dead->second;\r
- attributes.erase(dead);\r
- }
- else {
+ for (vector<Attribute*>::size_type a=0; a<attributes.size();) {
+ bool ruleFound = false;
+ Attribute* attr = attributes[a];
+ pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = p->m_rules.equal_range(attr->getId());
+ if (rules.first != rules.second) {
+ ruleFound = true;
// Run each rule in sequence.
- m_log.debug("filtering values of attribute (%s) from (%s)", a->second->getId(), issuer.get() ? issuer.get() : "unknown source");\r
+ m_log.debug(
+ "applying filtering rule(s) for attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
for (; rules.first!=rules.second; ++rules.first) {
- count = a->second->valueCount();
+ count = attr->valueCount();
for (index=0; index < count;) {
// The return value tells us whether to index past the accepted value, or stay put and decrement the count.
- if (rules.first->second->evaluatePermitValue(context, *(a->second), index))
+ if (rules.first->second->evaluatePermitValue(context, *attr, index)) {
index++;
- else
+ }
+ else {
+ m_log.warn(
+ "removed value at position (%lu) of attribute (%s) from (%s)",
+ index, attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ attr->removeValue(index);
count--;
+ }
}
}
- // See if any values are left, delete if not.
- if (count>0) {
- ++a;
+ }
+
+ rules = p->m_rules.equal_range("*");
+ if (rules.first != rules.second) {
+ // Run each rule in sequence.
+ if (!ruleFound) {
+ m_log.debug(
+ "applying wildcard rule(s) for attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ ruleFound = true;
}
- else {
- multimap<string,Attribute*>::iterator dead = a++;\r
- delete dead->second;\r
- attributes.erase(dead);\r
+ for (; rules.first!=rules.second; ++rules.first) {
+ count = attr->valueCount();
+ for (index=0; index < count;) {
+ // The return value tells us whether to index past the accepted value, or stay put and decrement the count.
+ if (rules.first->second->evaluatePermitValue(context, *attr, index)) {
+ index++;
+ }
+ else {
+ m_log.warn(
+ "removed value at position (%lu) of attribute (%s) from (%s)",
+ index, attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ attr->removeValue(index);
+ count--;
+ }
+ }
}
}
+
+ if (!ruleFound || attr->valueCount() == 0) {
+ if (!ruleFound) {
+ // No rule found, so we're filtering it out.
+ m_log.warn(
+ "no rule found, removing all values of attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ }
+ delete attr;
+ attributes.erase(attributes.begin() + a);
+ }
+ else {
+ ++a;
+ }
}
}
}