Back to index

nordugrid-arc-nox  1.1.0~rc6
saml_assertion_init.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 #include <cstdlib>
00008 #include <stdexcept>
00009 
00010 #include <arc/XMLNode.h>
00011 #include <arc/ArcConfig.h>
00012 #include <arc/URL.h>
00013 #include <arc/GUID.h>
00014 #include <arc/StringConv.h>
00015 #include <arc/message/MCC.h>
00016 #include <arc/client/ClientInterface.h>
00017 #include <arc/credential/Credential.h>
00018 
00019 #include <arc/ArcLocation.h>
00020 #include <arc/OptionParser.h>
00021 
00022 #include <arc/xmlsec/XmlSecUtils.h>
00023 #include <arc/xmlsec/XMLSecNode.h>
00024 
00025 #define SAML_NAMESPACE "urn:oasis:names:tc:SAML:2.0:assertion"
00026 #define SAMLP_NAMESPACE "urn:oasis:names:tc:SAML:2.0:protocol"
00027 
00028 #define XENC_NAMESPACE   "http://www.w3.org/2001/04/xmlenc#"
00029 #define DSIG_NAMESPACE   "http://www.w3.org/2000/09/xmldsig#"
00030 
00031 int main(int argc, char* argv[]){
00032 
00033     setlocale(LC_ALL, "");
00034 
00035     Arc::Logger logger(Arc::Logger::getRootLogger(), "voms_assertion_init");
00036     Arc::LogStream logcerr(std::cerr);
00037     logcerr.setFormat(Arc::ShortFormat);
00038     Arc::Logger::getRootLogger().addDestination(logcerr);
00039     Arc::Logger::getRootLogger().setThreshold(Arc::WARNING);
00040 
00041     Arc::ArcLocation::Init(argv[0]);
00042 
00043     Arc::OptionParser options(istring("service_url"));
00044 
00045     std::string config_path;
00046     options.AddOption('c', "config",
00047                       istring("path to config file"),
00048                       istring("path"), config_path);
00049 
00050     std::string debug;
00051     options.AddOption('d', "debug",
00052                       istring("FATAL, ERROR, WARNING, INFO, VERBOSE or DEBUG"),
00053                       istring("debuglevel"), debug);
00054 
00055     bool version = false;
00056     options.AddOption('v', "version", istring("print version information"),
00057                       version);
00058 
00059     std::list<std::string> params = options.Parse(argc, argv);
00060 
00061     if (!debug.empty())
00062         Arc::Logger::getRootLogger().setThreshold(Arc::string_to_level(debug));
00063 
00064     if (version) {
00065         std::cout << Arc::IString("%s version %s", "voms_assertion_init", VERSION)
00066                   << std::endl;
00067         return 0;
00068     }
00069 
00070     try{
00071       if (params.size()!=1) {
00072         throw std::invalid_argument("Wrong number of arguments!");
00073       }
00074 
00075       //Create a SOAP client
00076       std::list<std::string>::iterator it = params.begin();
00077       Arc::URL url(*it++);
00078       if(!url)
00079           throw std::invalid_argument("Can't parse specified URL");
00080       Arc::MCCConfig cfg;
00081       if(config_path != "") cfg.GetOverlay(config_path);
00082 
00083       Arc::ClientSOAP client(cfg,url);
00084 
00085       //Compose the soap which include <samlp:AttributeQuery/>
00086 
00087       //Use the credential which is configured in MCCConfig for the 
00088       //credential setup in <samlp:AttributeQuery> 
00089       std::string cert = (std::string)(cfg.overlay["Chain"]["Component"]["CertificatePath"]);
00090       std::string key = (std::string)(cfg.overlay["Chain"]["Component"]["KeyPath"]);
00091       std::string cafile = (std::string)(cfg.overlay["Chain"]["Component"]["CACertificatePath"]);
00092       std::string cadir = (std::string)(cfg.overlay["Chain"]["Component"]["CACertificatesDir"]);
00093 
00094       Arc::Credential cred(cert, key, cadir, cafile);
00095       std::string local_dn_str = cred.GetDN();
00096       std::string local_dn = Arc::convert_to_rdn(local_dn_str);
00097        
00098       //Compose <samlp:AttributeQuery/> 
00099       Arc::NS ns;
00100       ns["saml"] = SAML_NAMESPACE;
00101       ns["samlp"] = SAMLP_NAMESPACE;
00102 
00103       Arc::XMLNode attr_query(ns, "samlp:AttributeQuery");
00104       std::string query_id = Arc::UUID();
00105       attr_query.NewAttribute("ID") = query_id;
00106       Arc::Time t;
00107       std::string current_time = t.str(Arc::UTCTime);
00108       attr_query.NewAttribute("IssueInstant") = current_time;
00109       attr_query.NewAttribute("Version") = std::string("2.0");
00110 
00111       //<saml:Issuer/>
00112       std::string issuer_name = local_dn;
00113       Arc::XMLNode issuer = attr_query.NewChild("saml:Issuer");
00114       issuer = issuer_name;
00115       issuer.NewAttribute("Format") = std::string("urn:oasis:names:tc:SAML:1.1:nameid-format:x509SubjectName");
00116 
00117       //<saml:Subject/>
00118       Arc::XMLNode subject = attr_query.NewChild("saml:Subject");
00119       Arc::XMLNode name_id = subject.NewChild("saml:NameID");
00120       name_id.NewAttribute("Format")=std::string("urn:oasis:names:tc:SAML:1.1:nameid-format:x509SubjectName");
00121       name_id = local_dn;
00122  
00123       //Add one or more <Attribute>s into AttributeQuery here, which means the 
00124       //Requestor would get these <Attribute>s from AA <saml:Attribute/>
00125       //TODO
00126 
00127       //Initialize lib xmlsec
00128       Arc::init_xmlsec();
00129 
00130       //Put the attribute query into soap message
00131       Arc::NS soap_ns;
00132       Arc::SOAPEnvelope envelope(soap_ns);
00133       envelope.NewChild(attr_query);
00134       Arc::PayloadSOAP request(envelope);
00135 
00136       //Send the soap message to the other end
00137       Arc::PayloadSOAP *response = NULL;
00138       Arc::MCC_Status status = client.process(&request,&response);
00139       if (!response) {
00140         logger.msg(Arc::ERROR, "SOAP Request failed: No response");
00141         throw std::runtime_error("SOAP Request failed: No response");
00142       }
00143       if (!status) {
00144         logger.msg(Arc::ERROR, "SOAP Request failed: Error");
00145         throw std::runtime_error("SOAP Request failed: Error");
00146       }
00147 
00148       Arc::XMLNode saml_response = (*response).Body().Child(0);
00149       if(!saml_response) {
00150         logger.msg(Arc::ERROR, "No <saml:Response/> in SOAP response");
00151         throw std::runtime_error("No <saml:Response/> in SOAP response");
00152       }
00153       
00154       Arc::XMLNode saml_assertion = saml_response["Assertion"];
00155       if(!saml_assertion) {
00156         logger.msg(Arc::ERROR, "No <saml:Assertion/> in SAML response");
00157         throw std::runtime_error("No <saml:Assertion/> in SAML response");
00158       }
00159 
00160       std::string str;
00161       saml_assertion.GetXML(str);
00162       std::cout<<"SAML assertion: "<<str<<std::endl;
00163 
00164       //Verify the assertion
00165       std::string assertion_idname = "ID";
00166       Arc::XMLSecNode assertion_secnode(saml_assertion);
00167       if(assertion_secnode.VerifyNode(assertion_idname, cafile, cadir,false)) {
00168         logger.msg(Arc::INFO, "Succeeded to verify the signature under <saml:Assertion/>");
00169       }
00170       else {
00171         logger.msg(Arc::ERROR, "Failed to verify the signature under <saml:Assertion/>");
00172         throw std::runtime_error("Failed to verify the signature under <saml:Assertion/>");
00173       }
00174     } catch (std::exception& e){
00175       Arc::final_xmlsec();
00176       // Notify the user about the failure
00177       std::cerr << "ERROR: " << e.what() << std::endl;
00178       return EXIT_FAILURE;
00179     }
00180 
00181     Arc::final_xmlsec();
00182     return EXIT_SUCCESS;
00183 }