Back to index

nordugrid-arc-nox  1.1.0~rc6
PDPServiceInvoker.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <stdexcept>
00006 
00007 #include <arc/XMLNode.h>
00008 #include <arc/Thread.h>
00009 #include <arc/ArcConfig.h>
00010 #include <arc/Logger.h>
00011 #include <arc/URL.h>
00012 #include <arc/message/MCC.h>
00013 #include <arc/StringConv.h>
00014 #include <arc/GUID.h>
00015 #include <arc/credential/Credential.h>
00016 //#include <arc/security/ArcPDP/Response.h>
00017 //#include <arc/security/ArcPDP/attr/AttributeValue.h>
00018 
00019 #include "PDPServiceInvoker.h"
00020 
00021 Arc::Logger ArcSec::PDPServiceInvoker::logger(ArcSec::PDP::logger,"PDPServiceInvoker");
00022 
00023 #define SAML_NAMESPACE "urn:oasis:names:tc:SAML:2.0:assertion"
00024 #define SAMLP_NAMESPACE "urn:oasis:names:tc:SAML:2.0:protocol"
00025 #define XACML_SAMLP_NAMESPACE "urn:oasis:xacml:2.0:saml:protocol:schema:os"
00026 
00027 using namespace Arc;
00028 
00029 namespace ArcSec {
00030 Plugin* PDPServiceInvoker::get_pdpservice_invoker(PluginArgument* arg) {
00031     PDPPluginArgument* pdparg =
00032             arg?dynamic_cast<PDPPluginArgument*>(arg):NULL;
00033     if(!pdparg) return NULL;
00034     return new PDPServiceInvoker((Config*)(*pdparg));
00035 }
00036 
00037 PDPServiceInvoker::PDPServiceInvoker(Config* cfg):PDP(cfg), client(NULL), 
00038   is_xacml(false), is_saml(false) {
00039   XMLNode filter = (*cfg)["Filter"];
00040   if((bool)filter) {
00041     XMLNode select_attr = filter["Select"];
00042     XMLNode reject_attr = filter["Reject"];
00043     for(;(bool)select_attr;++select_attr) select_attrs.push_back((std::string)select_attr);
00044     for(;(bool)reject_attr;++reject_attr) reject_attrs.push_back((std::string)reject_attr);
00045   };
00046 
00047   //Create a SOAP client
00048   logger.msg(Arc::INFO, "Creating a pdpservice client");
00049 
00050   std::string url_str;
00051   url_str = (std::string)((*cfg)["ServiceEndpoint"]);
00052   Arc::URL url(url_str);
00053   
00054   std::cout<<"URL: "<<url_str<<std::endl;
00055 
00056   Arc::MCCConfig mcc_cfg;
00057   std::cout<<"Keypath: "<<(std::string)((*cfg)["KeyPath"])<<"CertificatePath: "<<(std::string)((*cfg)["CertificatePath"])<<"CAPath: "<<(std::string)((*cfg)["CACertificatePath"])<<std::endl;
00058   key_path = (std::string)((*cfg)["KeyPath"]);
00059   cert_path = (std::string)((*cfg)["CertificatePath"]);
00060   proxy_path = (std::string)((*cfg)["ProxyPath"]);
00061   ca_dir = (std::string)((*cfg)["CACertificatesDir"]);
00062   ca_file = (std::string)((*cfg)["CACertificatePath"]);
00063   mcc_cfg.AddPrivateKey(key_path);
00064   mcc_cfg.AddCertificate(cert_path);
00065   mcc_cfg.AddProxy(proxy_path);
00066   mcc_cfg.AddCAFile(ca_file);
00067   mcc_cfg.AddCADir(ca_dir);
00068 
00069   std::string format = (std::string)((*cfg)["RequestFormat"]);
00070   if(format=="XACML" || format=="xacml") is_xacml = true;
00071 
00072   std::string protocol = (std::string)((*cfg)["TransferProtocol"]);
00073   if(protocol=="SAML" || protocol=="saml") is_saml = true;
00074 
00075   client = new Arc::ClientSOAP(mcc_cfg,url,60);
00076 }
00077 
00078 bool PDPServiceInvoker::isPermitted(Message *msg) const {
00079   if((!is_xacml) && is_saml) {
00080     logger.msg(ERROR,"Arc policy can not been carried by SAML2.0 profile of XACML");
00081     return false;
00082   }
00083   //Compose the request
00084   MessageAuth* mauth = msg->Auth()->Filter(select_attrs,reject_attrs);
00085   MessageAuth* cauth = msg->AuthContext()->Filter(select_attrs,reject_attrs);
00086   if((!mauth) && (!cauth)) {
00087     logger.msg(ERROR,"Missing security object in message");
00088     return false;
00089   };
00090   NS ns;
00091   XMLNode requestxml(ns,"");
00092   if(mauth) {
00093     if(!mauth->Export(is_xacml? SecAttr::XACML : SecAttr::ARCAuth,requestxml)) {
00094       delete mauth;
00095       logger.msg(ERROR,"Failed to convert security information to ARC request");
00096       return false;
00097     };
00098     delete mauth;
00099   };
00100   if(cauth) {
00101     if(!cauth->Export(is_xacml? SecAttr::XACML : SecAttr::ARCAuth,requestxml)) {
00102       delete mauth;
00103       logger.msg(ERROR,"Failed to convert security information to ARC request");
00104       return false;
00105     };
00106     delete cauth;
00107   };
00108   {
00109     std::string s;
00110     requestxml.GetXML(s);
00111     logger.msg(DEBUG,"ARC Auth. request: %s",s);
00112   };
00113   if(requestxml.Size() <= 0) {
00114     logger.msg(ERROR,"No requested security information was collected");
00115     return false;
00116   };
00117 
00118   //Invoke the remote pdp service
00119   if(is_saml) {
00120     Arc::NS ns;
00121     ns["saml"] = SAML_NAMESPACE;
00122     ns["samlp"] = SAMLP_NAMESPACE;
00123     ns["xacml-samlp"] = XACML_SAMLP_NAMESPACE;
00124     Arc::XMLNode authz_query(ns, "xacml-samlp:XACMLAuthzDecisionQuery");
00125     std::string query_id = Arc::UUID();
00126     authz_query.NewAttribute("ID") = query_id;
00127     Arc::Time t;
00128     std::string current_time = t.str(Arc::UTCTime);
00129     authz_query.NewAttribute("IssueInstant") = current_time;
00130     authz_query.NewAttribute("Version") = std::string("2.0");
00131 
00132     Arc::Credential cred(cert_path.empty() ? proxy_path : cert_path,
00133          cert_path.empty() ? proxy_path : key_path, ca_dir, ca_file);
00134     std::string local_dn_str = cred.GetDN();
00135     std::string local_dn = Arc::convert_to_rdn(local_dn_str);
00136     std::string issuer_name = local_dn;
00137     authz_query.NewChild("saml:Issuer") = issuer_name;
00138 
00139     authz_query.NewAttribute("InputContextOnly") = std::string("false");
00140     authz_query.NewAttribute("ReturnContext") = std::string("true");
00141 
00142     authz_query.NewChild(requestxml);
00143 
00144     Arc::NS req_ns;
00145     Arc::SOAPEnvelope req_env(req_ns);
00146     req_env.NewChild(authz_query);
00147     Arc::PayloadSOAP req(req_env);
00148     Arc::PayloadSOAP* resp = NULL;
00149     if(client) {
00150       Arc::MCC_Status status = client->process(&req,&resp);
00151       if(!status) {
00152         logger.msg(Arc::ERROR, "Policy Decision Service invocation failed");
00153       }
00154       if(resp == NULL) {
00155         logger.msg(Arc::ERROR,"There was no SOAP response");
00156       }
00157     }
00158 
00159     std::string authz_res;
00160     if(resp) {
00161       std::string str;
00162       resp->GetXML(str);
00163       logger.msg(Arc::INFO, "Response: %s", str);
00164 
00165       std::string authz_res = (std::string)((*resp)["samlp:Response"]["saml:Assertion"]["xacml-saml:XACMLAuthzDecisionStatement"]["xacml-context:Response"]["xacml-context:Result"]["xacml-context:Decision"]);
00166 
00167       delete resp;
00168     }
00169 
00170     if(authz_res == "Permit") { logger.msg(Arc::INFO,"Authorized from remote pdp service"); return true; }
00171     else { logger.msg(Arc::INFO,"Unauthorized from remote pdp service"); return false; }
00172 
00173   } else {
00174     Arc::NS req_ns;
00175     //req_ns["ra"] = "http://www.nordugrid.org/schemas/request-arc";
00176     req_ns["pdp"] = "http://www.nordugrid.org/schemas/pdp";
00177     Arc::PayloadSOAP req(req_ns);
00178     Arc::XMLNode reqnode = req.NewChild("pdp:GetPolicyDecisionRequest");
00179     reqnode.NewChild(requestxml);
00180 
00181     Arc::PayloadSOAP* resp = NULL;
00182     if(client) {
00183       Arc::MCC_Status status = client->process(&req,&resp);
00184       if(!status) {
00185         logger.msg(Arc::ERROR, "Policy Decision Service invocation failed");
00186       }
00187       if(resp == NULL) {
00188         logger.msg(Arc::ERROR,"There was no SOAP response");
00189       }
00190     }
00191 
00192     std::string authz_res;
00193     if(resp) {
00194       std::string str;
00195       resp->GetXML(str);
00196       logger.msg(Arc::INFO, "Response: %s", str);
00197   
00198       // TODO: Fix namespaces
00199       authz_res=(std::string)((*resp)["pdp:GetPolicyDecisionResponse"]["response:Response"]["response:AuthZResult"]);
00200 
00201       delete resp;
00202     } 
00203 
00204     if(authz_res == "PERMIT") { logger.msg(Arc::INFO,"Authorized from remote pdp service"); return true; }
00205     else { logger.msg(Arc::INFO,"Unauthorized from remote pdp service"); return false; }
00206   }
00207 
00208 }
00209 
00210 PDPServiceInvoker::~PDPServiceInvoker(){
00211 }
00212 
00213 } // namespace ArcSec
00214