/// <summary> /// Sends a CyberSource transaction request. /// </summary> /// <param name="config">Configuration object to use.</param> /// <param name="requestMessage">RequestMessage object containing the request.</param> /// <returns>ReplyMessage containing the reply.</returns> public static ReplyMessage RunTransaction( Configuration config, RequestMessage requestMessage) { Logger logger = null; TransactionProcessorClient proc = null; try { DetermineEffectiveMerchantID(ref config, requestMessage); SetVersionInformation(requestMessage); logger = PrepareLog(config); SetConnectionLimit(config); CustomBinding currentBinding = getWCFCustomBinding(config); //Setup endpoint Address with dns identity AddressHeaderCollection headers = new AddressHeaderCollection(); EndpointAddress endpointAddress = new EndpointAddress(new Uri(config.EffectiveServerURL), EndpointIdentity.CreateDnsIdentity(config.EffectivePassword), headers); //Get instance of service using (proc = new TransactionProcessorClient(currentBinding, endpointAddress)) { // set the timeout TimeSpan timeOut = new TimeSpan(0, 0, 0, config.Timeout, 0); currentBinding.SendTimeout = timeOut; //add certificate credentials string keyFilePath = Path.Combine(config.KeysDirectory, config.EffectiveKeyFilename); X509Certificate2 merchantCert = null; X509Certificate2 cybsCert = null; DateTime dateFile = File.GetLastWriteTime(keyFilePath); if (config.CertificateCacheEnabled) { if (!merchantIdentities.ContainsKey(config.MerchantID) || IsMerchantCertExpired(logger, config.MerchantID, dateFile, merchantIdentities)) { if (logger != null) { logger.LogInfo("Loading certificate for merchantID " + config.MerchantID); } X509Certificate2Collection collection = new X509Certificate2Collection(); collection.Import(keyFilePath, config.EffectivePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); X509Certificate2 newMerchantCert = null; X509Certificate2 newCybsCert = null; foreach (X509Certificate2 cert1 in collection) { if (cert1.Subject.Contains(config.MerchantID)) { newMerchantCert = cert1; } if (cert1.Subject.Contains(CYBS_SUBJECT_NAME)) { newCybsCert = cert1; } } CertificateEntry newCert = new CertificateEntry { ModifiedTime = dateFile, CybsCert = newCybsCert, MerchantCert = newMerchantCert }; merchantIdentities.AddOrUpdate(config.MerchantID, newCert, (x, y) => newCert); } merchantCert = GetOrFindValidMerchantCertFromStore(config.MerchantID, merchantIdentities); if (config.UseSignedAndEncrypted) { cybsCert = GetOrFindValidCybsCertFromStore(config.MerchantID, merchantIdentities); } } else { // Changes for SHA2 certificates support X509Certificate2Collection collection = new X509Certificate2Collection(); collection.Import(keyFilePath, config.EffectivePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); foreach (X509Certificate2 cert1 in collection) { if (cert1.Subject.Contains(config.MerchantID)) { merchantCert = cert1; break; } } if (config.UseSignedAndEncrypted) { foreach (X509Certificate2 cert2 in collection) { //Console.WriteLine(cert1.Subject); if (cert2.Subject.Contains(CYBERSOURCE_PUBLIC_KEY)) { cybsCert = cert2; break; } } } } if (merchantCert == null) { throw new ApplicationException( "CONFIGURATION OR CODE BUG: merchant certificate is missing, check the p12 file"); } //Set protection level to sign only proc.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign; proc.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None; proc.ClientCredentials.ClientCertificate.Certificate = merchantCert; proc.ClientCredentials.ServiceCertificate.DefaultCertificate = merchantCert; if (config.UseSignedAndEncrypted) { if (cybsCert == null) { throw new ApplicationException( "CONFIGURATION OR CODE BUG: cybs certificate is missing, check the p12 file"); } //Set protection level to sign & encrypt only proc.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign; proc.ClientCredentials.ServiceCertificate.DefaultCertificate = cybsCert; } // Changes for NGT-3035 XmlNode req = SerializeObjectToXmlNode(requestMessage); if (logger != null) { logger.LogRequest(req, config.Demo); } ReplyMessage reply = proc.runTransaction(requestMessage); XmlNode rep = SerializeObjectToXmlNode(reply); if (logger != null) { logger.LogReply(rep, config.Demo); } return(reply); } } catch (Exception e) { if (logger != null) { logger.LogException(e); } if (proc != null) { proc.Abort(); } throw; } finally { if (proc != null) { proc.Close(); } } }
/// <summary> /// Sends a CyberSource transaction request. /// </summary> /// <param name="request">XmlDocument object containing the request.</param> /// <param name="config">Configuration object to use.</param> /// <returns>XmlDocument object containing the reply.</returns> public static XmlDocument RunTransaction( Configuration config, XmlDocument request) { Logger logger = null; string nspace = null; try { nspace = GetRequestNamespace(request); DetermineEffectiveMerchantID(ref config, request, nspace); SetVersionInformation(request, nspace); logger = PrepareLog(config); if (string.IsNullOrEmpty(nspace)) { throw new ApplicationException( REQUEST_MESSAGE + " is missing in the XML document."); } SetConnectionLimit(config); if (logger != null) { logger.LogRequest(request, config.Demo); } // obtain a copy of the request document enclosed in a SOAP envelope XmlDocument doc = SoapWrap(request, nspace); //Get the X509 cert and sign the SOAP Body string keyFilePath = Path.Combine(config.KeysDirectory, config.EffectiveKeyFilename); X509Certificate2 merchantCert = null; X509Certificate2 cybsCert = null; DateTime dateFile = File.GetLastWriteTime(keyFilePath); if (config.CertificateCacheEnabled) { if (!merchantIdentities.ContainsKey(config.MerchantID) || IsMerchantCertExpired(logger, config.MerchantID, dateFile, merchantIdentities)) { if (logger != null) { logger.LogInfo("Loading certificate for merchantID " + config.MerchantID); } X509Certificate2Collection collection = new X509Certificate2Collection(); collection.Import(keyFilePath, config.EffectivePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); X509Certificate2 newMerchantCert = null; X509Certificate2 newCybsCert = null; foreach (X509Certificate2 cert1 in collection) { if (cert1.Subject.Contains(config.MerchantID)) { newMerchantCert = cert1; } if (cert1.Subject.Contains(CYBS_SUBJECT_NAME)) { newCybsCert = cert1; } } CertificateEntry newCert = new CertificateEntry { ModifiedTime = dateFile, CybsCert = newCybsCert, MerchantCert = newMerchantCert }; merchantIdentities.AddOrUpdate(config.MerchantID, newCert, (x, y) => newCert); } merchantCert = GetOrFindValidMerchantCertFromStore(config.MerchantID, merchantIdentities); if (config.UseSignedAndEncrypted) { cybsCert = GetOrFindValidCybsCertFromStore(config.MerchantID, merchantIdentities); } } else { X509Certificate2Collection collection = new X509Certificate2Collection(); collection.Import(keyFilePath, config.EffectivePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); foreach (X509Certificate2 cert1 in collection) { if (cert1.Subject.Contains(config.MerchantID)) { merchantCert = cert1; break; } } if (config.UseSignedAndEncrypted) { foreach (X509Certificate2 cert1 in collection) { //Console.WriteLine(cert1.Subject); if (cert1.Subject.Contains("CyberSource_SJC_US")) { cybsCert = cert1; break; } } } } if (merchantCert == null) { throw new ApplicationException( "CONFIGURATION OR CODE BUG: merchant certificate is missing, check the p12 file"); } SignDocument(merchantCert, doc); if (config.UseSignedAndEncrypted) { if (cybsCert == null) { throw new ApplicationException( "CONFIGURATION OR CODE BUG: cybs certificate is missing, check the p12 file"); } encryptDocument(cybsCert, doc); } // convert the document into an array of bytes using the // encoding specified in the XML declaration line. Encoding enc = GetEncoding(doc); byte[] requestBytes = enc.GetBytes(doc.OuterXml); // create an HttpWebRequest object and set its properties HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create( config.EffectiveServerURL); httpRequest.Method = "POST"; httpRequest.ContentLength = requestBytes.Length; httpRequest.UserAgent = ".NET XML"; // set the timeout httpRequest.Timeout = config.Timeout * 1000; if (mProxy != null) { // assign our pre-created WebProxy object to the // HttpWebRequest object's Proxy property. httpRequest.Proxy = mProxy; } // obtain the request stream and write the byte array to it. Stream stream = httpRequest.GetRequestStream(); stream.Write(requestBytes, 0, requestBytes.Length); stream.Close(); // send request and get response. WebResponse webResponse = httpRequest.GetResponse(); // read returned XML document. XmlDocument reply = ReadXml(webResponse); XmlDocument unwrapped = SoapUnwrap(reply, nspace); if (logger != null) { logger.LogReply(unwrapped, config.Demo); } // return the XML document without the SOAP envelope. return(unwrapped); } catch (WebException we) { // if we got HTTP status 500 (Internal Server Error), it could // mean, the server threw a fault, in which case, we load the // xml document from the HTTP body and throw a FaultException. // The status would be ProtocolError if we did get HTTP 500 // and Response should not be null but we check for null just // in case. if (we.Status == WebExceptionStatus.ProtocolError && we.Response != null) { HttpWebResponse response = (HttpWebResponse)we.Response; // InternalServerError corresponds to HTTP 500. And we // proceed only if there's anything in the response body. // That is, the contentLength is greater than zero. if (response.StatusCode == HttpStatusCode.InternalServerError && response.ContentLength > 0) { try { // read the fault document and throw a // FaultException. FaultException fe = new FaultException( ReadXml(response), nspace); if (logger != null) { logger.LogFault(fe.LogString); } throw; } catch (XmlException) { if (logger != null) { logger.LogException(we); } // the response body is not a valid xml document. // It is therefore not a fault. Rethrow the // WebException object. throw; } } } if (logger != null) { logger.LogException(we); } // the server did not throw a fault. Rethrow the WebException // object. throw; } catch (Exception e) { if (logger != null) { logger.LogException(e); } throw; } }