blob: 0dfe4d632176789a0968c445fa18f036c3513c75 [file] [log] [blame]
//----------------------------------------------------------------------------
//
// Copyright (C) Intel Corporation, 2007.
// (C) Red Hat, Inc, 2015.
//
// File: OpenWsmanClient.cpp
//
// Contents: An implementation of the WsmanClient interface using openwsman
//
//----------------------------------------------------------------------------
#include "OpenWsmanClient.h"
extern "C" {
#include "u/libu.h"
#include "wsman-api.h"
}
#include "wsman-client-transport.h"
#define WSMAN_ENCODING "UTF-8"
using namespace WsmanClientNamespace;
static bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc);
static bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes);
static string XmlDocToString(WsXmlDocH& doc);
static client_opt_t *SetOptions(WsManClient* cl);
static string GetSubscribeContext(WsXmlDocH& doc);
static string ExtractPayload(WsXmlDocH& doc);
static string ExtractItems(WsXmlDocH& doc);
// Construct from params.
OpenWsmanClient::OpenWsmanClient(
const string &host,
const int port,
const string &path,
const string &scheme,
const string &auth_method,
const string &username,
const string &password,
// proxy address include proxy port
const string &proxy,
//proxy user name
const string &proxy_username,
//proxy password
const string &proxy_password
#ifdef _WIN32
// determines which cert store to search
,const bool local,
// search for a client cert with this name
const string &cert,
// search for a cient cert with this oid
const string &oid
#endif
)
{
cl = wsmc_create(
host.c_str(),
port,
path.c_str(),
scheme.c_str(),
username.c_str(),
password.c_str());
SetAuth(auth_method);
#ifdef _WIN32
SetClientCert(oid, cert, local);
#endif
SetProxy(proxy.c_str(), proxy_username, proxy_password);
wsmc_transport_init(cl, (void*)NULL);
}
// Destructor.
OpenWsmanClient::~OpenWsmanClient()
{
wsmc_transport_fini(cl);
wsmc_release(cl);
}
string OpenWsmanClient::Identify() const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
WsXmlDocH identifyResponse = wsmc_action_identify(cl, options);
CheckWsmanResponse(cl, identifyResponse);
string xml = ExtractPayload(identifyResponse);
ws_xml_destroy_doc(identifyResponse);
return xml;
}
string OpenWsmanClient::Create(const string &resourceUri, const string &data) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
WsXmlDocH createResponse = wsmc_action_create_fromtext(cl,
resourceUri.c_str(),
options,
data.c_str(), data.length(), WSMAN_ENCODING);
CheckWsmanResponse(cl, createResponse);
string xml = ExtractPayload(createResponse);
ws_xml_destroy_doc(createResponse);
return xml;
}
void OpenWsmanClient::Delete(const string &resourceUri, const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
WsXmlDocH deleteResponse = wsmc_action_delete(cl,
resourceUri.c_str(),
options);
CheckWsmanResponse(cl, deleteResponse);
ws_xml_destroy_doc(deleteResponse);
}
void OpenWsmanClient::Enumerate(
const string &resourceUri,
vector<string> &enumRes,
const WsmanOptions &options,
const WsmanFilter &filter) const
{
WsXmlDocH doc;
char *enumContext;
WsXmlDocH enum_response = wsmc_action_enumerate(cl, (char *)resourceUri.c_str(), options, filter);
if(ResourceNotFound(cl, enum_response))
throw WsmanResourceNotFound(resourceUri.c_str());
enumContext = wsmc_get_enum_context(enum_response);
ws_xml_destroy_doc(enum_response);
while (enumContext != NULL && enumContext[0] != 0 ) {
doc = wsmc_action_pull(cl, resourceUri.c_str(), options, NULL, enumContext);
CheckWsmanResponse(cl, doc);
string payload = ExtractItems(doc);
if (payload.length() > 0)
enumRes.push_back(payload);
wsmc_free_enum_context(enumContext);
enumContext = wsmc_get_enum_context(doc);
ws_xml_destroy_doc(doc);
}
wsmc_free_enum_context(enumContext);
}
void OpenWsmanClient::Enumerate(
const string &resourceUri,
vector<string> &enumRes,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
Enumerate(resourceUri, enumRes, options, WsmanFilter());
}
void OpenWsmanClient::Enumerate(
const string &resourceUri,
WsmanFilter &filter,
vector<string> &enumRes) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
Enumerate(resourceUri, enumRes, options, filter);
}
string OpenWsmanClient::Get(
const string &resourceUri,
const WsmanOptions &options) const
{
WsXmlDocH doc = wsmc_action_get(cl, (char *)resourceUri.c_str(), options);
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
ws_xml_destroy_doc(doc);
return xml;
}
string OpenWsmanClient::Get(
const string &resourceUri,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
return Get(resourceUri, options);
}
string OpenWsmanClient::Put(
const string &resourceUri,
const string &content,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
WsXmlDocH doc = wsmc_action_put_fromtext(
cl,
resourceUri.c_str(),
options,
content.c_str(),
content.length(),
WSMAN_ENCODING);
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
ws_xml_destroy_doc(doc);
return xml;
}
string OpenWsmanClient::Invoke(
const string &resourceUri,
const string &methodName,
const WsmanOptions &options) const
{
WsXmlDocH doc = wsmc_action_invoke(
cl,
resourceUri.c_str(),
options,
methodName.c_str(),
NULL);
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
ws_xml_destroy_doc(doc);
return xml;
}
string OpenWsmanClient::Invoke(
const string &resourceUri,
const string &methodName,
const string &content,
const WsmanOptions &options) const
{
WsXmlDocH doc = wsmc_action_invoke_fromtext(
cl,
resourceUri.c_str(),
options,
const_cast<char*>(methodName.c_str()),
content.c_str(),
content.length(),
WSMAN_ENCODING);
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
ws_xml_destroy_doc(doc);
return xml;
}
string OpenWsmanClient::Invoke(
const string &resourceUri,
const string &methodName,
const string &content,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
return Invoke(resourceUri, methodName, content, options);
}
string OpenWsmanClient::Subscribe(
const string &resourceUri,
const SubscribeInfo &info,
string &subsContext) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.setDeliveryMode(static_cast<WsmanDeliveryMode>(info.delivery_mode));
options.setDeliveryURI(info.delivery_uri);
if (!info.refenceParam.empty())
options.setReference(info.refenceParam);
// Add selectors.
options.addSelectors(info.selectorset);
options.setExpires(info.expires);
options.setHeartbeatInterval(info.heartbeat_interval);
WsXmlDocH doc = wsmc_action_subscribe(cl, (char *)resourceUri.c_str(), options, NULL);
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
subsContext = GetSubscribeContext(doc);
ws_xml_destroy_doc(doc);
return xml;
}
string OpenWsmanClient::Renew(
const string &resourceUri,
const string &subsContext,
float expire,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.setExpires(expire);
options.addSelectors(s);
WsXmlDocH doc = wsmc_action_renew(
cl,
resourceUri.c_str(),
options,
subsContext.c_str());
CheckWsmanResponse(cl, doc);
string xml = ExtractPayload(doc);
ws_xml_destroy_doc(doc);
return xml;
}
void OpenWsmanClient::Unsubscribe(
const string &resourceUri,
const string &subsContext,
const NameValuePairs *s) const
{
WsmanOptions options;
options.setNamespace(GetNamespace());
options.addSelectors(s);
WsXmlDocH doc = wsmc_action_unsubscribe(
cl,
resourceUri.c_str(),
options,
subsContext.c_str());
CheckWsmanResponse(cl, doc);
ws_xml_destroy_doc(doc);
return;
}
string GetSubscribeContext(WsXmlDocH& doc)
{
string str;
char *buf = NULL;
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc);
WsXmlNodeH tmp = NULL;
if(bodyNode == NULL) return str;
bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE_RESP);
if(bodyNode == NULL) return str;
bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIPTION_MANAGER);
if(bodyNode == NULL) return str;
tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS);
if(tmp == NULL) {
tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES);
if(tmp == NULL) return str;
}
wsmc_node_to_buf(tmp, &buf);
str = string(buf);
u_free(buf);
return str;
}
string ExtractPayload(WsXmlDocH& doc)
{
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc);
WsXmlNodeH payloadNode = ws_xml_get_child(bodyNode, 0, NULL, NULL);
char *buf = NULL;
wsmc_node_to_buf( payloadNode, &buf);
string payload = string(buf);
u_free(buf);
return payload;
}
string ExtractItems(WsXmlDocH& doc)
{
string payload;
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc);
WsXmlNodeH pullResponse = ws_xml_get_child(bodyNode, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP);
WsXmlNodeH itemsNode = ws_xml_get_child(pullResponse, 0, XML_NS_ENUMERATION, WSENUM_ITEMS);
WsXmlNodeH n = ws_xml_get_child(itemsNode, 0 , NULL, NULL );
if (n) {
char *buf = NULL;
wsmc_node_to_buf( n, &buf);
payload = string(buf);
u_free(buf);
}
return payload;
}
string XmlDocToString(WsXmlDocH& doc) {
char *buf;
int len;
ws_xml_dump_memory_enc(doc, &buf, &len, WSMAN_ENCODING);
string str = string(buf); // This constructor copies the data.
if (buf)
#ifdef _WIN32
ws_xml_free_memory(buf);
#else
u_free(buf);
#endif
return str;
}
bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc)
{
long lastError = wsmc_get_last_error(cl);
string error;
if(lastError) {
char tmp[10];
error = "Failed to establish a connection with the server.\n";
sprintf(tmp, "%ld", lastError);
error.append("Openwsman last error = ").append(tmp);
ws_xml_destroy_doc(doc);
throw WsmanClientException(error.c_str(), WSMAN_CONNECT_ERROR);
}
long responseCode = wsmc_get_response_code(cl);
if (responseCode != 200 &&
responseCode != 400 &&
responseCode != 500)
{
char tmp[10];
error = "An HTTP error occurred.\n";
sprintf(tmp, "%ld", responseCode);
error.append("HTTP Error = ").append(tmp);
ws_xml_destroy_doc(doc);
throw WsmanClientException(error.c_str(), WSMAN_HTTP_ERROR);
}
if(!doc)
throw WsmanClientException("The Wsman response was NULL.");
if (wsmc_check_for_fault(doc)) {
char tmp[10];
WsManFault *fault = wsmc_fault_new();
wsmc_get_fault_data(doc, fault);
string subcode_s = fault->subcode ? string(fault->subcode) : "";
string code_s = fault->code ? string(fault->code) : "";
string reason_s = fault->reason ? string(fault->reason) : "";
string detail_s = fault->fault_detail ? string(fault->fault_detail) : "";
ws_xml_destroy_doc(doc);
wsmc_fault_destroy(fault);
error = "A Soap Fault was received:";
error.append("\nFaultCode: " + code_s);
error.append("\nFaultSubCode: " + subcode_s);
error.append("\nFaultReason: " + reason_s);
error.append("\nFaultDetail: " + detail_s);
sprintf(tmp, "%ld", responseCode);
error.append("\nHttpCode: = ").append(tmp);
throw WsmanSoapFault(error.c_str(), code_s, subcode_s, reason_s, detail_s);
}
return true;
}
bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes)
{
long responseCode = wsmc_get_response_code(cl);
if(wsmc_get_last_error(cl) ||
(responseCode != 200 && responseCode != 400 && responseCode != 500) ||
!enumerationRes)
{
CheckWsmanResponse(cl, enumerationRes);
}
if (!wsmc_check_for_fault(enumerationRes))
return false;
WsManFault *fault = wsmc_fault_new();
bool ret = false;
wsmc_get_fault_data(enumerationRes, fault);
string subcode_s = fault->subcode ? string(fault->subcode) : "";
if(subcode_s.find("DestinationUnreachable") != string::npos) {
wsmc_fault_destroy(fault);
return true;
}
wsmc_fault_destroy(fault);
if(!ret)
CheckWsmanResponse(cl, enumerationRes);
return ret;
}
void OpenWsmanClient::SetAuth(const string &auth_method)
{
if (auth_method.empty())
return;
wsman_transport_set_auth_method(cl, auth_method.c_str());
if (wsmc_transport_get_auth_value(cl) == WS_MAX_AUTH ) {
// Authentication method not supported, reverting to digest
wsman_transport_set_auth_method(cl, "digest");
}
}
void OpenWsmanClient::SetTimeout(unsigned long mtime)
{
wsman_transport_set_timeout(cl,mtime);
}
void OpenWsmanClient::SetUserName(const string &user_name)
{
if (user_name.empty())
return;
wsman_transport_set_userName(cl, user_name.c_str());
}
void OpenWsmanClient::SetPassword(const string &password)
{
if (password.empty())
return;
wsman_transport_set_password(cl, password.c_str());
}
void OpenWsmanClient::SetEncoding(const string &encoding)
{
if (encoding.empty())
return;
wsmc_set_encoding(cl, encoding.c_str());
}
void OpenWsmanClient::SetNamespace(const string &ns)
{
if (ns.empty())
return;
wsmc_set_namespace(cl, ns.c_str());
}
void OpenWsmanClient::SetProxy(
const string &proxy,
const string &proxy_username,
const string &proxy_password)
{
if (!proxy.empty())
wsman_transport_set_proxy(cl, proxy.c_str());
if (!proxy_username.empty())
wsman_transport_set_proxy_username(cl, proxy_username.c_str());
if (!proxy_password.empty())
wsman_transport_set_proxy_password(cl, proxy_password.c_str());
}
#ifdef _WIN32
void OpenWsmanClient::SetClientCert(
const string &caOid,
const string &caName,
const bool localCert)
{
if (!caOid.empty())
wsman_transport_set_caoid(cl, caOid.c_str());
if (!caName.empty())
wsman_transport_set_cainfo(cl, caName.c_str());
wsman_transport_set_calocal(cl, localCert);
}
#else
// Set server certificate params
// params: cainfo - string naming a file holding one or more certificates to verify the peer with.
// capath - string naming a dierctory holding multiple CA certificates to verify the peer with.
// Give empty strings if you want curl to search for certificates inthe default path
void OpenWsmanClient::SetServerCert(
const string &cainfo,
const string &capath)
{
// This means curl verifies the server certificate
wsman_transport_set_verify_peer(cl, 1);
// This means the certificate must indicate that the server is the server to which you meant to connect.
wsman_transport_set_verify_host(cl, 2);
if (!cainfo.empty())
wsman_transport_set_cainfo(cl, cainfo.c_str());
if (!capath.empty())
wsman_transport_set_capath(cl, capath.c_str());
}
// Set client certificates params
// params: cert - file name of your certificate.
// key - file name of your private key.
void OpenWsmanClient::SetClientCert(
const string &cert,
const string &key)
{
if (!cert.empty())
wsman_transport_set_cert(cl, cert.c_str());
if (!key.empty())
wsman_transport_set_key(cl, key.c_str());
}
#endif
string OpenWsmanClient::GetNamespace() const
{
char *ns = wsmc_get_namespace(cl);
return ns ? string(ns) : string();
}