Back to index

nordugrid-arc-nox  1.1.0~rc6
slcs.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <iostream>
00006 
00007 #include <sys/types.h>
00008 
00009 #include <arc/loader/Loader.h>
00010 #include <arc/message/PayloadSOAP.h>
00011 #include <arc/message/PayloadRaw.h>
00012 #include <arc/message/PayloadStream.h>
00013 #include <arc/Thread.h>
00014 
00015 #include "slcs.h"
00016 
00017 namespace ArcSec {
00018 
00019 static Arc::LogStream logcerr(std::cerr);
00020 
00021 static Arc::Plugin* get_service(Arc::PluginArgument* arg) {
00022     Arc::ServicePluginArgument* srvarg =
00023             arg?dynamic_cast<Arc::ServicePluginArgument*>(arg):NULL;
00024     if(!srvarg) return NULL;
00025     return new Service_SLCS((Arc::Config*)(*srvarg));
00026 }
00027 
00028 Arc::MCC_Status Service_SLCS::make_soap_fault(Arc::Message& outmsg) {
00029   Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_,true);
00030   Arc::SOAPFault* fault = outpayload?outpayload->Fault():NULL;
00031   if(fault) {
00032     fault->Code(Arc::SOAPFault::Sender);
00033     fault->Reason("Failed processing slcs(short-lived certificate) request");
00034   };
00035   outmsg.Payload(outpayload);
00036   return Arc::MCC_Status(Arc::STATUS_OK);
00037 }
00038 
00039 Arc::MCC_Status Service_SLCS::process(Arc::Message& inmsg,Arc::Message& outmsg) {
00040   std::string method = inmsg.Attributes()->get("HTTP:METHOD");
00041 
00042   if(!ProcessSecHandlers(inmsg,"incoming")) {
00043     logger_.msg(Arc::ERROR, "Security Handlers processing failed");
00044     return Arc::MCC_Status();
00045   };
00046 
00047   //Get identity-related information from saml assertion which has been put 
00048   //as MessageAuthContext by SPService on the same connection as this slcs service
00049   std::string identity;
00050   std::string ou, cn;
00051   std::string saml_assertion_str; 
00052   {
00053     Arc::SecAttr* sattr = inmsg.Auth()->get("SAMLAssertion");
00054     if(!sattr) { 
00055       logger_.msg(Arc::ERROR, "Can not get SAMLAssertion SecAttr from message context");
00056       return Arc::MCC_Status();
00057     }
00058     Arc::XMLNode saml_assertion_nd;
00059     if(sattr->Export(Arc::SecAttr::SAML, saml_assertion_nd)) {
00060       saml_assertion_nd.GetXML(saml_assertion_str);
00061       //The following code is IdP implementation specific. So for
00062       //different types of saml assertion got from IdP, different 
00063       //ways should be implemented here to get the identity-related
00064       //information. 
00065       //Probably, a specific sec handler is needed here for the identity parsing.
00066       Arc::XMLNode attr_statement = saml_assertion_nd["AttributeStatement"];
00067       for(int i=0;; i++) {
00068         Arc::XMLNode cnd = attr_statement.Child(i);
00069         if(!cnd) break;
00070         //Since here we are specifically using shibboleth as IdP, and there
00071         //is one distinguished attribute value which is created by Shibboleth IdP,
00072         //see the following as an example:
00073         //<saml:Attribute FriendlyName="eduPersonPrincipalName" 
00074         //   Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" 
00075         //   NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
00076         //   <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" 
00077         //      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
00078         //      xsi:type="xs:string">
00079         //      staff@knowarc.eu
00080         //   </saml:AttributeValue>
00081         //</saml:Attribute>
00082         //Therefore we base on "eduPersonPrincipalName" to create the DN 
00083         //for the short-lived certificate. In addition, the "O=KnowARC" is 
00084         //fixedly used as "/O=KnowARC".
00085         //So in case of the above example, the DN is: /CN=staff/OU=knowarc.eu/O=KnowARC
00086         //
00087         //However, there should be more elegant and configurable way for creating DN.
00088         if((std::string)(cnd.Attribute("FriendlyName")) == "eduPersonPrincipalName") {
00089           identity = (std::string)(cnd["AttributeValue"]);
00090           std::size_t pos;
00091           pos = identity.find("@");
00092           if(pos != std::string::npos) {
00093             cn = identity.substr(0, pos);
00094             ou = identity.substr(pos+1);
00095           };
00096         };
00097       };
00098     };
00099   };
00100 
00101   // Identify which of served endpoints request is for.
00102   // SLCS can only accept POST method
00103   if(method == "POST") {
00104     logger.msg(Arc::VERBOSE, "process: POST");
00105     // Both input and output are supposed to be SOAP
00106     // Extracting payload
00107     Arc::PayloadSOAP* inpayload = NULL;
00108     try {
00109       inpayload = dynamic_cast<Arc::PayloadSOAP*>(inmsg.Payload());
00110     } catch(std::exception& e) { };
00111     if(!inpayload) {
00112       logger.msg(Arc::ERROR, "input is not SOAP");
00113       return make_soap_fault(outmsg);
00114     };
00115     // Analyzing request
00116     Arc::XMLNode request = (*inpayload)["GetSLCSCertificateRequest"];
00117     if(!request) {
00118       logger.msg(Arc::ERROR, "soap body does not include any request node");
00119       return make_soap_fault(outmsg);
00120     };
00121     {
00122       std::string req_xml;
00123       request.GetXML(req_xml);
00124       logger.msg(Arc::VERBOSE, "Request: %s",req_xml);
00125     };
00126 
00127     Arc::XMLNode x509_req_nd = request["X509Request"];
00128     if(!x509_req_nd) {
00129       logger.msg(Arc::ERROR, "There is no X509Request node in the request message");
00130       return make_soap_fault(outmsg);
00131     };
00132     //If no lifetime specified from request, default lifetime (12hours) will be used
00133     Arc::XMLNode lifetime_nd = request["LifeTime"];
00134     
00135     std::string x509_req = (std::string)x509_req_nd;
00136     std::string lifetime;
00137     if((bool)lifetime_nd) lifetime = (std::string)lifetime_nd;
00138 
00139     //Inquire the x509 request 
00140     Arc::Credential eec;
00141     eec.InquireRequest(x509_req, true);
00142 
00143     if(!(eec.AddExtension("1.3.6.1.4.1.3536.1.1.1.10", saml_assertion_str))) { //Need to investigate the OID 
00144       std::cout<<"Failed to add saml extension to certificate"<<std::endl;
00145     }
00146 
00147     //TODO: compose the base name from configuration and name from saml assertion?
00148     std::string dn("/O=KnowARC/OU=");
00149     dn.append(ou).append("/CN=").append(cn);
00150     logger_.msg(Arc::INFO, "Composed DN: %s",dn.c_str());
00151 
00152 
00153     //Sign the certificate
00154     std::string x509_cert;
00155     ca_credential_->SignEECRequest(&eec, dn, x509_cert);
00156 
00157     //Compose response message
00158     Arc::PayloadSOAP* outpayload = new Arc::PayloadSOAP(ns_);
00159     Arc::XMLNode response = outpayload->NewChild("slcs:GetSLCSCertificateResponse");
00160     Arc::XMLNode x509_res_nd = response.NewChild("slcs:X509Certificate");
00161     x509_res_nd = x509_cert;
00162     Arc::XMLNode ca_res_nd = response.NewChild("slcs:CACertificate");
00163     std::string ca_str;
00164     ca_credential_->OutputCertificate(ca_str);
00165     ca_res_nd = ca_str;
00166 
00167     outmsg.Payload(outpayload);
00168 
00169     if(!ProcessSecHandlers(outmsg,"outgoing")) {
00170       logger_.msg(Arc::ERROR, "Security Handlers processing failed");
00171       delete outmsg.Payload(NULL);
00172       return Arc::MCC_Status();
00173     };
00174 
00175     return Arc::MCC_Status(Arc::STATUS_OK);
00176   }
00177   else {
00178     delete inmsg.Payload();
00179     logger.msg(Arc::VERBOSE, "process: %s: not supported",method);
00180     return Arc::MCC_Status();
00181   }
00182   return Arc::MCC_Status();
00183 }
00184 
00185 Service_SLCS::Service_SLCS(Arc::Config *cfg):RegisteredService(cfg), 
00186     logger_(Arc::Logger::rootLogger, "SLCS_Service"), ca_credential_(NULL) {
00187 
00188   logger_.addDestination(logcerr);
00189   ns_["slcs"]="http://www.nordugrid.org/schemas/slcs";
00190 
00191   std::string CAcert, CAkey, CAserial;
00192   CAcert = (std::string)((*cfg)["CACertificate"]);
00193   CAkey = (std::string)((*cfg)["CAKey"]);
00194   CAserial = (std::string)((*cfg)["CASerial"]);
00195   ca_credential_ = new Arc::Credential(CAcert, CAkey, CAserial, 0, "", "", "");
00196 }
00197 
00198 Service_SLCS::~Service_SLCS(void) {
00199   if(ca_credential_) delete ca_credential_;
00200 }
00201 
00202 bool Service_SLCS::RegistrationCollector(Arc::XMLNode &doc) {
00203   Arc::NS isis_ns; isis_ns["isis"] = "http://www.nordugrid.org/schemas/isis/2008/08";
00204   Arc::XMLNode regentry(isis_ns, "RegEntry");
00205   regentry.NewChild("SrcAdv").NewChild("Type") = "org.nordugrid.security.slcs";
00206   regentry.New(doc);
00207   return true;
00208 }
00209 
00210 } // namespace ArcSec
00211 
00212 Arc::PluginDescriptor PLUGINS_TABLE_NAME[] = {
00213     { "slcs.service", "HED:SERVICE", 0, &ArcSec::get_service },
00214     { NULL, NULL, 0, NULL }
00215 };
00216