/*
- * Copyright 2001-2006 Internet2
+ * Copyright 2001-2007 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
public:
CURLSOAPTransport(const KeyInfoSource& peer, const char* endpoint)
: m_peer(peer), m_endpoint(endpoint), m_handle(NULL), m_headers(NULL),
- m_credResolver(NULL), m_trustEngine(NULL), m_keyResolver(NULL),
- m_ssl_callback(NULL), m_ssl_userptr(NULL) {
+#ifndef XMLTOOLING_NO_XMLSEC
+ m_credResolver(NULL), m_trustEngine(NULL), m_mandatory(false), m_keyResolver(NULL),
+#endif
+ m_ssl_callback(NULL), m_ssl_userptr(NULL), m_secure(false) {
m_handle = g_CURLPool->get(peer.getName(), endpoint);
curl_easy_setopt(m_handle,CURLOPT_URL,endpoint);
curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15);
curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0);
curl_easy_setopt(m_handle,CURLOPT_USERPWD,NULL);
curl_easy_setopt(m_handle,CURLOPT_HEADERDATA,this);
+ m_headers=curl_slist_append(m_headers,"Content-Type: text/xml");
+ m_headers=curl_slist_append(m_headers,"Transport-Encoding: chunked");
}
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_peer.getName(), m_endpoint.c_str(), m_handle);
}
bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const;
+#ifndef XMLTOOLING_NO_XMLSEC
bool setCredentialResolver(const CredentialResolver* credResolver) const {
const OpenSSLCredentialResolver* down = dynamic_cast<const OpenSSLCredentialResolver*>(credResolver);
if (!down) {
return true;
}
- bool setTrustEngine(const X509TrustEngine* trustEngine, const KeyResolver* keyResolver=NULL) const {
+ bool setTrustEngine(const X509TrustEngine* trustEngine, bool mandatory=true, const KeyResolver* keyResolver=NULL) const {
const OpenSSLTrustEngine* down = dynamic_cast<const OpenSSLTrustEngine*>(trustEngine);
if (!down) {
m_trustEngine = NULL;
}
m_trustEngine = down;
m_keyResolver = keyResolver;
+ m_mandatory = mandatory;
return true;
}
- size_t send(istream& in, ostream& out);
+#endif
+
+ void send(istream& in);
+
+ istream& receive() {
+ return m_stream;
+ }
+ bool isSecure() const {
+ return m_secure;
+ }
+
+ void setSecure(bool secure) {
+ m_secure = secure;
+ }
+
string getContentType() const;
bool setRequestHeader(const char* name, const char* val) const {
const KeyInfoSource& m_peer;
string m_endpoint;
CURL* m_handle;
+ stringstream m_stream;
mutable struct curl_slist* m_headers;
map<string,vector<string> > m_response_headers;
+#ifndef XMLTOOLING_NO_XMLSEC
mutable const OpenSSLCredentialResolver* m_credResolver;
mutable const OpenSSLTrustEngine* m_trustEngine;
+ mutable bool m_mandatory;
mutable const KeyResolver* m_keyResolver;
+#endif
mutable ssl_ctx_callback_fn m_ssl_callback;
mutable void* m_ssl_userptr;
+ bool m_secure;
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);
size_t XMLTOOL_DLLLOCAL curl_read_hook( void *ptr, size_t size, size_t nmemb, void *stream);
int XMLTOOL_DLLLOCAL curl_debug_hook(CURL* handle, curl_infotype type, char* data, size_t len, void* ptr);
CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
+#ifndef XMLTOOLING_NO_XMLSEC
int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg);
+#endif
SOAPTransport* CURLSOAPTransportFactory(const pair<const KeyInfoSource*,const char*>& dest)
{
return content_type ? content_type : "";
}
-size_t CURLSOAPTransport::send(istream& in, ostream& out)
+void CURLSOAPTransport::send(istream& in)
{
#ifdef _DEBUG
xmltooling::NDC ndc("send");
// caller should have executed any set functions to manipulate it.
// Setup standard per-call curl properties.
- size_t content_length=0;
- pair<ostream*,size_t*> output = make_pair(&out,&content_length);
curl_easy_setopt(m_handle,CURLOPT_POST,1);
curl_easy_setopt(m_handle,CURLOPT_READDATA,&in);
- curl_easy_setopt(m_handle,CURLOPT_FILE,&output);
+ curl_easy_setopt(m_handle,CURLOPT_FILE,&m_stream);
curl_easy_setopt(m_handle,CURLOPT_DEBUGDATA,&log_curl);
char curl_errorbuf[CURL_ERROR_SIZE];
if (m_ssl_callback || m_credResolver || m_trustEngine) {
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,xml_ssl_ctx_callback);
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,this);
+
+ // Restore security "state". Necessary because the callback only runs
+ // when handshakes occur. Even new TCP connections won't execute it.
+ char* priv=NULL;
+ curl_easy_getinfo(m_handle,CURLINFO_PRIVATE,&priv);
+ if (priv)
+ m_secure=true;
}
else {
curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL);
string("CURLSOAPTransport::send() failed while contacting SOAP responder: ") +
(curl_errorbuf[0] ? curl_errorbuf : "no further information available"));
}
-
- return content_length;
}
// callback to buffer headers from server
// callback to buffer data from server
size_t xmltooling::curl_write_hook(void* ptr, size_t size, size_t nmemb, void* stream)
{
- pair<ostream*,size_t*>* output = reinterpret_cast<pair<ostream*,size_t*>*>(stream);
size_t len = size*nmemb;
- output->first->write(reinterpret_cast<const char*>(ptr),len);
- *(output->second) += len;
+ reinterpret_cast<stringstream*>(stream)->write(reinterpret_cast<const char*>(ptr),len);
return len;
}
return 0;
}
+#ifndef XMLTOOLING_NO_XMLSEC
int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg)
{
Category::getInstance("OpenSSL").debug("invoking X509 verify callback");
// Bypass name check (handled for us by curl).
if (!ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,ctx->m_peer,false,ctx->m_keyResolver)) {
x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics
- return 0;
+ ctx->setSecure(false);
+ return ctx->m_mandatory ? 0 : 1;
}
// Signal success. Hopefully it doesn't matter what's actually in the structure now.
+ ctx->setSecure(true);
return 1;
}
+#endif
// callback to invoke a caller-defined SSL callback
CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr)
{
CURLSOAPTransport* conf = reinterpret_cast<CURLSOAPTransport*>(userptr);
+
+#ifndef XMLTOOLING_NO_XMLSEC
if (conf->m_credResolver)
conf->m_credResolver->attach(ssl_ctx);
SSL_CTX_set_verify_depth(ssl_ctx,reinterpret_cast<int>(userptr));
#endif
}
+#endif
- if (!conf->m_ssl_callback(ssl_ctx,conf->m_ssl_userptr))
+ if (!conf->m_ssl_callback(conf, ssl_ctx, conf->m_ssl_userptr))
return CURLE_SSL_CERTPROBLEM;
return CURLE_OK;