Back to index

nordugrid-arc-nox  1.1.0~rc6
test_client.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <string>
00006 #include <iostream>
00007 #include <fstream>
00008 #include <signal.h>
00009 
00010 #include <arc/ArcConfig.h>
00011 #include <arc/Logger.h>
00012 #include <arc/XMLNode.h>
00013 #include <arc/message/MCCLoader.h>
00014 #include <arc/message/SOAPEnvelope.h>
00015 #include <arc/message/PayloadSOAP.h>
00016 #include <arc/StringConv.h>
00017 #include <arc/XMLNode.h>
00018 #include <arc/DateTime.h>
00019 #include <arc/GUID.h>
00020 #include <arc/credential/Credential.h>
00021 
00022 #ifdef WIN32
00023 #include <arc/win32.h>
00024 #endif
00025 
00026 #include "../../hed/libs/xmlsec/XmlSecUtils.h"
00027 #include "../../hed/libs/xmlsec/XMLSecNode.h"
00028 
00029 #define SAML_NAMESPACE "urn:oasis:names:tc:SAML:2.0:assertion"
00030 #define SAMLP_NAMESPACE "urn:oasis:names:tc:SAML:2.0:protocol"
00031 
00032 #define XENC_NAMESPACE   "http://www.w3.org/2001/04/xmlenc#"
00033 #define DSIG_NAMESPACE   "http://www.w3.org/2000/09/xmldsig#"
00034 
00035 
00036 static std::string convert_dn(const std::string& dn) {
00037   std::string ret;
00038   size_t pos1 = std::string::npos;
00039   size_t pos2;
00040   do {
00041     std::string str;
00042     pos2 = dn.find_last_of("/", pos1);
00043     if(pos2 != std::string::npos && pos1 == std::string::npos) {
00044       str = dn.substr(pos2+1);
00045       ret.append(str);
00046       pos1 = pos2-1;
00047     }
00048     else if (pos2 != std::string::npos && pos1 != std::string::npos) {
00049       str = dn.substr(pos2+1, pos1-pos2);
00050       ret.append(str);
00051       pos1 = pos2-1;
00052     }
00053     if(pos2 != (std::string::npos+1)) ret.append(",");
00054   }while(pos2 != std::string::npos && pos2 != (std::string::npos+1));
00055   return ret;
00056 }
00057 
00060 int main(void) {
00061   signal(SIGTTOU,SIG_IGN);
00062   signal(SIGTTIN,SIG_IGN);
00063   signal(SIGPIPE,SIG_IGN);
00064   Arc::Logger logger(Arc::Logger::rootLogger, "SAMLTest");
00065   Arc::LogStream logcerr(std::cerr);
00066   Arc::Logger::rootLogger.addDestination(logcerr);
00067 
00068   // Create client chain
00069   logger.msg(Arc::INFO, "Creating client side chain");
00070   Arc::Config client_config("client.xml");
00071   if(!client_config) {
00072     logger.msg(Arc::ERROR, "Failed to load client configuration");
00073     return -1;
00074   };
00075   Arc::MCCLoader client_loader(client_config);
00076   logger.msg(Arc::INFO, "Client side MCCs are loaded");
00077   Arc::MCC* client_entry = client_loader["soap"];
00078   if(!client_entry) {
00079     logger.msg(Arc::ERROR, "Client chain does not have entry point");
00080     return -1;
00081   };
00082   
00083   // -------------------------------------------------------
00084   //    Compose request and send to aa service
00085   // -------------------------------------------------------
00086   //Compose request
00087   Arc::NS ns;
00088   ns["saml"] = SAML_NAMESPACE;
00089   ns["samlp"] = SAMLP_NAMESPACE;
00090 
00091   std::string cert("../../tests/echo/testcert.pem");
00092   std::string key("../../tests/echo/testkey-nopass.pem");
00093   std::string cafile("../../tests/echo/testcacert.pem");
00094   std::string cadir("../../tests/echo/certificates");
00095   Arc::Credential cred(cert, key, cadir, cafile);
00096   std::string local_dn = convert_dn(cred.GetDN());
00097 
00098   //Compose <samlp:AttributeQuery/>
00099   Arc::XMLNode attr_query(ns, "samlp:AttributeQuery");
00100   std::string sp_name("https://sp.com/SAML"); //TODO
00101   std::string query_id = Arc::UUID();
00102   attr_query.NewAttribute("ID") = query_id;
00103   Arc::Time t;
00104   std::string current_time = t.str(Arc::UTCTime);
00105   attr_query.NewAttribute("IssueInstant") = current_time;
00106   attr_query.NewAttribute("Version") = std::string("2.0");
00107   attr_query.NewChild("saml:Issuer") = sp_name;
00108 
00109   //<saml:Subject/>
00110   Arc::XMLNode subject = attr_query.NewChild("saml:Subject");
00111   Arc::XMLNode name_id = subject.NewChild("saml:NameID");
00112   name_id.NewAttribute("Format")=std::string("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName");
00113   name_id = local_dn;
00114 
00115   //Add one or more <Attribute>s into AttributeQuery here, which means the Requestor would
00116   //get these <Attribute>s from AA
00117   //<saml:Attribute/>
00118   Arc::XMLNode attribute = attr_query.NewChild("saml:Attribute");
00119   attribute.NewAttribute("Name")=std::string("urn:oid:1.3.6.1.4.1.5923.1.1.1.6");
00120   attribute.NewAttribute("NameFormat")=std::string("urn:oasis:names:tc:SAML:2.0:attrname-format:uri");
00121   attribute.NewAttribute("FriendlyName")=std::string("eduPersonPrincipalName");
00122 
00123   Arc::init_xmlsec();
00124   Arc::XMLSecNode attr_query_secnd(attr_query);
00125   std::string attr_query_idname("ID");
00126   attr_query_secnd.AddSignatureTemplate(attr_query_idname, Arc::XMLSecNode::RSA_SHA1);
00127   if(attr_query_secnd.SignNode(key,cert)) {
00128     std::cout<<"Succeeded to sign the signature under <samlp:AttributeQuery/>"<<std::endl;
00129   }
00130 
00131   std::string str;
00132   attr_query.GetXML(str);
00133   std::cout<<"++++ "<<str<<std::endl;
00134 
00135   Arc::NS soap_ns;
00136   Arc::SOAPEnvelope envelope(soap_ns);
00137   envelope.NewChild(attr_query);
00138   Arc::PayloadSOAP *payload = new Arc::PayloadSOAP(envelope);
00139 
00140   std::string tmp;
00141   payload->GetXML(tmp);
00142   std::cout<<"SOAP request from Arc client: ++++++++++++++++"<<tmp<<std::endl;
00143  
00144   // Send request
00145   Arc::MessageContext context;
00146   Arc::Message reqmsg;
00147   Arc::Message repmsg;
00148   Arc::MessageAttributes attributes_in;
00149   Arc::MessageAttributes attributes_out;
00150   reqmsg.Payload(payload);
00151   reqmsg.Attributes(&attributes_in);
00152   reqmsg.Context(&context);
00153   repmsg.Attributes(&attributes_out);
00154   repmsg.Context(&context);
00155 
00156   Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
00157   if(!status) {
00158     logger.msg(Arc::ERROR, "Request failed");
00159     return -1;
00160   };
00161   logger.msg(Arc::INFO, "Request succeeded!!!");
00162   if(repmsg.Payload() == NULL) {
00163     logger.msg(Arc::ERROR, "There is no response");
00164     return -1;
00165   };
00166 
00167   Arc::PayloadSOAP* resp = NULL;
00168   try {
00169    resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
00170   } catch(std::exception&) { };
00171   if(resp == NULL) {
00172     logger.msg(Arc::ERROR, "Response is not SOAP");
00173     delete repmsg.Payload();  Arc::final_xmlsec();
00174     return -1;
00175   };
00176 
00177   resp->GetXML(tmp);
00178   std::cout<<"SOAP resp from aa service: ++++++++++++++++"<<tmp<<std::endl;
00179 
00180   // -------------------------------------------------------
00181   //   Comsume the response from aa service
00182   // -------------------------------------------------------
00183   //
00184   //Consume the response from AA
00185   Arc::XMLNode attr_resp;
00186   
00187   //<samlp:Response/>
00188   attr_resp = (*resp).Body().Child(0);
00189  
00190   //TODO: metadata processing.
00191   //std::string aa_name = attr_resp["saml:Issuer"]; 
00192  
00193   //Check validity of the signature on <samlp:Response/>
00194   std::string resp_idname = "ID";
00195   std::string cafile1 = "../../tests/echo/testcacert.pem";
00196   std::string capath1 = "../../tests/echo/certificates";
00197   Arc::XMLSecNode attr_resp_secnode(attr_resp);
00198   if(attr_resp_secnode.VerifyNode(resp_idname, cafile1, capath1)) {
00199     logger.msg(Arc::INFO, "Succeeded to verify the signature under <samlp:Response/>");
00200   }
00201   else {
00202     logger.msg(Arc::ERROR, "Failed to verify the signature under <samlp:Response/>");
00203     delete repmsg.Payload(); Arc::final_xmlsec(); return -1;
00204   }
00205  
00206  
00207   //Check whether the "InResponseTo" is the same as the local ID
00208   std::string responseto_id = (std::string)(attr_resp.Attribute("InResponseTo"));
00209   if(query_id != responseto_id) {
00210     logger.msg(Arc::INFO, "The Response is not going to this end");
00211     delete repmsg.Payload(); Arc::final_xmlsec(); return -1;
00212   }
00213 
00214   std::string resp_time = attr_resp.Attribute("IssueInstant");
00215 
00216   //<samlp:Status/>
00217   std::string statuscode_value = attr_resp["samlp:Status"]["samlp:StatusCode"];
00218   if(statuscode_value == "urn:oasis:names:tc:SAML:2.0:status:Success")
00219     logger.msg(Arc::INFO, "The StatusCode is Success");
00220 
00221   //<saml:Assertion/>
00222   Arc::XMLNode assertion = attr_resp["saml:Assertion"];
00223 
00224   //TODO: metadata processing.
00225   //std::string aa_name = assertion["saml:Issuer"];
00226  
00227   //Check validity of the signature on <saml:Assertion/>
00228   std::string assertion_idname = "ID";
00229   std::string cafile2 = "../../tests/echo/testcacert.pem";
00230   std::string capath2 = "../../tests/echo/certificates";
00231   Arc::XMLSecNode assertion_secnode(assertion);
00232   if(assertion_secnode.VerifyNode(assertion_idname, cafile2, capath2)) {
00233     logger.msg(Arc::INFO, "Succeeded to verify the signature under <saml:Assertion/>");
00234   }
00235   else {
00236     logger.msg(Arc::ERROR, "Failed to verify the signature under <saml:Assertion/>");
00237     delete repmsg.Payload(); Arc::final_xmlsec(); return -1;
00238   }
00239 
00240   //<saml:Subject/>, TODO: 
00241   Arc::XMLNode subject_nd = assertion["saml:Subject"];
00242 
00243   //<saml:Condition/>, TODO: Condition checking
00244   Arc::XMLNode cond_nd = assertion["saml:Conditions"];
00245 
00246   //<saml:AttributeStatement/>
00247   Arc::XMLNode attr_statement = assertion["saml:AttributeStatement"];
00248 
00249   //<saml:Attribute/>
00250   Arc::XMLNode attr_nd;
00251   std::vector<std::string> attributes_value;
00252   for(int i=0;;i++) {
00253     attr_nd = attr_statement["saml:Attribute"][i];
00254     if(!attr_nd) break;
00255 
00256     std::string name = attr_nd.Attribute("Name");
00257     std::string nameformat = attr_nd.Attribute("NameFormat");
00258     std::string friendname = attribute.Attribute("FriendlyName");
00259 
00260     Arc::XMLNode attr_value = attr_nd["saml:AttributeValue"];
00261 
00262     std::string str;
00263     str.append("Name=").append(friendname).append(" Value=").append(attr_value);
00264     attributes_value.push_back(str);
00265   }
00266 
00267   for(int i=0; i<attributes_value.size(); i++) {
00268     std::cout<<"Attribute Value: "<<attributes_value[i]<<std::endl;  
00269   }
00270 
00271   delete repmsg.Payload();
00272 
00273   Arc::final_xmlsec();
00274 
00275   return 0;
00276 }