Back to index

nordugrid-arc-nox  1.1.0~rc6
ArcRule.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <string>
00006 #include <fstream>
00007 #include <iostream>
00008 #include <list>
00009 
00010 #include <arc/security/ArcPDP/attr/AttributeValue.h>
00011 #include <arc/security/ArcPDP/attr/BooleanAttribute.h>
00012 #include <arc/security/ArcPDP/fn/EqualFunction.h>
00013 #include <arc/security/ArcPDP/fn/MatchFunction.h>
00014 #include <arc/security/ArcPDP/fn/InRangeFunction.h>
00015 
00016 #include "ArcEvaluationCtx.h"
00017 #include "ArcRule.h"
00018 
00019 Arc::Logger ArcSec::ArcRule::logger(Arc::Logger::rootLogger, "ArcRule");
00020 
00021 using namespace Arc;
00022 using namespace ArcSec;
00023 
00024 #define DEFAULT_ATTRIBUTE_TYPE "string"
00025 
00026 void ArcRule::getItemlist(XMLNode& nd, OrList& items, const std::string& itemtype,
00027     const std::string& type_attr, const std::string& function_attr){
00028   XMLNode tnd;
00029   for(int i=0; i<nd.Size(); i++){
00030     for(int j=0;;j++){
00031       std::string type = type_attr;
00032       std::string funcname = function_attr;
00033 
00034       tnd = nd[itemtype][j];
00035       if(!tnd) break;
00036       if(!((std::string)(tnd.Attribute("Type"))).empty())
00037         type = (std::string)(tnd.Attribute("Type"));
00038       if(!((std::string)(tnd.Attribute("Function"))).empty())
00039         funcname = (std::string)(tnd.Attribute("Function"));
00040 
00041       if(!(type.empty())&&(tnd.Size()==0)){
00042         AndList item;
00043         std::string function;
00044         if(funcname.empty()) function = EqualFunction::getFunctionName(type);
00045         else if(funcname == "Match" || funcname == "match" || funcname == "MATCH")
00046           function = MatchFunction::getFunctionName(type);
00047         else if(funcname == "InRange" || funcname == "inrange" || funcname == "INRANGE" || funcname == "Inrange")
00048           function = InRangeFunction::getFunctionName(type);
00049         else std::cout<<"Function Name is wrong"<<std::endl;
00050         item.push_back(Match(attrfactory->createValue(tnd, type), fnfactory->createFn(function)));
00051         items.push_back(item);
00052       }
00053       else if((type.empty())&&(tnd.Size()>0)){
00054         AndList item;
00055         int size = tnd.Size();
00056         for(int k=0; k<size; k++){
00057           XMLNode snd = tnd.Child(k);
00058           type = (std::string)(snd.Attribute("Type"));
00059           // The priority of function definition: Subelement.Attribute("Function")
00060           // > Element.Attribute("Function") > Subelement.Attribute("Type") + "equal"
00061           if(!((std::string)(snd.Attribute("Function"))).empty())
00062             funcname = (std::string)(snd.Attribute("Function"));
00063           std::string function;
00064           if(funcname.empty()) function = EqualFunction::getFunctionName(type);
00065           else if(funcname == "Match" || funcname == "match" || funcname == "MATCH")
00066             function = MatchFunction::getFunctionName(type);
00067           else if(funcname == "InRange" || funcname == "inrange" || funcname == "INRANGE" || funcname == "Inrange")
00068             function = InRangeFunction::getFunctionName(type);
00069           else std::cout<<"Function Name is wrong"<<std::endl;
00070           item.push_back(Match(attrfactory->createValue(snd, type), fnfactory->createFn(function)));
00071         }
00072         items.push_back(item);
00073       }
00074       else if(!(type.empty())&&(tnd.Size()>0)){
00075         AndList item;
00076         int size = tnd.Size();
00077         for(int k=0; k<size; k++){
00078           XMLNode snd = tnd.Child(k);
00079           if(!((std::string)(snd.Attribute("Function"))).empty())
00080             funcname = (std::string)(snd.Attribute("Function"));
00081           std::string function;
00082           if(funcname.empty()) function = EqualFunction::getFunctionName(type);
00083           else if(funcname == "Match" || funcname == "match" || funcname == "MATCH")
00084             function = MatchFunction::getFunctionName(type);
00085           else if(funcname == "InRange" || funcname == "inrange" || funcname == "INRANGE" || funcname == "Inrange")
00086             function = InRangeFunction::getFunctionName(type);
00087           else std::cout<<"Function Name is wrong"<<std::endl;
00088           item.push_back(Match(attrfactory->createValue(snd, type), fnfactory->createFn(function)));
00089         }
00090         items.push_back(item);
00091       }
00092       else{
00093         //std::cerr <<"Error definition in policy"<<std::endl;
00094         //logger.msg(Arc::ERROR, "Error definition in policy"); 
00095         return;
00096       }
00097     }
00098 
00099     for(int l=0;;l++){
00100       tnd = nd["GroupIdRef"][l];
00101       if(!tnd) break;
00102       std::string location = (std::string)(tnd.Attribute("Location"));
00103  
00104       //Open the reference file and parse it to get external item information
00105       std::string xml_str = "";
00106       std::string str;
00107       std::ifstream f(location.c_str());
00108       while (f >> str) {
00109         xml_str.append(str);
00110         xml_str.append(" ");
00111       }
00112       f.close();
00113 
00114       XMLNode root(xml_str);
00115       XMLNode subref = root.Child();
00116 
00117       XMLNode snd;
00118       std::string itemgrouptype = itemtype + "Group";
00119 
00120       for(int k=0;;k++){
00121         snd = subref[itemgrouptype][k];
00122         if(!snd) break;
00123 
00124         //If the reference ID in the policy file matches the ID in the external file, 
00125         //try to get the subject information from the external file
00126         if((std::string)(snd.Attribute("GroupId")) == (std::string)tnd){
00127           getItemlist(snd, items, itemtype, type_attr, function_attr);
00128         }
00129       }
00130     }
00131   }
00132   return;
00133 }
00134 
00135 ArcRule::ArcRule(const XMLNode node, EvaluatorContext* ctx) : Policy(node) {
00136   rulenode = node;
00137   evalres.node = rulenode;
00138   evalres.effect = "Not_applicable";
00139 
00140   attrfactory = (AttributeFactory*)(*ctx);
00141   fnfactory = (FnFactory*)(*ctx);
00142   
00143   XMLNode nd, tnd;
00144 
00145   id = (std::string)(rulenode.Attribute("RuleId"));
00146   description = (std::string)(rulenode["Description"]);
00147   if((std::string)(rulenode.Attribute("Effect"))=="Permit")
00148     effect="Permit";
00149   else if((std::string)(rulenode.Attribute("Effect"))=="Deny")
00150     effect="Deny";
00151   //else
00152     //std::cerr<< "Invalid Effect" <<std::endl; 
00153     //logger.msg(Arc::ERROR, "Invalid Effect");
00154 
00155   std::string type,funcname;
00156   //Parse the "Subjects" part of a Rule
00157   nd = rulenode["Subjects"];
00158   type = (std::string)(nd.Attribute("Type"));
00159   funcname = (std::string)(nd.Attribute("Function"));
00160   if(type.empty()) type=DEFAULT_ATTRIBUTE_TYPE;
00161   getItemlist(nd, subjects, "Subject", type, funcname);  
00162 
00163   //Parse the "Resources" part of a Rule. The "Resources" does not include "Sub" item, 
00164   //so it is not such complicated, but we can handle it the same as "Subjects" 
00165   nd = rulenode["Resources"];
00166   type = (std::string)(nd.Attribute("Type"));
00167   funcname = (std::string)(nd.Attribute("Function"));
00168   if(type.empty()) type=DEFAULT_ATTRIBUTE_TYPE;
00169   getItemlist(nd, resources, "Resource", type, funcname);
00170 
00171   //Parse the "Actions" part of a Rule
00172   nd = rulenode["Actions"];
00173   type = (std::string)(nd.Attribute("Type"));
00174   funcname = (std::string)(nd.Attribute("Function"));
00175   if(type.empty()) type=DEFAULT_ATTRIBUTE_TYPE;
00176   getItemlist(nd, actions, "Action", type, funcname);
00177 
00178   //Parse the "Condition" part of a Rule
00179   nd = rulenode["Conditions"];
00180   type = (std::string)(nd.Attribute("Type"));
00181   funcname = (std::string)(nd.Attribute("Function"));
00182   if(type.empty()) type=DEFAULT_ATTRIBUTE_TYPE;
00183   getItemlist(nd, conditions, "Condition", type, funcname);
00184 
00185   //Set the initial value for id matching 
00186   sub_idmatched = ID_NO_MATCH;
00187   res_idmatched = ID_NO_MATCH;
00188   act_idmatched = ID_NO_MATCH;
00189   ctx_idmatched = ID_NO_MATCH;
00190  
00191 }
00192 
00193 static ArcSec::MatchResult itemMatch(ArcSec::OrList items, std::list<ArcSec::RequestAttribute*> req, Id_MatchResult& idmatched){
00194 
00195   ArcSec::OrList::iterator orit;
00196   ArcSec::AndList::iterator andit;
00197   std::list<ArcSec::RequestAttribute*>::iterator reqit;
00198 
00199   bool indeterminate = true;
00200 
00201   idmatched = ID_NO_MATCH;
00202 
00203   //Go through each <Subject> <Resource> <Action> or <Context> under 
00204   //<Subjects> <Resources> <Actions> or<Contexts>
00205   //For example, go through each <Subject> element under <Subjects> in a rule, 
00206   //once one <Subject> element is satisfied, skip out.
00207   for( orit = items.begin(); orit != items.end(); orit++ ){
00208     int all_fraction_matched = 0;
00209     int all_id_matched = 0;
00210     //For example, go through each <Attribute> element in one <Subject>, 
00211     //all of the <Attribute> elements should be satisfied 
00212     for(andit = (*orit).begin(); andit != (*orit).end(); andit++){
00213       bool one_req_matched = false;
00214       bool one_id_matched = false;
00215 
00216       //go through each <Attribute> element in one <Subject> in Request.xml, 
00217       //all of the <Attribute> should be satisfied.
00218       for(reqit = req.begin(); reqit != req.end(); reqit++){
00219         //evaluate two "AttributeValue*" based on "Function" definition in "Rule"
00220         AttributeValue* res = NULL;
00221         try{
00222           res = ((*andit).second)->evaluate((*andit).first, (*reqit)->getAttributeValue());
00223         } catch(std::exception&) { };
00224         BooleanAttribute bool_attr(true);
00225         if(res->equal(&bool_attr))
00226           one_req_matched = true;
00227         if(res) delete res;
00228 
00229         //distinguish whether the "id" of the two <Attribute>s (from request and policy) are matched
00230         //here we distinguish three kinds of situation: 
00231         //1. All the <Attribute> id under one <Subject> (or other type) in the policy side is matched by 
00232         //<Attribute> id under one <Subject> in the request side;
00233         //2. Part of id is matched;
00234         //3. None of id is matched at all.
00235         if( ((*andit).first)->getId() == ((*reqit)->getAttributeValue())->getId() )
00236           one_id_matched = true;
00237       }
00238       // if any of the <Attribute> in one Request's <Subject> matches one of the 
00239       // Rule.Subjects.Subject.Attribute, count the match number. Later if all of the 
00240       // <Attribute>s under Rule.Subjects.Subject are matched, then the Rule.Subjects.Subject
00241       // is mathed.
00242       if(one_req_matched) all_fraction_matched +=1;
00243 
00244       //Similar to above, except only "id" is considered, not including the "value" of <Attribute> 
00245       if(one_id_matched) all_id_matched +=1;
00246     }
00247     //One Rule.Subjects.Subject is satisfied (all of the Attribute value and Attribute Id are matched) 
00248     //by the RequestTuple.Subject
00249     if(all_fraction_matched == int((*orit).size())){
00250       idmatched = ID_MATCH;
00251       return MATCH;
00252     }
00253     else if(all_id_matched == int((*orit).size())) { idmatched = ID_MATCH; indeterminate = false; /*break;*/ }
00254     //else if(all_id_matched > 0) { idmatched = ID_PARTIAL_MATCH; }
00255   }
00256   if(indeterminate) return INDETERMINATE;
00257   return NO_MATCH;
00258 }
00259 
00260 MatchResult ArcRule::match(EvaluationCtx* eval_ctx){
00261   ArcEvaluationCtx* ctx = dynamic_cast<ArcEvaluationCtx*>(eval_ctx);
00262   ArcRequestTuple* evaltuple = dynamic_cast<ArcRequestTuple*>(ctx->getEvalTuple());  
00263 
00264   //Reset the value for id matching, since the Rule object could be 
00265   //used a number of times for match-making
00266   sub_idmatched = ID_NO_MATCH;
00267   res_idmatched = ID_NO_MATCH;
00268   act_idmatched = ID_NO_MATCH;
00269   ctx_idmatched = ID_NO_MATCH;
00270 
00271   MatchResult sub_matched, res_matched, act_matched, ctx_matched;
00272   sub_matched = itemMatch(subjects, evaltuple->sub, sub_idmatched);
00273   res_matched = itemMatch(resources, evaltuple->res, res_idmatched);
00274   act_matched = itemMatch(actions, evaltuple->act, act_idmatched);
00275   ctx_matched = itemMatch(conditions, evaltuple->ctx, ctx_idmatched);
00276 
00277   if(
00278       ( subjects.empty() || sub_matched==MATCH) &&
00279       ( resources.empty() || res_matched==MATCH) &&
00280       ( actions.empty() || act_matched==MATCH) &&
00281       ( conditions.empty() || ctx_matched==MATCH)
00282     )
00283     return MATCH;
00284 
00285   else if ( ( !(subjects.empty()) && sub_matched==INDETERMINATE ) || 
00286             ( !(resources.empty()) &&res_matched==INDETERMINATE ) || 
00287             ( !(actions.empty()) && act_matched==INDETERMINATE ) || 
00288             ( !(conditions.empty()) && ctx_matched==INDETERMINATE)
00289           )
00290     return INDETERMINATE;
00291 
00292   else return NO_MATCH;
00293 }
00294 
00295 Result ArcRule::eval(EvaluationCtx* ctx){
00296   Result result = DECISION_NOT_APPLICABLE;
00297   MatchResult match_res = match(ctx);
00298 
00299   if(match_res == MATCH) {
00300     if(effect == "Permit") {
00301       result = DECISION_PERMIT;
00302       evalres.effect = "Permit";
00303     }
00304     else if(effect == "Deny") {
00305       result = DECISION_DENY;
00306       evalres.effect = "Deny";
00307     }
00308     return result;
00309   }
00310   else if(match_res == INDETERMINATE) {
00311     if(effect == "Permit") evalres.effect = "Permit";
00312     else if(effect == "Deny") evalres.effect = "Deny";
00313     return DECISION_INDETERMINATE; 
00314   }
00315   else if(match_res == NO_MATCH){
00316     if(effect == "Permit") evalres.effect = "Permit";
00317     else if(effect == "Deny") evalres.effect = "Deny";
00318     return DECISION_NOT_APPLICABLE;
00319   }
00320 }
00321 
00322 std::string ArcRule::getEffect() const {
00323   return effect;
00324 }
00325 
00326 EvalResult& ArcRule::getEvalResult() {
00327   return evalres;
00328 }
00329 
00330 void ArcRule::setEvalResult(EvalResult& res){
00331   evalres = res;
00332 }
00333 
00334 ArcRule::operator bool(void) const {
00335   return true;
00336 }
00337 
00338 const char* ArcRule::getEvalName() const{
00339   return "arc.evaluator";
00340 }
00341 
00342 const char* ArcRule::getName() const{
00343   return "arc.rule";
00344 }
00345 
00346 ArcRule::~ArcRule(){
00347   while(!(subjects.empty())){
00348     AndList list = subjects.back();
00349     while(!(list.empty())){
00350       Match match = list.back();
00351       if(match.first){
00352         delete match.first;
00353       }
00354       list.pop_back();
00355     }
00356     subjects.pop_back();
00357   }
00358 
00359   while(!(resources.empty())){
00360     AndList list = resources.back();
00361     while(!(list.empty())){
00362       Match match = list.back();
00363       if(match.first)
00364         delete match.first;
00365       list.pop_back();
00366     }
00367     resources.pop_back();
00368   }
00369 
00370   while(!(actions.empty())){
00371     AndList list = actions.back();
00372     while(!(list.empty())){
00373       Match match = list.back();
00374       if(match.first)
00375         delete match.first;
00376       list.pop_back();
00377     }
00378     actions.pop_back();
00379   }
00380 
00381   while(!(conditions.empty())){
00382     AndList list = conditions.back();
00383     while(!(list.empty())){
00384       Match match = list.back();
00385       if(match.first)
00386         delete match.first;
00387       list.pop_back();
00388     }
00389     conditions.pop_back();
00390   }
00391 }