Back to index

nordugrid-arc-nox  1.1.0~rc6
InfoFilter.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <arc/security/ArcPDP/policy/Policy.h>
00006 #include <arc/security/ArcPDP/EvaluatorLoader.h>
00007 #include <arc/Utils.h>
00008 
00009 #include "InfoFilter.h"
00010 
00011 namespace Arc {
00012 
00013 class InfoPolicy {
00014  public:
00015   XMLNode xml;
00016   bool done;
00017   ArcSec::Result res;
00018   InfoPolicy(void):xml(),done(false),res(ArcSec::DECISION_DENY) { };
00019   InfoPolicy(XMLNode node):xml(node),done(false),res(ArcSec::DECISION_DENY) { };
00020   ~InfoPolicy(void) { };
00021   bool Evaluate(MessageAuth& id);
00022 };
00023 
00024 
00025 bool InfoPolicy::Evaluate(MessageAuth& id) {
00026   if(done) return true;
00027   // Parse internal policy
00028   ArcSec::EvaluatorLoader eloader;
00029   AutoPointer<ArcSec::Policy> policy(eloader.getPolicy(ArcSec::Source(xml)));
00030   if(!policy) { // Failed to parse policy
00031     return false;
00032   };
00033   // Find proper evaluator
00034   AutoPointer<ArcSec::Evaluator> eval(eloader.getEvaluator(policy));
00035   if(!eval) { // Failed to find proper evaluator
00036     return false;
00037   };
00038   // Generate request from identity of requestor
00039   std::string policyname = policy->getName();
00040   if((policyname.length() > 7) &&
00041      (policyname.substr(policyname.length()-7) == ".policy")) {
00042     policyname.resize(policyname.length()-7);
00043   };
00044   XMLNode req;
00045   // TODO: do it only once
00046   if(!id.Export(SecAttrFormat(policyname.c_str()),req)) { // Failed to generate request
00047     return false;
00048   };
00049   // Evaluate internal policy
00050   AutoPointer<ArcSec::Response> resp(eval->evaluate(ArcSec::Source(req),policy));
00051   if(!resp) { // Failed to evaluate policy
00052     return false;
00053   };
00054   ArcSec::ResponseList& rlist = resp->getResponseItems();
00055   // Most probably there will be only one item. So far
00056   // using hardcoded prorities for response results.
00057   int res_deny = 0;
00058   int res_permit = 0;
00059   int res_notapplicable = 0;
00060   int res_indeteminate = 0;
00061   for(int n = 0;n<rlist.size();++n) {
00062     ArcSec::ResponseItem* ritem = rlist.getItem(n);
00063     if(ritem) {
00064       switch(ritem->res) {
00065         case ArcSec::DECISION_PERMIT: ++res_permit; break;
00066         case ArcSec::DECISION_DENY: ++res_deny; break;
00067         case ArcSec::DECISION_INDETERMINATE: ++res_indeteminate; break;
00068         case ArcSec::DECISION_NOT_APPLICABLE: ++res_notapplicable; break;
00069         default: ++res_deny; break; // Safe
00070       };
00071     };
00072   };
00073   // Store evaluation result
00074   if(res_deny) { res=ArcSec::DECISION_DENY; }
00075   else if(res_permit) { res=ArcSec::DECISION_PERMIT; }
00076   else if(res_notapplicable) { res=ArcSec::DECISION_NOT_APPLICABLE; }
00077   else if(res_indeteminate) { res=ArcSec::DECISION_INDETERMINATE; };
00078   return true;
00079 }
00080 
00081 
00082 static void RemovePolicies(std::list< std::pair<XMLNode,std::list<InfoPolicy>::iterator> >& policies,XMLNode node) {
00083   // Remove nodes associated with external policies.
00084   // This is not most effective way to handle this problem, but
00085   // currently I could not find anything better.
00086   for(std::list< std::pair<XMLNode,std::list<InfoPolicy>::iterator> >::iterator p = policies.begin();
00087                                          p != policies.end();) {
00088     if(node == p->first) {
00089       p=policies.erase(p);
00090     } else {
00091       ++p;
00092     };
00093   };
00094   // Process children nodes
00095   XMLNode cnode = node.Child();
00096   for(;(bool)cnode;++cnode) RemovePolicies(policies,cnode);
00097 }
00098 
00099 static void RemoveEmbeddedPolicies(XMLNode node) {
00100   // Remove all children policies
00101   while(true) {
00102     XMLNode def = node["InfoFilterDefinition"];
00103     if(!def) break;
00104     def.Destroy();
00105   };
00106 
00107   // Remove tag
00108   XMLNode tag = node.Attribute("InfoFilterTag");
00109   tag.Destroy();
00110 
00111   // Process children nodes
00112   XMLNode cnode = node.Child();
00113   for(;(bool)cnode;++cnode) RemoveEmbeddedPolicies(cnode);
00114   return;
00115 }
00116 
00117 static bool FilterNode(MessageAuth& id,XMLNode node,std::list< std::pair<XMLNode,std::list<InfoPolicy>::iterator> >& policies,std::list<InfoPolicy>& epolicies,std::map<std::string,InfoPolicy>& ipolicies) {
00118   // Check if node has external policy
00119   for(std::list< std::pair<XMLNode,std::list<InfoPolicy>::iterator> >::iterator p = policies.begin();
00120                                          p != policies.end();) {
00121     if(node == p->first) {
00122       // Node has assigned policy - evaluate it
00123       if(!p->second->Evaluate(id)) { // Policy evaluation failed
00124         return false;
00125       };
00126       if(p->second->res != ArcSec::DECISION_PERMIT) {
00127         RemovePolicies(policies,node);
00128         node.Destroy();
00129         break;
00130       };
00131     };
00132     ++p;
00133   };
00134   if((bool)node) {
00135     // Check for internal policy
00136     // 1. Pick policy definitions
00137     XMLNode def = node["InfoFilterDefinition"];
00138     for(;(bool)def;++def) {
00139       // Create policy and store it in map
00140       // TODO: policies without identifier
00141       std::string pid = def.Attribute("id");
00142       ipolicies[pid]=InfoPolicy(def.Child());
00143     };
00144     // 2. Check for tag
00145     // TODO: policies without ids and tags
00146     std::string tag = node.Attribute("InfoFilterTag");
00147     if(!tag.empty()) {
00148       InfoPolicy& policy = ipolicies[tag];
00149       if(!policy.xml) { // No such policy defined
00150         return false;
00151       };
00152       if(!policy.Evaluate(id)) { // Failed to evaluate policy
00153         return false;
00154       };
00155       if(policy.res != ArcSec::DECISION_PERMIT) {
00156         RemovePolicies(policies,node);
00157         node.Destroy();
00158         return true;
00159       };
00160     };
00161   };
00162   if((bool)node) {
00163     // Process children nodes
00164     for(int n = 0;;++n) {
00165       XMLNode cnode = node.Child(n);
00166       if(!cnode) break;
00167       if(!FilterNode(id,cnode,policies,epolicies,ipolicies)) return false;
00168     };
00169   };
00170   return true;
00171 }
00172 
00173 InfoFilter::InfoFilter(MessageAuth& id):id_(id) {
00174 }
00175 
00176 bool InfoFilter::Filter(XMLNode doc) const {
00177   std::list< std::pair<std::string,XMLNode> > policies;
00178   NS ns;
00179   return Filter(doc,policies,ns);
00180 }
00181 
00182 bool InfoFilter::Filter(XMLNode doc,const std::list< std::pair<std::string,XMLNode> >& policies,const NS& ns) const {
00183   std::map<std::string,InfoPolicy> ipolicies_; // internal policies associated to their ids
00184   std::list<InfoPolicy> epolicies_; // external policies
00185   std::list< std::pair<XMLNode,std::list<InfoPolicy>::iterator> > policies_; // nodes associated to external policies
00186   for(std::list< std::pair<std::string,XMLNode> >::const_iterator p = policies.begin();
00187                      p != policies.end();++p) {
00188     XMLNodeList nodes = doc.XPathLookup(p->first,ns);
00189     if(nodes.size() > 0) {
00190       std::list<InfoPolicy>::iterator ep = epolicies_.insert(epolicies_.end(),InfoPolicy(p->second));
00191       for(XMLNodeList::iterator n = nodes.begin();n != nodes.end();++n) {
00192         policies_.push_back(std::pair<XMLNode,std::list<InfoPolicy>::iterator>(*n,ep));
00193       };
00194     };
00195   };
00196   // Go through nodes and check policies
00197   bool r = FilterNode(id_,doc,policies_,epolicies_,ipolicies_); 
00198   if(!r) return false;
00199   // Remove policies embedded into document
00200   RemoveEmbeddedPolicies(doc);
00201   return true;
00202 }
00203 
00204 
00205 } // namespace Arc
00206