diff --git a/docs/reference/lasso/lasso-sections.txt b/docs/reference/lasso/lasso-sections.txt index 2ae1dcac..2ec30682 100644 --- a/docs/reference/lasso/lasso-sections.txt +++ b/docs/reference/lasso/lasso-sections.txt @@ -5784,6 +5784,7 @@ lasso_idwsf2_profile_process_soap_request_msg lasso_idwsf2_profile_build_response_msg lasso_idwsf2_profile_process_soap_response_msg lasso_idwsf2_profile_build_soap_envelope +lasso_idwsf2_profile_get_name_identifier LASSO_IDWSF2_PROFILE LASSO_IS_IDWSF2_PROFILE diff --git a/lasso/id-wsf-2.0/data_service.c b/lasso/id-wsf-2.0/data_service.c index d361eb7d..79c3146b 100644 --- a/lasso/id-wsf-2.0/data_service.c +++ b/lasso/id-wsf-2.0/data_service.c @@ -42,33 +42,105 @@ #include "../xml/id-wsf-2.0/dstref_query_response.h" #include "../xml/id-wsf-2.0/dstref_data.h" #include "../xml/id-wsf-2.0/util_status.h" +#include "../xml/id-wsf-2.0/util_response.h" #include "../xml/id-wsf-2.0/sb2_redirect_request.h" #include "../xml/id-wsf-2.0/dstref_modify.h" #include "../xml/id-wsf-2.0/dstref_modify_item.h" #include "../xml/id-wsf-2.0/dstref_modify_response.h" +#include "../xml/id-wsf-2.0/dstref_create.h" +#include "../xml/id-wsf-2.0/dstref_delete.h" #include "../xml/soap_fault.h" #include "../utils.h" #include "./private.h" +#include "./idwsf2_helper.h" +#include "./soap_binding.h" struct _LassoIdWsf2DataServicePrivate { gboolean dispose_has_run; - LassoWsAddrEndpointReference *epr; - GList *credentials; + GList *query_items; /* of LassoIdWsf2DstRefQueryItem */ + GList *query_datas; /* of LassoIdWsf2DstRefData */ + GList *modify_items; /* of LassoIdWsf2DstRefModifyItem */ + gchar *service_type; + gchar *service_type_prefix; + GHashTable *namespaces; }; extern GHashTable *idwsf2_dst_services_by_prefix; /* cf xml/xml.c */ -static void lasso_register_idwsf2_xpath_namespaces(xmlXPathContext *xpathCtx); +#define lasso_idwsf2_data_service_set_dst_service_type(dst_node, service_type, prefix) \ + lasso_assign_string(dst_node->hrefServiceType, service_type); \ + lasso_assign_string(dst_node->prefixServiceType, prefix); \ -static GList* duplicate_glist_of_xmlnodes(GList*); +static void +lasso_idwsf2_data_service_clean_private_data(LassoIdWsf2DataService *service) +{ + LassoIdWsf2DataServicePrivate *pdata = service->private_data; -static gint lasso_idwsf2_data_service_parse_one_modify_item(LassoIdWsf2DstRefModifyItem *item, - xmlDoc *cur_doc, xmlXPathContext *cur_xpathCtx, int *error_code_ptr); -/*****************************************************************************/ -/* public methods */ -/*****************************************************************************/ + lasso_release_string(pdata->service_type); + lasso_release_string(pdata->service_type_prefix); + lasso_release_list_of_gobjects(pdata->query_items); + lasso_release_list_of_gobjects(pdata->modify_items); +} + + +/** + * lasso_idwsf2_data_service_set_service_type: + * @service: a #LassoIdWsf2DataService object + * @prefix: a prefix to use in producing XML documents + * @service_type: the service type URI + * + * Fix a service type for this @service. + */ +gint +lasso_idwsf2_data_service_set_service_type(LassoIdWsf2DataService *service, const char *prefix, + const char *service_type) +{ + if (!LASSO_IS_IDWSF2_DATA_SERVICE(service) || lasso_is_empty_string(prefix) + || lasso_is_empty_string(service_type)) + return LASSO_PARAM_ERROR_INVALID_VALUE; + lasso_assign_string(service->private_data->service_type_prefix, prefix); + lasso_assign_string(service->private_data->service_type, service_type); + return 0; +} + +const char* +lasso_idwsf2_data_service_get_service_type(LassoIdWsf2DataService *service) +{ + if (! LASSO_IS_IDWSF2_DATA_SERVICE(service)) + return NULL; + return service->private_data->service_type; +} + +const char* +lasso_idwsf2_data_service_get_service_type_prefix(LassoIdWsf2DataService *service) +{ + if (! LASSO_IS_IDWSF2_DATA_SERVICE(service)) + return NULL; + return service->private_data->service_type_prefix; +} + +static gint +lasso_idwsf2_data_service_init_request(LassoIdWsf2DataService *service, + LassoNode *(*constructor)()) +{ + int rc = 0; + LassoNode *request; + LassoSoapEnvelope *envelope; + + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + lasso_release_list_of_gobjects(service->private_data->query_items); + lasso_release_list_of_gobjects(service->private_data->modify_items); + lasso_check_good_rc(lasso_idwsf2_profile_init_request(&service->parent)); + request = (LassoNode*)constructor(); + envelope = lasso_idwsf2_profile_get_soap_envelope_request(&service->parent); + lasso_assign_new_gobject(service->parent.parent.request, request); + lasso_soap_envelope_add_to_body(envelope, request); + +cleanup: + return rc; +} /** * lasso_idwsf2_data_service_init_query: @@ -81,582 +153,8 @@ static gint lasso_idwsf2_data_service_parse_one_modify_item(LassoIdWsf2DstRefMod gint lasso_idwsf2_data_service_init_query(LassoIdWsf2DataService *service) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQuery *query; - LassoWsAddrEndpointReference *epr; - GList *metadata_item; - GList *i; - gchar *service_type = NULL; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - query = lasso_idwsf2_dstref_query_new(); - - if (LASSO_PROFILE(profile)->request) { - lasso_node_destroy(LASSO_NODE(LASSO_PROFILE(profile)->request)); - } - lasso_assign_new_gobject(LASSO_PROFILE(profile)->request, LASSO_NODE(query)); - - if (service == NULL || service->private_data == NULL - || service->private_data->epr == NULL - || service->private_data->epr->Metadata == NULL) { - return LASSO_PROFILE_ERROR_MISSING_ENDPOINT_REFERENCE; - } - - epr = service->private_data->epr; - - /* Get the service type from the EPR */ - metadata_item = epr->Metadata->any; - for (i = g_list_first(metadata_item); i != NULL; i = g_list_next(i)) { - if (LASSO_IS_IDWSF2_DISCO_SERVICE_TYPE(i->data)) { - service_type = LASSO_IDWSF2_DISCO_SERVICE_TYPE(i->data)->content; - break; - } - } - - /* Set hrefServiceType and prefixServiceType in query in order to set the profile */ - /* namespace in the request */ - if (service_type != NULL) { - query->hrefServiceType = g_strdup(service_type); - query->prefixServiceType = lasso_get_prefix_for_idwsf2_dst_service_href( - query->hrefServiceType); - } - if (query->prefixServiceType == NULL) { - return LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST; - } - - lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(query), service_type); - - /* Set msg_url as epr address, which is the SoapEndpoint */ - if (epr->Address != NULL) { - lasso_assign_string(LASSO_PROFILE(profile)->msg_url, epr->Address->content); - } else { - return LASSO_PROFILE_ERROR_MISSING_ENDPOINT_REFERENCE_ADDRESS; - } - - return 0; -} - -/** - * lasso_idwsf2_data_service_add_query_item: - * @service: a #LassoIdWsf2DataService - * @item_xpath: XPATH of the queried item - * @item_id: identifier of the queried item, which will allow to retrieve it in the response - * - * Add an item in the query request. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_data_service_add_query_item(LassoIdWsf2DataService *service, const gchar *item_xpath, - const gchar *item_id) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQuery *query; - LassoIdWsf2DstRefQueryItem *item; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(item_xpath != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(item_id != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - if (! LASSO_IS_IDWSF2_DSTREF_QUERY(LASSO_PROFILE(profile)->request)) { - return LASSO_PROFILE_ERROR_MISSING_REQUEST; - } - - query = LASSO_IDWSF2_DSTREF_QUERY(LASSO_PROFILE(profile)->request); - - item = lasso_idwsf2_dstref_query_item_new_full(item_xpath, item_id); - query->QueryItem = g_list_append(query->QueryItem, item); - - return 0; -} - -/** - * lasso_idwsf2_data_service_process_query_msg: - * @service: a #LassoIdWsf2DataService - * @message: received query soap request - * - * Process received query request. - * Parse query items and put the list of queried XPATH into @service->query_items. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_data_service_process_query_msg(LassoIdWsf2DataService *service, const gchar *message) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQuery *request = NULL; - LassoIdWsf2DstRefResultQuery *item = NULL; - GList *i; - int res = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); - - if (! LASSO_IS_IDWSF2_DSTREF_QUERY(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } else { - request = LASSO_IDWSF2_DSTREF_QUERY(LASSO_PROFILE(profile)->request); - lasso_assign_string(service->type, request->hrefServiceType); - } - - if (res == 0) { - /* Parse QueryItems to get a list of Xpath strings */ - for (i = g_list_first(request->QueryItem); i != NULL; i = g_list_next(i)) { - item = LASSO_IDWSF2_DSTREF_RESULT_QUERY(i->data); - if (item->Select != NULL) { - service->query_items = g_list_append( - service->query_items, g_strdup(item->Select)); - } - } - } - - return res; -} - -/** - * lasso_idwsf2_data_service_parse_query_items: - * @service: a #LassoIdWsf2DataService - * - * Parse query items and user data from @service->data and fill response->Data accordingly. - * Set response status code to OK is all items were parsed correctly, FAILED if no item was parsed - * correctly, or PARTIAL if some items were parsed corretly and some others not. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_data_service_parse_query_items(LassoIdWsf2DataService *service) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQuery *request; - LassoIdWsf2DstRefQueryResponse *response; - LassoIdWsf2UtilResponse *response2; - LassoSoapEnvelope *envelope; - xmlDoc *doc; - xmlXPathContext *xpathCtx; - xmlXPathObject *xpathObj; - LassoIdWsf2DstRefQueryItem *item; - LassoIdWsf2DstRefResultQuery *item_result_query; - LassoIdWsf2DstResultQueryBase *item_result_query_base; - xmlNode *node; - GList *iter; - int i; - /* How much query did we execute */ - int executed = 0; - /* How much query did succeed */ - int successful = 0; - int rc = 0; - int error_code = 0; - - lasso_bad_param(IDWSF2_DATA_SERVICE, service); - lasso_extract_node_or_fail(request, LASSO_PROFILE(profile)->request, IDWSF2_DSTREF_QUERY, LASSO_PROFILE_ERROR_MISSING_REQUEST); - - if (service->data == NULL) { - return LASSO_DST_ERROR_MISSING_SERVICE_DATA; - } - - /* Response envelope and body */ - lasso_extract_node_or_fail(envelope, profile->soap_envelope_response, SOAP_ENVELOPE, LASSO_SOAP_ERROR_MISSING_ENVELOPE); - response = lasso_idwsf2_dstref_query_response_new(); - lasso_assign_string(response->prefixServiceType, request->prefixServiceType); - lasso_assign_string(response->hrefServiceType, request->hrefServiceType); - lasso_assign_new_gobject(LASSO_PROFILE(profile)->response, LASSO_NODE(response)); - lasso_list_add_gobject(envelope->Body->any, response); - - /* Initialise XML parsing */ - doc = xmlNewDoc((xmlChar*)"1.0"); - xmlDocSetRootElement(doc, service->data); - xpathCtx = xmlXPathNewContext(doc); - lasso_register_idwsf2_xpath_namespaces(xpathCtx); - - /* Parse request QueryItems and fill response Data accordingly */ - /* XXX: needs another level, since there may be more than one */ - for (iter = g_list_first(request->QueryItem); iter != NULL; iter = g_list_next(iter)) { - LassoIdWsf2DstRefData *data; - LassoIdWsf2DstRefItemData *data_item; - - executed++; - item = iter->data; - item_result_query = LASSO_IDWSF2_DSTREF_RESULT_QUERY(item); - item_result_query_base = LASSO_IDWSF2_DST_RESULT_QUERY_BASE(item); - if (lasso_eval_xpath_expression(xpathCtx, item_result_query->Select, &xpathObj, - &error_code)) { - /* XXX: assuming there is only one matching node */ - data = lasso_idwsf2_dstref_data_new(); - data_item = LASSO_IDWSF2_DSTREF_ITEM_DATA(data); - for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { - node = xpathObj->nodesetval->nodeTab[i]; - if (node->type == XML_ATTRIBUTE_NODE) { - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any = g_list_append( - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any, - xmlNewText(xmlGetProp(node->parent, node->name))); - } else { - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any = g_list_append( - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any, xmlCopyNode(node, 1)); - } - } - lasso_release_xpath_object(xpathObj); - } else if (xpathObj && xpathObj->type == XPATH_STRING) { - data = lasso_idwsf2_dstref_data_new(); - data_item = LASSO_IDWSF2_DSTREF_ITEM_DATA(data); - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any = g_list_append( - LASSO_IDWSF2_DSTREF_APP_DATA(data_item)->any, - xmlNewText(xpathObj->stringval)); - lasso_release_xpath_object(xpathObj); - } else { - lasso_release_xpath_object(xpathObj); - /* Stop processing at first error, according to the specifications, or not - * ;) */ - if (lasso_flag_follow_id_wsf_stupid_semantic) - break; - else - continue; - } - - /* Finish handling of a successful item parsing */ - successful++; - lasso_assign_string(data_item->itemIDRef, item_result_query_base->itemID); - lasso_list_add_new_gobject(response->Data, data); - } - - /* Free XML parsing objects */ - xmlUnlinkNode(service->data); - lasso_release_xpath_job(xpathObj, xpathCtx, doc); - xmlSetTreeDoc(service->data, NULL); - - response2 = LASSO_IDWSF2_UTIL_RESPONSE(response); - lasso_assign_new_gobject(response2->Status, lasso_idwsf2_util_status_new()); - - if (executed == successful) { - lasso_assign_string(response2->Status->code, LASSO_DST_STATUS_CODE_OK); - } else if (successful == 0) { - lasso_assign_string(response2->Status->code, LASSO_DST_STATUS_CODE_FAILED); - rc = LASSO_DST_ERROR_QUERY_FAILED; - } else { - lasso_assign_string(response2->Status->code, LASSO_DST_STATUS_CODE_PARTIAL); - rc = LASSO_DST_ERROR_QUERY_PARTIALLY_FAILED; - } - if (error_code) { - LassoIdWsf2UtilStatus *status; - status = lasso_idwsf2_util_status_new(); - - lasso_list_add_new_gobject(response2->Status->Status, status); - status->code = g_strdup_printf("LIBXML_XPATH_ERROR_%d", error_code); - } -cleanup: - - return rc; -} - -static gint -lasso_idwsf2_data_service_process_query_response_soap_fault_msg(LassoIdWsf2DataService *service) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoSoapFault *fault; - LassoIdWsf2Sb2RedirectRequest *redirect_request = NULL; - GList *iter; - int res = 0; - - if (! LASSO_IS_SOAP_FAULT(LASSO_PROFILE(profile)->response)) { - /* Should not happen as it should be checked in caller */ - return 0; - } - - fault = LASSO_SOAP_FAULT(LASSO_PROFILE(profile)->response); - - if (fault->Detail == NULL || fault->Detail->any == NULL) { - return LASSO_SOAP_ERROR_MISSING_SOAP_FAULT_DETAIL; - } - - /* Get RedirectRequest element from soap fault detail */ - for (iter = fault->Detail->any; iter != NULL; iter = iter->next) { - if (LASSO_IS_IDWSF2_SB2_REDIRECT_REQUEST(iter->data) == TRUE) { - redirect_request = LASSO_IDWSF2_SB2_REDIRECT_REQUEST(iter->data); - break; - } - } - - if (redirect_request != NULL) { - /* This is not a failure, this exception code indicates the WSP needs to ask */ - /* user consent to get an attribute */ - res = LASSO_SOAP_ERROR_REDIRECT_REQUEST_FAULT; - /* Get redirect request url */ - service->redirect_url = g_strdup(redirect_request->redirectURL); - } - - return res; -} - -/** - * lasso_idwsf2_data_service_process_query_response_msg: - * @service: a #LassoIdWsf2DataService - * @message: received query soap response - * - * Process received query response. - * Check if the response if a normal response or a soap fault. - * Check response status code. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_data_service_process_query_response_msg(LassoIdWsf2DataService *service, - const gchar *message) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2UtilResponse *response; - int res; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); - if (res != 0) { - return res; - } - - /* Message can be either a SoapFault or a QueryResponse */ - if (LASSO_IS_SOAP_FAULT(LASSO_PROFILE(profile)->response)) { - return lasso_idwsf2_data_service_process_query_response_soap_fault_msg( - service); - } - - if (! LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE(LASSO_PROFILE(profile)->response)) { - return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* Check response status code */ - response = LASSO_IDWSF2_UTIL_RESPONSE(LASSO_PROFILE(profile)->response); - if (response->Status == NULL || response->Status->code == NULL) { - return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } - if (strcmp(response->Status->code, LASSO_DST_STATUS_CODE_PARTIAL) == 0) { - return LASSO_DST_ERROR_QUERY_PARTIALLY_FAILED; - } else if (strcmp(response->Status->code, LASSO_DST_STATUS_CODE_OK) != 0) { - return LASSO_DST_ERROR_QUERY_FAILED; - } - - return 0; -} - -/** - * lasso_idwsf2_data_service_get_attribute_nodes: - * @service: a #LassoIdWsf2DataService - * @item_id: identifier of the item to retrieve - * - * Get one of several items for specified @item_id and return them raw as a list of xmlnodes. - * - * Return value: a list of xmlnodes; or NULL if no item with the specified @item_id was found. - **/ -GList* -lasso_idwsf2_data_service_get_attribute_nodes(LassoIdWsf2DataService *service, - const gchar *item_id) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQueryResponse *response; - LassoIdWsf2DstRefAppData *data = NULL; - GList *iter; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), NULL); - - g_return_val_if_fail(LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE( - LASSO_PROFILE(profile)->response), NULL); - - response = LASSO_IDWSF2_DSTREF_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); - - /* If no item_id is given, return the first item */ - if (item_id == NULL && response->Data != NULL && response->Data->data != NULL) { - data = LASSO_IDWSF2_DSTREF_APP_DATA(response->Data->data); - if (data->any != NULL && data->any->data != NULL) { - return duplicate_glist_of_xmlnodes(data->any); - } - } - if (item_id == NULL) { - return NULL; - } - - /* Find the item which has the given item_id */ - for (iter = g_list_first(response->Data); iter != NULL; iter = g_list_next(iter)) { - if (! LASSO_IS_IDWSF2_DSTREF_ITEM_DATA(iter->data)) { - continue; - } - if (strcmp(LASSO_IDWSF2_DSTREF_ITEM_DATA(iter->data)->itemIDRef, item_id) == 0) { - data = LASSO_IDWSF2_DSTREF_APP_DATA(iter->data); - break; - } - } - - if (data == NULL || data->any == NULL || data->any->data == NULL) { - /* Item not found */ - return NULL; - } - - return duplicate_glist_of_xmlnodes(data->any); -} - -/** - * lasso_idwsf2_data_service_get_attribute_node: - * @service: a #LassoIdWsf2DataService - * @item_id: identifier of the item to retrieve - * - * Get one item for specified @item_id and return it raw as an xmlnode. - * - * Return value: an xmlnode; or NULL if no item with the specified @item_id was found. - **/ -xmlNode* -lasso_idwsf2_data_service_get_attribute_node(LassoIdWsf2DataService *service, const gchar *item_id) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefQueryResponse *response; - LassoIdWsf2DstRefAppData *data = NULL; - GList *iter; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), NULL); - - g_return_val_if_fail(LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE( - LASSO_PROFILE(profile)->response), NULL); - - response = LASSO_IDWSF2_DSTREF_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); - - /* If no item_id is given, return the first item */ - if (item_id == NULL && response->Data != NULL && response->Data->data != NULL) { - data = LASSO_IDWSF2_DSTREF_APP_DATA(response->Data->data); - if (data->any != NULL && data->any->data != NULL) { - return xmlCopyNode(data->any->data, 1); - } - } - if (item_id == NULL) { - return NULL; - } - - /* Find the item which has the given item_id */ - for (iter = g_list_first(response->Data); iter != NULL; iter = g_list_next(iter)) { - if (! LASSO_IS_IDWSF2_DSTREF_ITEM_DATA(iter->data)) { - continue; - } - if (strcmp(LASSO_IDWSF2_DSTREF_ITEM_DATA(iter->data)->itemIDRef, item_id) == 0) { - data = LASSO_IDWSF2_DSTREF_APP_DATA(iter->data); - break; - } - } - - if (data == NULL || data->any == NULL || data->any->data == NULL) { - /* Item not found */ - return NULL; - } - - /* XXX: there may be more than one xmlnode */ - return xmlCopyNode(data->any->data, 1); -} - -/** - * lasso_idwsf2_data_service_get_attribute_strings: - * @service: a #LassoIdWsf2DataService - * @item_id: identifier of the item to retrieve - * - * Get one of several items for specified @item_id and return their content as a list of strings. - * - * Return value: a list of strings; or NULL if no item with the specified @item_id was found. - **/ -GList* -lasso_idwsf2_data_service_get_attribute_strings(LassoIdWsf2DataService *service, - const gchar *item_id) -{ - GList *nodes = NULL; - xmlChar *xml_content = NULL; - GList *contents = NULL; - GList *iter; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), NULL); - - nodes = lasso_idwsf2_data_service_get_attribute_nodes(service, item_id); - for (iter = nodes; iter; iter = g_list_next(iter)) { - xml_content = xmlNodeGetContent(iter->data); - contents = g_list_append(contents, g_strdup((gchar*)xml_content)); - xmlFree(xml_content); - xmlFreeNode(iter->data); - } - - g_list_free(nodes); - - return contents; -} - -/** - * lasso_idwsf2_data_service_get_attribute_string: - * @service: a #LassoIdWsf2DataService - * @item_id: identifier of the item to retrieve - * - * Get one item for specified @item_id and return its content as a string. - * - * Return value: a string; or NULL if no item with the specified @item_id was found. - **/ -gchar* -lasso_idwsf2_data_service_get_attribute_string(LassoIdWsf2DataService *service, - const gchar *item_id) -{ - xmlNode *node; - xmlChar *xml_content; - gchar *content; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), NULL); - - node = lasso_idwsf2_data_service_get_attribute_node(service, item_id); - xml_content = xmlNodeGetContent(node); - content = g_strdup((gchar*)xml_content); - - xmlFree(xml_content); - xmlFreeNode(node); - - return content; -} - -/** - * lasso_idwsf2_data_service_init_redirect_user_for_consent: - * @service: a #LassoIdWsf2DataService - * @redirect_url: URL to ask for redirection - * - * Initialise a soap fault response to ask the requesting service to redirect to the @redirect_url. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_data_service_init_redirect_user_for_consent(LassoIdWsf2DataService *service, - const gchar *redirect_url) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoSoapEnvelope *envelope; - LassoSoapFault *fault; - LassoSoapDetail *detail; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(redirect_url != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - /* Response envelope */ - envelope = profile->soap_envelope_response; - if (envelope == NULL) { - return LASSO_SOAP_ERROR_MISSING_ENVELOPE; - } - - /* Build soap fault node */ - fault = lasso_soap_fault_new(); - fault->faultcode = g_strdup(LASSO_SOAP_FAULT_CODE_SERVER); - fault->faultstring = g_strdup(LASSO_SOAP_FAULT_STRING_SERVER); - detail = lasso_soap_detail_new(); - detail->any = g_list_append( - detail->any, lasso_idwsf2_sb2_redirect_request_new_full(redirect_url)); - fault->Detail = detail; - - /* Response envelope body */ - envelope->Body->any = g_list_append(envelope->Body->any, fault); - - return 0; + return lasso_idwsf2_data_service_init_request(service, + (LassoNode *(*)())lasso_idwsf2_dstref_query_new); } /** @@ -670,399 +168,731 @@ lasso_idwsf2_data_service_init_redirect_user_for_consent(LassoIdWsf2DataService gint lasso_idwsf2_data_service_init_modify(LassoIdWsf2DataService *service) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefModify *modify; - LassoWsAddrEndpointReference *epr; - GList *metadata_item; - GList *i; - gchar *service_type = NULL; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - modify = lasso_idwsf2_dstref_modify_new(); - lasso_assign_new_gobject(LASSO_PROFILE(profile)->request, LASSO_NODE(modify)); - - if (service == NULL || service->private_data == NULL - || service->private_data->epr == NULL - || service->private_data->epr->Metadata == NULL) { - return LASSO_PROFILE_ERROR_MISSING_ENDPOINT_REFERENCE; - } - - epr = service->private_data->epr; - - /* Get the service type from the EPR */ - metadata_item = epr->Metadata->any; - for (i = g_list_first(metadata_item); i != NULL; i = g_list_next(i)) { - if (LASSO_IS_IDWSF2_DISCO_SERVICE_TYPE(i->data)) { - service_type = LASSO_IDWSF2_DISCO_SERVICE_TYPE(i->data)->content; - break; - } - } - - /* Set hrefServiceType and prefixServiceType in query in order to set the profile */ - /* namespace in the request */ - if (service_type != NULL) { - modify->hrefServiceType = g_strdup(service_type); - modify->prefixServiceType = lasso_get_prefix_for_idwsf2_dst_service_href( - modify->hrefServiceType); - } - if (modify->prefixServiceType == NULL) { - return LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST; - } - - lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(modify), service_type); - - /* Set msg_url as epr address, which is the SoapEndpoint */ - if (epr->Address != NULL) { - LASSO_PROFILE(profile)->msg_url = g_strdup(epr->Address->content); - } else { - return LASSO_PROFILE_ERROR_MISSING_ENDPOINT_REFERENCE_ADDRESS; - } - - return 0; + return lasso_idwsf2_data_service_init_request(service, + (LassoNode *(*)())lasso_idwsf2_dstref_modify_new); } -static void set_xml_string(xmlNode **xmlnode, const char* string) +gint +lasso_idwsf2_data_service_init_create(LassoIdWsf2DataService *service) { - xmlDoc *doc; - xmlNode *node; + return lasso_idwsf2_data_service_init_request(service, + (LassoNode *(*)())lasso_idwsf2_dstref_create_new); +} - doc = xmlReadDoc((xmlChar*)string, NULL, NULL, XML_PARSE_NONET); - node = xmlDocGetRootElement(doc); - if (node != NULL) { - node = xmlCopyNode(node, 1); +gint +lasso_idwsf2_data_service_init_delete(LassoIdWsf2DataService *service) +{ + return lasso_idwsf2_data_service_init_request(service, + (LassoNode *(*)())lasso_idwsf2_dstref_delete_new); +} + +/** + * lasso_idwsf2_data_service_get_request_type: + * @service: a #LassoIdWsf2DataService object + * + * Return the type of the currently handled request. + */ +LassoIdWsf2DataServiceRequestType +lasso_idwsf2_data_service_get_request_type(LassoIdWsf2DataService *service) +{ + GType request_type = 0; + +#define check_request_type(a, b) \ + if (request_type == a) { \ + return b ;\ + } + if (! LASSO_IS_IDWSF2_DATA_SERVICE(service)) + return LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_UNKNOWN; + request_type = G_TYPE_FROM_INSTANCE(service->parent.parent.request); + check_request_type(LASSO_TYPE_IDWSF2_DSTREF_QUERY, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY); + check_request_type(LASSO_TYPE_IDWSF2_DSTREF_MODIFY, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY); +#undef check_request_type + return LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_UNKNOWN; +} + +/** + * lasso_idwsf2_data_service_add_query_item: + * @service: a #LassoIdWsf2DataService + * @item_query: a query string + * @item_id:(allow-none): identifier of the queried item, which will allow to retrieve it in the + * response + * + * Add an item in the query request. + * + * Return value: 0 on success; or a negative value otherwise. + **/ +gint +lasso_idwsf2_data_service_add_query_item(LassoIdWsf2DataService *service, const gchar *item_query, + const gchar *item_id) +{ + LassoIdWsf2DstRefQueryItem *item; + GList *i; + int rc = 0; + + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + lasso_check_non_empty_string(item_query); + + if (item_id == NULL) { + item_id = lasso_build_unique_id(10); } - lasso_release_doc(doc); - - if (*xmlnode) { - xmlFreeNode(*xmlnode); + /* Check duplicates */ + lasso_foreach(i, service->private_data->query_items) { + LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data; + if (g_strcmp0(old_item->parent.parent.itemID, item_id) == 0) { + return LASSO_IDWSF2_DST_ERROR_DUPLICATE_ITEM; + } } - - *xmlnode = node; + item = lasso_idwsf2_dstref_query_item_new_full(item_query, item_id); + lasso_list_add_gobject(service->private_data->query_items, item); +cleanup: + return rc; } /** * lasso_idwsf2_data_service_add_modify_item: * @service: a #LassoIdWsf2DataService - * @item_xpath: XPATH of the item to modify - * @item_id: identifier of the item to modify - * @new_data: new value for the selected item - * @overrideAllowed: FALSE means only allowing to create a new item, but not modify existing one, - * TRUE means allowing to modify existing item + * @item_query: XPATH of the item to modify + * @new_data:(allow-none):new value for the selected item + * @overrideAllowed:(allow-none)(default FALSE): FALSE means only allowing to create a new item, but + * not modify existing one, TRUE means allowing to modify existing item + * @item_id:(allow-none): identifier of the item to modify * * Add an item in the modification request. * * Return value: 0 on success; or a negative value otherwise. **/ gint -lasso_idwsf2_data_service_add_modify_item(LassoIdWsf2DataService *service, const gchar *item_xpath, - const gchar *item_id, const gchar *new_data, gboolean overrideAllowed) +lasso_idwsf2_data_service_add_modify_item(LassoIdWsf2DataService *service, const gchar *item_query, + xmlNode *new_data, gboolean overrideAllowed, const gchar *item_id) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefModify *modify; LassoIdWsf2DstRefModifyItem *item; - xmlNode *new_data_node = NULL; + int rc = 0; + GList *i; - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(item_xpath != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(item_id != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + lasso_check_non_empty_string(item_query); - if (! LASSO_IS_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request)) { - return LASSO_PROFILE_ERROR_MISSING_REQUEST; + if (item_id == NULL) { + item_id = lasso_build_unique_id(10); + } + lasso_foreach(i, service->private_data->modify_items) { + LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data; + if (g_strcmp0(old_item->id, item_id) == 0) { + return LASSO_IDWSF2_DST_ERROR_DUPLICATE_ITEM; + } + } + item = lasso_idwsf2_dstref_modify_item_new_full( + item_query, item_id, new_data, overrideAllowed); + lasso_list_add_gobject(service->private_data->modify_items, item); + +cleanup: + return rc; +} + +/** + * lasso_idwsf2_data_service_get_item_ids: + * @service: a #LassoIdWsf2DataService object + * + * Return the list of items ids for the currently handled request. + * + * Return value:(element-type utf8)(transfer full): a list of string ids, or NULL if none is found. + * The caller must free the return value. + */ +GList* +lasso_idwsf2_data_service_get_item_ids(LassoIdWsf2DataService *service) +{ + GList *i, *result = NULL; + + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + lasso_foreach(i, service->private_data->query_items) { + LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data; + lasso_list_add_string(result, old_item->parent.parent.itemID); + } + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + lasso_foreach(i, service->private_data->modify_items) { + LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data; + lasso_list_add_string(result, old_item->id); + } + break; + default: + break; + } + return result; +} + +/** + * lasso_idwsf2_data_service_get_items: + * @service: a #LassoIdWsf2DataService object + * + * Return value:(element-type LassoNode)(transfer none): a list of Query or Modify items, or NULL if + * none is found. + */ +GList* +lasso_idwsf2_data_service_get_items(LassoIdWsf2DataService *service) +{ + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + return service->private_data->query_items; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + return service->private_data->modify_items; + default: + break; + } + return NULL; +} + +/** + * lasso_idwsf2_data_service_get_item: + * @service: a #LassoIdWsf2DataService object + * @item_id: the itemID of the item to return, if NULL try to get the only one item (if there is + * more than one, it returns NULL). + * + * Retrieve a specific item from a request. + * + * Return value: a #LassoIdWsf2DstRefQueryItem or a #LassoIdWsf2DstRefModifyItem object, or NULL if + * no item for the given item_id exists. + */ +LassoNode* +lasso_idwsf2_data_service_get_item(LassoIdWsf2DataService *service, + const char *item_id) +{ + GList *i; + + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + if (item_id == NULL) { + if (g_list_length(service->private_data->query_items) == 1) + return (LassoNode*)service->private_data->query_items->data; + else + return NULL; + } + lasso_foreach(i, service->private_data->query_items) { + LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data; + if (g_strcmp0(old_item->parent.parent.itemID, item_id) == 0) { + return (LassoNode*)old_item; + } + } + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + if (item_id == NULL) { + if (g_list_length(service->private_data->modify_items) == 1) + return (LassoNode*)service->private_data->modify_items->data; + else + return NULL; + } + lasso_foreach(i, service->private_data->modify_items) { + LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data; + if (g_strcmp0(old_item->id, item_id) == 0) { + return (LassoNode*)old_item; + } + } + break; + default: + break; + } + return NULL; +} + +/** + * lasso_idwsf2_data_service_add_namespace: + * @service: a #LassoIdWsf2DataService object + * + * Add a new namespace to use for example in XPath elements or in Data or NewData objects. + * + * Return value: 0 if successful, an error code otherwise. + */ +gint +lasso_idwsf2_data_service_add_namespace(LassoIdWsf2DataService *service, const char *prefix, + const char *href) +{ + if (xmlValidateNCName(BAD_CAST prefix, 0) && ! lasso_is_empty_string(href)) + return LASSO_PARAM_ERROR_INVALID_VALUE; + + if (g_hash_table_lookup(service->private_data->namespaces, prefix) != NULL || + g_strcmp0(service->private_data->service_type_prefix, prefix) == 0 || + g_strcmp0(prefix, LASSO_IDWSF2_DSTREF_PREFIX) == 0) { + return LASSO_PARAM_ERROR_INVALID_VALUE; } - modify = LASSO_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request); - - set_xml_string(&new_data_node, new_data); - item = lasso_idwsf2_dstref_modify_item_new_full( - item_xpath, item_id, new_data_node, overrideAllowed); - modify->ModifyItem = g_list_append(modify->ModifyItem, item); - + g_hash_table_insert(service->private_data->namespaces, g_strdup(prefix), g_strdup(href)); return 0; } /** - * lasso_idwsf2_data_service_process_modify_msg: - * @service: a #LassoIdWsf2DataService - * @message: received modify soap request + * lasso_idwsf2_data_service_build_request: + * @service: a #LassoIdWsf2DataService object * - * Process received modify request. + * Build the request messages * - * Return value: 0 on success; or a negative value otherwise. - **/ + * Return value: 0 if successful, an error code otherwise. + */ gint -lasso_idwsf2_data_service_process_modify_msg(LassoIdWsf2DataService *service, const gchar *message) +lasso_idwsf2_data_service_build_request_msg(LassoIdWsf2DataService *service, + const char *security_mech_id) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefModify *request = NULL; - int res = 0; + int rc = 0; + LassoSoapEnvelope *envelope; + LassoIdWsf2DstRefQuery *query = (LassoIdWsf2DstRefQuery*)service->parent.parent.request; + LassoIdWsf2DstRefModify *modify = (LassoIdWsf2DstRefModify*)service->parent.parent.request; + const char *service_type = NULL; + const char *prefix = NULL; - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); + lasso_bad_param(IDWSF2_DATA_SERVICE, service); - res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); - - if (! LASSO_IS_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; + envelope = lasso_idwsf2_profile_get_soap_envelope_request(&service->parent); + service_type = lasso_wsa_endpoint_reference_get_idwsf2_service_type( + lasso_idwsf2_profile_get_epr(&service->parent)); + if (service_type) { + const char *prefix = lasso_get_prefix_for_idwsf2_dst_service_href(service_type); + if (! prefix) + prefix = "dstref"; } else { - request = LASSO_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request); - service->type = g_strdup(request->hrefServiceType); + service_type = service->private_data->service_type; + prefix = service->private_data->service_type_prefix; } - return res; + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + if (service_type) { + lasso_idwsf2_data_service_set_dst_service_type(query, service_type, prefix); + } + lasso_assign_list_of_gobjects(query->QueryItem, service->private_data->query_items); + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + if (service_type) { + lasso_idwsf2_data_service_set_dst_service_type(modify, service_type, prefix); + } + lasso_assign_list_of_gobjects(modify->ModifyItem, service->private_data->modify_items); + break; + default: + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST); + break; + } + rc = lasso_idwsf2_profile_build_request_msg(&service->parent, security_mech_id); +cleanup: + return rc; } static gint -lasso_idwsf2_data_service_parse_one_modify_item(LassoIdWsf2DstRefModifyItem *item, xmlDoc *cur_doc, - xmlXPathContext *cur_xpathCtx, int *error_code_ptr) +lasso_idwsf2_data_service_process_query(LassoIdWsf2DataService *service) { - xmlXPathObject *cur_xpathObj = NULL; - xmlNode *new_node = NULL; - xmlNode *cur_node = NULL; - gint rc = 0; + LassoIdWsf2DstRefQuery *query; + GList *i; + int rc = 0; - g_return_val_if_fail(item != NULL && cur_doc != NULL && cur_xpathCtx != NULL, LASSO_DST_ERROR_MODIFY_FAILED); + query = (LassoIdWsf2DstRefQuery*)service->parent.parent.request; + lasso_check_good_rc(lasso_idwsf2_data_service_set_service_type( + service, + query->prefixServiceType, + query->hrefServiceType)); - /* Check NewData existence */ - if (item->NewData == NULL || item->NewData->any == NULL - || item->NewData->any->data == NULL) { - if (item->overrideAllowed == TRUE) { - new_node = NULL; - } else { - goto_cleanup_with_rc(LASSO_DST_ERROR_NEW_DATA_MISSING); + /* Parse QueryItems to get a list of Query strings */ + /* FIXME: extract TestItems */ + lasso_foreach(i, query->QueryItem) + { + LassoIdWsf2DstRefQueryItem *item = (LassoIdWsf2DstRefQueryItem *)i->data; + /* FIXME: check more query items invariants. */ + if (! LASSO_IS_IDWSF2_DSTREF_QUERY_ITEM(item)) { + lasso_release_list_of_gobjects(service->private_data->query_items); + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST); } - } else { - new_node = (xmlNode*)item->NewData->any->data; + lasso_list_add_gobject(service->private_data->query_items, + item); } +cleanup: + return rc; +} - if (item->overrideAllowed == FALSE) { - /* Add the new item and add it to the current data */ - /* FIXME : when the ancestor nodes of the new node do not */ - /* exist either, they MUST be added */ - xmlAddChild(xmlDocGetRootElement(cur_doc), xmlCopyNode(new_node, 1)); - } else { - /* Modify an existing node */ - if (lasso_eval_xpath_expression(cur_xpathCtx, item->Select, &cur_xpathObj, error_code_ptr)) { - /* XXX: assuming there is only one matching node */ - cur_node = cur_xpathObj->nodesetval->nodeTab[0]; - if (new_node != NULL) { - /* Replace old node with new data */ - cur_node = xmlReplaceNode(cur_node, xmlCopyNode(new_node, 1)); - } - lasso_release_xml_node(cur_node); - } else { - rc = LASSO_DST_ERROR_MODIFY_FAILED; +static gint +lasso_idwsf2_data_service_process_modify(LassoIdWsf2DataService *service) +{ + LassoIdWsf2DstRefModify *modify; + GList *i; + int rc = 0; + + modify = (LassoIdWsf2DstRefModify*)service->parent.parent.request; + lasso_foreach(i, modify->ModifyItem) + { + LassoIdWsf2DstRefModifyItem *item = (LassoIdWsf2DstRefModifyItem*)i->data; + /* FIXME: check more Modify Item invariants */ + if (! LASSO_IS_IDWSF2_DSTREF_MODIFY_ITEM(item)) { + lasso_release_list_of_gobjects(service->private_data->modify_items); + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST); } - lasso_release_xpath_object(cur_xpathObj); + lasso_list_add_gobject(service->private_data->modify_items, item); } cleanup: return rc; } /** - * lasso_idwsf2_data_service_parse_modify_items: - * @service: a #LassoIdWsf2DataService + * lasso_idwsf2_data_service_process_request_msg: + * @service: a #LassoIdWsf2DataService object + * @msg: the message string * - * Parse modify items and modify @service->data accordingly. - * - * Return value: 0 on success; or a negative value otherwise. - **/ + * Process a newly received requests. + */ gint -lasso_idwsf2_data_service_parse_modify_items(LassoIdWsf2DataService *service) +lasso_idwsf2_data_service_process_request_msg(LassoIdWsf2DataService *service, const char *msg) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2DstRefModify *request; - LassoIdWsf2DstRefModifyResponse *response; - LassoIdWsf2UtilResponse *response2; - LassoSoapEnvelope *envelope; - xmlDoc *cur_doc; - xmlXPathContext *cur_xpathCtx; - LassoIdWsf2DstRefModifyItem *item; - xmlNode *cur_data; - LassoIdWsf2UtilStatus *secondary_status; - GList *iter; - int res = 0; + int rc = 0; - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + lasso_bad_param(IDWSF2_DATA_SERVICE, service); - if (! LASSO_IS_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request)) { - return LASSO_PROFILE_ERROR_MISSING_REQUEST; - } - request = LASSO_IDWSF2_DSTREF_MODIFY(LASSO_PROFILE(profile)->request); - - if (service->data == NULL) { - return LASSO_DST_ERROR_MISSING_SERVICE_DATA; - } else { - cur_data = xmlCopyNode(service->data, 1); - } - - /* Response envelope and body */ - envelope = profile->soap_envelope_response; - if (envelope == NULL) { - return LASSO_SOAP_ERROR_MISSING_ENVELOPE; - } - response = lasso_idwsf2_dstref_modify_response_new(); - response->prefixServiceType = g_strdup(request->prefixServiceType); - response->hrefServiceType = g_strdup(request->hrefServiceType); - lasso_assign_new_gobject(LASSO_PROFILE(profile)->response, LASSO_NODE(response)); - lasso_list_add_gobject(envelope->Body->any, response); - - response2 = LASSO_IDWSF2_UTIL_RESPONSE(response); - response2->Status = lasso_idwsf2_util_status_new(); - - /* Initialize XML parsing */ - cur_doc = xmlNewDoc((xmlChar*)"1.0"); - xmlDocSetRootElement(cur_doc, cur_data); - cur_xpathCtx = xmlXPathNewContext(cur_doc); - lasso_register_idwsf2_xpath_namespaces(cur_xpathCtx); - - /* Parse request ModifyItems and modify user current data accordingly */ - /* XXX: needs another level, since there may be more than one */ - for (iter = g_list_first(request->ModifyItem); iter != NULL; iter = g_list_next(iter)) { - int errorCode; - - item = iter->data; - res = lasso_idwsf2_data_service_parse_one_modify_item( - item, cur_doc, cur_xpathCtx, &errorCode); - if (res != 0) { - /* If one item fails, stop and roll back */ + lasso_check_good_rc(lasso_idwsf2_profile_process_request_msg(&service->parent, msg)); + lasso_idwsf2_data_service_clean_private_data(service); + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + rc = lasso_idwsf2_data_service_process_query(service); + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + rc = lasso_idwsf2_data_service_process_modify(service); + break; + default: + rc = LASSO_PROFILE_ERROR_INVALID_REQUEST; break; - } } - - if (res == 0) { - response2->Status->code = g_strdup(LASSO_DST_STATUS_CODE_OK); - /* Save new service data */ - xmlFreeNode(service->data); - service->data = xmlCopyNode(cur_data, 1); - } else { - response2->Status->code = g_strdup(LASSO_DST_STATUS_CODE_FAILED); - if (res == LASSO_DST_ERROR_NEW_DATA_MISSING) { - secondary_status = lasso_idwsf2_util_status_new(); - secondary_status->code = g_strdup( - LASSO_DST_STATUS_CODE_MISSING_NEW_DATA_ELEMENT); - response2->Status->Status = g_list_append( - response2->Status->Status, secondary_status); - } + if (rc == LASSO_PROFILE_ERROR_INVALID_REQUEST) { + lasso_idwsf2_data_service_set_status_code(service, + LASSO_DST2_STATUS_CODE1_FAILED, + "InvalidRequest"); } - - /* Free XML parsing objects */ - xmlXPathFreeContext(cur_xpathCtx); - lasso_release_doc(cur_doc); - - return res; +cleanup: + return rc; } /** - * lasso_idwsf2_data_service_process_modify_response_msg: - * @service: a #LassoIdWsf2DataService - * @message: received modify soap response + * lasso_idwsf2_data_service_init_response: + * @service: a #LassoIdWsf2DataService object * - * Process received modify response. - * Check response status code. + * Initialize a new response object corresponding to the current request. If not request if found or + * the request is invalid, an failure response is created. * - * Return value: 0 on success; or a negative value otherwise. - **/ + * Return value: 0 if successful, or LASSO_PROFILE_ERROR_INVALID_REQUEST. + */ gint -lasso_idwsf2_data_service_process_modify_response_msg(LassoIdWsf2DataService *service, - const gchar *message) +lasso_idwsf2_data_service_init_response(LassoIdWsf2DataService *service) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(service); - LassoIdWsf2UtilResponse *response; - int res; + LassoIdWsf2DstRefQueryResponse *query_response; + LassoIdWsf2DstRefModifyResponse *modify_response; + LassoNode *response = NULL; + int rc = 0; - g_return_val_if_fail(LASSO_IS_IDWSF2_DATA_SERVICE(service), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); + lasso_bad_param(IDWSF2_DATA_SERVICE, service); - res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); - if (res != 0) { - return res; + lasso_check_good_rc(lasso_idwsf2_profile_init_response(&service->parent)); + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + query_response = lasso_idwsf2_dstref_query_response_new(); + response = (LassoNode*)query_response; + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + modify_response = lasso_idwsf2_dstref_modify_response_new(); + response = (LassoNode*)modify_response; + break; + default: + lasso_idwsf2_data_service_set_status_code(service, + LASSO_DST2_STATUS_CODE1_FAILED, "InvalidRequest"); + return LASSO_PROFILE_ERROR_INVALID_REQUEST; } - - if (! LASSO_IS_IDWSF2_DSTREF_MODIFY_RESPONSE(LASSO_PROFILE(profile)->response)) { - return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; + if (response) { + LassoSoapEnvelope *envelope = + lasso_idwsf2_profile_get_soap_envelope_response(&service->parent); + lasso_assign_new_gobject(service->parent.parent.response, response); + lasso_soap_envelope_add_to_body(envelope, response); + lasso_idwsf2_data_service_set_status_code(service, LASSO_DST2_STATUS_CODE1_OK, NULL); } - - /* Check response status code */ - response = LASSO_IDWSF2_UTIL_RESPONSE(LASSO_PROFILE(profile)->response); - if (response->Status == NULL || response->Status->code == NULL) { - return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } - if (strcmp(response->Status->code, LASSO_DST_STATUS_CODE_PARTIAL) == 0) { - return LASSO_DST_ERROR_MODIFY_PARTIALLY_FAILED; - } else if (strcmp(response->Status->code, LASSO_DST_STATUS_CODE_OK) != 0) { - return LASSO_DST_ERROR_MODIFY_FAILED; - } - - return 0; +cleanup: + return rc; } -/*****************************************************************************/ -/* private methods */ -/*****************************************************************************/ +/** + * lasso_idwsf2_data_service_set_status_code: + * @service: a #LassoIdWsf2DataService + * @status_code: a first level status code + * @status_code2: a second level status code + * + * Set the status code for the current response, if no response exists, create start one using + * lasso_idwsf2_data_service_init_response(), if it fails, resport a SOAP Fault. + */ +gint +lasso_idwsf2_data_service_set_status_code(LassoIdWsf2DataService *service, + const char *status_code, const char *status_code2) +{ + LassoNode *response; + LassoIdWsf2UtilStatus **status = NULL; + LassoSoapFault *fault; + int rc = 0; + + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + status = &LASSO_IDWSF2_UTIL_RESPONSE(response)->Status; + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + status = &LASSO_IDWSF2_UTIL_RESPONSE(response)->Status; + break; + default: + lasso_check_good_rc(lasso_idwsf2_profile_init_soap_fault_response(&service->parent)); + fault = (LassoSoapFault*)service->parent.parent.response; + lasso_assign_string(fault->faultcode, LASSO_SOAP_FAULT_CODE_CLIENT); + lasso_assign_string(fault->faultstring, "Client Error"); + lasso_soap_fault_add_to_detail(fault, + (LassoNode*)lasso_idwsf2_util_status_new_with_code( + status_code, status_code2)); + return 0; + } + if (status) { + lasso_assign_new_gobject(*status, + lasso_idwsf2_util_status_new_with_code(status_code, status_code2)); + } +cleanup: + return rc; +} + +/** + * lasso_idwsf2_data_service_set_query_item_result: + * @service: a #LassoIdWsf2DataService object + * @item_id:(allow-none): target a certain QueryItem if NULL, means there is only one query item + * @xml_data:(allow-none): the data to add + * @add:(allow-none)(default FALSE): add data to existing datas + * + * Set result data for a certain query-item. + */ +gint +lasso_idwsf2_data_service_set_query_item_result(LassoIdWsf2DataService *service, + const char *item_id, xmlNode *xml_data, gboolean add) +{ + LassoIdWsf2DstRefQueryItem *item; + LassoIdWsf2DstRefData *data; + int rc = 0; + + if (lasso_idwsf2_data_service_get_request_type(service) + != LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY) { + goto_cleanup_with_rc(LASSO_IDWSF2_DST_ERROR_ITEM_NOT_FOUND); + } + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + item = (LassoIdWsf2DstRefQueryItem*)lasso_idwsf2_data_service_get_item(service, item_id); + if (! LASSO_IS_IDWSF2_DSTREF_QUERY_ITEM(item)) { + goto_cleanup_with_rc(LASSO_IDWSF2_DST_ERROR_ITEM_NOT_FOUND); + } + data = lasso_idwsf2_data_service_get_query_item_result(service, item_id); + if (data == NULL) { + data = lasso_idwsf2_dstref_data_new(); + } + if (xml_data) { + if (! add) { + lasso_release_list_of_xml_node(data->parent.parent.any); + } + lasso_list_add_xml_node(data->parent.parent.any, xml_data); + } + if (item_id) { + lasso_assign_string(data->parent.itemIDRef, item_id); + } + if (g_list_find(service->private_data->query_datas, data) == NULL) { + lasso_list_add_gobject(service->private_data->query_datas, data); + } +cleanup: + return rc; +} + +/** + * lasso_idwsf2_data_service_build_response_msg: + * @service: a #LassoIdWsf2DataService object + * + * Build the response message corresponding to the current request. + * + * Return value: 0 if successfull, an error code otherwise. + */ +gint +lasso_idwsf2_data_service_build_response_msg(LassoIdWsf2DataService *service) +{ + LassoIdWsf2DstRefQueryResponse *query_response; + GList *datas; + int rc = 0; + + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + goto_cleanup_if_fail_with_rc( + LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE( + service->parent.parent.response), + LASSO_PROFILE_ERROR_INVALID_RESPONSE); + query_response = (LassoIdWsf2DstRefQueryResponse*)service->parent.parent.response; + datas = lasso_idwsf2_data_service_get_query_item_results(service); + lasso_assign_list_of_gobjects(query_response->Data, datas); + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + goto_cleanup_with_rc(LASSO_ERROR_UNIMPLEMENTED); + break; + default: + break; + } + rc = lasso_idwsf2_profile_build_response_msg(&service->parent); +cleanup: + return rc; +} + +static gint +_lasso_idwsf2_data_service_process_query_response(LassoIdWsf2DataService * service, + LassoIdWsf2DstRefQueryResponse *response) +{ + int rc = 0; + + goto_cleanup_if_fail_with_rc(LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE(response), + LASSO_PROFILE_ERROR_INVALID_RESPONSE); + + if (service->private_data) { + lasso_assign_list_of_gobjects(service->private_data->query_datas, response->Data); + } +cleanup: + return rc; +} + +/** + * lasso_idwsf2_data_service_process_response_msg: + * @service: a #LassoIdWsf2DataService object + * @msg: (allow-none): the message content + * + * Process a received SOAP message response. + * + * Return value: 0 if successful, an error code otherwise. + */ +gint +lasso_idwsf2_data_service_process_response_msg( + LassoIdWsf2DataService *service, const char *msg) +{ + LassoIdWsf2DstRefQueryResponse *query_response; + LassoIdWsf2UtilStatus *status; + int rc = 0; + + lasso_bad_param(IDWSF2_DATA_SERVICE, service); + + status = lasso_idwsf2_data_service_get_response_status(service); + + if (! status || ! status->code) { + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE); + } + if (g_strcmp0(status->code, LASSO_DST2_STATUS_CODE1_FAILED) == 0) { + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS); + } + if (g_strcmp0(status->code, LASSO_DST2_STATUS_CODE1_PARTIAL) == 0) { + rc = LASSO_IDWSF2_DST_ERROR_PARTIAL_FAILURE; + } + if (g_strcmp0(status->code, LASSO_DST2_STATUS_CODE1_OK) != 0) { + rc = LASSO_IDWSF2_DST_ERROR_UNKNOWN_STATUS_CODE; + } + + lasso_check_good_rc(lasso_idwsf2_profile_process_response_msg(&service->parent, msg)); + switch (lasso_idwsf2_data_service_get_request_type(service)) { + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY: + query_response = (LassoIdWsf2DstRefQueryResponse*)service->parent.parent.response; + lasso_check_good_rc(_lasso_idwsf2_data_service_process_query_response(service, query_response)); + break; + case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY: + rc = LASSO_ERROR_UNIMPLEMENTED; + break; + default: + rc = LASSO_ERROR_UNDEFINED; + break; + } + +cleanup: + return rc; +} + +/** + * lasso_idwsf2_data_service_get_response_status: + * @service: a #LassoIdWsf2UtilStatus object + * + * Return the status from the current response. + * + * Return value: a #LassoIdWsf2UtilStatus object, or NULL. + */ +LassoIdWsf2UtilStatus* +lasso_idwsf2_data_service_get_response_status(LassoIdWsf2DataService *service) +{ + LassoIdWsf2UtilResponse *response; + LassoSoapFault *fault; + + response = (void*)(fault = (void*)service->parent.parent.response); + if (LASSO_IS_IDWSF2_UTIL_RESPONSE(response)) { + return response->Status; + } + if (LASSO_IS_SOAP_FAULT(fault)) { + if (LASSO_IS_SOAP_DETAIL(fault->Detail) && fault->Detail->any + && LASSO_IS_IDWSF2_UTIL_STATUS(fault->Detail->any->data)) { + return (LassoIdWsf2UtilStatus*)fault->Detail->any->data; + } + } + return NULL; +} + +/** + * lasso_idwsf2_data_service_get_query_item_result: + * @service: a #LassoIdWsf2DataService object + * @item_id:(allow-none): an item_id or NULL if only one data is present + * + * Return value:(transfer none): a #LassoIdWsf2DstRefData or NULL if none is found. + */ +LassoIdWsf2DstRefData* +lasso_idwsf2_data_service_get_query_item_result(LassoIdWsf2DataService *service, + const char *item_id) +{ + GList *i; + + if (! LASSO_IS_IDWSF2_DATA_SERVICE(service)) + return NULL; + if (! item_id) { + if (g_list_length(service->private_data->query_datas) == 1) { + return (LassoIdWsf2DstRefData*)service->private_data->query_datas->data; + } + return NULL; + } + lasso_foreach(i, service->private_data->query_datas) { + LassoIdWsf2DstRefData *data = (LassoIdWsf2DstRefData*)i->data; + if (g_strcmp0(data->parent.itemIDRef, item_id) == 0) { + return data; + } + } + return NULL; +} + +/** + * lasso_idwsf2_data_service_get_query_item_results: + * @service: a #LassoIdWsf2DataService object + * + * Return value:(transfer none)(element-type LassoIdWsf2DstRefData): the list of + * #LassoIdWsf2DstRefData or NULL if none is found. + */ +GList* +lasso_idwsf2_data_service_get_query_item_results(LassoIdWsf2DataService *service) +{ + + if (LASSO_IS_IDWSF2_DATA_SERVICE(service) && service->private_data) { + return service->private_data->query_datas; + } + return NULL; +} static LassoNodeClass *parent_class = NULL; -static void -register_xpath_namespace(gchar *prefix, gchar *href, xmlXPathContext *xpathCtx) -{ - xmlXPathRegisterNs(xpathCtx, (xmlChar*)prefix, (xmlChar*)href); -} - -static void -lasso_register_idwsf2_xpath_namespaces(xmlXPathContext *xpathCtx) -{ - if (idwsf2_dst_services_by_prefix == NULL) - return; - g_hash_table_foreach(idwsf2_dst_services_by_prefix, - (GHFunc)register_xpath_namespace, xpathCtx); -} - -static GList* -duplicate_glist_of_xmlnodes(GList *list) -{ - GList *r = NULL; - GList *t; - - for (t = list; t; t = g_list_next(t)) { - r = g_list_append(r, xmlCopyNode(t->data, 1)); - } - - return r; -} - - -/*****************************************************************************/ -/* overrided parent class methods */ -/*****************************************************************************/ - static void dispose(GObject *object) { LassoIdWsf2DataService *service = LASSO_IDWSF2_DATA_SERVICE(object); + LassoIdWsf2DataServicePrivate *pdata = service->private_data; - if (service->private_data->dispose_has_run == TRUE) + if (pdata->dispose_has_run == TRUE) return; - service->private_data->dispose_has_run = TRUE; - - g_free(service->type); - service->type = NULL; - - g_free(service->redirect_url); - service->redirect_url = NULL; - - if (service->query_items != NULL) { - g_list_foreach(service->query_items, (GFunc)g_free, NULL); - g_list_free(service->query_items); - service->query_items = NULL; - } - lasso_release_gobject(service->private_data->epr); + pdata->dispose_has_run = TRUE; + lasso_idwsf2_data_service_clean_private_data(service); + g_hash_table_destroy(pdata->namespaces); + pdata->namespaces = NULL; G_OBJECT_CLASS(parent_class)->dispose(object); } @@ -1075,21 +905,12 @@ finalize(GObject *object) G_OBJECT_CLASS(parent_class)->finalize(object); } - -/*****************************************************************************/ -/* instance and class init functions */ -/*****************************************************************************/ - static void instance_init(LassoIdWsf2DataService *service) { - service->data = NULL; - service->type = NULL; - service->redirect_url = NULL; - service->query_items = NULL; service->private_data = g_new0(LassoIdWsf2DataServicePrivate, 1); - service->private_data->epr = NULL; - service->private_data->credentials = NULL; + service->private_data->namespaces = g_hash_table_new_full(g_str_hash, g_str_equal, + (GDestroyNotify)g_free, (GDestroyNotify)g_free); } static void @@ -1129,7 +950,7 @@ lasso_idwsf2_data_service_get_type() /** * lasso_idwsf2_data_service_new: - * @server: the #LassoServer + * @server:(allow-none): a #LassoServer object, for resolving ProviderIDs * * Create a new #LassoIdWsf2DataService. * @@ -1140,36 +961,8 @@ lasso_idwsf2_data_service_new(LassoServer *server) { LassoIdWsf2DataService *service; - g_return_val_if_fail(LASSO_IS_SERVER(server), NULL); - service = g_object_new(LASSO_TYPE_IDWSF2_DATA_SERVICE, NULL); - - LASSO_PROFILE(service)->server = g_object_ref(server); + service->parent.parent.server = lasso_ref(server); return service; } - -/** - * lasso_idwsf2_data_service_new_full: - * @server: the #LassoServer - * @epr: the #LassoWsAddrEndpointReference - * - * Create a new #LassoIdWsf2DataService. - * - * Return value: a newly created #LassoIdWsf2DataService object; or NULL if an error occured. - **/ -LassoIdWsf2DataService* -lasso_idwsf2_data_service_new_full(LassoServer *server, LassoWsAddrEndpointReference *epr) -{ - LassoIdWsf2DataService *service; - - g_return_val_if_fail(LASSO_IS_SERVER(server), NULL); - g_return_val_if_fail(LASSO_IS_WSA_ENDPOINT_REFERENCE(epr), NULL); - - service = lasso_idwsf2_data_service_new(server); - - service->private_data->epr = g_object_ref(epr); - - return service; -} - diff --git a/lasso/id-wsf-2.0/data_service.h b/lasso/id-wsf-2.0/data_service.h index 5f4fd919..9a0f5861 100644 --- a/lasso/id-wsf-2.0/data_service.h +++ b/lasso/id-wsf-2.0/data_service.h @@ -33,6 +33,8 @@ extern "C" { #include "profile.h" #include "../xml/xml.h" #include "../xml/id-wsf-2.0/dstref_query_item.h" +#include "../xml/id-wsf-2.0/util_status.h" +#include "../xml/id-wsf-2.0/dstref_data.h" #include "../xml/ws/wsa_endpoint_reference.h" @@ -55,12 +57,6 @@ typedef struct _LassoIdWsf2DataServicePrivate LassoIdWsf2DataServicePrivate; struct _LassoIdWsf2DataService { LassoIdWsf2Profile parent; - /*< public >*/ - xmlNode *data; - gchar *type; - gchar *redirect_url; - GList *query_items; /* of strings */ - /*< private >*/ LassoIdWsf2DataServicePrivate *private_data; }; @@ -69,54 +65,76 @@ struct _LassoIdWsf2DataServiceClass { LassoIdWsf2ProfileClass parent; }; +typedef enum { + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_UNKNOWN, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_CREATE, + LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_DELETE +} LassoIdWsf2DataServiceRequestType; + LASSO_EXPORT GType lasso_idwsf2_data_service_get_type(void); +/* Service initialization */ LASSO_EXPORT LassoIdWsf2DataService* lasso_idwsf2_data_service_new(LassoServer *server); -LASSO_EXPORT LassoIdWsf2DataService* lasso_idwsf2_data_service_new_full(LassoServer *server, - LassoWsAddrEndpointReference *epr); - +/* Request initialization */ LASSO_EXPORT gint lasso_idwsf2_data_service_init_query(LassoIdWsf2DataService *service); - -LASSO_EXPORT gint lasso_idwsf2_data_service_add_query_item( - LassoIdWsf2DataService *service, const gchar *item_xpath, const gchar *item_id); - -LASSO_EXPORT gint lasso_idwsf2_data_service_process_query_msg(LassoIdWsf2DataService *service, - const gchar *message); - -LASSO_EXPORT gint lasso_idwsf2_data_service_parse_query_items(LassoIdWsf2DataService *service); - -LASSO_EXPORT gint lasso_idwsf2_data_service_process_query_response_msg( - LassoIdWsf2DataService *service, const gchar *message); - -LASSO_EXPORT GList* lasso_idwsf2_data_service_get_attribute_nodes(LassoIdWsf2DataService *service, - const gchar *item_id); - -LASSO_EXPORT xmlNode* lasso_idwsf2_data_service_get_attribute_node(LassoIdWsf2DataService *service, - const gchar *item_id); - -LASSO_EXPORT GList* lasso_idwsf2_data_service_get_attribute_strings(LassoIdWsf2DataService *service, - const gchar *item_id); - -LASSO_EXPORT gchar* lasso_idwsf2_data_service_get_attribute_string(LassoIdWsf2DataService *service, - const gchar *item_id); - -LASSO_EXPORT gint lasso_idwsf2_data_service_init_redirect_user_for_consent( - LassoIdWsf2DataService *service, const gchar *redirect_url); - LASSO_EXPORT gint lasso_idwsf2_data_service_init_modify(LassoIdWsf2DataService *service); +LASSO_EXPORT gint lasso_idwsf2_data_service_init_create(LassoIdWsf2DataService *service); +LASSO_EXPORT gint lasso_idwsf2_data_service_init_delete(LassoIdWsf2DataService *service); +LASSO_EXPORT gint lasso_idwsf2_data_service_set_service_type(LassoIdWsf2DataService *service, + const char *prefix, const char *service_type); +LASSO_EXPORT const char* lasso_idwsf2_data_service_get_service_type( + LassoIdWsf2DataService *service); +LASSO_EXPORT const char* lasso_idwsf2_data_service_get_service_type_prefix( + LassoIdWsf2DataService *service); -LASSO_EXPORT gint lasso_idwsf2_data_service_add_modify_item( - LassoIdWsf2DataService *service, const gchar *item_xpath, const gchar *item_id, - const gchar *new_data, gboolean overrideAllowed); +/* Manipulate request */ +LASSO_EXPORT LassoIdWsf2DataServiceRequestType lasso_idwsf2_data_service_get_request_type( + LassoIdWsf2DataService *service); +LASSO_EXPORT gint lasso_idwsf2_data_service_add_query_item( + LassoIdWsf2DataService *service, const gchar *item_query, const gchar *item_id); +LASSO_EXPORT gint lasso_idwsf2_data_service_add_modify_item(LassoIdWsf2DataService *service, + const gchar *item_query, xmlNode *new_data, gboolean overrideAllowed, + const gchar *item_id); +LASSO_EXPORT gint lasso_idwsf2_data_service_add_namespace(LassoIdWsf2DataService *data_service, + const char *prefix, const char *href); -LASSO_EXPORT gint lasso_idwsf2_data_service_process_modify_msg(LassoIdWsf2DataService *service, - const gchar *message); +/* Produce request */ +LASSO_EXPORT gint lasso_idwsf2_data_service_build_request_msg(LassoIdWsf2DataService *service, + const char *security_mech_id); -LASSO_EXPORT gint lasso_idwsf2_data_service_parse_modify_items(LassoIdWsf2DataService *service); +/* Handle request */ +LASSO_EXPORT gint lasso_idwsf2_data_service_process_request_msg(LassoIdWsf2DataService *service, + const char *msg); +LASSO_EXPORT GList *lasso_idwsf2_data_service_get_item_ids(LassoIdWsf2DataService *data_service); +LASSO_EXPORT GList *lasso_idwsf2_data_service_get_items(LassoIdWsf2DataService *data_service); +LASSO_EXPORT LassoNode* lasso_idwsf2_data_service_get_item(LassoIdWsf2DataService *data_service, + const char *item_id); -LASSO_EXPORT gint lasso_idwsf2_data_service_process_modify_response_msg( - LassoIdWsf2DataService *service, const gchar *message); +/* Reponse initialization */ +LASSO_EXPORT gint lasso_idwsf2_data_service_init_response(LassoIdWsf2DataService *service); +LASSO_EXPORT gint lasso_idwsf2_data_service_set_status_code(LassoIdWsf2DataService *service, + const char *status_code, const char *status_code2); + +/* Manipulate response */ +LASSO_EXPORT gint lasso_idwsf2_data_service_set_query_item_result( + LassoIdWsf2DataService *data_service, const char *item_id, xmlNode *xml_data, + gboolean add); + +/* Produce response */ +LASSO_EXPORT gint lasso_idwsf2_data_service_build_response_msg(LassoIdWsf2DataService *service); + +/* Handle response */ +LASSO_EXPORT gint lasso_idwsf2_data_service_process_response_msg( + LassoIdWsf2DataService *service, const char *msg); +LASSO_EXPORT LassoIdWsf2UtilStatus *lasso_idwsf2_data_service_get_response_status( + LassoIdWsf2DataService *service); +LASSO_EXPORT LassoIdWsf2DstRefData* lasso_idwsf2_data_service_get_query_item_result( + LassoIdWsf2DataService *service, const char *item_id); +LASSO_EXPORT GList* lasso_idwsf2_data_service_get_query_item_results( + LassoIdWsf2DataService *service); #ifdef __cplusplus } diff --git a/lasso/id-wsf-2.0/discovery.c b/lasso/id-wsf-2.0/discovery.c index 2ebb651d..203d5c57 100644 --- a/lasso/id-wsf-2.0/discovery.c +++ b/lasso/id-wsf-2.0/discovery.c @@ -38,6 +38,8 @@ #include +#include "../saml-2.0/saml2_helper.h" + #include "../xml/saml_attribute_value.h" #include "../xml/xml_enc.h" @@ -45,19 +47,32 @@ #include "../xml/saml-2.0/samlp2_name_id_policy.h" #include "../xml/id-wsf-2.0/disco_query.h" -#include "../xml/id-wsf-2.0/disco_requested_service.h" +#include "../xml/id-wsf-2.0/disco_query_response.h" +#include "../xml/id-wsf-2.0/disco_svc_md_query.h" +#include "../xml/id-wsf-2.0/disco_svc_md_query_response.h" #include "../xml/id-wsf-2.0/disco_svc_md_register.h" #include "../xml/id-wsf-2.0/disco_svc_md_register_response.h" +#include "../xml/id-wsf-2.0/disco_svc_md_replace.h" +#include "../xml/id-wsf-2.0/disco_svc_md_replace_response.h" +#include "../xml/id-wsf-2.0/disco_svc_md_delete.h" +#include "../xml/id-wsf-2.0/disco_svc_md_delete_response.h" +#include "../xml/id-wsf-2.0/disco_svc_md_association_query.h" +#include "../xml/id-wsf-2.0/disco_svc_md_association_query_response.h" #include "../xml/id-wsf-2.0/disco_svc_md_association_add.h" #include "../xml/id-wsf-2.0/disco_svc_md_association_add_response.h" -#include "../xml/id-wsf-2.0/disco_svc_md_association_add_response.h" +#include "../xml/id-wsf-2.0/disco_svc_md_association_delete.h" +#include "../xml/id-wsf-2.0/disco_svc_md_association_delete_response.h" +#include "../xml/id-wsf-2.0/disco_requested_service.h" #include "../xml/id-wsf-2.0/disco_abstract.h" #include "../xml/id-wsf-2.0/disco_provider_id.h" #include "../xml/id-wsf-2.0/disco_service_type.h" #include "../xml/id-wsf-2.0/disco_security_context.h" #include "../xml/id-wsf-2.0/disco_service_context.h" #include "../xml/id-wsf-2.0/disco_endpoint_context.h" +#include "../xml/id-wsf-2.0/disco_options.h" #include "../xml/id-wsf-2.0/sec_token.h" +#include "../xml/id-wsf-2.0/util_status.h" +#include "../xml/id-wsf-2.0/sbf_framework.h" #include "../xml/ws/wsa_endpoint_reference.h" @@ -65,254 +80,235 @@ #include "../id-ff/provider.h" #include "../id-ff/providerprivate.h" -#include "discovery.h" -#include "profile.h" -#include "identity.h" -#include "server.h" -#include "session.h" +#include "./discovery.h" +#include "./soap_binding.h" +#include "./idwsf2_helper.h" #include "../utils.h" struct _LassoIdWsf2DiscoveryPrivate { gboolean dispose_has_run; - GList *new_entry_ids; - char *security_mech_id; + GList *metadatas; /* of LassoIdWsf2DiscoSvcMetadata* */ + GList *requested_services; /* of LassoIdWsf2DiscoRequestedService */ + GList *svc_md_ids; /* of utf8 */ }; -/*****************************************************************************/ -/* public methods */ -/*****************************************************************************/ + +static void +lasso_idwsf2_discovery_add_identity_to_epr(LassoIdWsf2Discovery *discovery, + LassoWsAddrMetadata *epr_metadata, + const char *provider_id, + const char *security_mech_id) +{ + LassoIdentity *identity = discovery->parent.parent.identity; + LassoFederation *federation = NULL; + LassoSaml2Assertion *assertion; + LassoProvider *provider = NULL; + LassoIdWsf2DiscoSecurityContext *security_context; + LassoIdWsf2SecToken *sec_token; + LassoSaml2NameID *name_id; + + if (LASSO_IS_IDENTITY(identity)) + return; + + federation = lasso_identity_get_federation(identity, provider_id); + if (federation == NULL || ! LASSO_IS_SAML2_NAME_ID(federation->remote_nameIdentifier)) + return; + name_id = (LassoSaml2NameID*)federation->remote_nameIdentifier; + assertion = (LassoSaml2Assertion*)lasso_saml2_assertion_new(); + provider = lasso_server_get_provider(discovery->parent.parent.server, provider_id); + if (provider) + lasso_saml2_assertion_set_subject_name_id(assertion, + (LassoNode*)lasso_saml2_encrypted_element_build_encrypted_persistent_name_id( + name_id->content, + name_id->NameQualifier, + provider)); + else + lasso_saml2_assertion_set_subject_name_id(assertion, + (LassoNode*)lasso_saml2_name_id_build_persistent( + name_id->content, + name_id->NameQualifier, + provider_id)); + + sec_token = (LassoIdWsf2SecToken*)lasso_idwsf2_sec_token_new(); + sec_token->any = (LassoNode*)assertion; + security_context = (LassoIdWsf2DiscoSecurityContext*) + lasso_idwsf2_disco_security_context_new(); + lasso_list_add_string(security_context->SecurityMechID, + security_mech_id); + lasso_list_add_new_gobject(epr_metadata->any, security_context); +} + + + +static LassoWsAddrEndpointReference* +lasso_idwsf2_discovery_build_epr(LassoIdWsf2Discovery *discovery, + LassoIdWsf2DiscoSvcMetadata *svc_metadata, + LassoIdWsf2DiscoServiceContext *service_context, + LassoIdWsf2DiscoEndpointContext *endpoint_context) +{ + LassoIdentity *identity; + LassoWsAddrEndpointReference *epr = NULL; + LassoWsAddrMetadata *metadata = NULL; + LassoIdWsf2DiscoAbstract *abstract; + LassoIdWsf2DiscoProviderID *provider_id; + LassoIdWsf2DiscoServiceType *service_type; + LassoProvider *provider = NULL; + GList *i; + + + if (LASSO_IS_IDENTITY(discovery->parent.parent.identity)) { + identity = discovery->parent.parent.identity; + } + epr = lasso_wsa_endpoint_reference_new(); + epr->Address = lasso_wsa_attributed_uri_new_with_string( + (gchar*)endpoint_context->Address->data); + metadata = lasso_wsa_metadata_new(); + /* Abstract */ + if (svc_metadata->Abstract) { + abstract = lasso_idwsf2_disco_abstract_new_with_string(svc_metadata->Abstract); + lasso_list_add_new_gobject(metadata->any, abstract); + } + /* ProviderID */ + if (svc_metadata->ProviderID) { + provider_id = lasso_idwsf2_disco_provider_id_new_with_string(svc_metadata->ProviderID); + provider = lasso_server_get_provider(discovery->parent.parent.server, svc_metadata->ProviderID); + lasso_list_add_new_gobject(metadata->any, provider_id); + } + /* ServiceType */ + lasso_foreach(i, service_context->ServiceType) + { + service_type = lasso_idwsf2_disco_service_type_new_with_string(i->data); + lasso_list_add_new_gobject(metadata->any, service_type); + } + /* Framework */ + lasso_foreach(i, endpoint_context->Framework) + { + lasso_list_add_gobject(metadata->any, i->data); + } + /* Identity token */ + lasso_foreach(i, endpoint_context->SecurityMechID) + { + lasso_idwsf2_discovery_add_identity_to_epr(discovery, + metadata, + svc_metadata->ProviderID, + (char*)i->data); + } + + epr->Metadata = metadata; + return epr; +} + +static gint +lasso_idwsf2_discovery_status2rc(LassoIdWsf2UtilStatus *status) +{ + size_t i = 0; + static struct { + const char *code; + int rc; + } code2rc[] = { + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_OK, 0}, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_FAILED, LASSO_IDWSF2_DISCOVERY_ERROR_FAILED }, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_FORBIDDEN, LASSO_IDWSF2_DISCOVERY_ERROR_FORBIDDEN }, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_DUPLICATE, LASSO_IDWSF2_DISCOVERY_ERROR_DUPLICATE }, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_LOGICAL_DUPLICATE, + LASSO_IDWSF2_DISCOVERY_ERROR_LOGICAL_DUPLICATE }, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_NO_RESULTS, LASSO_IDWSF2_DISCOVERY_ERROR_NO_RESULTS }, + { LASSO_IDWSF2_DISCOVERY_STATUS_CODE_NOT_FOUND, LASSO_IDWSF2_DISCOVERY_ERROR_NOT_FOUND } + }; + + if (! LASSO_IS_IDWSF2_UTIL_STATUS(status) || ! status->code) + return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; + + for (i = 0; i < G_N_ELEMENTS(code2rc); ++i) { + if (g_strcmp0(status->code, code2rc[i].code) == 0) { + return code2rc[i].rc; + } + } + return LASSO_WSF_PROFILE_ERROR_UNKNOWN_STATUS_CODE; +} + +#define declare_init_request(name, request_element_type, constructor) \ +gint \ +lasso_idwsf2_discovery_init_##name(LassoIdWsf2Discovery *discovery) \ +{ \ + LassoIdWsf2Profile *idwsf2_profile = NULL; \ + LassoProfile *profile = NULL; \ + request_element_type *request_element = NULL; \ + LassoSoapEnvelope *envelope = NULL; \ + int rc = 0; \ + \ + lasso_bad_param(IDWSF2_DISCOVERY, discovery); \ + \ + lasso_release_list_of_gobjects(discovery->private_data->metadatas) \ + lasso_release_list_of_gobjects(discovery->private_data->requested_services) \ + idwsf2_profile = &discovery->parent; \ + profile = &idwsf2_profile->parent; \ + lasso_check_good_rc(lasso_idwsf2_profile_init_request(idwsf2_profile)); \ + request_element = constructor(); \ + envelope = lasso_idwsf2_profile_get_soap_envelope_request(idwsf2_profile); \ + lasso_assign_new_gobject(profile->request, request_element); \ + lasso_soap_envelope_add_to_body(envelope, (LassoNode*)request_element); \ + \ +cleanup: \ + return rc; \ +} + +/* Metadata requests */ /** - * lasso_idwsf2_discovery_metadata_register_self: + * lasso_idwsf2_discovery_init_query * @discovery: a #LassoIdWsf2Discovery - * @service_type: the service type of the registered metadata, for example LASSO_IDWSF2_DISCO_HREF - * @abstract: label/title of the service, free form - * @soap_endpoint: URL of the SoapEndpoint to the service - * @svcMDID: identifier of the metadatas if caller wants to specify which identifier it wants. - * If NULL, a random identifier will be generated. * - * Register metadata service on itself as an ID-WSF Provider (WSP). - * Typically used for an IdP to register itself as Discovery service. - * - * Return value: the svcMDID of the new metadata object if the call is successfull, NULL otherwise. These - * value must be freed using g_free. + * Initialise a request for ID-WSF discovery Query to a discovery service. + * + * Return value: 0 on success; or a negative value otherwise. **/ -gchar* -lasso_idwsf2_discovery_metadata_register_self(LassoIdWsf2Discovery *discovery, - const gchar *service_type, const gchar *abstract, - const gchar *soap_endpoint, const gchar *svcMDID) -{ - LassoIdWsf2Profile *profile; - LassoProvider *provider; - gchar *provider_id; - LassoIdWsf2DiscoSvcMetadata *metadata; - char *new_svcMDID; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), NULL); - g_return_val_if_fail(service_type != NULL && service_type[0] != '\0', NULL); - g_return_val_if_fail(abstract != NULL && abstract[0] != '\0', NULL); - g_return_val_if_fail(soap_endpoint != NULL && soap_endpoint[0] != '\0', NULL); - - profile = LASSO_IDWSF2_PROFILE(discovery); - provider = LASSO_PROVIDER(LASSO_PROFILE(profile)->server); - provider_id = provider->ProviderID; - metadata = lasso_idwsf2_disco_svc_metadata_new_full( - service_type, abstract, provider_id, soap_endpoint); - if (svcMDID != NULL) { - metadata->svcMDID = g_strdup(svcMDID); - } else { - metadata->svcMDID = lasso_build_unique_id(32); - } - lasso_server_add_svc_metadata(LASSO_PROFILE(profile)->server, metadata); - new_svcMDID = g_strdup(metadata->svcMDID); - g_object_unref(metadata); - - return new_svcMDID; -} +declare_init_request(query, LassoIdWsf2DiscoQuery, lasso_idwsf2_disco_query_new) /** * lasso_idwsf2_discovery_init_metadata_register: - * @discovery: a #LassoIdWsf2Discovery - * @service_type: the service type of the registered metadata, for example LASSO_IDWSF2_DISCO_HREF - * @abstract: label/title of the service, free form - * @disco_provider_id: provider identifier of the discovery service - * @soap_endpoint: URL of the SoapEndpoint to the service + * @discovery: a #LassoIdWsf2Discovery object * - * Initialise a ID-WSF service metadata registration request to a Discovery service - * specified by disco_provider_id. + * Initialise a ID-WSF service metadata registration request to a Discovery service. * * Return value: 0 on success; an error code otherwise. **/ -gint -lasso_idwsf2_discovery_init_metadata_register(LassoIdWsf2Discovery *discovery, - const gchar *service_type, const gchar *abstract, - const gchar *disco_provider_id, const gchar *soap_endpoint) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoSvcMDRegister *metadata_register; - LassoProvider *provider; - gchar *sp_provider_id; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(service_type != NULL && service_type[0] != '\0', - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(abstract != NULL && abstract[0] != '\0', - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(disco_provider_id != NULL && disco_provider_id[0] != '\0', - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(soap_endpoint != NULL && soap_endpoint[0] != '\0', - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - /* Get the providerId of this SP */ - provider = LASSO_PROVIDER(LASSO_PROFILE(profile)->server); - sp_provider_id = provider->ProviderID; - - /* Get a MetadataRegister node */ - metadata_register = lasso_idwsf2_disco_svc_md_register_new_full( - service_type, abstract, sp_provider_id, soap_endpoint); - - /* Create a request with this xml node */ - lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(metadata_register), - LASSO_IDWSF2_DISCO_HREF); - - return 0; -} +declare_init_request(metadata_register, LassoIdWsf2DiscoSvcMDRegister, + lasso_idwsf2_disco_svc_md_register_new); /** - * lasso_idwsf2_discovery_process_metadata_register_msg: - * @discovery: a #LassoIdWsf2Discovery - * @message: received metadata register soap request + * lasso_idwsf2_discovery_init_metadata_replace: + * @discovery: a #LassoIdWsf2Discovery object * - * Process received metadata register request. - * If successful, register the service metadata into the discovery service. + * Initialise a ID-WSF service metadata replace request to a Discovery service. * - * Return value: 0 on success; or a negative value otherwise. + * Return value: 0 on success; an error code otherwise. **/ -gint -lasso_idwsf2_discovery_process_metadata_register_msg(LassoIdWsf2Discovery *discovery, - const gchar *message) -{ - LassoIdWsf2Profile *profile; - LassoIdWsf2DiscoSvcMDRegisterResponse *response; - LassoSoapEnvelope *envelope; - int rc = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - profile = LASSO_IDWSF2_PROFILE(discovery); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - rc = lasso_idwsf2_profile_process_soap_request_msg(profile, message); - if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_REGISTER(LASSO_PROFILE(profile)->request)) { - rc = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* OK case */ - if (rc == 0) { - LassoIdWsf2DiscoSvcMDRegister *request; - GList *SvcMD; - - lasso_release_list_of_gobjects(discovery->metadatas); - - request = LASSO_IDWSF2_DISCO_SVC_MD_REGISTER(LASSO_PROFILE(profile)->request); - /* Allocate an ID and add the metadatas */ - for (SvcMD = request->SvcMD; SvcMD != NULL; SvcMD = g_list_next(SvcMD)) { - if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(SvcMD->data)) { - lasso_list_add_gobject(discovery->metadatas, SvcMD->data); - lasso_assign_new_string( - LASSO_IDWSF2_DISCO_SVC_METADATA( - SvcMD->data)->svcMDID, - lasso_build_unique_id(32)); - lasso_server_add_svc_metadata(LASSO_PROFILE(profile)->server, - LASSO_IDWSF2_DISCO_SVC_METADATA(SvcMD->data)); - } - } - } - - /* Build response */ - response = lasso_idwsf2_disco_svc_md_register_response_new(); - - /* OK case */ - if (rc == 0) { - GList *SvcMDs; - /* Return the allocated IDs */ - response->Status = - lasso_idwsf2_util_status_new_with_code(LASSO_DISCO_STATUS_CODE_OK, NULL); - for (SvcMDs = discovery->metadatas; SvcMDs != NULL; SvcMDs = g_list_next(SvcMDs)) { - lasso_list_add_string(response->SvcMDID, - LASSO_IDWSF2_DISCO_SVC_METADATA(SvcMDs->data)->svcMDID); - } - /* KO case */ - } else { - /* Return a failed status, with a second level code for explanation */ - response->Status = - lasso_idwsf2_util_status_new_with_code(LASSO_DISCO_STATUS_CODE_FAILED, - lasso_strerror(rc)); - } - - lasso_assign_new_gobject(profile->soap_envelope_response, - lasso_idwsf2_profile_build_soap_envelope(NULL, - LASSO_PROVIDER(LASSO_PROFILE(profile)->server)->ProviderID)); - - if (LASSO_IS_SOAP_ENVELOPE(profile->soap_envelope_response)) { - envelope = profile->soap_envelope_response; - envelope->Body->any = g_list_append(envelope->Body->any, response); - } else { - rc = LASSO_SOAP_ERROR_MISSING_ENVELOPE; - g_critical("soap_envelope_response is missing"); - } - - return rc; -} +declare_init_request(metadata_replace, LassoIdWsf2DiscoSvcMDReplace, + lasso_idwsf2_disco_svc_md_replace_new); /** - * lasso_idwsf2_discovery_process_metadata_register_response_msg: - * @discovery: a #LassoIdWsf2Discovery - * @message: received metadata register soap response + * lasso_idwsf2_discovery_init_metadata_query: + * @discovery: a #LassoIdWsf2Discovery object * - * Process received metadata register response. - * Check response status code. - * If successful, save into @discovery->svcMDID the service metadata identifier - * found in the response. + * Initialise a ID-WSF service metadata query request to a Discovery service * - * Return value: 0 on success; or a negative value otherwise. + * Return value: 0 on success; an error code otherwise. **/ -gint -lasso_idwsf2_discovery_process_metadata_register_response_msg(LassoIdWsf2Discovery *discovery, - const gchar *message) -{ - LassoIdWsf2Profile *profile; - LassoIdWsf2DiscoSvcMDRegisterResponse *response; - int rc = 0; +declare_init_request(metadata_query, LassoIdWsf2DiscoSvcMDQuery, + lasso_idwsf2_disco_svc_md_query_new); - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - profile = LASSO_IDWSF2_PROFILE(discovery); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - /* Process response */ - rc = lasso_idwsf2_profile_process_soap_response_msg(profile, message); - - if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_REGISTER_RESPONSE(LASSO_PROFILE(profile)->response)) { - rc = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* If the response has been correctly processed, */ - /* put interesting data into the discovery object */ - if (rc == 0) { - response = LASSO_IDWSF2_DISCO_SVC_MD_REGISTER_RESPONSE( - LASSO_PROFILE(profile)->response); - if (response->SvcMDID != NULL) { - lasso_assign_list_of_strings(discovery->svcMDIDs, response->SvcMDID); - } else { - rc = LASSO_DISCOVERY_ERROR_SVC_METADATA_REGISTER_FAILED; - } - } - - return rc; -} +/** + * lasso_idwsf2_discovery_init_metadata_delete: + * @discovery: a #LassoIdWsf2Discovery object + * + * Initialise a ID-WSF service metadata query request to a Discovery service + * + * Return value: 0 on success; an error code otherwise. + **/ +declare_init_request(metadata_delete, LassoIdWsf2DiscoSvcMDDelete, + lasso_idwsf2_disco_svc_md_delete_new); /** * lasso_idwsf2_discovery_init_metadata_association_add: @@ -324,609 +320,945 @@ lasso_idwsf2_discovery_process_metadata_register_response_msg(LassoIdWsf2Discove * * Return value: 0 on success; or a negative value otherwise. **/ -gint -lasso_idwsf2_discovery_init_metadata_association_add(LassoIdWsf2Discovery *discovery, - const gchar *svcMDID) +declare_init_request(metadata_association_add, LassoIdWsf2DiscoSvcMDAssociationAdd, + lasso_idwsf2_disco_svc_md_association_add_new) + +declare_init_request(metadata_association_delete, LassoIdWsf2DiscoSvcMDAssociationDelete, + lasso_idwsf2_disco_svc_md_association_delete_new) +declare_init_request(metadata_association_query, LassoIdWsf2DiscoSvcMDAssociationQuery, + lasso_idwsf2_disco_svc_md_association_query_new) + + +/** + * lasso_idwsf2_discovery_add_service_metadata: + * @idwsf2_discovery: a #LassoIdWsf2Discovery object + * @service_metadata: a #LassoIdWsf2DiscoSvcMetadata object to add to the register request. + * + * Add a new metadata object to a request. + * + * Return value: 0 if successful, an error code otherwise. + */ +int +lasso_idwsf2_discovery_add_service_metadata(LassoIdWsf2Discovery *discovery, + LassoIdWsf2DiscoSvcMetadata *service_metadata) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoSession *session = LASSO_PROFILE(profile)->session; - LassoIdWsf2DiscoSvcMDAssociationAdd *md_association_add; - LassoWsAddrEndpointReference *epr; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(svcMDID != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); - - /* Build a MetadataRegister node */ - md_association_add = lasso_idwsf2_disco_svc_md_association_add_new(); - md_association_add->SvcMDID = g_list_append(md_association_add->SvcMDID, g_strdup(svcMDID)); - - /* Create a request with this xml node */ - lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(md_association_add), - LASSO_IDWSF2_DISCO_HREF); - - epr = lasso_session_get_endpoint_reference(session, LASSO_IDWSF2_DISCO_HREF); - if (epr != NULL) { - LASSO_PROFILE(profile)->msg_url = g_strdup(epr->Address->content); - } - + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + lasso_bad_param(IDWSF2_DISCO_SVC_METADATA, service_metadata); + lasso_list_add_gobject(discovery->private_data->metadatas, + service_metadata); return 0; } /** - * lasso_idwsf2_discovery_process_metadata_association_add_msg: - * @discovery: a #LassoIdWsf2Discovery - * @message: received metadata association add soap request + * lasso_idwsf2_discovery_add_simple_service_metadata: + * @idwsf2_discovery: a #LassoIdWsf2Discovery object + * @abstract:(allow-none): a human description of the service + * @provider_id:(allow-none): the provider id of the service to register, if none is given, + * providerId of the current #LassoServer object is used + * @service_types:(element-type utf8)(allow-none): an array of service type URIs + * @options:(element-type LassoIdWsf2DiscoOptions)(allow-none): an array of option string + * @address:(allow-none): the URI of the service endpoint for the default EndpointContext + * @security_mech_ids:(allow-none)(element-type utf8): the security mechanisms supported by the service * - * Process received metadata association add request. + * Add new metadata to the current Metadata Register request. * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_process_metadata_association_add_msg(LassoIdWsf2Discovery *discovery, - const gchar *message) + * Return value: 0 if successful, an error code otherwise. + */ +int +lasso_idwsf2_discovery_add_simple_service_metadata(LassoIdWsf2Discovery *idwsf2_discovery, + const char *abstract, const char *provider_id, GList *service_types, GList *options, + const char *address, GList *security_mech_ids) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; - LassoSoapEnvelope *envelope; - int res = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - /* Process request */ - res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); - - if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* Build response */ - response = lasso_idwsf2_disco_svc_md_association_add_response_new(); - - envelope = profile->soap_envelope_response; - envelope->Body->any = g_list_append(envelope->Body->any, response); - - lasso_assign_gobject(LASSO_PROFILE(profile)->response, LASSO_NODE(response)); - - return res; -} - -/** - * lasso_idwsf2_discovery_register_metadata: - * @discovery: a #LassoIdWsf2Discovery - * - * Add service metadata identifier into user identity object. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_register_metadata(LassoIdWsf2Discovery *discovery) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoSvcMDAssociationAdd *request; - LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; - LassoIdentity *identity; - GList *i; - int res = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - /* verify if identity already exists else create it */ - if (LASSO_PROFILE(profile)->identity == NULL) { - LASSO_PROFILE(profile)->identity = lasso_identity_new(); - } - identity = LASSO_PROFILE(profile)->identity; - - if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } else if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( - LASSO_PROFILE(profile)->response)) { - res = LASSO_PROFILE_ERROR_MISSING_RESPONSE; - } - - /* If the request has been correctly processed, */ - /* put interesting data into the discovery object */ - request = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request); - /* Copy the service metadatas with given svcMDIDs into the identity object */ - for (i = g_list_first(request->SvcMDID); i != NULL; i = g_list_next(i)) { - lasso_identity_add_svc_md_id(identity, (gchar *)(i->data)); - } - - /* Set response status code */ - response = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( - LASSO_PROFILE(profile)->response); - if (res == 0) { - response->Status = lasso_idwsf2_util_status_new(); - response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_OK); - } else { - response->Status = lasso_idwsf2_util_status_new(); - response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_FAILED); - } - - return res; -} - -/** - * lasso_idwsf2_discovery_process_metadata_association_add_response_msg: - * @discovery: a #LassoIdWsf2Discovery - * @message: received metadata association add soap response - * - * Process received metadata association add response. - * Check response status code. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_process_metadata_association_add_response_msg( - LassoIdWsf2Discovery *discovery, const gchar *message) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; - int res = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - /* Process response */ - res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); - if (res != 0) { - return res; - } - - if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( - LASSO_PROFILE(profile)->response)) { - return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* Check response status code */ - response = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( - LASSO_PROFILE(profile)->response); - if (response->Status == NULL || response->Status->code == NULL) { - return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } - if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0) { - return LASSO_DISCOVERY_ERROR_SVC_METADATA_ASSOCIATION_ADD_FAILED; - } - - return 0; -} - -/** - * lasso_idwsf2_discovery_init_query - * @discovery: a #LassoIdWsf2Discovery - * @security_mech_id: obsolete ; can be NULL - * - * Initialise a request for ID-WSF discovery Query to a discovery service. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_init_query(LassoIdWsf2Discovery *discovery, G_GNUC_UNUSED const gchar *security_mech_id) -{ - /* FIXME: add support of security mechanims */ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoSession *session = LASSO_PROFILE(profile)->session; - LassoWsAddrEndpointReference *epr; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); - - lasso_assign_new_gobject(LASSO_PROFILE(profile)->request, (LassoNode*)lasso_idwsf2_disco_query_new()); - - lasso_idwsf2_profile_init_soap_request(profile, - LASSO_PROFILE(profile)->request, LASSO_IDWSF2_DISCO_HREF); - - epr = lasso_session_get_endpoint_reference(session, LASSO_IDWSF2_DISCO_HREF); - if (epr != NULL) { - LASSO_PROFILE(profile)->msg_url = g_strdup(epr->Address->content); - } - - return 0; -} - -/** - * lasso_idwsf2_discovery_add_requested_service_type - * @discovery: a #LassoIdWsf2Discovery - * @service_type: the service type (or data profile) requested - * - * Select the requested service type which will be queried. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_add_requested_service_type(LassoIdWsf2Discovery *discovery, - const gchar *service_type) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoQuery *query; - LassoIdWsf2DiscoRequestedService *service; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request), - LASSO_PROFILE_ERROR_MISSING_REQUEST); - - query = LASSO_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request); - service = lasso_idwsf2_disco_requested_service_new(); - service->ServiceType = g_list_append(service->ServiceType, g_strdup(service_type)); - query->RequestedService = g_list_append(query->RequestedService, service); - - return 0; -} - -/** - * lasso_idwsf2_discovery_process_query_msg: - * @discovery: a #LassoIdWsf2Discovery - * @message: received query soap request - * - * Process received query request. - * - * Return value: 0 on success; or a negative value otherwise. - **/ -gint -lasso_idwsf2_discovery_process_query_msg(LassoIdWsf2Discovery *discovery, const gchar *message) -{ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - int res = 0; - - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - /* Process request */ - res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); - - if (! LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - return res; -} - -/** - * lasso_idwsf2_discovery_build_epr: - * @service: a #LassoIdWsf2DiscoRequestedService containing the query criteria - * @identity: a #LassoIdentity of the current user - * @server: current #LassoServer - * - * Build an EndpointReference (EPR) which contains all the information about a WSP providing - * the requested service type and matching other query criteria to allow a WSC to request it. - * - * Return value: the newly built EPR; or NULL if no WSP match the query criteria. - **/ -static LassoWsAddrEndpointReference* -lasso_idwsf2_discovery_build_epr(LassoIdWsf2DiscoRequestedService *service, - LassoIdentity *identity, LassoServer *server) -{ - gchar *service_type = NULL; - GList *svcMDIDs; - GList *svcMDs; - LassoIdWsf2DiscoSvcMetadata *svcMD; - LassoWsAddrEndpointReference *epr; - LassoWsAddrMetadata *metadata; - LassoIdWsf2DiscoSecurityContext *security_context; - LassoIdWsf2SecToken *sec_token; - LassoSaml2Assertion *assertion; - LassoSaml2Subject *subject; - LassoFederation* federation; - LassoProvider *provider; - LassoSaml2EncryptedElement *encrypted_element; - LassoIdWsf2DiscoEndpointContext *endpoint_context; + LassoIdWsf2DiscoSvcMetadata *service_metadata; LassoIdWsf2DiscoServiceContext *service_context; + LassoIdWsf2DiscoEndpointContext *endpoint_context; + int rc = 0; - if (service != NULL && service->ServiceType != NULL && service->ServiceType->data != NULL) { - service_type = (gchar *)service->ServiceType->data; - } else { - /* Can only search for service type at the moment */ + lasso_bad_param(IDWSF2_DISCOVERY, idwsf2_discovery); + lasso_check_non_empty_string(address); + service_metadata = lasso_idwsf2_disco_svc_metadata_new(); + if (abstract) { + lasso_assign_string(service_metadata->Abstract, abstract); + } + if (provider_id) { + lasso_assign_string(service_metadata->ProviderID, provider_id); + } + service_context = lasso_idwsf2_disco_service_context_new(); + if (service_types) { + lasso_assign_list_of_strings(service_context->ServiceType, service_types); + } + if (options) { + lasso_assign_list_of_gobjects(service_context->Options, options); + } + endpoint_context = lasso_idwsf2_disco_endpoint_context_new(); + if (address) { + lasso_list_add_string(endpoint_context->Address, address); + } + lasso_list_add_new_gobject(endpoint_context->Framework, lasso_idwsf2_sbf_framework_new_full("2.0")); + if (security_mech_ids) { + lasso_list_add_gstrv(endpoint_context->SecurityMechID, security_mech_ids); + } + + lasso_list_add_new_gobject(service_context->EndpointContext, endpoint_context); + lasso_list_add_new_gobject(service_metadata->ServiceContext, service_context); + + rc = lasso_idwsf2_discovery_add_service_metadata(idwsf2_discovery, service_metadata); + lasso_release_gobject(service_metadata); +cleanup: + return rc; +} + +/** + * lasso_idwsf2_discovery_get_metadatas: + * @discovery: a #LassoIdWsf2Discovery object + * + * Return the current list of metadatas in the @discovery object. They can be metadatas just + * received through a #LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER request or added through + * lasso_idwsf2_discovery_add_service_metadata() or + * lasso_idwsf2_discovery_add_simple_service_metadata(). + * + * Return value:(element-type LassoIdWsf2DiscoSvcMetadata): the list of metadatas. + */ +GList* +lasso_idwsf2_discovery_get_metadatas(LassoIdWsf2Discovery *discovery) +{ + if (! LASSO_IS_IDWSF2_DISCOVERY(discovery) || ! discovery->private_data) return NULL; - } + return discovery->private_data->metadatas; +} - svcMDIDs = lasso_identity_get_svc_md_ids(identity); - svcMDs = lasso_server_get_svc_metadatas_with_id_and_type(server, svcMDIDs, service_type); - if (svcMDs == NULL) { +/** + * lasso_idwsf2_discovery_get_endpoint_references(LassoIdWsf2Discovery *discovery) + * @discovery: a #LassoIdWsf2Discovery object + * + * Return the list of wsa:EndpointReference returned by the last discovery query. + * + * Return value: (element-type LassoWsAddrEndpointReference)(transfer full): a #GList of + * LassoWsAddrEndpointReference objects, or NULL if none is found + */ +GList* +lasso_idwsf2_discovery_get_endpoint_references(LassoIdWsf2Discovery *discovery) +{ + LassoProfile *profile; + LassoIdWsf2DiscoQueryResponse *response; + GList *rc = NULL; + + g_return_val_if_fail (LASSO_IS_IDWSF2_DISCOVERY (discovery), NULL); + profile = &discovery->parent.parent; + + lasso_extract_node_or_fail (response, profile->response, IDWSF2_DISCO_QUERY_RESPONSE, NULL); + rc = response->EndpointReference; +cleanup: + return rc; +} + +/** + * lasso_idwsf2_discovery_get_svcmdids: + * @discovery: a #LassoIdWsf2Discovery object + * + * Return the list of SvcMDID, or service metadata ids, returned by the last discovery query. + * + * Return value:(element-type utf8): a list of SvcMDID's. + */ +GList* +lasso_idwsf2_discovery_get_svcmdids(LassoIdWsf2Discovery *discovery) +{ + GList *content; + GList **svc_md_ids; + + if (! LASSO_IS_IDWSF2_DISCOVERY(discovery)) return NULL; + content = + lasso_soap_envelope_get_body_content( + lasso_idwsf2_profile_get_soap_envelope_request( + &discovery->parent)); + switch (lasso_idwsf2_discovery_get_request_type(discovery)) { + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDQuery*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDDelete*) + lasso_list_get_first_child(content))->SvcMDID; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationAdd*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationDelete*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationQuery*) + lasso_list_get_first_child(content))->SvcMDID; + break; + default: + break; } - - /* FIXME : foreach on the whole list and build an epr for each svcMD */ - svcMD = svcMDs->data; - - if (svcMD == NULL || svcMD->ServiceContext == NULL || svcMD->ServiceContext->data == NULL) { - g_list_foreach(svcMDs, (GFunc)lasso_node_destroy, NULL); - g_list_free(svcMDs); - return NULL; + if (svc_md_ids) { + return *svc_md_ids; } + return NULL; +} - /* Build EndpointReference */ - epr = lasso_wsa_endpoint_reference_new(); - service_context = LASSO_IDWSF2_DISCO_SERVICE_CONTEXT(svcMD->ServiceContext->data); - endpoint_context = LASSO_IDWSF2_DISCO_ENDPOINT_CONTEXT( - service_context->EndpointContext->data); +/** + * lasso_idwsf2_discovery_build_request_msg: + * @discovery: a #LassoIdWsf2Discovery object + * @security_mech_id:(allow-none):the security mech id to use, if NULL a Bearer mechanism is used. + * + * + */ +gint +lasso_idwsf2_discovery_build_request_msg(LassoIdWsf2Discovery *discovery, + const char *security_mech_id) +{ + GList *content = NULL; + LassoIdWsf2DiscoQuery *query = NULL; + GList **svc_md_ids = NULL; + GList **metadatas = NULL; + gboolean check_svcMDID = FALSE; + int rc = 0; - /* XXX: there may be more than one endpoint context */ - epr->Address = lasso_wsa_attributed_uri_new_with_string( - (gchar*)endpoint_context->Address->data); + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + content = + lasso_soap_envelope_get_body_content( + lasso_idwsf2_profile_get_soap_envelope_request( + &discovery->parent)); + switch (lasso_idwsf2_discovery_get_request_type(discovery)) { + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY: + query = (LassoIdWsf2DiscoQuery*)lasso_list_get_first_child(content); + lasso_assign_list_of_gobjects(query->RequestedService, + discovery->private_data->requested_services); - metadata = lasso_wsa_metadata_new(); - - /* Abstract */ - metadata->any = g_list_append(metadata->any, - lasso_idwsf2_disco_abstract_new_with_string(svcMD->Abstract)); - /* ProviderID */ - metadata->any = g_list_append(metadata->any, - lasso_idwsf2_disco_provider_id_new_with_string(svcMD->ProviderID)); - /* ServiceType */ - metadata->any = g_list_append(metadata->any, - lasso_idwsf2_disco_service_type_new_with_string( - (char*)service_context->ServiceType->data)); - /* Framework */ - if (endpoint_context->Framework != NULL) { - metadata->any = g_list_append(metadata->any, - g_object_ref((GObject*)endpoint_context->Framework->data)); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER: + metadatas = &((LassoIdWsf2DiscoSvcMDRegister*)lasso_list_get_first_child(content))->SvcMD; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDQuery*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE: + check_svcMDID = TRUE; + metadatas = &((LassoIdWsf2DiscoSvcMDReplace*) + lasso_list_get_first_child(content))->SvcMD; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDDelete*) + lasso_list_get_first_child(content))->SvcMDID; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationAdd*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationDelete*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY: + svc_md_ids = &((LassoIdWsf2DiscoSvcMDAssociationQuery*) + lasso_list_get_first_child(content))->SvcMDID; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN: + default: + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST); + break; } - - /* Identity token */ - federation = lasso_identity_get_federation(identity, svcMD->ProviderID); - if (federation != NULL) { - assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new()); - - /* Identity token Subject */ - subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new()); - if (federation->remote_nameIdentifier != NULL) { - subject->NameID = g_object_ref(federation->remote_nameIdentifier); + if (metadatas) { + if (! check_svcMDID) { + lasso_assign_list_of_gobjects(*metadatas, discovery->private_data->metadatas); } else { - subject->NameID = g_object_ref(federation->local_nameIdentifier); - } - assertion->Subject = subject; - - /* Encrypt NameID */ - provider = g_hash_table_lookup(server->providers, svcMD->ProviderID); - if (provider - && provider->private_data->encryption_mode & LASSO_ENCRYPTION_MODE_NAMEID - && provider->private_data->encryption_public_key != NULL) { - - encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_node_encrypt( - LASSO_NODE(assertion->Subject->NameID), - provider->private_data->encryption_public_key, - provider->private_data->encryption_sym_key_type)); - if (encrypted_element != NULL) { - assertion->Subject->EncryptedID = encrypted_element; - lasso_release_gobject(assertion->Subject->NameID); - } else { - /** FIXME: find a return value for this case */ + GList *i; + lasso_foreach(i, discovery->private_data->metadatas) { + LassoIdWsf2DiscoSvcMetadata *metadata = (LassoIdWsf2DiscoSvcMetadata *)i->data; + if (lasso_is_empty_string(metadata->svcMDID)) { + g_warning("disco:MetadataReplace method called with " \ + "non registered metadatas " \ + "(svcMDID attribute is missing)"); + } else { + lasso_list_add_gobject(*metadatas, metadata); + } } } - - sec_token = LASSO_IDWSF2_SEC_TOKEN(lasso_idwsf2_sec_token_new()); - sec_token->any = LASSO_NODE(assertion); - - security_context = LASSO_IDWSF2_DISCO_SECURITY_CONTEXT( - lasso_idwsf2_disco_security_context_new()); - security_context->SecurityMechID = g_list_append( - security_context->SecurityMechID, g_strdup(LASSO_SECURITY_MECH_TLS_BEARER)); - security_context->Token = g_list_append(security_context->Token, sec_token); - - metadata->any = g_list_append(metadata->any, security_context); } - - epr->Metadata = metadata; - - /* Free resources */ - g_list_foreach(svcMDs, (GFunc)lasso_node_destroy, NULL); - g_list_free(svcMDs); - - return epr; + if (svc_md_ids) { + GList *i; + lasso_foreach(i, discovery->private_data->metadatas) + { + if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(i->data)) { + lasso_list_add_string(*svc_md_ids, + ((LassoIdWsf2DiscoSvcMetadata*)i->data)->svcMDID); + } + } + } + rc = lasso_idwsf2_profile_build_request_msg(&discovery->parent, security_mech_id); +cleanup: + return rc; } /** - * lasso_idwsf2_discovery_build_query_response_eprs: - * @discovery: a #LassoIdWsf2Discovery + * lasso_idwsf2_discovery_get_request_type: + * @discovery: a #LassoIdWsf2Discovery object * - * Build a query response containing one or more EndpointReference (EPR) for each WSP providing - * the requested service type and matching other query criteria to allow a WSC to request them. + * Return the type of the last parsed request. + * + * Return value: the type of the last parsed request. + */ +LassoIdWsf2DiscoveryRequestType +lasso_idwsf2_discovery_get_request_type(LassoIdWsf2Discovery *discovery) +{ + if (LASSO_IS_IDWSF2_DISCOVERY(discovery)) + { + GType request_type = 0; + + request_type = G_TYPE_FROM_INSTANCE(discovery->parent.parent.request); + +#define check_request_type(a, b) \ + if (request_type == a) { \ + return b ;\ + } + + check_request_type(LASSO_TYPE_IDWSF2_DISCO_QUERY, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_QUERY, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_REGISTER, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_REPLACE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_DELETE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_ASSOCIATION_DELETE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE); + check_request_type(LASSO_TYPE_IDWSF2_DISCO_SVC_MD_ASSOCIATION_QUERY, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY); + } +#undef check_request_type + return LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN; + +} + +/** + * lasso_idwsf2_discovery_fail_request: + * @discovery: a #LassoIdWsf2Discovery + * @status_code: a status code string + * @status_code2:(allow-none): a second-level status code + * + * Fail the last request with the given status code. * * Return value: 0 on success; or a negative value otherwise. - **/ + */ gint -lasso_idwsf2_discovery_build_query_response_eprs(LassoIdWsf2Discovery *discovery) +lasso_idwsf2_discovery_fail_request(LassoIdWsf2Discovery *discovery, const char *status_code, + const char *status_code2) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdentity *identity = LASSO_PROFILE(profile)->identity; - LassoServer *server = LASSO_PROFILE(profile)->server; - LassoIdWsf2DiscoQuery* request; - LassoIdWsf2DiscoRequestedService *service = NULL; - LassoIdWsf2DiscoQueryResponse *response; - LassoWsAddrEndpointReference *epr; - LassoSoapEnvelope *envelope; - int res = 0; + LassoIdWsf2DiscoSvcMDAssociationAddResponse *md_association_add_response; + LassoIdWsf2DiscoSvcMDAssociationDeleteResponse *md_association_delete_response; + LassoIdWsf2DiscoSvcMDAssociationQueryResponse *md_association_query_response; + LassoIdWsf2DiscoSvcMDRegisterResponse *md_register_response; + LassoIdWsf2DiscoSvcMDQueryResponse *md_query_response; + LassoIdWsf2DiscoSvcMDDeleteResponse *md_delete_response; + LassoIdWsf2DiscoSvcMDReplaceResponse *md_replace_response; + LassoIdWsf2DiscoQueryResponse *query_response; + int rc = 0; + LassoIdWsf2UtilStatus **status = NULL; + LassoNode *response = NULL; - if (! LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request)) { - res = LASSO_PROFILE_ERROR_MISSING_REQUEST; - } else if (! LASSO_IS_IDENTITY(identity)) { - res = LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND; + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + + lasso_check_good_rc(lasso_idwsf2_profile_init_response(&discovery->parent)); + switch (lasso_idwsf2_discovery_get_request_type(discovery)) { + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY: + query_response = lasso_idwsf2_disco_query_response_new(); + response = (LassoNode*)query_response; + status = &query_response->Status; + break; + + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER: + md_register_response = lasso_idwsf2_disco_svc_md_register_response_new(); + response = (LassoNode*)md_register_response; + status = &md_register_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY: + md_query_response = lasso_idwsf2_disco_svc_md_query_response_new(); + response = (LassoNode*)md_query_response; + status = &md_query_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE: + md_replace_response = lasso_idwsf2_disco_svc_md_replace_response_new(); + response = (LassoNode*)md_replace_response; + status = &md_replace_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE: + md_delete_response = lasso_idwsf2_disco_svc_md_delete_response_new(); + response = (LassoNode*)md_delete_response; + status = &md_delete_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD: + md_association_add_response = + lasso_idwsf2_disco_svc_md_association_add_response_new(); + response = (LassoNode*)md_association_add_response; + status = &md_association_add_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE: + md_association_delete_response = + lasso_idwsf2_disco_svc_md_association_delete_response_new(); + response = (LassoNode*)md_association_delete_response; + status = &md_association_delete_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY: + md_association_query_response = + lasso_idwsf2_disco_svc_md_association_query_response_new(); + response = (LassoNode*)md_association_query_response; + status = &md_association_query_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN: + default: + response = (LassoNode*)lasso_soap_fault_new_full( + LASSO_SOAP_FAULT_CODE_CLIENT, "Invalid request"); + break; + } + if (response) { + LassoSoapEnvelope *envelope = + lasso_idwsf2_profile_get_soap_envelope_response(&discovery->parent); + lasso_assign_new_gobject(discovery->parent.parent.response, response); + lasso_soap_envelope_add_to_body(envelope, response); + } + if (status) { + lasso_assign_new_gobject(*status, + lasso_idwsf2_util_status_new_with_code(status_code, status_code2)); } - if (res == 0) { - request = LASSO_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request); - /* FIXME : foreach on the list instead */ - if (request->RequestedService != NULL) { - service = LASSO_IDWSF2_DISCO_REQUESTED_SERVICE( - request->RequestedService->data); - } - if (service == NULL) { - res = LASSO_DISCOVERY_ERROR_MISSING_REQUESTED_SERVICE; - } +cleanup: + return rc; +} + +static gboolean +_string_list_intersect(GList *a, GList *b) +{ + GList *i, *j; + + if (a == NULL) { + return TRUE; } + lasso_foreach(i, a) + { + lasso_foreach(j, b) + if (g_strcmp0(i->data, j->data) == 0) { + return TRUE; + } + } + return FALSE; +} - /* Build response */ - response = lasso_idwsf2_disco_query_response_new(); +static gboolean +_string_list_contains(GList *a, const char *str) +{ + GList *i; - if (res == 0) { - /* FIXME : foreach here as well */ - epr = lasso_idwsf2_discovery_build_epr(service, identity, server); - if (epr != NULL) { - response->EndpointReference = - g_list_append(response->EndpointReference, epr); - /* XXX : Should probably check if the epr contains a SecurityContext, */ - /* otherwise return a "federation not found" error code */ + if (a == NULL) + return TRUE; + lasso_foreach(i, a) + if (g_strcmp0(i->data, str) == 0) { + return TRUE; + } + return FALSE; +} + +static gboolean +_string_list_contains_list(GList *a, GList *b) +{ + GList *i; + /* empty = all */ + if (a == NULL) + return TRUE; + lasso_foreach(i, b) + if (! _string_list_contains(a, i->data)) + return FALSE; + return TRUE; +} + +void +lasso_idwsf2_discovery_match_request_service_and_metadata2( + LassoIdWsf2Discovery *discovery, + LassoIdWsf2DiscoRequestedService *requested_service, + LassoIdWsf2DiscoSvcMetadata *metadata, + LassoIdWsf2DiscoServiceContext *service_context, + LassoIdWsf2DiscoEndpointContext *endpoint_context, + GList **eprs) +{ + GList *i; + gboolean result = TRUE; + gboolean option_result = TRUE; + LassoIdWsf2DiscoOptions *options; + GList *service_options; + + + result = result && + _string_list_intersect(requested_service->ServiceType, service_context->ServiceType); + if (result) { + result = result && _string_list_contains(requested_service->ProviderID, metadata->ProviderID); + } + /* Accumulate options */ + if (result) { + lasso_foreach(i, service_context->Options) + { + options = (LassoIdWsf2DiscoOptions*)i->data; + service_options = g_list_concat(service_options, + g_list_copy(options->Option)); + } + lasso_foreach(i, requested_service->Options) + { + option_result = FALSE; + if (_string_list_contains_list(service_options, + ((LassoIdWsf2DiscoOptions*)i->data)->Option)) + { + option_result = TRUE; + break; + } + } + g_list_free(service_options); + result = result && option_result; + } + if (result) { + result = result && + _string_list_intersect(requested_service->SecurityMechID, endpoint_context->SecurityMechID); + } + if (result) { + if (requested_service->Framework) { + result = result && + _string_list_intersect(requested_service->Framework, endpoint_context->Framework); } else { - res = LASSO_DISCOVERY_ERROR_FAILED_TO_BUILD_ENDPOINT_REFERENCE; + /* FIXME: should be the value of the query SOAP header sbf:Framework */ + result = result && _string_list_contains(endpoint_context->Framework, "2.0"); } } - - /* Set response status code */ - if (res == 0) { - response->Status = lasso_idwsf2_util_status_new(); - response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_OK); - } else { - response->Status = lasso_idwsf2_util_status_new(); - response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_FAILED); - /* XXX : May add secondary status codes here */ + if (result) { + result = result && _string_list_intersect(endpoint_context->Action, requested_service->Action); } - envelope = profile->soap_envelope_response; - envelope->Body->any = g_list_append(envelope->Body->any, response); + if (result) { + lasso_list_add_new_gobject(*eprs, + lasso_idwsf2_discovery_build_epr( + discovery, + metadata, + service_context, + endpoint_context)); + } - return res; +} + +void +lasso_idwsf2_discovery_match_request_service_and_metadata( + LassoIdWsf2Discovery *discovery, + LassoIdWsf2DiscoRequestedService *requested_service, + LassoIdWsf2DiscoSvcMetadata *metadata, + GList **eprs) +{ + GList *i, *j; + + lasso_foreach(i, metadata->ServiceContext) + lasso_foreach(j, ((LassoIdWsf2DiscoServiceContext*)i->data)->EndpointContext) + + lasso_idwsf2_discovery_match_request_service_and_metadata2( + discovery, + requested_service, + metadata, + (LassoIdWsf2DiscoServiceContext*)i->data, + (LassoIdWsf2DiscoEndpointContext*)j->data, eprs); + +} + +static gint +lasso_idwsf2_discovery_validate_request_query(LassoIdWsf2Discovery *discovery) +{ + LassoIdWsf2DiscoQuery *query; + LassoIdWsf2DiscoQueryResponse *query_response; + GList *eprs = NULL; + int rc = 0; + + /* Build EPRs */ + query = (LassoIdWsf2DiscoQuery*)discovery->parent.parent.request; + lasso_foreach_full_begin(LassoIdWsf2DiscoRequestedService*, requested_service, i, + query->RequestedService) + lasso_foreach_full_begin(LassoIdWsf2DiscoSvcMetadata*, metadata, j, + discovery->private_data->metadatas) + lasso_idwsf2_discovery_match_request_service_and_metadata(discovery, requested_service, + metadata, &eprs); + lasso_foreach_full_end() + lasso_foreach_full_end() + + if (eprs) { + query_response = lasso_idwsf2_disco_query_response_new(); + query_response->Status = lasso_idwsf2_util_status_new_with_code( + LASSO_IDWSF2_DISCOVERY_STATUS_CODE_OK, NULL); + query_response->EndpointReference = eprs; + lasso_check_good_rc(lasso_idwsf2_profile_init_response(&discovery->parent)); + lasso_soap_envelope_add_to_body( + lasso_idwsf2_profile_get_soap_envelope_response(&discovery->parent), + (LassoNode*)query_response); + discovery->parent.parent.response = &query_response->parent; + } else { + return lasso_idwsf2_discovery_fail_request(discovery, + LASSO_IDWSF2_DISCOVERY_STATUS_CODE_NO_RESULTS, NULL); + } +cleanup: + return rc; } /** - * lasso_idwsf2_discovery_process_query_response_msg: + * lasso_idwsf2_discovery_validate_md_register: * @discovery: a #LassoIdWsf2Discovery - * @message: received query soap response * - * Process received query response. - * Copy returned EPRs into session object. - * Check response status code. + * Process received metadata register request. + * If successful, register the service metadata into the discovery service. + * + * Return value: 0 on success; or a negative value otherwise. + **/ +static gint +lasso_idwsf2_discovery_validate_md_register(LassoIdWsf2Discovery *discovery) +{ + LassoIdWsf2Profile *profile = NULL; + LassoIdWsf2DiscoSvcMDRegisterResponse *response = NULL; + LassoSoapEnvelope *envelope = NULL; + LassoIdWsf2DiscoSvcMDRegister *request = NULL; + GList *SvcMD = NULL; + GList *SvcMDs = NULL; + int rc = 0; + + profile = LASSO_IDWSF2_PROFILE(discovery); + lasso_release_list_of_gobjects(discovery->private_data->metadatas); + request = (LassoIdWsf2DiscoSvcMDRegister*)profile->parent.request; + + lasso_release_list_of_gobjects(discovery->private_data->metadatas); + /* Allocate SvcMDIDs and add the metadatas */ + for (SvcMD = request->SvcMD; SvcMD != NULL; SvcMD = g_list_next(SvcMD)) { + if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(SvcMD->data)) { + lasso_list_add_gobject(discovery->private_data->metadatas, SvcMD->data); + lasso_assign_new_string( + LASSO_IDWSF2_DISCO_SVC_METADATA( + SvcMD->data)->svcMDID, + lasso_build_unique_id(32)); + } + } + + response = lasso_idwsf2_disco_svc_md_register_response_new(); + response->Status = + lasso_idwsf2_util_status_new_with_code(LASSO_DISCO_STATUS_CODE_OK, NULL); + for (SvcMDs = discovery->private_data->metadatas; SvcMDs != NULL; SvcMDs = g_list_next(SvcMDs)) { + lasso_list_add_string(response->SvcMDID, + LASSO_IDWSF2_DISCO_SVC_METADATA(SvcMDs->data)->svcMDID); + } + + lasso_check_good_rc(lasso_idwsf2_profile_init_response(&discovery->parent)); + envelope = lasso_idwsf2_profile_get_soap_envelope_response(profile); + lasso_soap_envelope_add_to_body(envelope, &response->parent); +cleanup: + return rc; +} + +/** + * lasso_idwsf2_discovery_validate_request: + * @discovery: a #LassoIdWsf2Discovery object + * + * Accept the discovery request, and produce the response. + * + * Return value: 0 on success; or a negative value otherwise. + */ +gint +lasso_idwsf2_discovery_validate_request(LassoIdWsf2Discovery *discovery) +{ + LassoIdWsf2DiscoSvcMDAssociationAddResponse *md_association_add_response; + LassoIdWsf2DiscoSvcMDAssociationDeleteResponse *md_association_delete_response; + LassoIdWsf2DiscoSvcMDAssociationQueryResponse *md_association_query_response; + LassoIdWsf2DiscoSvcMDQueryResponse *md_query_response; + LassoIdWsf2DiscoSvcMDQuery *md_query; + LassoIdWsf2DiscoSvcMDDeleteResponse *md_delete_response; + LassoIdWsf2DiscoSvcMDReplaceResponse *md_replace_response; + LassoNode *response = NULL; + int rc = 0; + GList *i; + LassoIdWsf2UtilStatus **status = NULL; + + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + switch (lasso_idwsf2_discovery_get_request_type(discovery)) { + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY: + lasso_check_good_rc(lasso_idwsf2_discovery_validate_request_query(discovery)); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER: + lasso_check_good_rc(lasso_idwsf2_discovery_validate_md_register(discovery)); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY: + md_query_response = lasso_idwsf2_disco_svc_md_query_response_new(); + md_query = (LassoIdWsf2DiscoSvcMDQuery*)discovery->parent.parent.request; + response = (LassoNode*)md_query_response; + if (md_query->SvcMDID) { + lasso_foreach(i, discovery->private_data->metadatas) { + LassoIdWsf2DiscoSvcMetadata *metadata = i->data; + if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(metadata) + && _string_list_contains(md_query->SvcMDID, metadata->svcMDID)) { + lasso_list_add_gobject(md_query_response->SvcMD, i->data); + } + } + } + status = &md_query_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE: + md_replace_response = lasso_idwsf2_disco_svc_md_replace_response_new(); + response = (LassoNode*)md_replace_response; + status = &md_replace_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE: + md_delete_response = lasso_idwsf2_disco_svc_md_delete_response_new(); + response = (LassoNode*)md_delete_response; + status = &md_delete_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD: + md_association_add_response = + lasso_idwsf2_disco_svc_md_association_add_response_new(); + response = (LassoNode*)md_association_add_response; + status = &md_association_add_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE: + md_association_delete_response = + lasso_idwsf2_disco_svc_md_association_delete_response_new(); + response = (LassoNode*)md_association_delete_response; + status = &md_association_delete_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY: + md_association_query_response = + lasso_idwsf2_disco_svc_md_association_query_response_new(); + response = (LassoNode*)md_association_query_response; + lasso_foreach(i, discovery->private_data->metadatas) { + if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(i->data)) { + lasso_list_add_string(md_association_query_response->SvcMDID, + ((LassoIdWsf2DiscoSvcMetadata*)i->data)->svcMDID); + } + } + status = &md_association_query_response->Status; + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN: + default: + lasso_idwsf2_discovery_fail_request(discovery, NULL, NULL); + rc = LASSO_PROFILE_ERROR_INVALID_REQUEST; + break; + } + if (response) { + LassoSoapEnvelope *envelope = + lasso_idwsf2_profile_get_soap_envelope_response(&discovery->parent); + lasso_assign_new_gobject(discovery->parent.parent.response, response); + lasso_soap_envelope_add_to_body(envelope, response); + } + + if (status) { + lasso_assign_new_gobject(*status, + lasso_idwsf2_util_status_new_with_code( + LASSO_IDWSF2_DISCOVERY_STATUS_CODE_OK, NULL)); + } + +cleanup: + return rc; +} + +static gint +lasso_idwsf2_discovery_process_metadata_register_response_msg(LassoIdWsf2Discovery *discovery) +{ + LassoIdWsf2Profile *profile; + LassoIdWsf2DiscoSvcMDRegisterResponse *response; + LassoIdWsf2DiscoSvcMDRegister *request; + GList *i, *j; + int rc = 0; + + profile = &discovery->parent; + lasso_extract_node_or_fail(request, profile->parent.request, IDWSF2_DISCO_SVC_MD_REGISTER, + LASSO_PROFILE_ERROR_MISSING_REQUEST); + + response = (LassoIdWsf2DiscoSvcMDRegisterResponse*)profile->parent.response; + + goto_cleanup_if_fail_with_rc( + LASSO_IS_IDWSF2_DISCO_SVC_MD_REGISTER_RESPONSE(response), + LASSO_PROFILE_ERROR_INVALID_RESPONSE); + lasso_check_good_rc(lasso_idwsf2_discovery_status2rc(response->Status)); + goto_cleanup_if_fail_with_rc(g_list_length(response->SvcMDID) != + g_list_length(request->SvcMD), LASSO_PROFILE_ERROR_INVALID_RESPONSE); + /* Check IDs */ + i = response->SvcMDID; + lasso_foreach(i, response->SvcMDID) { + if (i->data == NULL || ((char*)i->data)[0] == '\0') { + rc = LASSO_PROFILE_ERROR_INVALID_RESPONSE; + goto cleanup; + } + } + + /* Assign IDs to metadatas */ + i = response->SvcMDID; + j = request->SvcMD; + while (i && j) { + lasso_assign_string(((LassoIdWsf2DiscoSvcMetadata*)j->data)->svcMDID, + i->data); + lasso_list_add_gobject(discovery->private_data->metadatas, request->SvcMD); + i = i->next; + j = j->next; + } +cleanup: + return rc; +} + + +/** + * lasso_idwsf2_discovery_add_requested_service: + * @discovery: a #LassoIdWsf2Discovery + * @service_types:(element-type utf8)(allow-none): the service type (or data profile) requested + * @provider_ids:(element-type utf8)(allow-none): the providers ids to select + * @options:(element-type utf8)(allow-none): the options to select + * @security_mech_ids:(element-type utf8)(allow-none): the security mechanisms to select + * @frameworks:(element-type utf8)(allow-none): the ID-WSF framework version to select + * @actions:(element-type utf8)(allow-none): the actions to select + * @result_type:(allow-none)(default LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_NONE): how to filter the generated EPRs + * @req_id:(allow-none): an eventual ID to put on the request, that can be matched with the + * generated EndpointReferences + * + * Add a new request to find some specific services associated to the current principal at the + * discovery service. * * Return value: 0 on success; or a negative value otherwise. **/ gint -lasso_idwsf2_discovery_process_query_response_msg(LassoIdWsf2Discovery *discovery, - const gchar *message) +lasso_idwsf2_discovery_add_requested_service(LassoIdWsf2Discovery *discovery, + GList *service_types, GList *provider_ids, GList *options, GList *security_mech_ids, + GList *frameworks, GList *actions, LassoIdWsf2DiscoveryQueryResultType result_type, + const char *req_id) { - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoSession *session = LASSO_PROFILE(profile)->session; - LassoIdWsf2DiscoQueryResponse *response; - int res = 0; + LassoIdWsf2DiscoRequestedService *service; - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + const char *result_type_s = NULL; - g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); - /* Process request */ - res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); - if (res != 0) { - return res; - } - - if (! LASSO_IS_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response)) { - return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; - } - - /* Check response status code */ - response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); - if (response->Status == NULL || response->Status->code == NULL) { - return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } - if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0) { - return LASSO_DISCOVERY_ERROR_SVC_METADATA_ASSOCIATION_ADD_FAILED; - } - - /* If the response has been correctly processed, */ - /* put interesting data into the discovery object */ - response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); - /* FIXME : foreach on the list instead */ - if (response->EndpointReference != NULL - && response->EndpointReference->data != NULL) { - lasso_session_add_endpoint_reference(session, - response->EndpointReference->data); + service = lasso_idwsf2_disco_requested_service_new(); + lasso_assign_list_of_strings(service->ServiceType, service_types); + lasso_assign_list_of_strings(service->ProviderID, provider_ids); + lasso_assign_list_of_strings(service->Framework, frameworks); + lasso_assign_list_of_strings(service->Action, actions); + lasso_assign_list_of_strings(service->SecurityMechID, security_mech_ids); + lasso_assign_list_of_gobjects(service->Options, options); + switch (result_type) { + case LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_BEST: + result_type_s = LASSO_IDWSF2_DISCOVERY_RESULT_TYPE_BEST; + break; + case LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ALL: + result_type_s = LASSO_IDWSF2_DISCOVERY_RESULT_TYPE_ALL; + break; + case LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ONLY_ONE: + result_type_s = LASSO_IDWSF2_DISCOVERY_RESULT_TYPE_ONLY_ONE; + break; + default: + break; } + lasso_assign_string(service->resultsType, result_type_s); + lasso_assign_string(service->reqID, req_id); + lasso_list_add_new_gobject(discovery->private_data->requested_services, service); return 0; } /** - * lasso_idwsf2_discovery_get_service: - * @discovery: a #LassoIdWsf2Discovery - * @service_type: the requested service type + * lasso_idwsf2_discovery_process_response_msg: + * @discovery: a #LassoIdWsf2Discovery object + * @msg: a string containing the response messages * - * After a discovery query message, create a #LassoIdWsf2DataService instance for the - * requested @service_type. - * - * Return value: a newly created #LassoIdWsf2DataService object; or NULL if an error occured. - **/ -LassoIdWsf2DataService* -lasso_idwsf2_discovery_get_service(LassoIdWsf2Discovery *discovery, G_GNUC_UNUSED const gchar *service_type) + * Return value: 0 if successful, an error code otherwise. + */ +gint +lasso_idwsf2_discovery_process_response_msg(LassoIdWsf2Discovery *discovery, + const char *msg) { - /* FIXME: service_type is unused, should we remove it from public API ? */ - LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); - LassoIdWsf2DiscoQueryResponse *response; - LassoWsAddrEndpointReference *epr = NULL; - LassoIdWsf2DataService *service; + LassoIdWsf2DiscoSvcMDAssociationAddResponse *md_association_add_response; + LassoIdWsf2DiscoSvcMDAssociationDeleteResponse *md_association_delete_response; + LassoIdWsf2DiscoSvcMDAssociationQueryResponse *md_association_query_response; + LassoIdWsf2DiscoSvcMDQueryResponse *md_query_response; + LassoIdWsf2DiscoSvcMDDeleteResponse *md_delete_response; + LassoIdWsf2DiscoSvcMDReplaceResponse *md_replace_response; + LassoIdWsf2DiscoQueryResponse *query_response; + LassoProfile *profile; + LassoNode *response; + int rc = 0; - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), NULL); + lasso_bad_param(IDWSF2_DISCOVERY, discovery); + profile = &discovery->parent.parent; + response = profile->response; - g_return_val_if_fail(LASSO_IS_IDWSF2_DISCO_QUERY_RESPONSE( - LASSO_PROFILE(profile)->response), NULL); + lasso_check_good_rc(lasso_idwsf2_profile_process_response_msg(&discovery->parent, msg)); - response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); - - /* FIXME : foreach on the list instead */ - if (response->EndpointReference != NULL && response->EndpointReference->data != NULL) { - epr = LASSO_WSA_ENDPOINT_REFERENCE(response->EndpointReference->data); - } else { - return NULL; + switch (lasso_idwsf2_discovery_get_request_type(discovery)) { + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY: + if (! LASSO_IS_IDWSF2_DISCO_QUERY_RESPONSE(response)) + goto bad_response; + query_response = (LassoIdWsf2DiscoQueryResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(query_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER: + rc = lasso_idwsf2_discovery_process_metadata_register_response_msg( + discovery); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY: + if (! LASSO_IDWSF2_DISCO_SVC_MD_QUERY_RESPONSE(response)) + goto bad_response; + md_query_response = (LassoIdWsf2DiscoSvcMDQueryResponse*)response; + lasso_check_good_rc(lasso_idwsf2_discovery_status2rc(md_query_response->Status)); + lasso_assign_list_of_gobjects(discovery->private_data->metadatas, md_query_response->SvcMD); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE: + if (! LASSO_IDWSF2_DISCO_SVC_MD_REPLACE_RESPONSE(response)) + goto bad_response; + md_replace_response = (LassoIdWsf2DiscoSvcMDReplaceResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(md_replace_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE: + if (! LASSO_IDWSF2_DISCO_SVC_MD_DELETE_RESPONSE(response)) + goto bad_response; + md_delete_response = (LassoIdWsf2DiscoSvcMDDeleteResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(md_delete_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD: + if (! LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE(response)) + goto bad_response; + md_association_add_response = (LassoIdWsf2DiscoSvcMDAssociationAddResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(md_association_add_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE: + if (! LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_DELETE_RESPONSE(response)) + goto bad_response; + md_association_delete_response = (LassoIdWsf2DiscoSvcMDAssociationDeleteResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(md_association_delete_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY: + if (! LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_QUERY_RESPONSE(response)) + goto bad_response; + md_association_query_response = (LassoIdWsf2DiscoSvcMDAssociationQueryResponse*)response; + rc = lasso_idwsf2_discovery_status2rc(md_association_query_response->Status); + break; + case LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN: + default: + rc = LASSO_PROFILE_ERROR_INVALID_REQUEST; + break; } - - service = lasso_idwsf2_data_service_new_full(LASSO_PROFILE(profile)->server, epr); - lasso_assign_gobject(LASSO_PROFILE(service)->session, LASSO_PROFILE(profile)->session); - - return service; +cleanup: + return rc; +bad_response: + return LASSO_PROFILE_ERROR_INVALID_RESPONSE; } -/*****************************************************************************/ -/* private methods */ -/*****************************************************************************/ - static LassoNodeClass *parent_class = NULL; -static xmlNode* -get_xmlNode(LassoNode *node, gboolean lasso_dump) -{ - xmlNode *xmlnode; - - xmlnode = parent_class->get_xmlNode(node, lasso_dump); - xmlNodeSetName(xmlnode, (xmlChar*)"Discovery"); - xmlSetProp(xmlnode, (xmlChar*)"DiscoveryDumpVersion", (xmlChar*)"2"); - - return xmlnode; -} - -/*****************************************************************************/ -/* overrided parent class methods */ -/*****************************************************************************/ - static void dispose(GObject *object) { LassoIdWsf2Discovery *discovery = LASSO_IDWSF2_DISCOVERY(object); - if (discovery->private_data->dispose_has_run == TRUE) return; discovery->private_data->dispose_has_run = TRUE; - G_OBJECT_CLASS(parent_class)->dispose(object); } @@ -939,10 +1271,6 @@ finalize(GObject *object) G_OBJECT_CLASS(parent_class)->finalize(object); } -/*****************************************************************************/ -/* instance and class init functions */ -/*****************************************************************************/ - static void instance_init(LassoIdWsf2Discovery *discovery) { @@ -954,7 +1282,8 @@ static void class_init(LassoIdWsf2DiscoveryClass *klass) { parent_class = g_type_class_peek_parent(klass); - LASSO_NODE_CLASS(klass)->get_xmlNode = get_xmlNode; + lasso_node_class_set_nodename(LASSO_NODE_CLASS(klass), "Discovery"); + lasso_node_class_set_ns(LASSO_NODE_CLASS(klass), LASSO_LASSO_HREF, LASSO_LASSO_PREFIX); G_OBJECT_CLASS(klass)->dispose = dispose; G_OBJECT_CLASS(klass)->finalize = finalize; } @@ -986,7 +1315,7 @@ lasso_idwsf2_discovery_get_type() /** * lasso_idwsf2_discovery_new: - * @server: the #LassoServer + * @server:(allow-none):a #LassoServer object, for resolving ProviderID names * * Create a new #LassoIdWsf2Discovery. * @@ -997,10 +1326,8 @@ lasso_idwsf2_discovery_new(LassoServer *server) { LassoIdWsf2Discovery *discovery = NULL; - g_return_val_if_fail(LASSO_IS_SERVER(server), NULL); - discovery = g_object_new(LASSO_TYPE_IDWSF2_DISCOVERY, NULL); - LASSO_PROFILE(discovery)->server = g_object_ref(server); + discovery->parent.parent.server = lasso_ref(server); return discovery; } diff --git a/lasso/id-wsf-2.0/discovery.h b/lasso/id-wsf-2.0/discovery.h index d5be3cdc..abfda2c3 100644 --- a/lasso/id-wsf-2.0/discovery.h +++ b/lasso/id-wsf-2.0/discovery.h @@ -56,9 +56,6 @@ typedef struct _LassoIdWsf2DiscoveryPrivate LassoIdWsf2DiscoveryPrivate; struct _LassoIdWsf2Discovery { LassoIdWsf2Profile parent; - GList *metadatas; /* of LassoIdWsf2DiscoSvcMetadata* */ - GList *svcMDIDs; /* of char* */ - /*< private >*/ LassoIdWsf2DiscoveryPrivate *private_data; }; @@ -71,48 +68,78 @@ LASSO_EXPORT GType lasso_idwsf2_discovery_get_type(void); LASSO_EXPORT LassoIdWsf2Discovery* lasso_idwsf2_discovery_new(LassoServer *server); -LASSO_EXPORT gchar* lasso_idwsf2_discovery_metadata_register_self(LassoIdWsf2Discovery *discovery, - const gchar *service_type, const gchar *abstract, - const gchar *soap_endpoint, const gchar *svcMDID); +/** + * LassoIdWsf2DiscoveryRequestType: + * @LASSO_IDWSF2_DISCOVERY_METADATA_REGISTER_REQUEST: + * @LASSO_IDWSF2_DISCOVERY_METADATA_ASSOCIATION_REQUEST: + * @LASSO_IDWSF2_DISCOVERY_METADATA_DISSOCIATION_REQUEST: + * @LASSO_IDWSF2_DISCOVERY_QUERY: + */ +typedef enum { + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_UNKNOWN, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_QUERY, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_QUERY, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REGISTER, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_REPLACE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_DELETE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_ADD, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_DELETE, + LASSO_IDWSF2_DISCOVERY_REQUEST_TYPE_MD_ASSOCIATION_QUERY, +} LassoIdWsf2DiscoveryRequestType; -LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_register(LassoIdWsf2Discovery *discovery, - const gchar *service_type, const gchar *abstract, - const gchar *disco_provider_id, const gchar *soap_endpoint); - -LASSO_EXPORT gint lasso_idwsf2_discovery_process_metadata_register_msg( - LassoIdWsf2Discovery *discovery, const gchar *message); - -LASSO_EXPORT gint lasso_idwsf2_discovery_process_metadata_register_response_msg( - LassoIdWsf2Discovery *discovery, const gchar *message); +/** + * LassoIdWsf2DiscoveryQueryResultType: + * @LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_BEST: + * @LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ALL: + * @LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ONLY_ONE: + */ +typedef enum { + LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_NONE, + LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_BEST, + LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ALL, + LASSO_IDWSF2_DISCOVERY_QUERY_RESULT_TYPE_ONLY_ONE +} LassoIdWsf2DiscoveryQueryResultType; +/* Request initialization */ +LASSO_EXPORT gint lasso_idwsf2_discovery_init_query(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_query(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_register(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_replace(LassoIdWsf2Discovery *discovery); LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_association_add( - LassoIdWsf2Discovery *discovery, const gchar *svcMDID); - -LASSO_EXPORT gint lasso_idwsf2_discovery_process_metadata_association_add_msg( - LassoIdWsf2Discovery *discovery, const gchar *message); - -LASSO_EXPORT gint lasso_idwsf2_discovery_register_metadata(LassoIdWsf2Discovery *discovery); - -LASSO_EXPORT gint lasso_idwsf2_discovery_process_metadata_association_add_response_msg( - LassoIdWsf2Discovery *discovery, const gchar *message); - -LASSO_EXPORT gint lasso_idwsf2_discovery_init_query(LassoIdWsf2Discovery *discovery, - const gchar *security_mech_id); - -LASSO_EXPORT gint lasso_idwsf2_discovery_add_requested_service_type(LassoIdWsf2Discovery *discovery, - const gchar *service_type); - -LASSO_EXPORT gint lasso_idwsf2_discovery_process_query_msg(LassoIdWsf2Discovery *discovery, - const gchar *message); - -LASSO_EXPORT gint lasso_idwsf2_discovery_build_query_response_eprs( + LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_association_delete( + LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_init_metadata_association_query( LassoIdWsf2Discovery *discovery); -LASSO_EXPORT gint lasso_idwsf2_discovery_process_query_response_msg( - LassoIdWsf2Discovery *discovery, const gchar *message); +/* Add metadatas to operate on, to make request, but also to make responses. */ +LASSO_EXPORT int lasso_idwsf2_discovery_add_service_metadata( + LassoIdWsf2Discovery *idwsf2_discovery, LassoIdWsf2DiscoSvcMetadata *service_metadata); +LASSO_EXPORT int lasso_idwsf2_discovery_add_simple_service_metadata( + LassoIdWsf2Discovery *idwsf2_discovery, const char *abstract, + const char *provider_id, GList *service_types, GList *options, const char *address, + GList *security_mech_ids); +LASSO_EXPORT GList* lasso_idwsf2_discovery_get_metadatas(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_add_requested_service(LassoIdWsf2Discovery *discovery, + GList *service_types, GList *provider_ids, GList *options, GList *security_mech_ids, + GList *frameworks, GList *actions, LassoIdWsf2DiscoveryQueryResultType result_type, + const char *req_id); + +/* Build the request message */ +LASSO_EXPORT gint lasso_idwsf2_discovery_build_request_msg(LassoIdWsf2Discovery *discovery, + const char *security_mech_id); + +/* Handle a request */ +LASSO_EXPORT LassoIdWsf2DiscoveryRequestType lasso_idwsf2_discovery_get_request_type(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_validate_request(LassoIdWsf2Discovery *discovery); +LASSO_EXPORT gint lasso_idwsf2_discovery_fail_request(LassoIdWsf2Discovery *discovery, + const char *status_code, const char *status_code2); + +/* Process the response */ +LASSO_EXPORT gint lasso_idwsf2_discovery_process_response_msg(LassoIdWsf2Discovery *discovery, + const char *msg); +LASSO_EXPORT GList* lasso_idwsf2_discovery_get_endpoint_references(LassoIdWsf2Discovery *discovery); -LASSO_EXPORT LassoIdWsf2DataService* lasso_idwsf2_discovery_get_service( - LassoIdWsf2Discovery *discovery, const gchar *service_type); #ifdef __cplusplus } diff --git a/lasso/id-wsf-2.0/profile.c b/lasso/id-wsf-2.0/profile.c index 62347317..5086a833 100644 --- a/lasso/id-wsf-2.0/profile.c +++ b/lasso/id-wsf-2.0/profile.c @@ -35,6 +35,8 @@ #include "../id-ff/serverprivate.h" #include "../id-ff/providerprivate.h" +#include "../saml-2.0/profileprivate.h" + #include "profile.h" #include "session.h" @@ -43,22 +45,85 @@ #include "../xml/soap_binding_provider.h" #include "../xml/soap_binding_processing_context.h" #include "../xml/xml_enc.h" +#include "../xml/id-wsf-2.0/sb2_sender.h" +#include "../xml/id-wsf-2.0/sb2_redirect_request.h" #include "../xml/ws/wsse_security_header.h" #include "../xml/saml-2.0/saml2_assertion.h" #include "../utils.h" +#include "./idwsf2_helper.h" +#include "./soap_binding.h" +#include "../id-wsf/utils.h" +#include "../saml-2.0/saml2_helper.h" -/*****************************************************************************/ -/* private methods */ -/*****************************************************************************/ +/** + * LassoIdWsf2ProfilePrivate: + * @epr: the #LassoWsAddrEndpointReference object representing the targetd service + */ +struct _LassoIdWsf2ProfilePrivate { + LassoWsAddrEndpointReference *epr; + LassoSoapEnvelope *soap_envelope_request; + LassoSoapEnvelope *soap_envelope_response; +}; -LassoSoapEnvelope* -lasso_idwsf2_profile_build_soap_envelope(G_GNUC_UNUSED const char *refToMessageId, G_GNUC_UNUSED const char *providerId) +#define private_accessors(type, name) \ +static type \ +_get_##name(LassoIdWsf2Profile *idwsf2_profile)\ +{ \ + if (idwsf2_profile && idwsf2_profile->private_data) \ + { \ + return idwsf2_profile->private_data->name; \ + } \ + return 0; \ +} \ +static void \ +_set_##name(LassoIdWsf2Profile *idwsf2_profile, \ + type what) \ +{ \ + if (idwsf2_profile && idwsf2_profile->private_data) \ + { \ + lasso_assign_gobject(idwsf2_profile->private_data->name, what); \ + } \ +} + +private_accessors(LassoWsAddrEndpointReference*,epr) +private_accessors(LassoSoapEnvelope*,soap_envelope_request) +private_accessors(LassoSoapEnvelope*,soap_envelope_response) + + +static void +_add_fault_for_rc(LassoIdWsf2Profile *profile, int rc) +{ + LassoSoapFault *fault; + char *code; + + if (rc) { + code = g_strdup_printf("LASSO_ERROR_%i", rc); + fault = lasso_soap_fault_new_full(code, lasso_strerror(rc)); + g_free(code); + lasso_release_list_of_gobjects(_get_soap_envelope_response(profile)->Header->Other); + lasso_soap_envelope_add_to_body(_get_soap_envelope_response(profile), (LassoNode*)fault); + } +} + +/** + * lasso_idwsf2_profile_build_soap_envelope: + * @refToMessageId: (allow-none): the string ID of the request + * @providerId: (allow-none): the providerID of the sender + * + * Build a new SOAP envelope, for transmitting an ID-WSF request of response. If the message is a + * response, refer to the request whose ID is @refToMessageId. + * + * Return value: a new #LassoSoapEnvelope if successful, NULL otherwise. + */ +static LassoSoapEnvelope* +lasso_idwsf2_profile_build_soap_envelope(const char *refToMessageId, const char *providerID) { LassoSoapEnvelope *envelope; LassoSoapHeader *header; LassoSoapBody *body; + LassoIdWsf2Sb2Sender *sender; /* Body */ body = lasso_soap_body_new(); @@ -69,125 +134,424 @@ lasso_idwsf2_profile_build_soap_envelope(G_GNUC_UNUSED const char *refToMessageI header = lasso_soap_header_new(); envelope->Header = header; + if (providerID) { + /* Sender */ + sender = lasso_idwsf2_sb2_sender_new(); + lasso_assign_string(sender->providerID, providerID); + lasso_list_add_gobject(header->Other, sender); + } + + if (refToMessageId) { + LassoWsAddrAttributedURI *relates_to; + relates_to = lasso_wsa_attributed_uri_new_with_string(refToMessageId); + lasso_node_set_custom_nodename((LassoNode*)relates_to, "RelatesTo"); + lasso_list_add_gobject(header->Other, relates_to); + } + return envelope; } -/*****************************************************************************/ -/* public methods */ -/*****************************************************************************/ - +/** + * lasso_idwsf2_profile_init_request: + * @profile: a #LassoIdWsf2Profile object + * + * Initialize a new SOAP ID-WSF 2.0 request. Clear the existing request if one is currently set. + * + * Return value: 0 if successful, an error code otherwise. + */ gint -lasso_idwsf2_profile_init_soap_request(LassoIdWsf2Profile *profile, LassoNode *request, - gchar *service_type) +lasso_idwsf2_profile_init_request(LassoIdWsf2Profile *idwsf2_profile) { - LassoSoapEnvelope *envelope; - LassoSession *session = LASSO_PROFILE(profile)->session; - LassoSaml2Assertion *assertion; - LassoWsSec1SecurityHeader *wsse_security; + LassoSoapEnvelope *envelope = NULL; + LassoProfile *profile = NULL; + LassoWsAddrEndpointReference *epr; + const char *provider_id = NULL; + int rc = 0; - /* Initialise soap envelope */ - envelope = lasso_idwsf2_profile_build_soap_envelope(NULL, - LASSO_PROVIDER(LASSO_PROFILE(profile)->server)->ProviderID); - lasso_assign_new_gobject(profile->soap_envelope_request, envelope); + lasso_bad_param(IDWSF2_PROFILE, idwsf2_profile); + profile = &idwsf2_profile->parent; + epr = lasso_idwsf2_profile_get_epr(idwsf2_profile); - /* Add identity token (if it exists in the session) in soap header */ - assertion = lasso_session_get_assertion_identity_token(session, service_type); + if (epr) { + LassoIdWsf2DiscoSecurityContext *security_context; - /* FIXME: use sb2:TargetIdentity if security mech is :null */ - if (assertion != NULL) { - wsse_security = lasso_wsse_security_header_new(); - lasso_list_add_new_gobject(wsse_security->any, assertion); - lasso_list_add_new_gobject(envelope->Header->Other, wsse_security); + security_context = + lasso_wsa_endpoint_reference_get_idwsf2_security_context_for_security_mechanism( + epr, lasso_security_mech_id_is_bearer_authentication, NULL, FALSE); + if (! security_context) { + return LASSO_WSF_PROFILE_ERROR_UNSUPPORTED_SECURITY_MECHANISM; + } } - /* Add the given request in soap body */ - lasso_list_add_gobject(envelope->Body->any, request); + if (LASSO_IS_SERVER(profile->server)) { + provider_id = profile->server->parent.ProviderID; + } + envelope = lasso_idwsf2_profile_build_soap_envelope(NULL, provider_id); + _set_soap_envelope_request(idwsf2_profile, envelope); + lasso_release_gobject(profile->request); - return 0; + lasso_release_gobject(envelope); + return rc; } +/** + * lasso_idwsf2_profile_init_response: + * @profile: a #LassoIdWsf2Profile object + * + * Initialize a new SOAP ID-WSF 2.0 response. Clear the existing response if one is currently set. + * + * Return value: 0 if successful, an error code otherwise. + */ gint -lasso_idwsf2_profile_build_request_msg(LassoIdWsf2Profile *profile) +lasso_idwsf2_profile_init_response(LassoIdWsf2Profile *profile) { - g_return_val_if_fail(LASSO_IS_IDWSF2_PROFILE(profile), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + char *provider_id = NULL; + LassoSoapEnvelope *soap_envelope; + char *request_message_id = NULL; + int rc = 0; + + lasso_bad_param(IDWSF2_PROFILE, profile); + + if (LASSO_IS_SERVER(profile->parent.server)) { + provider_id = profile->parent.server->parent.ProviderID; + } + request_message_id = lasso_soap_envelope_get_message_id( + lasso_idwsf2_profile_get_soap_envelope_request(profile)); + soap_envelope = lasso_idwsf2_profile_build_soap_envelope(request_message_id, provider_id); + _set_soap_envelope_response(profile, soap_envelope); + lasso_release_gobject(profile->parent.response); + + return rc; +} + +/** + * lasso_idwsf2_profile_build_request_msg: + * @profile: a #LassoIdWsf2Profile object + * + * Serialize and sign, if needed, the SOAP request message, put the result in + * LASSO_PROFILE(profile)->msg_body. + * + * FIXME: really do sign messages. + * + * Return value: 0 if successful, LASSO_PROFILE_ERROR_BUILDING_REQUEST_FAILED. + */ +gint +lasso_idwsf2_profile_build_request_msg(LassoIdWsf2Profile *profile, const char *security_mech_id) +{ + LassoWsAddrEndpointReference *epr; + LassoSoapEnvelope *envelope; + + lasso_bad_param(IDWSF2_PROFILE, profile); + epr = lasso_idwsf2_profile_get_epr(profile); + envelope = _get_soap_envelope_request(profile); + + /* Handle SOAP Binding and WS-Security, when given an EPR */ + if (LASSO_IS_WSA_ENDPOINT_REFERENCE(epr)) { + if (epr->Address != NULL) { + lasso_assign_string(profile->parent.msg_url, epr->Address->content); + } + + /* Default try bearer */ + if (security_mech_id == NULL || lasso_security_mech_id_is_bearer_authentication( + security_mech_id)) { + LassoNode *security_token; + + security_token = lasso_wsa_endpoint_reference_get_security_token(epr, + lasso_security_mech_id_is_bearer_authentication, NULL); + if (security_token) { + lasso_soap_envelope_add_security_token (envelope, security_token); + } else { + g_warning ("No security mechanism specified, " \ + "failed to find security token for Bearer mechanism"); + } + if (lasso_wsa_endpoint_reference_get_target_identity_token(epr, + lasso_security_mech_id_is_bearer_authentication, NULL) != NULL) { + g_critical("TargetIdentity token are not supported"); + } + } else { + g_critical("Only Bearer security mechanism is supported by ID-WSF 2.0 module of Lasso"); + } + } LASSO_PROFILE(profile)->msg_body = lasso_node_export_to_xml( - LASSO_NODE(profile->soap_envelope_request)); + LASSO_NODE(_get_soap_envelope_request(profile))); + + if (! LASSO_PROFILE(profile)->msg_body) + return LASSO_PROFILE_ERROR_BUILDING_REQUEST_FAILED; return 0; } +/** + * lasso_idwsf2_profile_process_request_msg: + * @wsf2_profile: a #LassoIdWsf2Profile object + * @message: a received SOAP message + * + * Parse a SOAP request message and initialize the SOAP Envelope for the response. + * + * Return value: 0 if successful, an error code otherwise among: + * + * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if @profile is not a #LassoIdWsf2Profile + * object, + * LASSO_PARAM_ERROR_INVALID_VALUE if message is NULL, + * LASSO_PROFILE_ERROR_INVALID_MSG if we cannot parse the message, + * LASSO_SOAP_ERROR_MISSING_BODY if the message has no body + * content. + * + */ gint -lasso_idwsf2_profile_process_soap_request_msg(LassoIdWsf2Profile *wsf2_profile, const gchar *message) +lasso_idwsf2_profile_process_request_msg(LassoIdWsf2Profile *wsf2_profile, const gchar *message) { LassoProfile *profile = NULL; LassoSoapEnvelope *envelope = NULL; + char *message_id; + char *provider_id; int rc = 0; - g_return_val_if_fail(LASSO_IS_IDWSF2_PROFILE(wsf2_profile), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); + lasso_bad_param(IDWSF2_PROFILE, wsf2_profile); + lasso_check_non_empty_string(message); + + /* Clean some fields */ + lasso_release_gobject(wsf2_profile->parent.nameIdentifier); + lasso_release_string(wsf2_profile->parent.remote_providerID); + lasso_release_string(wsf2_profile->parent.msg_body); + lasso_release_gobject(wsf2_profile->private_data->soap_envelope_response); + lasso_release_gobject(wsf2_profile->parent.response); /* Get soap request */ profile = LASSO_PROFILE(wsf2_profile); - lasso_assign_new_gobject(wsf2_profile->soap_envelope_request, lasso_soap_envelope_new_from_message(message)); - if (! LASSO_IS_SOAP_ENVELOPE(wsf2_profile->soap_envelope_request)) { + + lasso_assign_new_gobject(wsf2_profile->private_data->soap_envelope_request, + lasso_soap_envelope_new_from_message(message)); + if (! LASSO_IS_SOAP_ENVELOPE(_get_soap_envelope_request(wsf2_profile))) { return LASSO_PROFILE_ERROR_INVALID_MSG; } - envelope = wsf2_profile->soap_envelope_request; + envelope = _get_soap_envelope_request(wsf2_profile); if (envelope != NULL && envelope->Body != NULL && envelope->Body->any != NULL && LASSO_IS_NODE(envelope->Body->any->data)) { - lasso_assign_gobject(LASSO_PROFILE(profile)->request, (LassoNode*)envelope->Body->any->data); + lasso_assign_gobject(profile->request, envelope->Body->any->data); } else { rc = LASSO_SOAP_ERROR_MISSING_BODY; } /* Initialize soap response */ - lasso_assign_new_gobject(wsf2_profile->soap_envelope_response, lasso_idwsf2_profile_build_soap_envelope(NULL, - LASSO_PROVIDER(profile->server)->ProviderID)); + message_id = lasso_soap_envelope_get_message_id( + _get_soap_envelope_request(wsf2_profile)); + if (LASSO_IS_SERVER(profile->server)) { + provider_id = profile->server->parent.ProviderID; + lasso_assign_new_gobject(wsf2_profile->private_data->soap_envelope_response, + lasso_idwsf2_profile_build_soap_envelope(message_id, provider_id)); + } + _add_fault_for_rc(wsf2_profile, rc); +cleanup: return rc; } +/** + * lasso_idwsf2_profile_check_security_mechanism: + * @profile: a #LassoIdWsf2Profile object + * @security_mech_id:(allow-none): the security mechanism to enforce, if none is provided Bearer is + * assumed. + * + * Check ID-WSF 2.0 Security Mechanism upon the received request. + * + * Return value: 0 if the request passed the check, an error code otherwise. + */ gint -lasso_idwsf2_profile_build_response_msg(LassoIdWsf2Profile *profile) +lasso_idwsf2_profile_check_security_mechanism(LassoIdWsf2Profile *profile, + const char *security_mech_id) { - g_return_val_if_fail(LASSO_IS_IDWSF2_PROFILE(profile), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + LassoSoapEnvelope *envelope = NULL; + int rc = LASSO_WSF_PROFILE_ERROR_SECURITY_MECHANISM_CHECK_FAILED; - LASSO_PROFILE(profile)->msg_body = lasso_node_export_to_xml(LASSO_NODE( - profile->soap_envelope_response)); + lasso_bad_param(IDWSF2_PROFILE, profile); + envelope = _get_soap_envelope_request(profile); + /* Verify security mechanism */ + if (security_mech_id == NULL || + lasso_security_mech_id_is_bearer_authentication(security_mech_id)) { + LassoSaml2Assertion *assertion; + LassoProvider *issuer; + assertion = lasso_soap_envelope_get_saml2_security_token (envelope); + if (assertion == NULL) + goto cleanup; + if (! lasso_saml2_assertion_validate_conditions(assertion, NULL)) + goto cleanup; + issuer = lasso_saml2_assertion_get_issuer_provider(assertion, profile->parent.server); + if (! issuer || issuer->role != LASSO_PROVIDER_ROLE_IDP) + goto cleanup; + if (lasso_provider_verify_single_node_signature(issuer, (LassoNode*)assertion, "ID") != 0) + goto cleanup; + } else { + g_warning("Only Bearer mechanism is supported!"); + rc = LASSO_ERROR_UNIMPLEMENTED; + goto cleanup; + } + rc = 0; +cleanup: + _add_fault_for_rc(profile, rc); + return rc; +} + +/** + * lasso_idwsf2_profile_init_soap_fault_response: + * @profile: a #LassoIdWsf2Profile object + * + * Initialize a new SOAP 1.1 fault. + * + * Return value: 0 if successful, an error code otherwise. + */ +gint +lasso_idwsf2_profile_init_soap_fault_response(LassoIdWsf2Profile *profile) +{ + int rc = 0; + LassoSoapEnvelope *envelope; + LassoSoapFault *fault; + + lasso_check_good_rc(lasso_idwsf2_profile_init_response(profile)); + envelope = lasso_idwsf2_profile_get_soap_envelope_response(profile); + if (envelope) { + fault = lasso_soap_fault_new(); + lasso_list_add_new_gobject(envelope->Body->any, fault); + lasso_assign_gobject(profile->parent.response, fault); + } +cleanup: + return rc; +} + +/** + * lasso_idwsf2_profile_redirect_user_for_interaction: + * @profile: a #LassoIdWsf2Profile object + * @redirect_url: an URL where the user must be redirected + * + * Create a SOAP fault asking for user + * + * Return value: 0 if successful, an error code otherwise. + */ +gint +lasso_idwsf2_profile_redirect_user_for_interaction( + LassoIdWsf2Profile *profile, const gchar *redirect_url, gboolean for_data) +{ + LassoSoapFault *fault = NULL; + LassoIdWsf2Sb2RedirectRequest *redirect_request = NULL; + LassoIdWsf2Sb2UserInteractionHint hint; + int rc = 0; + + lasso_bad_param(IDWSF2_PROFILE, profile); + lasso_check_non_empty_string(redirect_url); + + hint = lasso_soap_envelope_get_sb2_user_interaction_hint( + lasso_idwsf2_profile_get_soap_envelope_request(profile)); + switch (hint) { + case LASSO_IDWSF2_SB2_USER_INTERACTION_HINT_DO_NOT_INTERACT: + return LASSO_WSF_PROFILE_ERROR_SERVER_INTERACTION_REQUIRED; + case LASSO_IDWSF2_SB2_USER_INTERACTION_HINT_DO_NOT_INTERACT_FOR_DATA: + if (for_data) { + return LASSO_WSF_PROFILE_ERROR_SERVER_INTERACTION_REQUIRED_FOR_DATA; + } + default: + break; + } + + lasso_check_good_rc(lasso_idwsf2_profile_init_soap_fault_response(profile)); + fault = (LassoSoapFault*)profile->parent.response; + lasso_assign_string(fault->faultcode, LASSO_SOAP_FAULT_CODE_SERVER); + lasso_assign_string(fault->faultstring, "Server error"); + redirect_request = lasso_idwsf2_sb2_redirect_request_new_full(redirect_url); + lasso_soap_fault_add_to_detail(fault, (LassoNode*)redirect_request); + +cleanup: + lasso_release_gobject(redirect_request); + return rc; +} +/** + * lasso_idwsf2_profile_build_response_msg: + * @idwsf2_profile: a #LassoIdWsf2Profile object + * + * Serialize and sign the SOAP, if needed, the response message, put the result in + * LASSO_PROFILE(profile)->msg_body. + * + * Return value: 0 if successful, LASSO_PROFILE_ERROR_BUILDING_RESPONSE_FAILED otherwise. + */ +gint +lasso_idwsf2_profile_build_response_msg(LassoIdWsf2Profile *idwsf2_profile) +{ + LassoSoapEnvelope *envelope; + + lasso_bad_param(IDWSF2_PROFILE, idwsf2_profile); + + envelope = lasso_idwsf2_profile_get_soap_envelope_response(idwsf2_profile); + if (envelope == NULL) { + return LASSO_PROFILE_ERROR_MISSING_RESPONSE; + } + idwsf2_profile->parent.msg_body = lasso_node_export_to_xml((LassoNode*)envelope); + + if (! LASSO_PROFILE(idwsf2_profile)->msg_body) { + return LASSO_PROFILE_ERROR_BUILDING_RESPONSE_FAILED; + } return 0; } +/** + * lasso_idwsf2_profile_process_response_msg: + * @profile: a #LassoIdWsf2Profile object + * @message: a string containing a response message + * + * Parse a response received by SOAP. Place the parsed message in the #LassoIdWsf2Profile structure + * in the @soap_envelope_response field and the content of the body in the @response field. + * + * Return value: 0 if successful, one of those error codes if the call fails: + * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if first parameter is not + * a #LassoIdWsf2Profile object, + * LASSO_PARAM_ERROR_INVALID_VALUE if message is NULL, + * LASSO_SOAP_ERROR_MISSING_BODY if no body element is found, + * LASSO_PROFILE_ERROR_MISSING_RESPONSE if the body element is + * empty. + */ gint -lasso_idwsf2_profile_process_soap_response_msg(LassoIdWsf2Profile *profile, const gchar *message) +lasso_idwsf2_profile_process_response_msg(LassoIdWsf2Profile *profile, const gchar *message) { LassoSoapEnvelope *envelope = NULL; - int res = 0; + int rc = 0; - g_return_val_if_fail(LASSO_IS_IDWSF2_PROFILE(profile), - LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); + lasso_bad_param(IDWSF2_PROFILE, profile); + lasso_check_non_empty_string(message); - /* Get soap response */ envelope = lasso_soap_envelope_new_from_message(message); + _set_soap_envelope_response(profile, envelope); - lasso_assign_new_gobject(profile->soap_envelope_response, envelope); + goto_cleanup_if_fail_with_rc (envelope != NULL, + LASSO_PROFILE_ERROR_INVALID_RESPONSE); + goto_cleanup_if_fail_with_rc (envelope->Body != NULL, + LASSO_SOAP_ERROR_MISSING_BODY); + goto_cleanup_if_fail_with_rc (envelope->Body->any != NULL && + LASSO_IS_NODE(envelope->Body->any->data), + LASSO_PROFILE_ERROR_MISSING_RESPONSE); - if (envelope != NULL && envelope->Body != NULL && envelope->Body->any != NULL) { - lasso_assign_gobject(LASSO_PROFILE(profile)->response, LASSO_NODE(envelope->Body->any->data)); - } else { - res = LASSO_SOAP_ERROR_MISSING_BODY; + lasso_assign_gobject(profile->parent.response, + envelope->Body->any->data); + + if (LASSO_IS_SOAP_FAULT(profile->parent.response)) { + LassoSoapFault *fault = (LassoSoapFault*)profile->parent.response; + if (LASSO_IS_SOAP_DETAIL(fault->Detail)) { + LassoIdWsf2Sb2RedirectRequest *redirect_request; + redirect_request = + lasso_extract_gobject_from_list( + LassoIdWsf2Sb2RedirectRequest, + LASSO_TYPE_IDWSF2_SB2_REDIRECT_REQUEST, + fault->Detail->any); + if (redirect_request) { + lasso_assign_string(profile->parent.msg_url, redirect_request->redirectURL); + return LASSO_WSF_PROFILE_ERROR_REDIRECT_REQUEST; + } + return LASSO_WSF_PROFILE_ERROR_SOAP_FAULT; + + } } - if (LASSO_PROFILE(profile)->response == NULL) { - res = LASSO_PROFILE_ERROR_MISSING_RESPONSE; - } - - return res; +cleanup: + return rc; } /** @@ -196,12 +560,13 @@ lasso_idwsf2_profile_process_soap_response_msg(LassoIdWsf2Profile *profile, cons * * Return the last parsed SOAP request object. * - * Return value: a #LassoSoapEnvelope object or NULL if no request as ever been parsed with this - * object. You must free this object. + * Return value:(transfer none): a #LassoSoapEnvelope object or NULL if no request as ever been + * parsed with this object. You must free this object. */ -LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_request(LassoIdWsf2Profile *idwsf2_profile) +LassoSoapEnvelope* +lasso_idwsf2_profile_get_soap_envelope_request(LassoIdWsf2Profile *idwsf2_profile) { - return g_object_ref(idwsf2_profile->soap_envelope_request); + return _get_soap_envelope_request(idwsf2_profile); } @@ -211,59 +576,133 @@ LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_request(LassoIdWsf2Pro * * Return the last parsed SOAP response object. * - * Return value: a #LassoSoapEnvelope object or NULL if no response as ever been parsed with this - * object. You must free this object. + * Return value:(transfer none): a #LassoSoapEnvelope object or NULL if no response as ever been + * parsed with this objects. You must free this object. */ -LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_response(LassoIdWsf2Profile *idwsf2_profile) +LassoSoapEnvelope* +lasso_idwsf2_profile_get_soap_envelope_response(LassoIdWsf2Profile *idwsf2_profile) { - return g_object_ref(idwsf2_profile->soap_envelope_response); + return _get_soap_envelope_response(idwsf2_profile); } /** - * lasso_idwsf2_profile_set_response: + * lasso_idwsf2_profile_get_name_identifier: * @idwsf2_profile: a #LassoIdWsf2Profile object - * @response: (transfer full) (allow-none): a #LassoNode to set as the new content of the SOAP - * response * - * Replace the current content of the response with node. + * Return the NameIdentifier found in a WS-Security authentication token, when Bearer or SAML + * security mechanism is used. * + * Return value: (allow-none): a #LassoNode object or NULL. */ -void -lasso_idwsf2_profile_set_response(LassoIdWsf2Profile *idwsf2_profile, LassoNode *response) +LassoNode * +lasso_idwsf2_profile_get_name_identifier(LassoIdWsf2Profile *idwsf2_profile) { - if (! LASSO_IDWSF2_PROFILE(idwsf2_profile) || !idwsf2_profile->soap_envelope_response || - ! idwsf2_profile->soap_envelope_response->Body) - return; - lasso_assign_new_gobject(((LassoProfile*)idwsf2_profile)->response, response); - lasso_release_list_of_gobjects(idwsf2_profile->soap_envelope_response->Body->any); - lasso_list_add_gobject(idwsf2_profile->soap_envelope_response->Body->any, response); - return; + LassoSaml2Assertion *assertion = NULL; + LassoSaml2NameID *nameID = NULL; + LassoIdWsf2Sb2TargetIdentity *target_identity = NULL; + LassoSaml2EncryptedElement *encryptedID = NULL; + + + if (! LASSO_IS_IDWSF2_PROFILE(idwsf2_profile)) + return NULL; + + /** Already extracted, return it */ + if (idwsf2_profile->parent.nameIdentifier != NULL) + goto cleanup; + + /* Try to get a SAML2 assertion */ + assertion = lasso_soap_envelope_get_saml2_security_token + (lasso_idwsf2_profile_get_soap_envelope_request(idwsf2_profile)); + if (assertion && assertion->Subject) { + + /* We need a server object to check for audience and decrypt encrypted NameIDs */ + if (! LASSO_IS_SERVER(idwsf2_profile->parent.server)) { + goto cleanup; + } + + /* Check validity of the assertion */ + /* FIXME: get tolerance from profile */ + if (lasso_saml2_assertion_validate_conditions(assertion, + idwsf2_profile->parent.server->parent.ProviderID) != + LASSO_SAML2_ASSERTION_VALID) { + goto cleanup; + } + + lasso_assign_gobject (nameID, assertion->Subject->NameID); + lasso_assign_gobject (encryptedID, assertion->Subject->EncryptedID); + } + if (!nameID && !encryptedID) { + GList *it; + /* Go look at the target identity */ + target_identity = lasso_soap_envelope_sb2_get_target_identity_header ( + lasso_idwsf2_profile_get_soap_envelope_request (idwsf2_profile)); + if (target_identity) { + lasso_foreach (it, target_identity->any) + { + if (LASSO_IS_SAML2_NAME_ID(it->data)) { + lasso_assign_gobject (nameID, it->data); + break; + } + if (LASSO_IS_SAML2_ENCRYPTED_ELEMENT(it->data)) { + lasso_assign_gobject (encryptedID, it->data); + break; + } + } + } + + } + + if (lasso_saml20_profile_process_name_identifier_decryption(&idwsf2_profile->parent, &nameID, + &encryptedID) != 0) { + g_warning("process_name_identifier_decryption failed "\ + "when retrieving name identifier for ID-WSF profile"); + } + if (nameID) { + goto cleanup; + } + +cleanup: + lasso_release_gobject (assertion); + lasso_release_gobject (encryptedID); + lasso_assign_gobject (idwsf2_profile->parent.nameIdentifier, nameID); + return (LassoNode*)nameID; } /** - * lasso_idwsf2_profile_set_request: + * lasso_idwsf2_profile_get_epr: * @idwsf2_profile: a #LassoIdWsf2Profile object - * @request: (transfer full) (allow-none): a #LassoNode to set as the new content of the SOAP - * request. + * @epr: a #LassoWsAddrEndpointReference object * - * Replace the current content of the request with node. + * Set the EPR for the service targeted by the profile object. * */ void -lasso_idwsf2_profile_set_request(LassoIdWsf2Profile *idwsf2_profile, LassoNode *request) +lasso_idwsf2_profile_set_epr(LassoIdWsf2Profile *idwsf2_profile, + LassoWsAddrEndpointReference *epr) { - if (! LASSO_IDWSF2_PROFILE(idwsf2_profile) || !idwsf2_profile->soap_envelope_request || - ! idwsf2_profile->soap_envelope_request->Body) + if (! LASSO_IS_IDWSF2_PROFILE(idwsf2_profile) || ! LASSO_IS_WSA_ENDPOINT_REFERENCE(epr) || + ! idwsf2_profile->private_data) return; - lasso_assign_new_gobject(((LassoProfile*)idwsf2_profile)->request, request); - lasso_release_list_of_gobjects(idwsf2_profile->soap_envelope_request->Body->any); - lasso_list_add_gobject(idwsf2_profile->soap_envelope_request->Body->any, request); - return; + _set_epr(idwsf2_profile, epr); } -/*****************************************************************************/ -/* overridden parent class methods */ -/*****************************************************************************/ + +/** + * lasso_idwsf2_profile_get_epr: + * @idwsf2_profile: a #LassoIdWsf2Profile object + * + * Return the EPR used by this profile. + * + * Return value:(transfer none): a #LassoWsAddrEndpointReference object, or NULL if none is set. + */ +LassoWsAddrEndpointReference* +lasso_idwsf2_profile_get_epr(LassoIdWsf2Profile *idwsf2_profile) +{ + if (! LASSO_IS_IDWSF2_PROFILE(idwsf2_profile) || ! idwsf2_profile->private_data) + return NULL; + return _get_epr(idwsf2_profile); +} + static LassoNodeClass *parent_class = NULL; @@ -272,21 +711,16 @@ dispose(GObject *object) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(object); - lasso_release_gobject(profile->soap_envelope_request); - lasso_release_gobject(profile->soap_envelope_response); + lasso_release_gobject(profile->private_data->soap_envelope_request); + lasso_release_gobject(profile->private_data->soap_envelope_response); G_OBJECT_CLASS(parent_class)->dispose(object); } -/*****************************************************************************/ -/* instance and class init functions */ -/*****************************************************************************/ - static void -instance_init(LassoIdWsf2Profile *profile) +instance_init(LassoIdWsf2Profile *discovery) { - profile->soap_envelope_request = NULL; - profile->soap_envelope_response = NULL; + discovery->private_data = g_new0(LassoIdWsf2ProfilePrivate, 1); } static void diff --git a/lasso/id-wsf-2.0/profile.h b/lasso/id-wsf-2.0/profile.h index 895360f1..333bcff0 100644 --- a/lasso/id-wsf-2.0/profile.h +++ b/lasso/id-wsf-2.0/profile.h @@ -31,6 +31,7 @@ extern "C" { #include "../id-ff/profile.h" #include "../xml/soap_envelope.h" +#include "../xml/ws/wsa_endpoint_reference.h" #define LASSO_TYPE_IDWSF2_PROFILE (lasso_idwsf2_profile_get_type()) #define LASSO_IDWSF2_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ @@ -53,9 +54,6 @@ struct _LassoIdWsf2Profile { LassoProfile parent; /*< private >*/ - LassoSoapEnvelope *soap_envelope_request; - LassoSoapEnvelope *soap_envelope_response; - LassoIdWsf2ProfilePrivate *private_data; }; @@ -65,30 +63,43 @@ struct _LassoIdWsf2ProfileClass { LASSO_EXPORT GType lasso_idwsf2_profile_get_type(void); -LASSO_EXPORT gint lasso_idwsf2_profile_init_soap_request(LassoIdWsf2Profile *profile, - LassoNode *request, gchar *service_type); +/* Initialize profile */ +LASSO_EXPORT void lasso_idwsf2_profile_set_epr(LassoIdWsf2Profile *idwsf2_profile, + LassoWsAddrEndpointReference *epr); +LASSO_EXPORT LassoWsAddrEndpointReference* lasso_idwsf2_profile_get_epr( + LassoIdWsf2Profile *idwsf2_profile); -LASSO_EXPORT gint lasso_idwsf2_profile_build_request_msg(LassoIdWsf2Profile *profile); +/* Initialize requests */ +LASSO_EXPORT gint lasso_idwsf2_profile_init_request(LassoIdWsf2Profile *profile); -LASSO_EXPORT gint lasso_idwsf2_profile_process_soap_request_msg(LassoIdWsf2Profile *profile, - const gchar *message); +/* Build request message */ +LASSO_EXPORT gint lasso_idwsf2_profile_build_request_msg(LassoIdWsf2Profile *profile, + const char *security_mech_id); +/* Handle request */ +LASSO_EXPORT gint lasso_idwsf2_profile_process_request_msg(LassoIdWsf2Profile *profile, + const char *msg); +LASSO_EXPORT gint lasso_idwsf2_profile_check_security_mechanism(LassoIdWsf2Profile *profile, + const char *security_mech_id); +LASSO_EXPORT LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_request( + LassoIdWsf2Profile *idwsf2_profile); +LASSO_EXPORT LassoNode *lasso_idwsf2_profile_get_name_identifier( + LassoIdWsf2Profile *idwsf2_profile); + +/* Initialize response */ +LASSO_EXPORT gint lasso_idwsf2_profile_init_response(LassoIdWsf2Profile *profile); +LASSO_EXPORT gint lasso_idwsf2_profile_init_soap_fault_response(LassoIdWsf2Profile *profile); +LASSO_EXPORT gint lasso_idwsf2_profile_redirect_user_for_interaction(LassoIdWsf2Profile *profile, + const gchar *redirect_url, gboolean for_data); + +/* Build response message */ LASSO_EXPORT gint lasso_idwsf2_profile_build_response_msg(LassoIdWsf2Profile *profile); -LASSO_EXPORT gint lasso_idwsf2_profile_process_soap_response_msg(LassoIdWsf2Profile *profile, - const gchar *message); - -LASSO_EXPORT LassoSoapEnvelope* lasso_idwsf2_profile_build_soap_envelope( - const char *refToMessageId, - const char *providerId); - -LASSO_EXPORT LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_request(LassoIdWsf2Profile *idwsf2_profile); - -LASSO_EXPORT LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_response(LassoIdWsf2Profile *idwsf2_profile); - -LASSO_EXPORT void lasso_idwsf2_profile_set_response(LassoIdWsf2Profile *idwsf2_profile, LassoNode *response); - -LASSO_EXPORT void lasso_idwsf2_profile_set_request(LassoIdWsf2Profile *idwsf2_profile, LassoNode *request); +/* Handle response */ +LASSO_EXPORT gint lasso_idwsf2_profile_process_response_msg(LassoIdWsf2Profile *profile, + const char *msg); +LASSO_EXPORT LassoSoapEnvelope* lasso_idwsf2_profile_get_soap_envelope_response( + LassoIdWsf2Profile *idwsf2_profile); #ifdef __cplusplus }