Back to index

nordugrid-arc-nox  1.1.0~rc6
ArcPDP.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <iostream>
00006 #include <fstream>
00007 
00008 #include <arc/XMLNode.h>
00009 #include <arc/Thread.h>
00010 #include <arc/ArcConfig.h>
00011 #include <arc/ArcLocation.h>
00012 #include <arc/Logger.h>
00013 #include <arc/security/ArcPDP/Response.h>
00014 #include <arc/security/ArcPDP/attr/AttributeValue.h>
00015 #include <arc/security/ArcPDP/EvaluatorLoader.h>
00016 
00017 #include "ArcPDP.h"
00018 
00019 Arc::Logger ArcSec::ArcPDP::logger(ArcSec::PDP::logger,"ArcPDP");
00020 
00021 /*
00022 static ArcSec::PDP* get_pdp(Arc::Config *cfg,Arc::ChainContext *ctx) {
00023     return new ArcSec::ArcPDP(cfg);
00024 }
00025 
00026 pdp_descriptors ARC_PDP_LOADER = {
00027     { "arc.pdp", 0, &get_pdp},
00028     { NULL, 0, NULL }
00029 };
00030 */
00031 
00032 using namespace Arc;
00033 
00034 namespace ArcSec {
00035 
00036 Plugin* ArcPDP::get_arc_pdp(PluginArgument* arg) {
00037     ArcSec::PDPPluginArgument* pdparg =
00038             arg?dynamic_cast<ArcSec::PDPPluginArgument*>(arg):NULL;
00039     if(!pdparg) return NULL;
00040     return new ArcPDP((Arc::Config*)(*pdparg));
00041 }
00042 
00043 // This class is used to store Evaluator per connection
00044 class ArcPDPContext:public Arc::MessageContextElement {
00045  friend class ArcPDP;
00046  private:
00047   Evaluator* eval;
00048  public:
00049   ArcPDPContext(Evaluator* e);
00050   ArcPDPContext(void);
00051   virtual ~ArcPDPContext(void);
00052 };
00053 
00054 ArcPDPContext::~ArcPDPContext(void) {
00055   if(eval) delete eval;
00056 }
00057 
00058 ArcPDPContext::ArcPDPContext(Evaluator* e):eval(e) {
00059 }
00060 
00061 ArcPDPContext::ArcPDPContext(void):eval(NULL) {
00062   std::string evaluator = "arc.evaluator"; 
00063   EvaluatorLoader eval_loader;
00064   eval = eval_loader.getEvaluator(evaluator);
00065 }
00066 
00067 ArcPDP::ArcPDP(Config* cfg):PDP(cfg) /*, eval(NULL)*/ {
00068   XMLNode pdp_node(*cfg);
00069 
00070   XMLNode filter = (*cfg)["Filter"];
00071   if((bool)filter) {
00072     XMLNode select_attr = filter["Select"];
00073     XMLNode reject_attr = filter["Reject"];
00074     for(;(bool)select_attr;++select_attr) select_attrs.push_back((std::string)select_attr);
00075     for(;(bool)reject_attr;++reject_attr) reject_attrs.push_back((std::string)reject_attr);
00076   };
00077   XMLNode policy_store = (*cfg)["PolicyStore"];
00078   XMLNode policy_location = policy_store["Location"];
00079   for(;(bool)policy_location;++policy_location) policy_locations.push_back((std::string)policy_location);
00080   XMLNode policy = (*cfg)["Policy"];
00081   for(;(bool)policy;++policy) policies.AddNew(policy);
00082   policy_combining_alg = (std::string)((*cfg)["PolicyCombiningAlg"]);
00083 }
00084 
00085 bool ArcPDP::isPermitted(Message *msg) const {
00086   //Compose Request based on the information inside message, the Request will be like below:
00087   /*
00088   <Request xmlns="http://www.nordugrid.org/schemas/request-arc">
00089     <RequestItem>
00090         <Subject>
00091           <Attribute AttributeId="123" Type="string">123.45.67.89</Attribute>
00092           <Attribute AttributeId="xyz" Type="string">/O=NorduGrid/OU=UIO/CN=test</Attribute>
00093         </Subject>
00094         <Action AttributeId="ijk" Type="string">GET</Action>
00095     </RequestItem>
00096   </Request>
00097   */
00098   Evaluator* eval = NULL;
00099 
00100   std::string ctxid = "arcsec.arcpdp";
00101   try {
00102     Arc::MessageContextElement* mctx = (*(msg->Context()))[ctxid];
00103     if(mctx) {
00104       ArcPDPContext* pdpctx = dynamic_cast<ArcPDPContext*>(mctx);
00105       if(pdpctx) {
00106         eval=pdpctx->eval;
00107       }
00108       else { logger.msg(INFO, "Can not find ArcPDPContext"); }
00109     };
00110   } catch(std::exception& e) { };
00111   if(!eval) {
00112     ArcPDPContext* pdpctx = new ArcPDPContext();
00113     if(pdpctx) {
00114       eval=pdpctx->eval;
00115       if(eval) {
00116         //for(Arc::AttributeIterator it = (msg->Attributes())->getAll("PDP:POLICYLOCATION"); it.hasMore(); it++) {
00117         //  eval->addPolicy(SourceFile(*it));
00118         //}
00119         for(std::list<std::string>::const_iterator it = policy_locations.begin(); it!= policy_locations.end(); it++) {
00120           eval->addPolicy(SourceFile(*it));
00121         }
00122         for(int n = 0;n<policies.Size();++n) {
00123           eval->addPolicy(Source(const_cast<Arc::XMLNodeContainer&>(policies)[n]));
00124         }
00125         if(!policy_combining_alg.empty()) {
00126           if(policy_combining_alg == "EvaluatorFailsOnDeny") {
00127             eval->setCombiningAlg(EvaluatorFailsOnDeny);
00128           } else if(policy_combining_alg == "EvaluatorStopsOnDeny") {
00129             eval->setCombiningAlg(EvaluatorStopsOnDeny);
00130           } else if(policy_combining_alg == "EvaluatorStopsOnPermit") {
00131             eval->setCombiningAlg(EvaluatorStopsOnPermit);
00132           } else if(policy_combining_alg == "EvaluatorStopsNever") {
00133             eval->setCombiningAlg(EvaluatorStopsNever);
00134           } else {
00135             AlgFactory* factory = eval->getAlgFactory();
00136             if(!factory) {
00137               logger.msg(WARNING, "Evaluator does not support loadable Combining Algorithms");
00138             } else {
00139               CombiningAlg* algorithm = factory->createAlg(policy_combining_alg);
00140               if(!algorithm) {
00141                 logger.msg(ERROR, "Evaluator does not support specified Combining Algorithm - %s",policy_combining_alg);
00142               } else {
00143                 eval->setCombiningAlg(algorithm);
00144               };
00145             };
00146           };
00147         };
00148         msg->Context()->Add(ctxid, pdpctx);
00149       } else {
00150         delete pdpctx;
00151       }
00152     }
00153     if(!eval) logger.msg(ERROR, "Can not dynamically produce Evaluator");
00154   }
00155   if(!eval) {
00156     logger.msg(ERROR,"Evaluator for ArcPDP was not loaded"); 
00157     return false;
00158   };
00159 
00160   MessageAuth* mauth = msg->Auth()->Filter(select_attrs,reject_attrs);
00161   MessageAuth* cauth = msg->AuthContext()->Filter(select_attrs,reject_attrs);
00162   if((!mauth) && (!cauth)) {
00163     logger.msg(ERROR,"Missing security object in message");
00164     return false;
00165   };
00166   NS ns;
00167   XMLNode requestxml(ns,"");
00168   if(mauth) {
00169     if(!mauth->Export(SecAttr::ARCAuth,requestxml)) {
00170       delete mauth;
00171       logger.msg(ERROR,"Failed to convert security information to ARC request");
00172       return false;
00173     };
00174     delete mauth;
00175   };
00176   if(cauth) {
00177     if(!cauth->Export(SecAttr::ARCAuth,requestxml)) {
00178       delete mauth;
00179       logger.msg(ERROR,"Failed to convert security information to ARC request");
00180       return false;
00181     };
00182     delete cauth;
00183   };
00184   {
00185     std::string s;
00186     requestxml.GetXML(s);
00187     logger.msg(DEBUG,"ARC Auth. request: %s",s);
00188     std::cout<<"ARC Auth. request "<<s<<std::endl;
00189   };
00190   if(requestxml.Size() <= 0) {
00191     logger.msg(ERROR,"No requested security information was collected");
00192     return false;
00193   };
00194 
00195   //Call the evaluation functionality inside Evaluator
00196   Response *resp = eval->evaluate(requestxml);
00197   if(!resp) {
00198     logger.msg(ERROR, "Not authorized from arc.pdp - failed to get reponse from Evaluator");
00199     return false;
00200   };
00201   ResponseList rlist = resp->getResponseItems();
00202   int size = rlist.size();
00203 
00204   //  The current ArcPDP is supposed to be used as policy decision point for Arc1 HED components, and
00205   // those services which are based on HED.
00206   //  Each message/session comes with one unique <Subject/> (with a number of <Attribute/>s),
00207   // and different <Resource/> and <Action/> elements (possibly plus <Context/>).
00208   //  The results from all tuples are combined using following decision algorithm: 
00209   // 1. If any of tuples made of <Subject/>, <Resource/>, <Action/> and <Context/> gets "DENY"
00210   //    then final result is negative (false).
00211   // 2. Otherwise if any of tuples gets "PERMIT" then final result is positive (true).
00212   // 3. Otherwise result is negative (false).
00213 
00214   bool atleast_onedeny = false;
00215   bool atleast_onepermit = false;
00216 
00217   for(int i = 0; i < size; i++) {
00218     ResponseItem* item = rlist[i];
00219     RequestTuple* tp = item->reqtp;
00220 
00221     if(item->res == DECISION_DENY)
00222       atleast_onedeny = true;
00223     if(item->res == DECISION_PERMIT)
00224       atleast_onepermit = true;
00225 
00226     Subject::iterator it;
00227     Subject subject = tp->sub;
00228     for (it = subject.begin(); it!= subject.end(); it++){
00229       AttributeValue *attrval;
00230       RequestAttribute *attr;
00231       attr = dynamic_cast<RequestAttribute*>(*it);
00232       if(attr){
00233         attrval = (*it)->getAttributeValue();
00234         if(attrval) logger.msg(INFO, "%s", attrval->encode());
00235       }
00236     }
00237   } 
00238   
00239   bool result = false;
00240   if(atleast_onedeny) result = false;
00241   else if(atleast_onepermit) result = true;
00242   else result = false;
00243 
00244   if(result) logger.msg(INFO, "Authorized by arc.pdp");
00245   else logger.msg(INFO, "Not authorized by arc.pdp - some of the RequestItem elements do not satisfy Policy");
00246   
00247   if(resp) delete resp;
00248     
00249   return result;
00250 }
00251 
00252 ArcPDP::~ArcPDP(){
00253   //if(eval)
00254   //  delete eval;
00255   //eval = NULL;
00256 }
00257 
00258 } // namespace ArcSec
00259