Back to index

nordugrid-arc-nox  1.1.0~rc6
ArcEvaluator.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <fstream>
00006 #include <iostream>
00007 
00008 #include <arc/security/ClassLoader.h>
00009 #include <arc/security/ArcPDP/Request.h>
00010 #include <arc/security/ArcPDP/Response.h>
00011 #include <arc/security/ArcPDP/EvaluationCtx.h>
00012 
00013 #include "ArcEvaluator.h"
00014 #include "ArcEvaluationCtx.h"
00015 
00016 Arc::Plugin* ArcSec::ArcEvaluator::get_evaluator(Arc::PluginArgument* arg) {
00017     Arc::ClassLoaderPluginArgument* clarg =
00018             arg?dynamic_cast<Arc::ClassLoaderPluginArgument*>(arg):NULL;
00019     if(!clarg) return NULL;
00020     return new ArcSec::ArcEvaluator((Arc::XMLNode*)(*clarg));
00021 }
00022 
00023 //loader_descriptors __arc_evaluator_modules__  = {
00024 //    { "arc.evaluator", 0, &ArcSec::ArcEvaluator::get_evaluator },
00025 //    { NULL, 0, NULL }
00026 //};
00027 
00028 using namespace Arc;
00029 using namespace ArcSec;
00030 
00031 Arc::Logger ArcSec::ArcEvaluator::logger(Arc::Logger::rootLogger, "ArcEvaluator");
00032 
00033 void ArcEvaluator::parsecfg(Arc::XMLNode& cfg){
00034   std::string policystore, policylocation, functionfactory, attributefactory, combingalgfactory;
00035   XMLNode nd;
00036 
00037   Arc::NS nsList;
00038   std::list<XMLNode> res;
00039   nsList.insert(std::pair<std::string, std::string>("pdp","http://www.nordugrid.org/schemas/pdp/Config"));
00040   
00041   //Get the name of "PolicyStore" class
00042   //res = cfg.XPathLookup("//pdp:PolicyStore", nsList);
00043   //presently, there can be only one PolicyStore
00044   //if(!(res.empty())){
00045   //  nd = *(res.begin());
00046   //  policystore = (std::string)(nd.Attribute("name"));
00047   //  policylocation =  (std::string)(nd.Attribute("location"));
00048   //}
00049   //else if (res.empty()){ 
00050   //  logger.msg(ERROR, "No any policy exists, the policy engine can not be loaded");
00051   //  exit(1);
00052   //}
00053 
00054   //Get the name of "FunctionFactory" class
00055   res = cfg.XPathLookup("//pdp:FunctionFactory", nsList);
00056   if(!(res.empty())){
00057     nd = *(res.begin());
00058     functionfactory = (std::string)(nd.Attribute("name"));
00059   } 
00060   else { logger.msg(ERROR, "Can not parse classname for FunctionFactory from configuration"); return;}
00061           
00062   //Get the name of "AttributeFactory" class
00063   res = cfg.XPathLookup("//pdp:AttributeFactory", nsList);
00064   if(!(res.empty())){
00065     nd = *(res.begin());
00066     attributefactory = (std::string)(nd.Attribute("name"));
00067   }  
00068   else { logger.msg(ERROR, "Can not parse classname for AttributeFactory from configuration"); return;}
00069 
00070   //Get the name of "CombiningAlgorithmFactory" class
00071   res = cfg.XPathLookup("//pdp:CombingAlgorithmFactory", nsList);
00072   if(!(res.empty())){
00073     nd = *(res.begin());
00074     combingalgfactory = (std::string)(nd.Attribute("name"));
00075   }
00076   else { logger.msg(ERROR, "Can not parse classname for CombiningAlgorithmFactory from configuration"); return;}
00077 
00078   //Get the name of the "Request" class
00079   res = m_cfg->XPathLookup("//pdp:Request", nsList);
00080   if(!(res.empty())){
00081     nd = *(res.begin());
00082     request_classname = (std::string)(nd.Attribute("name"));
00083   }
00084   else { logger.msg(ERROR, "Can not parse classname for Request from configuration"); return;}
00085 
00086   //Get the name of the "Policy" class
00087   std::string policy_classname;
00088   res = m_cfg->XPathLookup("//pdp:Policy", nsList);
00089   if(!(res.empty())){
00090     nd = *(res.begin());
00091     policy_classname = (std::string)(nd.Attribute("name"));
00092   }
00093   else { logger.msg(ERROR, "Can not parse classname for Policy from configuration"); return;}
00094 
00095   //Get the ClassLoader object; The object which loads this ArcEvaluator should have 
00096   //constructed ClassLoader by using ClassLoader(cfg), and putting the configuration 
00097   //information into it; meanwhile ClassLoader is designed as a Singleton, so here 
00098   //we don't need to intialte ClassLoader by using ClassLoader(cfg);
00099   ClassLoader* classloader;
00100   classloader=ClassLoader::getClassLoader();
00101 
00102   attrfactory=NULL;
00103   attrfactory = (AttributeFactory*)(classloader->Instance(attributefactory));
00104   if(attrfactory == NULL)
00105     logger.msg(ERROR, "Can not dynamically produce AttributeFactory");
00106 
00107   fnfactory=NULL;
00108   fnfactory = (FnFactory*)(classloader->Instance(functionfactory));
00109   if(fnfactory == NULL)
00110     logger.msg(ERROR, "Can not dynamically produce FnFactory");
00111 
00112   algfactory=NULL;
00113   algfactory = (AlgFactory*)(classloader->Instance(combingalgfactory));
00114   if(algfactory == NULL)
00115     logger.msg(ERROR, "Can not dynamically produce AlgFacroty");
00116 
00117   //Create the EvaluatorContext for the usage of creating Policy
00118   context = new EvaluatorContext(this);
00119 
00120   std::string alg("Permit-Overrides");
00121   //std::list<std::string> filelist;
00122   //filelist.push_back(policylocation);
00123   //plstore = new PolicyStore(filelist, alg, policy_classname, context);
00124   plstore = new PolicyStore(alg, policy_classname, context);
00125   if(plstore == NULL)
00126     logger.msg(ERROR, "Can not create PolicyStore object");
00127 }
00128 
00129 ArcEvaluator::ArcEvaluator(Arc::XMLNode* cfg) : Evaluator(cfg), m_cfg(cfg) {
00130   plstore = NULL;;
00131   fnfactory = NULL;
00132   attrfactory = NULL;
00133   algfactory = NULL;
00134   combining_alg = EvaluatorFailsOnDeny;
00135   combining_alg_ex = NULL;
00136   context = NULL;
00137 
00138   parsecfg(*m_cfg);
00139 }
00140 
00141 ArcEvaluator::ArcEvaluator(const char * cfgfile) : Evaluator(cfgfile){
00142   combining_alg = EvaluatorFailsOnDeny;
00143   combining_alg_ex = NULL;
00144   std::string str;
00145   std::string xml_str = "";
00146   std::ifstream f(cfgfile);
00147   while (f >> str) {
00148     xml_str.append(str);
00149     xml_str.append(" ");
00150   }
00151   f.close();
00152 
00153   Arc::XMLNode node(xml_str);
00154   parsecfg(node); 
00155 }
00156 
00157 void ArcEvaluator::setCombiningAlg(EvaluatorCombiningAlg alg) {
00158   combining_alg = alg;
00159 }
00160 
00161 void ArcEvaluator::setCombiningAlg(CombiningAlg* alg) {
00162   combining_alg_ex = alg;
00163 }
00164 
00165 Request* ArcEvaluator::make_reqobj(XMLNode& reqnode){
00166   Request* request = NULL;
00167   std::string requestor;
00168 
00169   Arc::ClassLoader* classloader = NULL;
00170   //Since the configuration information for loader has been got before (when create ArcEvaluator), 
00171   //it is not necessary to get once more here
00172   classloader = ClassLoader::getClassLoader();
00173 
00174   //Load the Request object
00175   request = (ArcSec::Request*)(classloader->Instance(request_classname,&reqnode));
00176   if(request == NULL)
00177     logger.msg(Arc::ERROR, "Can not dynamically produce Request");
00178 
00179   return request;
00180 }
00181 
00182 Response* ArcEvaluator::evaluate(Request* request){
00183   Request* req = request;
00184   req->setAttributeFactory(attrfactory);
00185   req->make_request();
00186 
00187   EvaluationCtx * evalctx = NULL;
00188   evalctx =  new ArcEvaluationCtx(req);
00189 
00190   //evaluate the request based on policy
00191   if(evalctx)
00192     return evaluate(evalctx);
00193   return NULL;
00194 }
00195 
00196 
00197 Response* ArcEvaluator::evaluate(const Source& req){
00198   //0.Prepare request for evaluation
00199   Arc::XMLNode node = req.Get();
00200   NS ns;
00201   ns["ra"]="http://www.nordugrid.org/schemas/request-arc";
00202   node.Namespaces(ns);
00203 
00204   //1.Create the request object according to the configuration
00205   Request* request = make_reqobj(node);
00206   if(request == NULL) return NULL;
00207   
00208   //2.Pre-process the Request object
00209   request->setAttributeFactory(attrfactory);
00210   request->make_request();
00211   
00212   EvaluationCtx * evalctx = new ArcEvaluationCtx(request);
00213   
00214   //3.evaluate the request based on policy
00215   Response* resp = evaluate(evalctx);
00216 
00217   delete request;
00218 
00219   return resp;
00220 }
00221 
00222 // NOTE: This method deletes passed context on exit
00223 Response* ArcEvaluator::evaluate(EvaluationCtx* evl_ctx){
00224   if(!evl_ctx) return NULL;
00225   //Split request into <subject, action, object, environment> tuples
00226   ArcEvaluationCtx* ctx = dynamic_cast<ArcEvaluationCtx*>(evl_ctx);
00227   if(!ctx) {
00228     delete evl_ctx;
00229     return NULL;
00230   }
00231   ctx->split();
00232   
00233   std::list<PolicyStore::PolicyElement> policies;
00234   std::list<PolicyStore::PolicyElement>::iterator policyit;
00235   std::list<RequestTuple*> reqtuples = ctx->getRequestTuples();
00236   std::list<RequestTuple*>::iterator it;
00237   
00238   Response* resp = new Response();
00239   resp->setRequestSize(reqtuples.size());
00240   for(it = reqtuples.begin(); it != reqtuples.end(); it++){
00241     //set the current RequestTuple for evaluation
00242     //RequestTuple will be evaluated one by one
00243     ctx->setEvalTuple(*it);
00244 
00245     policies = plstore->findPolicy(ctx);
00246 
00247     std::list<PolicyStore::PolicyElement> permitset;
00248     
00249     if(!combining_alg) {
00250 
00251     bool atleast_onepermit = false;
00252     bool atleast_onedeny = false;
00253     bool atleast_onenotapplicable = false;
00254     bool atleast_oneindeterminate = false;
00255     Result result = DECISION_NOT_APPLICABLE;
00256 
00257     //Each policy evaluates the present RequestTuple, using default combiningalg between <Policy>s: PERMIT-OVERRIDES
00258     for(policyit = policies.begin(); policyit != policies.end(); policyit++){
00259       Result res = ((Policy*)(*policyit))->eval(ctx);
00260 
00261       logger.msg(INFO,"Result value (0=Permit, 1=Deny, 2=Indeterminate, 3=Not_Applicable): %d", res);
00262 
00263       if(combining_alg == EvaluatorStopsOnDeny) {
00264         if(res == DECISION_PERMIT){
00265           permitset.push_back(*policyit);
00266           atleast_onepermit = true;
00267         }
00268        else if(res == DECISION_DENY) {
00269           atleast_onedeny = true; 
00270           break;
00271         }
00272         else if(res == DECISION_INDETERMINATE)
00273           atleast_oneindeterminate = true;
00274         else if(res == DECISION_NOT_APPLICABLE)
00275           atleast_onenotapplicable = true;
00276 
00277       } else if(combining_alg == EvaluatorStopsOnPermit) {
00278         if(res == DECISION_PERMIT){
00279           permitset.push_back(*policyit);
00280           atleast_onepermit = true;
00281           break;
00282         }
00283         else if(res == DECISION_DENY)
00284           atleast_onedeny = true;
00285         else if(res == DECISION_INDETERMINATE)
00286           atleast_oneindeterminate = true;
00287         else if(res == DECISION_NOT_APPLICABLE)
00288           atleast_onenotapplicable = true;
00289 
00290       } else if(combining_alg == EvaluatorStopsNever) {
00291         if(res == DECISION_PERMIT){
00292           permitset.push_back(*policyit);
00293           atleast_onepermit = true;
00294         }
00295         else if(res == DECISION_DENY) 
00296           atleast_onedeny = true;
00297         else if(res == DECISION_INDETERMINATE)
00298           atleast_oneindeterminate = true;
00299         else if(res == DECISION_NOT_APPLICABLE)
00300           atleast_onenotapplicable = true;
00301 
00302       } else { // EvaluatorFailsOnDeny
00303         //If there is one policy gives negative evaluation result, then jump out
00304         //For RequestTuple which is denied, we will not feedback any information so far
00305         if(res == DECISION_PERMIT){
00306           permitset.push_back(*policyit);
00307           atleast_onepermit = true;
00308         } 
00309         else if (res == DECISION_DENY) {
00310           atleast_onedeny = true;
00311           permitset.clear();
00312           break;
00313         }
00314         else if(res == DECISION_INDETERMINATE)
00315           atleast_oneindeterminate = true;
00316         else if(res == DECISION_NOT_APPLICABLE)
00317           atleast_onenotapplicable = true;
00318       };
00319     }
00320 
00321     //The decision for this RequestTuple is recorded. Here the algorithm is Permit-Overides,
00322     //if any policy gives "Permit", the result is "Permit";
00323     //if no policy gives "Permit", and any policy gives "Deny", the result is "Deny"; 
00324     //if no policy gives "Permit", no policy gives "Deny", 
00325     if(atleast_onepermit == true) result = DECISION_PERMIT;
00326     else if(atleast_onepermit == false && atleast_onedeny ==true) result = DECISION_DENY;
00327     else if(atleast_onepermit == false && atleast_onedeny ==false && atleast_oneindeterminate == true) result = DECISION_INDETERMINATE;
00328     else if(atleast_onepermit == false && atleast_onedeny ==false && atleast_oneindeterminate == false && 
00329             atleast_onenotapplicable == true) result = DECISION_NOT_APPLICABLE;
00330 
00331 
00332     ResponseItem* item = new ResponseItem;
00333     ArcRequestTuple* reqtuple = new ArcRequestTuple;
00334     reqtuple->duplicate(*it);
00335 
00336     item->reqtp = reqtuple;
00337     item->reqxml = reqtuple->getNode();
00338     item->res = result;
00339 
00340     //For RequestTuple that passes the evaluation check, fill the information into ResponseItem
00341     if(atleast_onepermit){
00342       std::list<PolicyStore::PolicyElement>::iterator permit_it;
00343       for(permit_it = permitset.begin(); permit_it != permitset.end(); permit_it++){
00344         item->pls.push_back((Policy*)(*permit_it));
00345         EvalResult evalres = ((Policy*)(*permit_it))->getEvalResult();
00346         //TODO, handle policyset
00347         XMLNode policyxml = evalres.node;
00348         (item->plsxml).push_back(policyxml);
00349       }
00350     }
00351     //Store the ResponseItem
00352     resp->addResponseItem(item);
00353     
00354     } else { // if(combining_alg_ex)
00355       // Now if real combining algorithm defined use it instead
00356       // of hardcoded mess above.
00357       std::list<Policy*> plist;
00358       // Preparing list of policies to evaluate
00359       for(policyit = policies.begin(); policyit != policies.end(); policyit++){
00360         plist.push_back((Policy*)(*policyit));
00361       };
00362       // Running request tuple and policies through evaluator 
00363       // and combining results 
00364       // TODO: record permitset (is it really needed?)
00365       Result result = combining_alg_ex->combine(ctx,plist);
00366       ResponseItem* item = new ResponseItem;
00367       ArcRequestTuple* reqtuple = new ArcRequestTuple;
00368 //      reqtuple->duplicate((ArcRequestTuple*)(*it));
00369       reqtuple->duplicate(*it);
00370       item->reqtp = reqtuple;
00371       item->reqxml = reqtuple->getNode();
00372       item->res = result;
00373       // Recording positive response - not implemented yet
00374       //if(result == DECISION_PERMIT) {
00375       //  std::list<PolicyStore::PolicyElement>::iterator permit_it;
00376       //  for(pit = permitset.begin(); pit != permitset.end(); pit++){
00377       //    item->pls.push_back((Policy*)(*pit));
00378       //    EvalResult evalres = ((Policy*)(*pit))->getEvalResult();
00379       //    //TODO, handle policyset
00380       //    XMLNode policyxml = evalres.node;
00381       //    (item->plsxml).push_back(policyxml);
00382       //  }
00383       //}
00384       //Store the ResponseItem
00385       resp->addResponseItem(item);
00386     }
00387   }
00388 
00389   delete evl_ctx; 
00390 
00391   return resp;
00392 }
00393 
00394 Response* ArcEvaluator::evaluate(Request* request, const Source& policy) {
00395   plstore->removePolicies();
00396   plstore->addPolicy(policy, context, "");
00397   Response* resp = evaluate(request);
00398   plstore->removePolicies();
00399   return resp;
00400 }
00401 
00402 Response* ArcEvaluator::evaluate(const Source& request, const Source& policy) {
00403   plstore->removePolicies();
00404   plstore->addPolicy(policy, context, "");
00405   Response* resp = evaluate(request);
00406   plstore->removePolicies();
00407   return resp;
00408 }
00409 
00410 Response* ArcEvaluator::evaluate(Request* request, Policy* policyobj) {
00411   plstore->removePolicies();
00412   plstore->addPolicy(policyobj, context, "");
00413   Response* resp = evaluate(request);
00414   plstore->releasePolicies();
00415   return resp;
00416 }
00417 
00418 Response* ArcEvaluator::evaluate(const Source& request, Policy* policyobj) {
00419   plstore->removePolicies();
00420   plstore->addPolicy(policyobj, context, "");
00421   Response* resp = evaluate(request);
00422   plstore->releasePolicies();
00423   return resp;
00424 }
00425 
00426 const char* ArcEvaluator::getName(void) const {
00427   return "arc.evaluator";
00428 }
00429 
00430 ArcEvaluator::~ArcEvaluator(){
00431   //TODO delete all the object
00432   if(plstore)
00433     delete plstore;
00434   if(context)
00435     delete context;
00436   if(fnfactory)
00437     delete fnfactory;
00438   if(attrfactory)
00439     delete attrfactory;
00440   if(algfactory)
00441     delete algfactory;
00442 }
00443