1
/* $Id: data_service.c,v 1.14 2005/09/27 08:07:10 nclapies Exp $
3
* Lasso - A free implementation of the Liberty Alliance specifications.
5
* Copyright (C) 2004, 2005 Entr'ouvert
6
* http://lasso.entrouvert.org
8
* Authors: See AUTHORS file in top-level directory.
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include <libxml/xpath.h>
26
#include <libxml/xpathInternals.h>
28
#include <lasso/id-wsf/discovery.h>
29
#include <lasso/id-wsf/data_service.h>
30
#include <lasso/id-wsf/data_service_private.h>
31
#include <lasso/xml/dst_query.h>
32
#include <lasso/xml/dst_query_response.h>
33
#include <lasso/xml/dst_modify.h>
34
#include <lasso/xml/dst_modify_response.h>
35
#include <lasso/xml/soap_binding_correlation.h>
38
struct _LassoDataServicePrivate
40
gboolean dispose_has_run;
41
LassoDiscoResourceOffering *offering;
45
/*****************************************************************************/
47
/*****************************************************************************/
50
lasso_data_service_add_credential(LassoDataService *service,
51
LassoSamlAssertion *assertion)
53
service->private_data->credentials = g_list_append(
54
service->private_data->credentials,
55
g_object_ref(assertion));
59
lasso_data_service_add_modification(LassoDataService *service, const gchar *select)
61
LassoWsfProfile *profile;
62
LassoDstModification *modification;
64
g_return_val_if_fail(LASSO_IS_PROFILE_SERVICE(service), NULL);
65
g_return_val_if_fail(select != NULL, NULL);
67
profile = LASSO_WSF_PROFILE(service);
69
modification = lasso_dst_modification_new(select);
70
LASSO_DST_MODIFY(profile->request)->Modification = g_list_append(
71
LASSO_DST_MODIFY(profile->request)->Modification, (gpointer)modification);
78
* lasso_data_service_add_query_item:
79
* @service: a #LassoDataService
80
* @select: resource selection string (typically a XPath query)
81
* @item_id: query item identifier
83
* Adds a dst:QueryItem to the current dst:Query request.
85
* Return value: a newly created #LassoDstQueryItem with the query item that
86
* has been created. Note that it is internally allocated and shouldn't
87
* be freed by the caller.
90
lasso_data_service_add_query_item(LassoDataService *service,
91
const char *select, const char *item_id)
94
LassoDstQueryItem *item;
96
g_return_val_if_fail(LASSO_IS_PROFILE_SERVICE(service), NULL);
97
g_return_val_if_fail(select != NULL, NULL);
99
if (! LASSO_IS_DST_QUERY(LASSO_WSF_PROFILE(service)->request)) {
103
query = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request);
105
if (query->QueryItem && query->QueryItem->data &&
106
LASSO_DST_QUERY_ITEM(query->QueryItem->data)->itemID == NULL) {
107
/* XXX: all items must have itemID if there is more than one,
108
* perhaps we could generate an item id for those lacking it */
112
item = lasso_dst_query_item_new(select, item_id);
113
query->QueryItem = g_list_append(query->QueryItem, item);
119
* lasso_data_service_init_query
120
* @service: a #LassoDataService
121
* @select: resource selection string (typically a XPath query)
122
* @item_id: query item identifier (optional)
124
* Initializes a new dst:Query request, asking for element @select (with
125
* optional itemID set to @item_id). @item_id may be NULL only if the query
126
* won't contain other query items.
128
* If both @select and @item_id are NULL, only a skeleton request is created
129
* and calls to lasso_data_service_add_query_item() will need to be done.
131
* Return value: 0 on success; or a negative value otherwise.
134
lasso_data_service_init_query(LassoDataService *service, const char *select,
135
const char *item_id, const char *security_mech_id)
137
LassoWsfProfile *profile;
138
LassoDstQuery *query;
139
LassoDiscoResourceOffering *offering;
140
LassoDiscoDescription *description;
143
profile = LASSO_WSF_PROFILE(service);
146
query = lasso_dst_query_new(lasso_dst_query_item_new(select, item_id));
148
query = lasso_dst_query_new(NULL);
150
profile->request = LASSO_NODE(query);
152
offering = service->private_data->offering;
154
query->hrefServiceType = g_strdup(offering->ServiceInstance->ServiceType);
155
query->prefixServiceType = lasso_get_prefix_for_dst_service_href(
156
query->hrefServiceType);
157
if (query->prefixServiceType == NULL) {
158
return LASSO_ERROR_UNDEFINED;
161
if (offering->ResourceID) {
162
query->ResourceID = g_object_ref(offering->ResourceID);
163
} else if (offering->EncryptedResourceID) {
164
query->EncryptedResourceID = g_object_ref(offering->EncryptedResourceID);
166
/* XXX: no resource id, implied:resource, etc. */
167
return LASSO_ERROR_UNIMPLEMENTED;
170
profile->soap_envelope_request = lasso_wsf_profile_build_soap_envelope(
172
profile->soap_envelope_request->Body->any = g_list_append(
173
profile->soap_envelope_request->Body->any, query);
175
if (security_mech_id)
176
description = lasso_discovery_get_description_auto(
177
offering, security_mech_id);
179
description = lasso_discovery_get_description_auto(
180
offering, LASSO_SECURITY_MECH_NULL);
184
if (description->Endpoint != NULL) {
185
profile->msg_url = g_strdup(description->Endpoint);
187
/* XXX: else, description->WsdlURLI, get endpoint automatically */
188
return LASSO_ERROR_UNIMPLEMENTED;
191
/* Added needed credential for remote service */
192
if (description->CredentialRef) {
193
char *credentialRef = description->CredentialRef->data;
194
iter = service->private_data->credentials;
196
LassoSamlAssertion *credential = LASSO_SAML_ASSERTION(
198
if (strcmp(credentialRef, credential->AssertionID) == 0)
199
lasso_wsf_profile_add_saml_authentication(
200
LASSO_WSF_PROFILE(service), credential);
209
* lasso_data_service_process_query_msg:
210
* @service: a #LassoDataService
211
* @message: the dst query message
213
* Processes a dst:Query message. Rebuilds a request object from the message
214
* and extracts ResourceID.
216
* Return value: 0 on success; or a negative value otherwise.
219
lasso_data_service_process_query_msg(LassoDataService *service, const char *message,
220
const char *security_mech_id)
222
LassoDstQuery *query;
223
LassoWsfProfile *profile;
226
profile = LASSO_WSF_PROFILE(service);
227
rc = lasso_wsf_profile_process_soap_request_msg(profile, message, security_mech_id);
232
/* Verify needed credential */
233
if (lasso_security_mech_id_is_saml_authentication(security_mech_id) == TRUE) {
234
int res = lasso_wsf_profile_verify_saml_authentication(LASSO_WSF_PROFILE(service));
239
query = LASSO_DST_QUERY(profile->request);
240
if (query->ResourceID)
241
service->resource_id = g_object_ref(query->ResourceID);
242
else if (query->EncryptedResourceID)
243
service->encrypted_resource_id = g_object_ref(query->EncryptedResourceID);
245
return LASSO_ERROR_UNIMPLEMENTED; /* implied ? */
252
lasso_data_service_build_modify_response_msg(LassoDataService *service) {
253
LassoWsfProfile *profile;
254
LassoDstModify *request;
255
LassoDstModifyResponse *response;
259
xmlXPathContext *xpathCtx;
260
xmlXPathObject *xpathObj;
262
LassoSoapEnvelope *envelope;
264
profile = LASSO_WSF_PROFILE(service);
265
request = LASSO_DST_MODIFY(profile->request);
267
response = lasso_dst_modify_response_new(
268
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
269
profile->response = LASSO_NODE(response);
270
response->prefixServiceType = g_strdup(request->prefixServiceType);
271
response->hrefServiceType = g_strdup(request->hrefServiceType);
272
envelope = profile->soap_envelope_response;
273
envelope->Body->any = g_list_append(envelope->Body->any, response);
275
doc = xmlNewDoc((xmlChar*)"1.0");
276
xmlDocSetRootElement(doc, service->resource_data);
277
xpathCtx = xmlXPathNewContext(doc);
278
xmlXPathRegisterNs(xpathCtx, (xmlChar*)response->prefixServiceType,
279
(xmlChar*)response->hrefServiceType);
281
iter = request->Modification;
283
LassoDstModification *modification = iter->data;
284
xmlNode *newNode = modification->NewData->any->data;
285
xpathObj = xmlXPathEvalExpression((xmlChar*)modification->Select,
287
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
288
xmlNode *node = xpathObj->nodesetval->nodeTab[0];
289
xmlReplaceNode(node, newNode);
292
iter = g_list_next(iter);
295
return lasso_wsf_profile_build_soap_response_msg(profile);
299
* lasso_data_service_build_response_msg:
300
* @service: a #LassoDataService
302
* Builds a dst:QueryResponse message.
304
* Return value: 0 on success; or a negative value otherwise.
307
lasso_data_service_build_response_msg(LassoDataService *service)
309
LassoWsfProfile *profile;
310
LassoDstQuery *request;
311
LassoDstQueryResponse *response;
314
xmlXPathContext *xpathCtx;
315
xmlXPathObject *xpathObj;
316
LassoSoapEnvelope *envelope;
318
profile = LASSO_WSF_PROFILE(service);
319
request = LASSO_DST_QUERY(profile->request);
321
response = lasso_dst_query_response_new(
322
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
323
profile->response = LASSO_NODE(response);
324
response->prefixServiceType = g_strdup(request->prefixServiceType);
325
response->hrefServiceType = g_strdup(request->hrefServiceType);
326
envelope = profile->soap_envelope_response;
327
envelope->Body->any = g_list_append(envelope->Body->any, response);
329
doc = xmlNewDoc((xmlChar*)"1.0");
330
xmlDocSetRootElement(doc, service->resource_data);
331
xpathCtx = xmlXPathNewContext(doc);
332
xmlXPathRegisterNs(xpathCtx, (xmlChar*)response->prefixServiceType,
333
(xmlChar*)response->hrefServiceType);
335
/* XXX: needs another level, since there may be more than one <dst:Query> */
336
iter = request->QueryItem;
338
LassoDstQueryItem *item = iter->data;
339
xpathObj = xmlXPathEvalExpression((xmlChar*)item->Select, xpathCtx);
340
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
342
xmlNode *node = xpathObj->nodesetval->nodeTab[0];
343
/* XXX: assuming there is only one matching node */
344
data = lasso_dst_data_new();
345
data->any = g_list_append(data->any, xmlCopyNode(node, 1));
347
data->itemIDRef = g_strdup(item->itemID);
349
response->Data = g_list_append(response->Data, data);
351
iter = g_list_next(iter);
354
xmlUnlinkNode(service->resource_data);
357
return lasso_wsf_profile_build_soap_response_msg(profile);
361
* lasso_data_service_get_answer:
362
* @service: a #LassoDataService
363
* @select: resource selection string (typically a XPath query)
365
* Returns the answer for the specified @select request.
367
* Return value: the node (libxml2 xmlNode*); or NULL if it was not found.
368
* This xmlnode must be freed by caller.
371
lasso_data_service_get_answer(LassoDataService *service, const char *select)
373
LassoDstQueryResponse *response;
374
LassoDstData *data = NULL;
376
char *item_id = NULL;
378
response = LASSO_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response);
379
iter = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request)->QueryItem;
381
if (select == NULL) {
382
/* if only one element; default to first */
383
if (g_list_length(iter) > 1)
385
if (response->Data == NULL)
387
data = response->Data->data;
389
LassoDstQueryItem *item = NULL;
390
/* lookup select in query to get itemId, then get data with itemIdRef */
391
/* XXX: needs another level, since there may be more than one dst:Query */
394
iter = g_list_next(iter);
395
if (strcmp(item->Select, select) == 0) {
401
iter = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request)->QueryItem;
406
item_id = item->itemID;
407
if (item_id == NULL) {
408
/* item_id is not mandatory when there is only one item */
409
if (response->Data == NULL)
411
data = response->Data->data;
414
iter = response->Data;
415
while (iter && item_id) {
416
LassoDstData *t = iter->data;
417
iter = g_list_next(iter);
418
if (strcmp(t->itemIDRef, item_id) == 0) {
429
/* XXX: there may be more than one xmlnode */
430
return xmlCopyNode(data->any->data, 1);
434
* lasso_data_service_get_answer_for_item_id:
435
* @service: a #LassoDataService
436
* @item_id: query item identifier
438
* Returns the answer for the specified @item_id query item.
440
* Return value: the node (libxml2 xmlNode*); or NULL if it was not found.
441
* This xmlnode must be freed by caller.
444
lasso_data_service_get_answer_for_item_id(LassoDataService *service, const char *item_id)
446
LassoDstQueryResponse *response;
447
LassoDstData *data = NULL;
450
response = LASSO_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response);
451
iter = LASSO_DST_QUERY(LASSO_WSF_PROFILE(service)->request)->QueryItem;
453
iter = response->Data;
454
while (iter && item_id) {
455
LassoDstData *t = iter->data;
456
iter = g_list_next(iter);
457
if (strcmp(t->itemIDRef, item_id) == 0) {
467
/* XXX: there may be more than one xmlnode */
468
return xmlCopyNode(data->any->data, 1);
473
* lasso_data_service_process_query_response_msg:
474
* @service: a #LassoDataService
475
* @message: the dst query response message
477
* Processes a dst:Query message. Rebuilds a request object from the message
478
* and extracts ResourcedID.
480
* Return value: 0 on success; or a negative value otherwise.
483
lasso_data_service_process_query_response_msg(LassoDataService *service,
487
LassoDstQueryResponse *response;
489
rc = lasso_wsf_profile_process_soap_response_msg(LASSO_WSF_PROFILE(service), message);
492
if (! LASSO_IS_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response))
493
return LASSO_ERROR_UNDEFINED;
495
response = LASSO_DST_QUERY_RESPONSE(LASSO_WSF_PROFILE(service)->response);
496
if (response->Status == NULL || strcmp(response->Status->code, "OK") != 0)
497
return LASSO_ERROR_UNDEFINED;
504
lasso_data_service_init_modify(LassoDataService *service, const gchar *select,
507
LassoDstModification *modification;
508
LassoDstNewData *newData;
509
LassoDiscoResourceOffering *offering;
510
LassoDiscoDescription *description;
511
LassoWsfProfile *profile;
513
LassoSoapEnvelope *envelope;
514
LassoDstModify *modify;
517
profile = LASSO_WSF_PROFILE(service);
520
modification = lasso_dst_modification_new(select);
521
newData = lasso_dst_new_data_new();
522
newData->any = g_list_append(newData->any, xmlData);
523
modification->NewData = newData;
525
modify = lasso_dst_modify_new(modification);
526
profile->request = LASSO_NODE(modify);
528
offering = service->private_data->offering;
530
modify->hrefServiceType = g_strdup(offering->ServiceInstance->ServiceType);
531
modify->prefixServiceType = lasso_get_prefix_for_dst_service_href(
532
modify->hrefServiceType);
533
if (modify->prefixServiceType == NULL) {
534
return LASSO_ERROR_UNDEFINED;
537
/* get ResourceID / EncryptedResourceID */
538
if (offering->ResourceID) {
539
modify->ResourceID = offering->ResourceID;
541
else if (offering->EncryptedResourceID) {
542
modify->EncryptedResourceID = offering->EncryptedResourceID;
545
/* XXX: no resource id, implied:resource, etc. */
546
return LASSO_ERROR_UNIMPLEMENTED;
549
envelope = lasso_wsf_profile_build_soap_envelope(NULL, NULL);
550
LASSO_WSF_PROFILE(service)->soap_envelope_request = envelope;
551
envelope->Body->any = g_list_append(envelope->Body->any, modify);
554
/* TODO : implement WSDLRef */
555
if (description->Endpoint) {
556
profile->msg_url = g_strdup(description->Endpoint);
564
lasso_data_service_process_modify_msg(LassoDataService *service,
565
const gchar *modify_soap_msg, const gchar *security_mech_id)
567
LassoDstModify *modify;
568
LassoWsfProfile *profile;
571
profile = LASSO_WSF_PROFILE(service);
572
rc = lasso_wsf_profile_process_soap_request_msg(profile, modify_soap_msg, security_mech_id);
577
modify = LASSO_DST_MODIFY(profile->request);
578
if (modify->ResourceID)
579
service->resource_id = g_object_ref(modify->ResourceID);
580
else if (modify->EncryptedResourceID)
581
service->encrypted_resource_id = g_object_ref(modify->EncryptedResourceID);
583
return LASSO_ERROR_UNIMPLEMENTED; /* implied ? */
589
lasso_data_service_process_modify_response_msg(LassoDataService *service, const gchar *soap_msg)
591
LassoDstModifyResponse *response;
592
LassoSoapEnvelope *envelope;
594
g_return_val_if_fail(LASSO_IS_PROFILE_SERVICE(service), -1);
595
g_return_val_if_fail(soap_msg != NULL, -1);
597
envelope = LASSO_SOAP_ENVELOPE(lasso_node_new_from_dump(soap_msg));
598
LASSO_WSF_PROFILE(service)->soap_envelope_response = envelope;
600
response = envelope->Body->any->data;
601
LASSO_WSF_PROFILE(service)->response = LASSO_NODE(response);
607
/*****************************************************************************/
608
/* private methods */
609
/*****************************************************************************/
611
static LassoNodeClass *parent_class = NULL;
614
lasso_data_service_set_offering(LassoDataService *service,
615
LassoDiscoResourceOffering *offering)
617
service->private_data->offering = g_object_ref(offering);
620
/*****************************************************************************/
621
/* overrided parent class methods */
622
/*****************************************************************************/
625
dispose(GObject *object)
627
LassoDataService *service = LASSO_DATA_SERVICE(object);
629
if (service->private_data->dispose_has_run == TRUE)
631
service->private_data->dispose_has_run = TRUE;
633
G_OBJECT_CLASS(parent_class)->dispose(object);
637
finalize(GObject *object)
639
LassoDataService *service = LASSO_DATA_SERVICE(object);
640
if (service->private_data->offering) {
641
lasso_node_destroy(LASSO_NODE(service->private_data->offering));
642
service->private_data->offering = NULL;
644
g_free(service->private_data);
645
service->private_data = NULL;
646
G_OBJECT_CLASS(parent_class)->finalize(object);
650
/*****************************************************************************/
651
/* instance and class init functions */
652
/*****************************************************************************/
655
instance_init(LassoDataService *service)
657
service->resource_data = NULL;
658
service->private_data = g_new0(LassoDataServicePrivate, 1);
662
class_init(LassoDataServiceClass *klass)
664
parent_class = g_type_class_peek_parent(klass);
666
G_OBJECT_CLASS(klass)->dispose = dispose;
667
G_OBJECT_CLASS(klass)->finalize = finalize;
671
lasso_data_service_get_type()
673
static GType this_type = 0;
676
static const GTypeInfo this_info = {
677
sizeof(LassoDataServiceClass),
680
(GClassInitFunc) class_init,
683
sizeof(LassoDataService),
685
(GInstanceInitFunc) instance_init,
688
this_type = g_type_register_static(LASSO_TYPE_WSF_PROFILE,
689
"LassoDataService", &this_info, 0);
696
* lasso_data_service_new:
697
* @server: the #LassoServer
699
* Creates a new #LassoDataService.
701
* Return value: a newly created #LassoDataService object; or NULL if an
705
lasso_data_service_new(LassoServer *server)
707
LassoDataService *service;
709
g_return_val_if_fail(LASSO_IS_SERVER(server) == TRUE, NULL);
711
service = g_object_new(LASSO_TYPE_PROFILE_SERVICE, NULL);
712
LASSO_WSF_PROFILE(service)->server = g_object_ref(server);
718
lasso_data_service_new_full(LassoServer *server, LassoDiscoResourceOffering *offering)
720
LassoDataService *service;
722
service = lasso_data_service_new(server);
726
service->private_data->offering = g_object_ref(offering);