Back to index

nordugrid-arc-nox  1.1.0~rc6
arcslcs.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <cstdlib>
00008 #include <iostream>
00009 #include <fstream>
00010 #include <string>
00011 #include <stdexcept>
00012 #include <unistd.h>
00013 #include <sys/types.h>
00014 #include <sys/stat.h>
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <openssl/ssl.h>
00018 #include <openssl/err.h>
00019 #include <openssl/x509.h>
00020 #include <openssl/bio.h>
00021 
00022 #include <arc/ArcLocation.h>
00023 #include <arc/Logger.h>
00024 #include <arc/credential/Credential.h>
00025 #include <arc/client/ClientSAML2SSO.h>
00026 #include <arc/message/MCC.h>
00027 #include <arc/OptionParser.h>
00028 #include <arc/StringConv.h>
00029 #include <arc/User.h>
00030 #include <arc/Utils.h>
00031 #include <arc/URL.h>
00032 #include <arc/UserConfig.h>
00033 #include <arc/xmlsec/XmlSecUtils.h>
00034 
00035 static Arc::Logger& logger = Arc::Logger::rootLogger;
00036 
00037 static void tls_process_error(void) {
00038   unsigned long err;
00039   err = ERR_get_error();
00040   if (err != 0) {
00041     logger.msg(Arc::ERROR, "OpenSSL Error -- %s", ERR_error_string(err, NULL));
00042     logger.msg(Arc::ERROR, "Library  : %s", ERR_lib_error_string(err));
00043     logger.msg(Arc::ERROR, "Function : %s", ERR_func_error_string(err));
00044     logger.msg(Arc::ERROR, "Reason   : %s", ERR_reason_error_string(err));
00045   }
00046   return;
00047 }
00048 
00049 std::string slcs_url;
00050 std::string idp_name;
00051 std::string username;
00052 std::string password;
00053 int keysize = 0;
00054 std::string keypass;
00055 std::string storedir;
00056 int lifetime;
00057 
00058 //certificate and key file to be generated by SLCS service
00059 std::string key_path, cert_path;
00060 std::string cert_req_path;
00061 //CA path or CA directory for certifying the server's credential
00062 //Note: this client itself will not provide credential (server side
00063 //will not verify client's certificate).
00064 std::string trusted_ca_path, trusted_ca_dir;
00065 Arc::MCCConfig mcc_cfg;
00066 
00067 
00068 void handleSLCS() {
00069     //Generate certificate request
00070     Arc::Time t;
00071     Arc::User user;
00072     Arc::Credential request(t, Arc::Period(lifetime * 3600), keysize, "EEC");
00073     std::string cert_req_str;
00074     if (!request.GenerateRequest(cert_req_str))
00075       throw std::runtime_error("Failed to generate certificate request");
00076 
00077     std::ofstream out_cert_req(cert_req_path.c_str(), std::ofstream::out);
00078     out_cert_req.write(cert_req_str.c_str(), cert_req_str.size());
00079     out_cert_req.close();
00080     std::string private_key;
00081     //If the passphrase for protecting private key has not been set,
00082     // the private key will not be protected by passphrase.
00083     if (keypass.empty())
00084       request.OutputPrivatekey(private_key);
00085     else
00086       request.OutputPrivatekey(private_key, true, keypass);
00087     std::ofstream out_key(key_path.c_str(), std::ofstream::out);
00088     out_key.write(private_key.c_str(), private_key.size());
00089     out_key.close();
00090 
00091     //Send soap message to service, implicitly including the SAML2SSO profile
00092 
00093     Arc::URL url(slcs_url);
00094 
00095     Arc::ClientSOAPwithSAML2SSO *client_soap = NULL;
00096     client_soap = new Arc::ClientSOAPwithSAML2SSO(mcc_cfg, url);
00097     logger.msg(Arc::INFO, "Creating and sending soap request");
00098 
00099     Arc::NS slcs_ns;
00100     slcs_ns["slcs"] = "http://www.nordugrid.org/schemas/slcs";
00101     Arc::PayloadSOAP req_soap(slcs_ns);
00102     req_soap.NewChild("GetSLCSCertificateRequest").NewChild("X509Request") = cert_req_str;
00103 
00104     Arc::PayloadSOAP *resp_soap = NULL;
00105     if (client_soap) {
00106       Arc::MCC_Status status = client_soap->process(&req_soap, &resp_soap, idp_name, username, password);
00107       if (!status) {
00108         logger.msg(Arc::ERROR, "SOAP with SAML2SSO invokation failed");
00109         delete client_soap;
00110         throw std::runtime_error("SOAP with SAML2SSO invokation failed");
00111       }
00112       if (resp_soap == NULL) {
00113         logger.msg(Arc::ERROR, "There was no SOAP response");
00114         delete client_soap;
00115         throw std::runtime_error("There was no SOAP response");
00116       }
00117     }
00118 
00119     std::string cert_str = (std::string)((*resp_soap)["GetSLCSCertificateResponse"]["X509Certificate"]);
00120     std::string ca_str = (std::string)((*resp_soap)["GetSLCSCertificateResponse"]["CACertificate"]);
00121     if (resp_soap)
00122       delete resp_soap;
00123     if (client_soap)
00124       delete client_soap;
00125 
00126     //Output the responded slcs certificate and CA certificate
00127     std::ofstream out_cert(cert_path.c_str(), std::ofstream::out);
00128     out_cert.write(cert_str.c_str(), cert_str.size());
00129     out_cert.close();
00130 
00131     char ca_name[20];
00132     if (!ca_str.empty()) {
00133       BIO *ca_bio = BIO_new_mem_buf((void*)(ca_str.c_str()), ca_str.length());
00134       X509 *ca_cert = PEM_read_bio_X509(ca_bio, NULL, NULL, NULL);
00135       unsigned long ca_hash;
00136       ca_hash = X509_subject_name_hash(ca_cert);
00137       snprintf(ca_name, 20, "%08lx.0", ca_hash);
00138       BIO_free_all(ca_bio);
00139       X509_free(ca_cert);
00140     }
00141     std::string ca_path = cert_path.substr(0, (cert_path.size() - 13)) + "/certificates/" + ca_name;
00142     std::ofstream out_ca(ca_path.c_str(), std::ofstream::out);
00143     out_ca.write(ca_str.c_str(), ca_str.size());
00144     out_ca.close();
00145 
00146     Arc::final_xmlsec();
00147 }
00148 
00149 int main(int argc, char *argv[]) {
00150 
00151   setlocale(LC_ALL, "");
00152 
00153   Arc::LogStream logcerr(std::cerr);
00154   logcerr.setFormat(Arc::ShortFormat);
00155   Arc::Logger::getRootLogger().addDestination(logcerr);
00156   Arc::Logger::getRootLogger().setThreshold(Arc::WARNING);
00157 
00158   Arc::User user;
00159 
00160   Arc::ArcLocation::Init(argv[0]);
00161 
00162   Arc::OptionParser options("", "", "");
00163 
00164   Arc::init_xmlsec();
00165 
00166   options.AddOption('S', "url", istring("URL of SLCS service"),
00167                     istring("url"), slcs_url);
00168 
00169   options.AddOption('I', "idp", istring("IdP name"),
00170                     istring("string"), idp_name);
00171 
00172   options.AddOption('U', "user", istring("User account to IdP"),
00173                     istring("string"), username);
00174 
00175   options.AddOption('P', "password", istring("Password for user account to IdP"),
00176                     istring("string"), password);
00177 
00178   options.AddOption('Z', "keysize", istring("Key size of the private key (512, 1024, 2048)"),
00179                     istring("number"), keysize);
00180 
00181   options.AddOption('K', "keypass", istring("Private key passphrase"),
00182                     istring("passphrase"), keypass);
00183 
00184   int lifetime = 0;
00185   options.AddOption('L', "lifetime", istring("Lifetime of the certificate, start with current time, hour as unit"),
00186                     istring("period"), lifetime);
00187 
00188   options.AddOption('D', "storedir", istring("Store directory for key and signed certificate"),
00189                     istring("directory"), storedir);
00190 
00191   std::string conffile;
00192   options.AddOption('z', "conffile",
00193                     istring("configuration file (default ~/.arc/client.conf)"),
00194                     istring("filename"), conffile);
00195 
00196   std::string debug;
00197   options.AddOption('d', "debug",
00198                     istring("FATAL, ERROR, WARNING, INFO, VERBOSE or DEBUG"),
00199                     istring("debuglevel"), debug);
00200 
00201   bool version = false;
00202   options.AddOption('v', "version", istring("print version information"),
00203                     version);
00204 
00205   std::list<std::string> params = options.Parse(argc, argv);
00206 
00207   // If debug is specified as argument, it should be set before loading the configuration.
00208   if (!debug.empty())
00209     Arc::Logger::getRootLogger().setThreshold(Arc::string_to_level(debug));
00210 
00211   Arc::UserConfig usercfg(conffile,  Arc::initializeCredentialsType(Arc::initializeCredentialsType::SkipCredentials));
00212   if (!usercfg) {
00213     logger.msg(Arc::ERROR, "Failed configuration initialization");
00214     return 1;
00215   }
00216 
00217   if (debug.empty() && !usercfg.Verbosity().empty())
00218     Arc::Logger::getRootLogger().setThreshold(Arc::string_to_level(usercfg.Verbosity()));
00219 
00220   if (slcs_url.empty() && usercfg.SLCS())
00221     slcs_url = usercfg.SLCS().str();
00222 
00223   if (idp_name.empty() && usercfg.IdPName().empty())
00224     idp_name = usercfg.IdPName();
00225 
00226   if (username.empty() && !usercfg.UserName().empty())
00227     username = usercfg.UserName();
00228 
00229   if (password.empty() && !usercfg.Password().empty())
00230     password = usercfg.Password();
00231 
00232   if (keysize == 0 && usercfg.KeySize() > 0)
00233     keysize = usercfg.KeySize();
00234   else if (keysize == 0)
00235     keysize = 1024;
00236 
00237   if (keypass.empty() && !usercfg.KeyPassword().empty())
00238     keypass = usercfg.KeyPassword();
00239 
00240   if (lifetime == 0 && usercfg.CertificateLifeTime() > 0) {
00241     lifetime = usercfg.CertificateLifeTime().GetPeriod();
00242   }
00243   if (lifetime == 0)
00244     lifetime = 12;
00245 
00246   if (storedir.empty() && !usercfg.StoreDirectory().empty())
00247     storedir = usercfg.StoreDirectory();
00248 
00249   trusted_ca_path = usercfg.CACertificatePath();
00250   trusted_ca_dir = usercfg.CACertificatesDirectory();
00251 
00252   if (version) {
00253     std::cout << Arc::IString("%s version %s", "arcslcs", VERSION) << std::endl;
00254     return 0;
00255   }
00256 
00257   try {
00258     if (params.size() != 0)
00259       throw std::invalid_argument("Wrong number of arguments!");
00260 
00261     if (storedir.empty()) {
00262       key_path = Arc::GetEnv("X509_USER_KEY");
00263       if (key_path.empty())
00264         key_path = /*user.get_uid() == 0 ? "/etc/grid-security/hostkey.pem" :*/
00265                    user.Home() + "/.globus/userkey.pem";
00266     }
00267     else
00268       key_path = storedir + "/userkey.pem";
00269 
00270     if (storedir.empty()) {
00271       cert_path = Arc::GetEnv("X509_USER_CERT");
00272       if (cert_path.empty())
00273         cert_path = /*user.get_uid() == 0 ? "/etc/grid-security/hostcert.pem" :*/
00274                     user.Home() + "/.globus/usercert.pem";
00275     }
00276     else {
00277       cert_path = storedir + "/usercert.pem";
00278       cert_req_path = cert_path.substr(0, (cert_path.size() - 13)) + "/usercert_request.pem";
00279     }
00280 
00281   if (!trusted_ca_path.empty())
00282      mcc_cfg.AddCAFile(trusted_ca_path);
00283 
00284   if (trusted_ca_dir.empty())
00285      trusted_ca_dir = user.get_uid() == 0 ? "/etc/grid-security/certificates" :
00286             user.Home() + "/.globus/certificates";
00287   if (!trusted_ca_dir.empty())
00288      mcc_cfg.AddCADir(trusted_ca_dir);
00289 
00290   handleSLCS();
00291 
00292     return EXIT_SUCCESS;
00293   } catch (std::exception& err) {
00294     std::cerr << "ERROR: " << err.what() << std::endl;
00295     tls_process_error();
00296     return EXIT_FAILURE;
00297   }
00298 }