Back to index

nordugrid-arc-nox  1.1.0~rc6
DelegationSH.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 <openssl/md5.h>
00009 
00010 #include <arc/ArcConfig.h>
00011 #include <arc/message/PayloadSOAP.h>
00012 #include <arc/message/MCC.h>
00013 #include <arc/XMLNode.h>
00014 #include <arc/client/ClientInterface.h>
00015 #include <arc/client/ClientX509Delegation.h>
00016 
00017 #include "DelegationSH.h"
00018 
00019 static Arc::Logger logger(Arc::Logger::rootLogger, "DelegationSH");
00020 Arc::Logger ArcSec::DelegationSH::logger(Arc::Logger::rootLogger,"DelegationSH");
00021 
00022 Arc::Plugin* ArcSec::DelegationSH::get_sechandler(Arc::PluginArgument* arg) {
00023     ArcSec::SecHandlerPluginArgument* shcarg =
00024             arg?dynamic_cast<ArcSec::SecHandlerPluginArgument*>(arg):NULL;
00025     if(!shcarg) return NULL;
00026     return new ArcSec::DelegationSH((Arc::Config*)(*shcarg),(Arc::ChainContext*)(*shcarg));
00027 }
00028 
00029 /*
00030 sechandler_descriptors ARC_SECHANDLER_LOADER = {
00031     { "delegation.handler", 0, &get_sechandler},
00032     { NULL, 0, NULL }
00033 };
00034 */
00035 
00036 namespace ArcSec {
00037 using namespace Arc;
00038 
00039 class DelegationContext:public Arc::MessageContextElement{
00040  public:
00041   bool have_delegated_;
00042   DelegationContext(void){ have_delegated_ = false; };
00043   virtual ~DelegationContext(void) { };
00044 };
00045 
00046 DelegationSH::DelegationSH(Config *cfg,ChainContext*):SecHandler(cfg) {
00047   std::string delegation_type = (std::string)((*cfg)["Type"]);
00048   std::string delegation_role = (std::string)((*cfg)["Role"]);
00049   ds_endpoint_ = (std::string)((*cfg)["DelegationServiceEndpoint"]);
00050   peers_endpoint_ =  (std::string)((*cfg)["PeerServiceEndpoint"]);// And this value will be parsed from main chain later 
00051   delegation_id_ = (std::string)((*cfg)["DelegationID"]);
00052   delegation_cred_identity_ = (std::string)((*cfg)["DelegationCredIdentity"]);  
00053 
00054   if(delegation_type.empty()) delegation_type = "x509";
00055 
00056   if(delegation_type == "x509") {
00057     proxy_file_=(std::string)((*cfg)["ProxyPath"]);
00058     cert_file_=(std::string)((*cfg)["CertificatePath"]);
00059     if(cert_file_.empty()&&proxy_file_.empty()&&delegation_cred_identity_.empty()) {
00060       logger.msg(ERROR,"Missing CertificatePath element or ProxyPath element, or <DelegationCredIdentity/> is missing");
00061       return;
00062     };
00063     key_file_=(std::string)((*cfg)["KeyPath"]);
00064     if(key_file_.empty()&&proxy_file_.empty()&&delegation_cred_identity_.empty()) {
00065       logger.msg(ERROR,"Missing or empty KeyPath element, or <DelegationCredIdentity/> is missing");
00066       return;
00067     };
00068     ca_file_=(std::string)((*cfg)["CACertificatePath"]);
00069     ca_dir_=(std::string)((*cfg)["CACertificatesDir"]);
00070     if(ca_file_.empty() && ca_dir_.empty()) {
00071       logger.msg(ERROR,"Missing or empty CertificatePath or CACertificatesDir element");
00072       return;
00073     }
00074     delegation_type_=delegation_x509;
00075     if(delegation_role == "delegator") delegation_role_ = delegation_delegator;
00076     else if(delegation_role == "delegatee") delegation_role_ = delegation_delegatee;
00077     else {
00078       logger.msg(ERROR,"Delegation role not supported: %s",delegation_role);
00079       return;
00080     }
00081   } else if(delegation_type == "saml") {
00082     //TODO:
00083     
00084     
00085     delegation_type_=delegation_saml;
00086   } else {
00087     logger.msg(ERROR,"Delegation type not supported: %s",delegation_type);
00088     return;
00089   }
00090 
00091   mcontext_ = new DelegationContext();
00092 }
00093 
00094 DelegationSH::~DelegationSH() {
00095   delete mcontext_;
00096 }
00097 
00098 DelegationContext* DelegationSH::get_delegcontext(Arc::Message& msg) const {
00099   DelegationContext* deleg_ctx=NULL;
00100   Arc::MessageContextElement* mcontext = (*msg.Context())["deleg.context"];
00101   if(mcontext) {
00102     try {
00103       deleg_ctx = dynamic_cast<DelegationContext*>(mcontext);
00104     } catch(std::exception& e) { };
00105   };
00106   if(deleg_ctx) return deleg_ctx;
00107   deleg_ctx = new DelegationContext();
00108   if(deleg_ctx) {
00109     msg.Context()->Add("deleg.context",deleg_ctx);
00110   } else {
00111     logger.msg(Arc::ERROR, "Failed to acquire delegation context");
00112   }
00113   return deleg_ctx;
00114 }
00115 
00116 //Generate hash value for a string
00117 static unsigned long string_hash(const std::string& value){
00118   unsigned long ret=0;
00119   unsigned char md[16];
00120   MD5((unsigned char *)(value.c_str()),value.length(),&(md[0]));
00121   ret=(((unsigned long)md[0])|((unsigned long)md[1]<<8L)|
00122        ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
00123        )&0xffffffffL;
00124   return ret;
00125 }
00126 
00127 bool DelegationSH::Handle(Arc::Message* msg) const {
00128   if(delegation_type_ == delegation_x509) {
00129     try {
00130       PayloadSOAP* soap = dynamic_cast<PayloadSOAP*>(msg->Payload());
00131 
00132       if(delegation_role_ == delegation_delegatee) {
00133         //Try to get the delegation service and delegation ID
00134         //information from incoming message
00135 
00136         //Store delegation context into message context
00137         DelegationContext* deleg_ctx = get_delegcontext(*msg); //dynamic_cast<DelegationContext*>(mcontext_);
00138         if(!deleg_ctx) {
00139           logger.msg(Arc::ERROR, "Can't create delegation context");
00140           return false;
00141         }
00142         //Credential delegation will only be triggered once for each connection
00143         if(deleg_ctx->have_delegated_) return true;
00144 
00145         logger.msg(Arc::INFO,"Delegation handler with delegatee role starts to process");
00146         std::string method = (*msg).Attributes()->get("HTTP:METHOD");
00147         if(method == "POST") {
00148           logger.msg(Arc::VERBOSE, "process: POST");
00149           // Extracting payload
00150           Arc::PayloadSOAP* inpayload = NULL;
00151           try {
00152             inpayload = dynamic_cast<Arc::PayloadSOAP*>(msg->Payload());
00153           } catch(std::exception& e) { };
00154           if(!inpayload) {
00155             logger.msg(Arc::ERROR, "input is not SOAP");
00156             return false;
00157           };
00158           // Analyzing request
00159           std::string ds_endpoint = (std::string)((*inpayload)["DelegationService"]);
00160           std::string delegation_id = (std::string)((*inpayload)["DelegationID"]);
00161           if(!ds_endpoint.empty()) {
00162             logger.msg(Arc::INFO, "Delegation service: %s",ds_endpoint.c_str());
00163             Arc::MCCConfig ds_client_cfg;
00164             //Use service's credential to acquire delegation credential which
00165             //will be used by this service to act on behalf of the original
00166             //EEC credential's holder.
00167             if(!cert_file_.empty())ds_client_cfg.AddCertificate(cert_file_);
00168             if(!key_file_.empty())ds_client_cfg.AddPrivateKey(key_file_);
00169             if(!proxy_file_.empty())ds_client_cfg.AddProxy(proxy_file_);
00170             if(!ca_dir_.empty()) ds_client_cfg.AddCADir(ca_dir_);
00171             if(!ca_file_.empty())ds_client_cfg.AddCAFile(ca_file_);
00172             Arc::URL ds_url(ds_endpoint);
00173             Arc::ClientX509Delegation client_deleg(ds_client_cfg,ds_url);
00174             std::string delegation_cred;
00175             if(!delegation_id.empty()) {
00176               if(!client_deleg.acquireDelegation(DELEG_ARC,delegation_cred,delegation_id)) {
00177                 logger.msg(ERROR,"Can not get the delegation credential: %s from delegation service:%s",delegation_id.c_str(),ds_endpoint.c_str());
00178                 return false;
00179               };
00180             } else {
00181               std::string cred_identity = msg->Attributes()->get("TLS:IDENTITYDN");
00182               std::string cred_delegator_ip = msg->Attributes()->get("TCP:REMOTEHOST");
00183               if(!client_deleg.acquireDelegation(DELEG_ARC,delegation_cred,delegation_id,cred_identity,cred_delegator_ip)) {
00184                 logger.msg(ERROR,"Can not get the delegation credential: %s from delegation service:%s",delegation_id.c_str(),ds_endpoint.c_str());
00185                 return false;
00186               };
00187             }
00188 
00189 
00190             std::string cred_identity = msg->Attributes()->get("TLS:IDENTITYDN");
00191             unsigned long hash_value = string_hash(cred_identity);
00192             //Store the delegated credential (got from delegation service)
00193             //into local temporary path; this delegated credential will be 
00194             //used by the client functionality in this service (intemidiate 
00195             //service) to contact the next service. 
00196             std::string deleg_cred_path="/tmp/";
00197             char text[20];
00198             snprintf(text, sizeof(text), "%08lx", hash_value);
00199             deleg_cred_path.append(text).append(".pem");
00200             logger.msg(INFO,"Delegated credential identity: %s",cred_identity.c_str());
00201             logger.msg(INFO,"The delegated credential got from delegation service is stored into path: %s",deleg_cred_path.c_str());
00202             std::ofstream proxy_f(deleg_cred_path.c_str());
00203             proxy_f.write(delegation_cred.c_str(),delegation_cred.size());
00204             proxy_f.close();
00205 
00206             //Remove the delegation information inside the payload 
00207             //since this information ('DelegationService' and 'DelegationID') 
00208             //is only supposed to be consumer by this security handler, not 
00209             //the hosted service itself.
00210             if((*inpayload)["DelegationService"]) ((*inpayload)["DelegationService"]).Destroy();
00211             if((*inpayload)["DelegationID"]) ((*inpayload)["DelegationID"]).Destroy();
00212 
00213           } else {
00214             logger.msg(ERROR,"The endpoint of delgation service should be configured");
00215             return false;
00216           }
00217         };
00218 
00219         //Set the 'have_delegated_' value of DelegationContext to
00220         //be true, so that the delegation process will only be triggered
00221         //once for each communication.
00222         deleg_ctx->have_delegated_=true;
00223 
00224         logger.msg(Arc::INFO,"Delegation handler with delegatee role ends");
00225         return true;
00226       }
00227       else if(delegation_role_ == delegation_delegator) {
00228         //Create one more level of delegation
00229         Arc::MCCConfig ds_client_cfg;
00230         //Use delegation credential (one option is to use the one got and stored 
00231         //in the delegation handler with 'delegatee' delegation role, note in this 
00232         //case the service implementation should configure the client interface 
00233         //(the client interface which is called by the service implementation to
00234         //contact another service) with the 'Identity' of the credential on which 
00235         //this service will act on behalf, then the delegation handler with 'delegator' 
00236         //delegation role (configured in this client interface's configuration) will
00237         //get the delegated credential from local temporary path (this path is 
00238         //decided according to the 'Identity'); the other option is cofigure the credential
00239         //(EEC credential or delegated credential) in this 'delegator' role delegation
00240         //handler's configuration. What can be concluded here is: the former option
00241         //applies to intermediate service; the later option applies to the client
00242         //utilities. 
00243         //By creating one more level of delegation, the delegated credential
00244         //will be used by the next intermediate service to act on behalf of
00245         //the EEC credential's holder
00246 
00247         //Store delegation context into message context
00248         DelegationContext* deleg_ctx = dynamic_cast<DelegationContext*>(mcontext_); //get_delegcontext(*msg);
00249         if(!deleg_ctx) {
00250           logger.msg(Arc::ERROR, "Can't create delegation context");
00251           return false;
00252         }
00253         //Credential delegation will only be triggered once for each connection
00254         if(deleg_ctx->have_delegated_) return true;
00255 
00256         logger.msg(Arc::INFO,"Delegation handler with delegator role starts to process");
00257         std::string proxy_path;
00258         if(!delegation_cred_identity_.empty()) {
00259           unsigned long hash_value = string_hash(delegation_cred_identity_);
00260           proxy_path="/tmp/";
00261           char text[20];
00262           snprintf(text, sizeof(text), "%08lx", hash_value);
00263           proxy_path.append(text).append(".pem");
00264           logger.msg(INFO,"Delegated credential identity: %s",delegation_cred_identity_.c_str());
00265           logger.msg(INFO,"The delegated credential got from path: %s",proxy_path.c_str());
00266           ds_client_cfg.AddProxy(proxy_path);
00267         }else if(!proxy_file_.empty()) {        
00268           ds_client_cfg.AddProxy(proxy_file_);
00269         }else if(!cert_file_.empty()&&!key_file_.empty()) {
00270           ds_client_cfg.AddCertificate(cert_file_); 
00271           ds_client_cfg.AddPrivateKey(key_file_); 
00272         }
00273         if(!ca_dir_.empty()) ds_client_cfg.AddCADir(ca_dir_);
00274         if(!ca_file_.empty())ds_client_cfg.AddCAFile(ca_file_);
00275         //Note here the delegation service endpoint to which this service will
00276         //create the delegation credential ('n+1' level delegation) could be
00277         //different with the delegation service endpoint from which this service
00278         //acquire the delegation credential ('n' level delegation)
00279 
00280         Arc::URL ds_url(ds_endpoint_);
00281         Arc::ClientX509Delegation client_deleg(ds_client_cfg,ds_url);
00282         std::string delegation_id;
00283         //delegation_id will be used later to interact           
00284         //with the next intermediate service.
00285         if(!client_deleg.createDelegation(DELEG_ARC,delegation_id)) {
00286           logger.msg(ERROR,"Can not create delegation crendential to delgation service: %s",ds_endpoint_.c_str());
00287           return false;
00288         };
00289 
00290         //Send the endpoint of delegation service and delegation ID to 
00291         //the peer service side, on which the delegation handler with 
00292         //'delegation_delegatee' role will get the endpoint of delegation
00293         //service and delegation ID to aquire delegation credential.
00294         //
00295         //The delegation service and delegation ID
00296         //information will be sent to the service side by the 
00297         //client side. If the client functionality is hosted/called by
00298         //some intermediate service, this handler (delegation handler with
00299         //delegator role) should be configured into the 'incoming' message of 
00300         //the hosted service; if the client functionality is called by
00301         //some independent client utility, this handler should be configured 
00302         //into the 'incoming' message of the client itself.
00303         //
00304         //The credential used to send delegation service and delegation ID
00305         //information is the same credential which is used to interact with
00306         //the peer service. And the target service is the peer service.
00307         Arc::MCCConfig peers_client_cfg;
00308         if(!cert_file_.empty())peers_client_cfg.AddCertificate(cert_file_);
00309         if(!key_file_.empty())peers_client_cfg.AddPrivateKey(key_file_);
00310         if(!proxy_file_.empty())peers_client_cfg.AddProxy(proxy_file_);
00311         if(!ca_dir_.empty()) peers_client_cfg.AddCADir(ca_dir_);
00312         if(!ca_file_.empty())peers_client_cfg.AddCAFile(ca_file_);
00313         Arc::URL peers_url(peers_endpoint_);
00314         Arc::ClientSOAP client_peer(peers_client_cfg,peers_url,60);
00315         Arc::NS delegation_ns; delegation_ns["deleg"]="urn:delegation"; //
00316 
00317         //Treat the delegation information as 'out-of-bound' information
00318         //to SOAP message
00319         Arc::PayloadSOAP* outpayload = NULL;
00320         try {
00321           outpayload = dynamic_cast<Arc::PayloadSOAP*>(msg->Payload());
00322         } catch(std::exception& e) { };
00323         if(!outpayload) {
00324           logger.msg(Arc::ERROR, "output is not SOAP");
00325           return false;
00326         };
00327         outpayload->NewChild("deleg:DelegationService")=ds_endpoint_;
00328         outpayload->NewChild("deleg:DelegationID")=delegation_id;
00329 
00330         //Set the 'have_delegated_' value of DelegationContext to
00331         //be true, so that the delegation process will only be triggered
00332         //once for each communication.
00333         deleg_ctx->have_delegated_=true;      
00334 
00335         logger.msg(Arc::INFO, "Succeeded to send DelegationService: %s and DelegationID: %s info to peer service",ds_endpoint_.c_str(),delegation_id.c_str());
00336         logger.msg(Arc::INFO,"Delegation handler with delegatee role ends");
00337         return true;     
00338       }
00339 
00340     } catch(std::exception) {
00341       logger.msg(ERROR,"Incoming Message is not SOAP");
00342       return false;
00343     }  
00344   } else if(delegation_type_ == delegation_saml) {
00345     try {
00346       PayloadSOAP* soap = dynamic_cast<PayloadSOAP*>(msg->Payload());
00347 
00348 
00349 
00350     } catch(std::exception) {
00351       logger.msg(ERROR,"Outgoing Message is not SOAP");
00352       return false;
00353     }
00354   } else {
00355     logger.msg(ERROR,"Delegation handler is not configured");
00356     return false;
00357   } 
00358   return true;
00359 }
00360 
00361 }
00362 
00363