#include "internal.h"
#include "exceptions.h"
+#include "logging.h"
#include "security/CredentialCriteria.h"
#include "security/OpenSSLTrustEngine.h"
#include "security/OpenSSLCredential.h"
#include <list>
#include <curl/curl.h>
-#include <log4cpp/Category.hh>
#include <openssl/x509_vfy.h>
+using namespace xmltooling::logging;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
namespace xmltooling {
m_log(Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURLPool")) {}
~CURLPool();
- CURL* get(const char* to, const char* endpoint);
- void put(const char* to, const char* endpoint, CURL* handle);
+ CURL* get(const SOAPTransport::Address& addr);
+ void put(const char* from, const char* to, const char* endpoint, CURL* handle);
private:
typedef map<string,vector<CURL*> > poolmap_t;
class XMLTOOL_DLLLOCAL CURLSOAPTransport : public HTTPSOAPTransport, public OpenSSLSOAPTransport
{
public:
- CURLSOAPTransport(const char* peerName, const char* endpoint)
- : m_peerName(peerName ? peerName : ""), m_endpoint(endpoint), m_handle(NULL), m_headers(NULL),
+ CURLSOAPTransport(const Address& addr)
+ : m_sender(addr.m_from ? addr.m_from : ""), m_peerName(addr.m_to ? addr.m_to : ""), m_endpoint(addr.m_endpoint),
+ m_handle(NULL), m_headers(NULL),
#ifndef XMLTOOLING_NO_XMLSEC
m_cred(NULL), m_trustEngine(NULL), m_peerResolver(NULL), m_mandatory(false),
#endif
- m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_secure(false) {
- m_handle = g_CURLPool->get(peerName, endpoint);
- curl_easy_setopt(m_handle,CURLOPT_URL,endpoint);
+ m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_authenticated(false) {
+ m_handle = g_CURLPool->get(addr);
+ curl_easy_setopt(m_handle,CURLOPT_URL,addr.m_endpoint);
curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15);
curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,30);
curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0);
curl_easy_setopt(m_handle,CURLOPT_USERPWD,NULL);
+ curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYHOST,2);
curl_easy_setopt(m_handle,CURLOPT_HEADERDATA,this);
m_headers=curl_slist_append(m_headers,"Content-Type: text/xml");
}
virtual ~CURLSOAPTransport() {
curl_slist_free_all(m_headers);
curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL);
- curl_easy_setopt(m_handle,CURLOPT_PRIVATE,m_secure ? "secure" : NULL); // Save off security "state".
- g_CURLPool->put(m_peerName.c_str(), m_endpoint.c_str(), m_handle);
+ curl_easy_setopt(m_handle,CURLOPT_PRIVATE,m_authenticated ? "secure" : NULL); // Save off security "state".
+ g_CURLPool->put(m_sender.c_str(), m_peerName.c_str(), m_endpoint.c_str(), m_handle);
}
bool isConfidential() const {
bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL);
+ bool setVerifyHost(bool verify) {
+ return (curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYHOST,verify ? 2 : 0)==CURLE_OK);
+ }
+
#ifndef XMLTOOLING_NO_XMLSEC
bool setCredential(const Credential* cred=NULL) {
const OpenSSLCredential* down = dynamic_cast<const OpenSSLCredential*>(cred);
return true;
}
+ bool setProviderOption(const char* provider, const char* option, const char* value) {
+ if (!provider || strcmp(provider, "CURL"))
+ return false;
+ // For libcurl, the option is an enum and the value type depends on the option.
+ CURLoption opt = static_cast<CURLoption>(strtol(option, NULL, 10));
+ if (opt < CURLOPTTYPE_OBJECTPOINT)
+ return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+ else if (opt < CURLOPTTYPE_OFF_T)
+ return (curl_easy_setopt(m_handle, opt, value) == CURLE_OK);
+ else if (sizeof(curl_off_t) == sizeof(long))
+ return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+ return false;
+ }
+
void send(istream& in);
istream& receive() {
return m_stream;
}
- bool isSecure() const {
- return m_secure;
+ bool isAuthenticated() const {
+ return m_authenticated;
}
- void setSecure(bool secure) {
- m_secure = secure;
+ void setAuthenticated(bool auth) {
+ m_authenticated = auth;
}
string getContentType() const;
private:
// per-call state
- string m_peerName,m_endpoint,m_simplecreds;
+ string m_sender,m_peerName,m_endpoint,m_simplecreds;
CURL* m_handle;
stringstream m_stream;
struct curl_slist* m_headers;
ssl_ctx_callback_fn m_ssl_callback;
void* m_ssl_userptr;
bool m_chunked;
- bool m_secure;
+ bool m_authenticated;
friend size_t XMLTOOL_DLLLOCAL curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream);
friend CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg);
#endif
- SOAPTransport* CURLSOAPTransportFactory(const pair<const char*,const char*>& dest)
+ SOAPTransport* CURLSOAPTransportFactory(const SOAPTransport::Address& addr)
{
- return new CURLSOAPTransport(dest.first, dest.second);
+ return new CURLSOAPTransport(addr);
}
};
delete m_lock;
}
-CURL* CURLPool::get(const char* to, const char* endpoint)
+CURL* CURLPool::get(const SOAPTransport::Address& addr)
{
#ifdef _DEBUG
xmltooling::NDC("get");
#endif
- m_log.debug("getting connection handle to %s", endpoint);
+ m_log.debug("getting connection handle to %s", addr.m_endpoint);
+ string key(addr.m_endpoint);
+ if (addr.m_from)
+ key = key + '|' + addr.m_from;
+ if (addr.m_to)
+ key = key + '|' + addr.m_to;
m_lock->lock();
- poolmap_t::iterator i=m_bindingMap.find(string(to) + "|" + endpoint);
+ poolmap_t::iterator i=m_bindingMap.find(key);
if (i!=m_bindingMap.end()) {
// Move this pool to the front of the list.
curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(handle,CURLOPT_NOSIGNAL,1);
curl_easy_setopt(handle,CURLOPT_FAILONERROR,1);
- curl_easy_setopt(handle,CURLOPT_SSLVERSION,3);
+ curl_easy_setopt(handle,CURLOPT_SSLVERSION,CURL_SSLVERSION_SSLv3);
+ curl_easy_setopt(handle,CURLOPT_SSL_CIPHER_LIST,"ALL:!aNULL:!LOW:!EXPORT:!SSLv2");
// Verification of the peer is via TrustEngine only.
curl_easy_setopt(handle,CURLOPT_SSL_VERIFYPEER,0);
- curl_easy_setopt(handle,CURLOPT_SSL_VERIFYHOST,2);
curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,&curl_header_hook);
curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,&curl_write_hook);
curl_easy_setopt(handle,CURLOPT_DEBUGFUNCTION,&curl_debug_hook);
return handle;
}
-void CURLPool::put(const char* to, const char* endpoint, CURL* handle)
+void CURLPool::put(const char* from, const char* to, const char* endpoint, CURL* handle)
{
- string key = string(to) + "|" + endpoint;
+ string key(endpoint);
+ if (from)
+ key = key + '|' + from;
+ if (to)
+ key = key + '|' + to;
m_lock->lock();
poolmap_t::iterator i=m_bindingMap.find(key);
if (i==m_bindingMap.end())
// Set request headers.
curl_easy_setopt(m_handle,CURLOPT_HTTPHEADER,m_headers);
+#ifndef XMLTOOLING_NO_XMLSEC
if (m_ssl_callback || m_cred || m_trustEngine) {
+#else
+ if (m_ssl_callback) {
+#endif
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,xml_ssl_ctx_callback);
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,this);
char* priv=NULL;
curl_easy_getinfo(m_handle,CURLINFO_PRIVATE,&priv);
if (priv)
- m_secure=true;
+ m_authenticated=true;
}
else {
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL);
// *ptr is actually a logging object
if (!ptr) return 0;
CategoryStream log=reinterpret_cast<Category*>(ptr)->debugStream();
- for (char* ch=data; len && (isprint(*ch) || isspace(*ch)); len--)
+ for (unsigned char* ch=(unsigned char*)data; len && (isprint(*ch) || isspace(*ch)); len--)
log << *ch++;
- log << CategoryStream::ENDLINE;
return 0;
}
bool success=false;
if (ctx->m_criteria) {
- ctx->m_criteria->setUsage(CredentialCriteria::TLS_CREDENTIAL);
+ ctx->m_criteria->setUsage(Credential::TLS_CREDENTIAL);
// Bypass name check (handled for us by curl).
ctx->m_criteria->setPeerName(NULL);
success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),ctx->m_criteria);
else {
// Bypass name check (handled for us by curl).
CredentialCriteria cc;
- cc.setUsage(CredentialCriteria::TLS_CREDENTIAL);
+ cc.setUsage(Credential::TLS_CREDENTIAL);
success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),&cc);
}
if (!success) {
log.error("supplied TrustEngine failed to validate SSL/TLS server certificate");
x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics
- ctx->setSecure(false);
+ ctx->setAuthenticated(false);
return ctx->m_mandatory ? 0 : 1;
}
// Signal success. Hopefully it doesn't matter what's actually in the structure now.
- ctx->setSecure(true);
+ ctx->setAuthenticated(true);
return 1;
}
#endif