1047 lines
30 KiB
C
1047 lines
30 KiB
C
/* $Id$
|
|
*
|
|
* Lasso - A free implementation of the Liberty Alliance specifications.
|
|
*
|
|
* Copyright (C) 2004-2007 Entr'ouvert
|
|
* http://lasso.entrouvert.org
|
|
*
|
|
* Authors: See AUTHORS file in top-level directory.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/**
|
|
* SECTION:data_service
|
|
* @short_description: ID-WSF Data Service Profile
|
|
*
|
|
* Following up on #LassoDiscovery first example, it created a @service object,
|
|
* this is a #LassoDataService instance. This example continues from that step
|
|
* and retrieves the name of the principal:
|
|
*
|
|
* <informalexample>
|
|
* <programlisting>
|
|
* char *soap_answer; // SOAP answer from data service
|
|
* xmlNode *principal_name; // libxml2 xmlNode with the principal name
|
|
*
|
|
* service = lasso_discovery_get_service(discovery);
|
|
* lasso_data_service_init_query(service, "/pp:PP/pp:InformalName", NULL);
|
|
* lasso_data_service_build_request_msg(service);
|
|
*
|
|
* // service must perform SOAP call to LASSO_WSF_PROFILE(service)->msg_url
|
|
* // the SOAP message is LASSO_WSF_PROFILE(service)->msg_body. The answer
|
|
* // is stored in char* soap_answer;
|
|
*
|
|
* lasso_data_service_process_query_response_msg(service, soap_answer);
|
|
* principal_name = lasso_data_service_get_answer(service, "/pp:PP/pp:InformalName");
|
|
*
|
|
* // app should probably then use xmlNodeGetContent libxml2 function to get
|
|
* // access to node content.
|
|
* </programlisting>
|
|
* </informalexample>
|
|
*
|
|
*/
|
|
|
|
#include "../utils.h"
|
|
#include <libxml/xpath.h>
|
|
#include <libxml/xpathInternals.h>
|
|
|
|
#include <lasso/id-wsf/discovery.h>
|
|
#include <lasso/id-wsf/data_service.h>
|
|
#include <lasso/id-wsf/data_service_private.h>
|
|
#include <lasso/xml/dst_query.h>
|
|
#include <lasso/xml/dst_query_response.h>
|
|
#include <lasso/xml/dst_modify.h>
|
|
#include <lasso/xml/dst_modify_response.h>
|
|
#include <lasso/xml/soap_binding_correlation.h>
|
|
#include <lasso/xml/soap_fault.h>
|
|
#include <lasso/xml/is_redirect_request.h>
|
|
|
|
#include <xmlsec/xmltree.h>
|
|
#include <xmlsec/xmldsig.h>
|
|
#include <xmlsec/templates.h>
|
|
#include <xmlsec/crypto.h>
|
|
|
|
extern GHashTable *dst_services_by_prefix; /* cf xml/xml.c */
|
|
|
|
struct _LassoDataServicePrivate
|
|
{
|
|
gboolean dispose_has_run;
|
|
LassoDiscoResourceOffering *offering;
|
|
GList *credentials;
|
|
LassoSoapFault *fault;
|
|
};
|
|
|
|
static void lasso_register_idwsf_xpath_namespaces(xmlXPathContext *xpathCtx);
|
|
|
|
/*****************************************************************************/
|
|
/* public methods */
|
|
/*****************************************************************************/
|
|
|
|
gint
|
|
lasso_data_service_add_credential(LassoDataService *service,
|
|
LassoSamlAssertion *assertion)
|
|
{
|
|
service->private_data->credentials = g_list_append(
|
|
service->private_data->credentials,
|
|
g_object_ref(assertion));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_init_query
|
|
* @service: a #LassoDataService
|
|
* @select: resource selection string (typically a XPath query)
|
|
* @item_id: query item identifier (optional)
|
|
*
|
|
* Initializes a new dst:Query request, asking for element @select (with
|
|
* optional itemID set to @item_id). @item_id may be NULL only if the query
|
|
* won't contain other query items.
|
|
*
|
|
* If both @select and @item_id are NULL, only a skeleton request is created
|
|
* and calls to lasso_data_service_add_query_item() will need to be done.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_data_service_init_query(LassoDataService *service, const char *select,
|
|
const char *item_id, const char *security_mech_id)
|
|
{
|
|
LassoWsfProfile *profile;
|
|
LassoDstQuery *query;
|
|
LassoDiscoResourceOffering *offering;
|
|
LassoDiscoDescription *description;
|
|
GList *iter;
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
|
|
if (select) {
|
|
query = lasso_dst_query_new(lasso_dst_query_item_new(select, item_id));
|
|
} else {
|
|
query = lasso_dst_query_new(NULL);
|
|
}
|
|
profile->request = LASSO_NODE(query);
|
|
|
|
if (service == NULL || service->private_data == NULL
|
|
|| service->private_data->offering == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_RESOURCE_OFFERING;
|
|
}
|
|
offering = service->private_data->offering;
|
|
|
|
if (offering->ServiceInstance == NULL
|
|
|| offering->ServiceInstance->ServiceType == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_SERVICE_TYPE;
|
|
}
|
|
query->hrefServiceType = g_strdup(offering->ServiceInstance->ServiceType);
|
|
query->prefixServiceType = lasso_get_prefix_for_dst_service_href(
|
|
query->hrefServiceType);
|
|
if (query->prefixServiceType == NULL) {
|
|
return LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST;
|
|
}
|
|
|
|
if (offering->ResourceID) {
|
|
query->ResourceID = g_object_ref(offering->ResourceID);
|
|
} else if (offering->EncryptedResourceID) {
|
|
query->EncryptedResourceID = g_object_ref(offering->EncryptedResourceID);
|
|
} else {
|
|
/* XXX: no resource id, implied:resource, etc. */
|
|
return LASSO_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
lasso_wsf_profile_init_soap_request(LASSO_WSF_PROFILE(service), LASSO_NODE(query));
|
|
|
|
/* Set description */
|
|
if (security_mech_id == NULL) {
|
|
description = LASSO_DISCO_DESCRIPTION(offering->ServiceInstance->Description->data);
|
|
} else {
|
|
description = lasso_discovery_get_description_auto(offering, security_mech_id);
|
|
}
|
|
if (description == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_SERVICE_DESCRIPTION;
|
|
}
|
|
lasso_wsf_profile_set_description(LASSO_WSF_PROFILE(service), description);
|
|
|
|
/* Set msgUrl */
|
|
if (description->Endpoint != NULL) {
|
|
profile->msg_url = g_strdup(description->Endpoint);
|
|
} else {
|
|
/* XXX: else, description->WsdlURLI, get endpoint automatically */
|
|
return LASSO_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
/* Added needed credential for remote service */
|
|
if (description->CredentialRef) {
|
|
char *credentialRef = description->CredentialRef->data;
|
|
iter = service->private_data->credentials;
|
|
while (iter) {
|
|
LassoSamlAssertion *credential = LASSO_SAML_ASSERTION(iter->data);
|
|
if (strcmp(credentialRef, credential->AssertionID) == 0) {
|
|
/* lasso_wsf_profile_add_saml_authentication(
|
|
LASSO_WSF_PROFILE(service), credential); */
|
|
iter = iter->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_add_query_item:
|
|
* @service: a #LassoDataService
|
|
* @select: resource selection string (typically a XPath query)
|
|
* @item_id: query item identifier
|
|
*
|
|
* Adds a dst:QueryItem to the current dst:Query request.
|
|
*
|
|
* Return value: a newly created #LassoDstQueryItem with the query item that
|
|
* has been created. Note that it is internally allocated and shouldn't
|
|
* be freed by the caller.
|
|
**/
|
|
LassoDstQueryItem*
|
|
lasso_data_service_add_query_item(LassoDataService *service,
|
|
const char *select, const char *item_id)
|
|
{
|
|
LassoDstQuery *query;
|
|
LassoDstQueryItem *item;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DATA_SERVICE(service), NULL);
|
|
g_return_val_if_fail(select != NULL, NULL);
|
|
|
|
if (! LASSO_IS_DST_QUERY(LASSO_WSF_PROFILE(service)->request)) {
|
|
return NULL;
|
|
}
|
|
|
|
query = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request);
|
|
|
|
if (query->QueryItem && query->QueryItem->data &&
|
|
LASSO_DST_QUERY_ITEM(query->QueryItem->data)->itemID == NULL) {
|
|
/* XXX: all items must have itemID if there is more than one,
|
|
* perhaps we could generate an item id for those lacking it */
|
|
return NULL;
|
|
}
|
|
|
|
item = lasso_dst_query_item_new(select, item_id);
|
|
query->QueryItem = g_list_append(query->QueryItem, item);
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_process_query_msg:
|
|
* @service: a #LassoDataService
|
|
* @message: the dst query message
|
|
*
|
|
* Processes a dst:Query message. Rebuilds a request object from the message
|
|
* and extracts ResourceID.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_data_service_process_query_msg(LassoDataService *service, const char *message,
|
|
const char *security_mech_id)
|
|
{
|
|
LassoDstQuery *query;
|
|
LassoWsfProfile *profile;
|
|
int rc;
|
|
gchar *service_type;
|
|
GList *node_list;
|
|
LassoSoapEnvelope *envelope;
|
|
xmlDoc *doc;
|
|
xmlNode *xmlnode;
|
|
|
|
/* FIXME: another way to get the service type ? */
|
|
|
|
g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
|
|
doc = lasso_xml_parse_memory(message, strlen(message));
|
|
if (doc == NULL) {
|
|
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
|
|
}
|
|
|
|
xmlnode = xmlSecFindNode(xmlDocGetRootElement(doc), xmlSecNodeSignature,
|
|
xmlSecDSigNs);
|
|
if (xmlnode) {
|
|
xmlUnlinkNode(xmlnode);
|
|
xmlFreeNode(xmlnode);
|
|
xmlnode = NULL;
|
|
}
|
|
|
|
envelope = LASSO_SOAP_ENVELOPE(lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc)));
|
|
if (envelope->Body == NULL || envelope->Body->any == NULL
|
|
|| envelope->Body->any->data == NULL) {
|
|
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
|
|
}
|
|
query = LASSO_DST_QUERY(envelope->Body->any->data);
|
|
service_type = g_strdup(query->hrefServiceType);
|
|
xmlFreeDoc(doc);
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
rc = lasso_wsf_profile_process_soap_request_msg(profile, message, service_type,
|
|
security_mech_id);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
/* get provider id from soap:Header */
|
|
for (node_list = profile->soap_envelope_request->Header->Other;
|
|
node_list; node_list = g_list_next(node_list)) {
|
|
LassoNode *node = node_list->data;
|
|
if (LASSO_IS_SOAP_BINDING_PROVIDER(node)) {
|
|
if (service->provider_id)
|
|
g_free(service->provider_id);
|
|
service->provider_id = g_strdup(
|
|
LASSO_SOAP_BINDING_PROVIDER(node)->providerID);
|
|
}
|
|
}
|
|
|
|
if (query->ResourceID) {
|
|
service->resource_id = g_object_ref(query->ResourceID);
|
|
} else if (query->EncryptedResourceID) {
|
|
service->encrypted_resource_id = g_object_ref(query->EncryptedResourceID);
|
|
} else {
|
|
return LASSO_ERROR_UNIMPLEMENTED; /* implied ? */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_build_response_msg:
|
|
* @service: a #LassoDataService
|
|
*
|
|
* Builds a dst:QueryResponse message.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_data_service_build_response_msg(LassoDataService *service)
|
|
{
|
|
LassoWsfProfile *profile;
|
|
LassoDstQuery *request;
|
|
LassoDstQueryResponse *response;
|
|
GList *iter;
|
|
xmlDoc *doc;
|
|
xmlXPathContext *xpathCtx;
|
|
xmlXPathObject *xpathObj;
|
|
LassoSoapEnvelope *envelope;
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
request = LASSO_DST_QUERY(profile->request);
|
|
|
|
envelope = profile->soap_envelope_response;
|
|
|
|
if (service->private_data->fault != NULL) {
|
|
envelope->Body->any = g_list_append(
|
|
envelope->Body->any, service->private_data->fault);
|
|
return lasso_wsf_profile_build_soap_response_msg(profile);
|
|
}
|
|
|
|
response = lasso_dst_query_response_new(
|
|
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
|
|
profile->response = LASSO_NODE(response);
|
|
response->prefixServiceType = g_strdup(request->prefixServiceType);
|
|
response->hrefServiceType = g_strdup(request->hrefServiceType);
|
|
envelope->Body->any = g_list_append(envelope->Body->any, response);
|
|
|
|
doc = xmlNewDoc((xmlChar*)"1.0");
|
|
xmlDocSetRootElement(doc, service->resource_data);
|
|
xpathCtx = xmlXPathNewContext(doc);
|
|
lasso_register_idwsf_xpath_namespaces(xpathCtx);
|
|
|
|
/* XXX: needs another level, since there may be more than one <dst:Query> */
|
|
iter = request->QueryItem;
|
|
while (iter) {
|
|
LassoDstQueryItem *item = iter->data;
|
|
LassoDstData *data;
|
|
|
|
xpathObj = xmlXPathEvalExpression((xmlChar*)item->Select, xpathCtx);
|
|
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
|
|
xmlNode *node = xpathObj->nodesetval->nodeTab[0];
|
|
/* XXX: assuming there is only one matching node */
|
|
data = lasso_dst_data_new();
|
|
data->any = g_list_append(data->any, xmlCopyNode(node, 1));
|
|
} else if (xpathObj && xpathObj->type == XPATH_STRING) {
|
|
data = lasso_dst_data_new();
|
|
data->any = g_list_append(data->any,
|
|
xmlNewText(xpathObj->stringval));
|
|
} else {
|
|
/* no response was found, break here */
|
|
if (xpathObj) {
|
|
xmlXPathFreeObject(xpathObj);
|
|
}
|
|
break;
|
|
}
|
|
if (item->itemID) {
|
|
data->itemIDRef = g_strdup(item->itemID);
|
|
}
|
|
response->Data = g_list_append(response->Data, data);
|
|
xmlXPathFreeObject(xpathObj);
|
|
xpathObj = NULL;
|
|
iter = g_list_next(iter);
|
|
}
|
|
|
|
xmlUnlinkNode(service->resource_data);
|
|
xmlXPathFreeContext(xpathCtx);
|
|
xmlFreeDoc(doc);
|
|
|
|
return lasso_wsf_profile_build_soap_response_msg(profile);
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_get_answer:
|
|
* @service: a #LassoDataService
|
|
* @select: resource selection string (typically a XPath query)
|
|
*
|
|
* Returns the answer for the specified @select request.
|
|
*
|
|
* Return value: the node (libxml2 xmlNode*); or NULL if it was not found.
|
|
* This xmlnode must be freed by caller.
|
|
**/
|
|
xmlNode*
|
|
lasso_data_service_get_answer(LassoDataService *service, const char *select)
|
|
{
|
|
LassoDstQueryResponse *response;
|
|
LassoDstData *data = NULL;
|
|
GList *iter;
|
|
char *item_id = NULL;
|
|
|
|
response = LASSO_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response);
|
|
iter = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request)->QueryItem;
|
|
|
|
if (select == NULL) {
|
|
/* if only one element; default to first */
|
|
if (g_list_length(iter) > 1)
|
|
return NULL;
|
|
if (response->Data == NULL)
|
|
return NULL;
|
|
data = response->Data->data;
|
|
} else {
|
|
LassoDstQueryItem *item = NULL;
|
|
/* lookup select in query to get itemId, then get data with itemIdRef */
|
|
/* XXX: needs another level, since there may be more than one dst:Query */
|
|
while (iter) {
|
|
item = iter->data;
|
|
iter = g_list_next(iter);
|
|
if (strcmp(item->Select, select) == 0) {
|
|
break;
|
|
}
|
|
item = NULL;
|
|
}
|
|
|
|
iter = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request)->QueryItem;
|
|
if (item == NULL) {
|
|
/* not found */
|
|
return NULL;
|
|
}
|
|
item_id = item->itemID;
|
|
if (item_id == NULL) {
|
|
/* item_id is not mandatory when there is only one item */
|
|
if (response->Data == NULL)
|
|
return NULL;
|
|
data = response->Data->data;
|
|
}
|
|
|
|
iter = response->Data;
|
|
while (iter && item_id) {
|
|
LassoDstData *t = iter->data;
|
|
iter = g_list_next(iter);
|
|
if (strcmp(t->itemIDRef, item_id) == 0) {
|
|
data = t;
|
|
break;
|
|
}
|
|
}
|
|
if (data == NULL) {
|
|
/* not found */
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* XXX: there may be more than one xmlnode */
|
|
return xmlCopyNode(data->any->data, 1);
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_get_answer_for_item_id:
|
|
* @service: a #LassoDataService
|
|
* @item_id: query item identifier
|
|
*
|
|
* Returns the answer for the specified @item_id query item.
|
|
*
|
|
* Return value: the node (libxml2 xmlNode*); or NULL if it was not found.
|
|
* This xmlnode must be freed by caller.
|
|
**/
|
|
xmlNode*
|
|
lasso_data_service_get_answer_for_item_id(LassoDataService *service, const char *item_id)
|
|
{
|
|
LassoDstQueryResponse *response;
|
|
LassoDstData *data = NULL;
|
|
GList *iter;
|
|
|
|
response = LASSO_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response);
|
|
|
|
iter = response->Data;
|
|
while (iter && item_id) {
|
|
LassoDstData *t = iter->data;
|
|
iter = g_list_next(iter);
|
|
if (strcmp(t->itemIDRef, item_id) == 0) {
|
|
data = t;
|
|
break;
|
|
}
|
|
}
|
|
if (data == NULL) {
|
|
/* not found */
|
|
return NULL;
|
|
}
|
|
|
|
/* XXX: there may be more than one xmlnode */
|
|
return xmlCopyNode(data->any->data, 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* lasso_data_service_process_query_response_msg:
|
|
* @service: a #LassoDataService
|
|
* @message: the dst query response message
|
|
*
|
|
* Processes a dst:Query message. Rebuilds a request object from the message
|
|
* and extracts ResourcedID.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_data_service_process_query_response_msg(LassoDataService *service,
|
|
const char *message)
|
|
{
|
|
int rc;
|
|
LassoSoapFault *fault = NULL;
|
|
LassoIsRedirectRequest *redirect_request = NULL;
|
|
GList *iter;
|
|
|
|
rc = lasso_wsf_profile_process_soap_response_msg(LASSO_WSF_PROFILE(service), message);
|
|
if (rc) return rc;
|
|
|
|
/* Process Soap Faults response */
|
|
iter = LASSO_WSF_PROFILE(service)->soap_envelope_response->Body->any;
|
|
while (iter) {
|
|
if (LASSO_IS_SOAP_FAULT(iter->data) == TRUE) {
|
|
fault = LASSO_SOAP_FAULT(iter->data);
|
|
break;
|
|
}
|
|
iter = iter->next;
|
|
}
|
|
if (!fault)
|
|
return 0;
|
|
|
|
iter = fault->Detail->any;
|
|
while (iter) {
|
|
if (LASSO_IS_IS_REDIRECT_REQUEST(iter->data) == TRUE) {
|
|
redirect_request = LASSO_IS_REDIRECT_REQUEST(iter->data);
|
|
break;
|
|
}
|
|
iter = iter->next;
|
|
}
|
|
if (redirect_request)
|
|
return LASSO_SOAP_FAULT_REDIRECT_REQUEST;
|
|
|
|
return 0;
|
|
}
|
|
|
|
gint
|
|
lasso_data_service_need_redirect_user(LassoDataService *service, const char *redirectUrl)
|
|
{
|
|
LassoSoapDetail *detail;
|
|
|
|
/* Find a SOAP fault element */
|
|
service->private_data->fault = lasso_soap_fault_new();
|
|
service->private_data->fault->faultcode = g_strdup(LASSO_SOAP_FAULT_CODE_SERVER);
|
|
detail = lasso_soap_detail_new();
|
|
detail->any = g_list_append(detail->any, lasso_is_redirect_request_new(redirectUrl));
|
|
service->private_data->fault->Detail = detail;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_get_redirect_request_url:
|
|
* @service: a #LassoDataService
|
|
* @message: the dst query message
|
|
*
|
|
* Tells if Attribute Provider needs user interaction.
|
|
*
|
|
* Return value: TRUE if needed; or FALSE otherwise.
|
|
**/
|
|
gchar*
|
|
lasso_data_service_get_redirect_request_url(LassoDataService *service)
|
|
{
|
|
LassoSoapFault *fault = NULL;
|
|
LassoIsRedirectRequest *redirect_request = NULL;
|
|
GList *iter;
|
|
|
|
if (LASSO_WSF_PROFILE(service)->soap_envelope_response == NULL ||
|
|
LASSO_WSF_PROFILE(service)->soap_envelope_response->Body == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
iter = LASSO_WSF_PROFILE(service)->soap_envelope_response->Body->any;
|
|
while (iter) {
|
|
if (LASSO_IS_SOAP_FAULT(iter->data) == TRUE) {
|
|
fault = LASSO_SOAP_FAULT(iter->data);
|
|
break;
|
|
}
|
|
iter = iter->next;
|
|
}
|
|
if (fault == NULL || fault->Detail == NULL)
|
|
return NULL;
|
|
|
|
iter = fault->Detail->any;
|
|
while (iter) {
|
|
if (LASSO_IS_IS_REDIRECT_REQUEST(iter->data) == TRUE) {
|
|
redirect_request = LASSO_IS_REDIRECT_REQUEST(iter->data);
|
|
break;
|
|
}
|
|
iter = g_list_next(iter);
|
|
}
|
|
if (redirect_request == NULL)
|
|
return NULL;
|
|
|
|
return g_strdup(redirect_request->redirectURL);
|
|
}
|
|
|
|
gint
|
|
lasso_data_service_init_modify(LassoDataService *service, const gchar *select,
|
|
xmlNode *xmlData)
|
|
{
|
|
LassoDstModification *modification;
|
|
LassoDstNewData *newData;
|
|
LassoDiscoResourceOffering *offering;
|
|
LassoDiscoDescription *description;
|
|
LassoWsfProfile *profile;
|
|
LassoDstModify *modify;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DATA_SERVICE(service),
|
|
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(service != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
g_return_val_if_fail(xmlData != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
|
|
/* init Modify */
|
|
modification = lasso_dst_modification_new(select);
|
|
newData = lasso_dst_new_data_new();
|
|
newData->any = g_list_append(newData->any, xmlCopyNode(xmlData, 1));
|
|
modification->NewData = newData;
|
|
|
|
modify = lasso_dst_modify_new(modification);
|
|
profile->request = LASSO_NODE(modify);
|
|
|
|
if (service == NULL || service->private_data == NULL
|
|
|| service->private_data->offering == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_RESOURCE_OFFERING;
|
|
}
|
|
offering = service->private_data->offering;
|
|
|
|
if (offering->ServiceInstance == NULL
|
|
|| offering->ServiceInstance->ServiceType == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_SERVICE_TYPE;
|
|
}
|
|
modify->hrefServiceType = g_strdup(offering->ServiceInstance->ServiceType);
|
|
modify->prefixServiceType = lasso_get_prefix_for_dst_service_href(
|
|
modify->hrefServiceType);
|
|
if (modify->prefixServiceType == NULL) {
|
|
return LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST;
|
|
}
|
|
|
|
/* get ResourceID / EncryptedResourceID */
|
|
if (offering->ResourceID) {
|
|
modify->ResourceID = offering->ResourceID;
|
|
} else if (offering->EncryptedResourceID) {
|
|
modify->EncryptedResourceID = offering->EncryptedResourceID;
|
|
} else {
|
|
/* XXX: no resource id, implied:resource, etc. */
|
|
return LASSO_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
lasso_wsf_profile_init_soap_request(LASSO_WSF_PROFILE(service), LASSO_NODE(modify));
|
|
|
|
/* Set description */
|
|
if (offering->ServiceInstance != NULL && offering->ServiceInstance->Description != NULL) {
|
|
description = LASSO_DISCO_DESCRIPTION(offering->ServiceInstance->Description->data);
|
|
}
|
|
if (description == NULL) {
|
|
return LASSO_PROFILE_ERROR_MISSING_SERVICE_DESCRIPTION;
|
|
}
|
|
lasso_wsf_profile_set_description(LASSO_WSF_PROFILE(service), description);
|
|
|
|
/* Set msgUrl */
|
|
if (description->Endpoint != NULL) {
|
|
profile->msg_url = g_strdup(description->Endpoint);
|
|
} else {
|
|
/* XXX: else, description->WsdlURLI, get endpoint automatically */
|
|
return LASSO_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LassoDstModification*
|
|
lasso_data_service_add_modification(LassoDataService *service, const gchar *select)
|
|
{
|
|
LassoWsfProfile *profile;
|
|
LassoDstModification *modification;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DATA_SERVICE(service), NULL);
|
|
g_return_val_if_fail(select != NULL, NULL);
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
|
|
modification = lasso_dst_modification_new(select);
|
|
LASSO_DST_MODIFY(profile->request)->Modification = g_list_append(
|
|
LASSO_DST_MODIFY(profile->request)->Modification, (gpointer)modification);
|
|
|
|
return modification;
|
|
}
|
|
|
|
gint
|
|
lasso_data_service_build_modify_response_msg(LassoDataService *service)
|
|
{
|
|
LassoWsfProfile *profile;
|
|
LassoDstModify *request;
|
|
LassoDstModifyResponse *response;
|
|
LassoSoapEnvelope *envelope;
|
|
GList *iter;
|
|
xmlNode *cur_data;
|
|
xmlDoc *doc;
|
|
xmlXPathContext *xpathCtx;
|
|
xmlXPathObject *xpathObj;
|
|
int res = 0;
|
|
GList *node_to_free = NULL;
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
request = LASSO_DST_MODIFY(profile->request);
|
|
|
|
if (service->private_data->fault != NULL) {
|
|
envelope = profile->soap_envelope_response;
|
|
envelope->Body->any = g_list_append(
|
|
envelope->Body->any, service->private_data->fault);
|
|
return lasso_wsf_profile_build_soap_response_msg(profile);
|
|
}
|
|
|
|
if (service->resource_data == NULL) {
|
|
return LASSO_DST_ERROR_MISSING_SERVICE_DATA;
|
|
} else {
|
|
cur_data = xmlCopyNode(service->resource_data, 1);
|
|
}
|
|
|
|
response = lasso_dst_modify_response_new(
|
|
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
|
|
profile->response = LASSO_NODE(response);
|
|
response->prefixServiceType = g_strdup(request->prefixServiceType);
|
|
response->hrefServiceType = g_strdup(request->hrefServiceType);
|
|
envelope = profile->soap_envelope_response;
|
|
envelope->Body->any = g_list_append(envelope->Body->any, response);
|
|
|
|
doc = xmlNewDoc((xmlChar*)"1.0");
|
|
xmlDocSetRootElement(doc, cur_data);
|
|
xpathCtx = xmlXPathNewContext(doc);
|
|
lasso_register_idwsf_xpath_namespaces(xpathCtx);
|
|
|
|
for (iter = request->Modification; iter != NULL; iter = g_list_next(iter)) {
|
|
LassoDstModification *modification = iter->data;
|
|
xmlNode *newNode = modification->NewData->any->data;
|
|
xpathObj = xmlXPathEvalExpression((xmlChar*)modification->Select,
|
|
xpathCtx);
|
|
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
|
|
xmlNode *node = xpathObj->nodesetval->nodeTab[0];
|
|
if (node != NULL) {
|
|
/* If we must replace the root element, change it in the xmlDoc */
|
|
if (node == cur_data) {
|
|
xmlDocSetRootElement(doc, xmlCopyNode(newNode,1));
|
|
lasso_list_add(node_to_free, node);
|
|
cur_data = NULL;
|
|
} else {
|
|
xmlReplaceNode(node, xmlCopyNode(newNode,1));
|
|
/* Node is a free node now but is still reference by the xpath nodeset
|
|
we must wait for the deallocation of the nodeset to free it. */
|
|
lasso_list_add(node_to_free, node);
|
|
}
|
|
}
|
|
} else {
|
|
res = LASSO_DST_ERROR_MODIFY_FAILED;
|
|
}
|
|
xmlXPathFreeObject(xpathObj);
|
|
xpathObj = NULL;
|
|
}
|
|
|
|
if (res == 0 && doc->children != NULL) {
|
|
/* Save new service resource data */
|
|
xmlNode *root = xmlDocGetRootElement(doc);
|
|
xmlFreeNode(service->resource_data);
|
|
service->resource_data = xmlCopyNode(root,1);
|
|
}
|
|
|
|
xmlXPathFreeContext(xpathCtx);
|
|
g_list_foreach(node_to_free, (GFunc)xmlFreeNode, NULL);
|
|
xmlFreeDoc(doc);
|
|
lasso_release_list(node_to_free);
|
|
|
|
return lasso_wsf_profile_build_soap_response_msg(profile);
|
|
}
|
|
|
|
gint
|
|
lasso_data_service_process_modify_msg(LassoDataService *service,
|
|
const gchar *modify_soap_msg, const gchar *security_mech_id)
|
|
{
|
|
LassoDstModify *modify;
|
|
LassoWsfProfile *profile;
|
|
LassoSoapEnvelope *envelope;
|
|
xmlDoc *doc;
|
|
int rc;
|
|
gchar *service_type;
|
|
|
|
|
|
doc = lasso_xml_parse_memory(modify_soap_msg, strlen(modify_soap_msg));
|
|
if (doc == NULL) {
|
|
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
|
|
}
|
|
|
|
envelope = LASSO_SOAP_ENVELOPE(lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc)));
|
|
if (envelope->Body == NULL || envelope->Body->any == NULL
|
|
|| envelope->Body->any->data == NULL) {
|
|
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
|
|
}
|
|
|
|
modify = LASSO_DST_MODIFY(envelope->Body->any->data);
|
|
service_type = g_strdup(modify->hrefServiceType);
|
|
xmlFreeDoc(doc);
|
|
|
|
profile = LASSO_WSF_PROFILE(service);
|
|
rc = lasso_wsf_profile_process_soap_request_msg(profile, modify_soap_msg, service_type,
|
|
security_mech_id);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
if (modify->ResourceID) {
|
|
service->resource_id = g_object_ref(modify->ResourceID);
|
|
} else if (modify->EncryptedResourceID) {
|
|
service->encrypted_resource_id = g_object_ref(modify->EncryptedResourceID);
|
|
} else {
|
|
return LASSO_ERROR_UNIMPLEMENTED; /* implied ? */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_process_modify_response_msg
|
|
* @service: a #LassoDataService
|
|
* @soap_msg: the SOAP message
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_data_service_process_modify_response_msg(LassoDataService *service, const gchar *soap_msg)
|
|
{
|
|
LassoDstModifyResponse *response;
|
|
LassoSoapEnvelope *envelope;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DATA_SERVICE(service),
|
|
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(soap_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
|
|
envelope = LASSO_SOAP_ENVELOPE(lasso_node_new_from_dump(soap_msg));
|
|
if (envelope == NULL || ! envelope->Body || ! envelope->Body->any ||
|
|
! LASSO_IS_NODE(envelope->Body->any->data)) {
|
|
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
|
|
}
|
|
|
|
LASSO_WSF_PROFILE(service)->soap_envelope_response = envelope;
|
|
response = envelope->Body->any->data;
|
|
LASSO_WSF_PROFILE(service)->response = LASSO_NODE(response);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_data_service_get_resource_offering:
|
|
* @service: a #LassoDataService
|
|
*
|
|
* Gets the #LassoDiscoResourceOffering of the @service.
|
|
*
|
|
* Return value: the #LassoDiscoResourceOffering associated to service.
|
|
**/
|
|
LassoDiscoResourceOffering*
|
|
lasso_data_service_get_resource_offering(LassoDataService *service)
|
|
{
|
|
return g_object_ref(service->private_data->offering);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* private methods */
|
|
/*****************************************************************************/
|
|
|
|
static LassoNodeClass *parent_class = NULL;
|
|
|
|
void
|
|
lasso_data_service_set_offering(LassoDataService *service, LassoDiscoResourceOffering *offering)
|
|
{
|
|
service->private_data->offering = g_object_ref(offering);
|
|
if (offering->ResourceID != NULL) {
|
|
service->resource_id = g_object_ref(offering->ResourceID);
|
|
}
|
|
if (offering->EncryptedResourceID != NULL) {
|
|
service->encrypted_resource_id = g_object_ref(offering->EncryptedResourceID);
|
|
}
|
|
service->provider_id = g_strdup(offering->ServiceInstance->ProviderID);
|
|
service->abstract_description = g_strdup(offering->Abstract);
|
|
}
|
|
|
|
static void
|
|
register_xpath_namespace(gchar *prefix, gchar *href, xmlXPathContext *xpathCtx)
|
|
{
|
|
xmlXPathRegisterNs(xpathCtx, (xmlChar*)prefix, (xmlChar*)href);
|
|
}
|
|
|
|
static void
|
|
lasso_register_idwsf_xpath_namespaces(xmlXPathContext *xpathCtx)
|
|
{
|
|
xmlXPathRegisterNs(xpathCtx, (xmlChar*)LASSO_PP_PREFIX,
|
|
(xmlChar*)LASSO_PP_HREF);
|
|
xmlXPathRegisterNs(xpathCtx, (xmlChar*)LASSO_EP_PREFIX,
|
|
(xmlChar*)LASSO_EP_HREF);
|
|
if (dst_services_by_prefix == NULL)
|
|
return;
|
|
g_hash_table_foreach(dst_services_by_prefix,
|
|
(GHFunc)register_xpath_namespace, xpathCtx);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* overrided parent class methods */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
dispose(GObject *object)
|
|
{
|
|
LassoDataService *service = LASSO_DATA_SERVICE(object);
|
|
|
|
if (service->private_data->dispose_has_run == TRUE)
|
|
return;
|
|
g_free(service->provider_id);
|
|
service->provider_id = NULL;
|
|
service->private_data->dispose_has_run = TRUE;
|
|
|
|
G_OBJECT_CLASS(parent_class)->dispose(object);
|
|
}
|
|
|
|
static void
|
|
finalize(GObject *object)
|
|
{
|
|
LassoDataService *service = LASSO_DATA_SERVICE(object);
|
|
if (service->private_data->offering) {
|
|
lasso_node_destroy(LASSO_NODE(service->private_data->offering));
|
|
service->private_data->offering = NULL;
|
|
}
|
|
g_free(service->private_data);
|
|
service->private_data = NULL;
|
|
G_OBJECT_CLASS(parent_class)->finalize(object);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* instance and class init functions */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
instance_init(LassoDataService *service)
|
|
{
|
|
service->resource_data = NULL;
|
|
service->private_data = g_new0(LassoDataServicePrivate, 1);
|
|
service->private_data->fault = NULL;
|
|
}
|
|
|
|
static void
|
|
class_init(LassoDataServiceClass *klass)
|
|
{
|
|
parent_class = g_type_class_peek_parent(klass);
|
|
|
|
G_OBJECT_CLASS(klass)->dispose = dispose;
|
|
G_OBJECT_CLASS(klass)->finalize = finalize;
|
|
}
|
|
|
|
GType
|
|
lasso_data_service_get_type()
|
|
{
|
|
static GType this_type = 0;
|
|
|
|
if (!this_type) {
|
|
static const GTypeInfo this_info = {
|
|
sizeof(LassoDataServiceClass),
|
|
NULL,
|
|
NULL,
|
|
(GClassInitFunc) class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof(LassoDataService),
|
|
0,
|
|
(GInstanceInitFunc) instance_init,
|
|
};
|
|
|
|
this_type = g_type_register_static(LASSO_TYPE_WSF_PROFILE,
|
|
"LassoDataService", &this_info, 0);
|
|
}
|
|
return this_type;
|
|
}
|
|
|
|
|
|
/**
|
|
* lasso_data_service_new:
|
|
* @server: the #LassoServer
|
|
*
|
|
* Creates a new #LassoDataService.
|
|
*
|
|
* Return value: a newly created #LassoDataService object; or NULL if an
|
|
* error occured.
|
|
**/
|
|
LassoDataService*
|
|
lasso_data_service_new(LassoServer *server)
|
|
{
|
|
LassoDataService *service;
|
|
|
|
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
|
|
|
|
service = g_object_new(LASSO_TYPE_DATA_SERVICE, NULL);
|
|
LASSO_WSF_PROFILE(service)->server = g_object_ref(server);
|
|
|
|
return service;
|
|
}
|
|
|
|
LassoDataService*
|
|
lasso_data_service_new_full(LassoServer *server, LassoDiscoResourceOffering *offering)
|
|
{
|
|
LassoDataService *service = lasso_data_service_new(server);
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCO_RESOURCE_OFFERING(offering), NULL);
|
|
|
|
if (service == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
lasso_data_service_set_offering(LASSO_DATA_SERVICE(service), offering);
|
|
|
|
return service;
|
|
}
|