1 /* $Id$
2  *
3  * Lasso - A free implementation of the Liberty Alliance specifications.
4  *
5  * Copyright (C) 2004-2007 Entr'ouvert
6  * http://lasso.entrouvert.org
7  *
8  * Authors: See AUTHORS file in top-level directory.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "../xml/private.h"
25 #include <libxml/xpath.h>
26 #include <libxml/xpathInternals.h>
27 
28 #include <xmlsec/xmltree.h>
29 #include <xmlsec/xmldsig.h>
30 #include <xmlsec/templates.h>
31 #include <xmlsec/crypto.h>
32 
33 #include "../utils.h"
34 
35 #include "wsf_profile.h"
36 #include "../xml/idwsf_strings.h"
37 #include "wsf_profile_private.h"
38 #include "discovery.h"
39 #include "wsf_utils.h"
40 #include "../xml/disco_modify.h"
41 #include "../xml/soap-1.1/soap_fault.h"
42 #include "../xml/soap_binding_correlation.h"
43 #include "../xml/soap_binding_provider.h"
44 #include "../xml/soap_binding_processing_context.h"
45 #include "../xml/saml_assertion.h"
46 #include "../xml/saml_authentication_statement.h"
47 #include "../xml/saml_subject_statement_abstract.h"
48 #include "../xml/saml_subject.h"
49 #include "../xml/ds_key_info.h"
50 #include "../xml/ds_key_value.h"
51 #include "../xml/ds_rsa_key_value.h"
52 #include "../xml/soap-1.1/soap_fault.h"
53 #include "../xml/soap-1.1/soap_detail.h"
54 #include "../xml/is_redirect_request.h"
55 #include "../xml/ws/wsse_security_header.h"
56 
57 
58 #include "../id-ff/server.h"
59 #include "../id-ff/providerprivate.h"
60 #include "../id-ff/sessionprivate.h"
61 #include "../xml/misc_text_node.h"
62 
63 /**
64  * SECTION:wsf_profile
65  * @short_description: Base class for ID-WSF 1.0 services
66  * @stability: Unstable
67  *
68  * Use this class to base your ID-WSF 1.0 services.
69  */
70 
71 /*****************************************************************************/
72 /* private methods                                                           */
73 /*****************************************************************************/
74 
75 static LassoDiscoDescription* lasso_wsf_profile_get_description_auto(
76 		const LassoDiscoServiceInstance *si, const gchar *security_mech_id);
77 static gint lasso_wsf_profile_add_saml_signature(LassoWsfProfile *wsf_profile, xmlDoc *doc);
78 static LassoSoapBindingCorrelation* lasso_wsf_profile_utils_get_header_correlation(
79 		LassoSoapEnvelope *envelope);
80 static char* lasso_wsf_profile_utils_get_message_id(LassoSoapEnvelope *envelope);
81 static char* lasso_wsf_profile_utils_get_ref_message_id(LassoSoapEnvelope *envelope);
82 
83 static struct XmlSnippet schema_snippets[] = {
84 	{ "Server", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoWsfProfile, server), NULL, NULL, NULL},
85 	{ "Request", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoWsfProfile, request), NULL, NULL, NULL},
86 	{ "Response", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoWsfProfile, response), NULL, NULL, NULL},
87 	{ "SOAP-Request", SNIPPET_NODE_IN_CHILD,
88 		G_STRUCT_OFFSET(LassoWsfProfile, soap_envelope_request), NULL, NULL, NULL},
89 	{ "SOAP-Response", SNIPPET_NODE_IN_CHILD,
90 		G_STRUCT_OFFSET(LassoWsfProfile, soap_envelope_response), NULL, NULL, NULL},
91 	{ "MsgUrl", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoWsfProfile, msg_url), NULL, NULL, NULL},
92 	{ "MsgBody", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoWsfProfile, msg_body), NULL, NULL, NULL},
93 	{ "Identity", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoWsfProfile, identity), NULL, NULL, NULL},
94 	{ "Session", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoWsfProfile, session), NULL, NULL, NULL},
95 	{NULL, 0, 0, NULL, NULL, NULL}
96 };
97 
98 static LassoSoapBindingCorrelation*
lasso_wsf_profile_utils_get_header_correlation(LassoSoapEnvelope * envelope)99 lasso_wsf_profile_utils_get_header_correlation(LassoSoapEnvelope *envelope)
100 {
101 	LassoSoapHeader *header;
102 	GList *header_list;
103 
104 	if (LASSO_IS_SOAP_HEADER(envelope->Header)) {
105 		header = envelope->Header;
106 	} else {
107 		goto cleanup;
108 	}
109 	lasso_foreach(header_list, header->Other)
110 	{
111 		if (LASSO_IS_SOAP_BINDING_CORRELATION(header_list->data)) {
112 			return (LassoSoapBindingCorrelation*)header_list->data;
113 		}
114 	}
115 cleanup:
116 	return NULL;
117 }
118 
119 static char*
lasso_wsf_profile_utils_get_ref_message_id(LassoSoapEnvelope * envelope)120 lasso_wsf_profile_utils_get_ref_message_id(LassoSoapEnvelope *envelope)
121 {
122 	LassoSoapBindingCorrelation *correlation_header;
123 
124 	correlation_header = lasso_wsf_profile_utils_get_header_correlation(envelope);
125 	if (! correlation_header) {
126 		return NULL;
127 	}
128 	return correlation_header->refToMessageID;
129 }
130 
131 static char*
lasso_wsf_profile_utils_get_message_id(LassoSoapEnvelope * envelope)132 lasso_wsf_profile_utils_get_message_id(LassoSoapEnvelope *envelope)
133 {
134 	LassoSoapBindingCorrelation *correlation_header;
135 
136 	correlation_header = lasso_wsf_profile_utils_get_header_correlation(envelope);
137 	if (! correlation_header) {
138 		return NULL;
139 	}
140 	return correlation_header->messageID;
141 }
142 /**
143  * lasso_wsf_profile_build_soap_fault_response_msg:
144  * @profile: a #LassoWsfProfile
145  * @rc: an error code from Lasso
146  *
147  * Build a new SOAP fault, eventually fill it with the given rc code
148  */
149 gint
lasso_wsf_profile_build_soap_fault_response_msg(LassoWsfProfile * profile,gint rc)150 lasso_wsf_profile_build_soap_fault_response_msg(LassoWsfProfile *profile, gint rc)
151 {
152 	g_return_val_if_fail(LASSO_IS_WSF_PROFILE(profile), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
153 
154 	lasso_assign_new_gobject(profile->response, lasso_soap_fault_new());
155 	if (rc) {
156 		LassoMiscTextNode *node;
157 
158 		if (rc == LASSO_PROFILE_ERROR_INVALID_MSG) {
159 			lasso_assign_string(LASSO_SOAP_FAULT(profile->response)->faultcode,
160 					LASSO_SOAP_ENV_PREFIX ":" LASSO_SOAP_FAULT_CODE_CLIENT);
161 		} else {
162 			lasso_assign_string(LASSO_SOAP_FAULT(profile->response)->faultcode,
163 					LASSO_SOAP_ENV_PREFIX ":" LASSO_SOAP_FAULT_CODE_SERVER);
164 		}
165 		lasso_assign_string(LASSO_SOAP_FAULT(profile->response)->faultstring,
166 				LASSO_SOAP_FAULT_STRING_SERVER);
167 		lasso_assign_new_gobject(LASSO_SOAP_FAULT(profile->response)->Detail, lasso_soap_detail_new());
168 		node = (LassoMiscTextNode*)lasso_misc_text_node_new();
169 		lasso_assign_string(node->content, lasso_strerror(rc));
170 		node->name = "LassoError";
171 		node->ns_href = LASSO_LASSO_HREF;
172 		node->ns_prefix = LASSO_LASSO_PREFIX;
173 	}
174 	return rc;
175 }
176 
177 /**
178  * lasso_wsf_set_msg_url_from_description:
179  * @profile: the #LassoWsfProfile object
180  *
181  * Initialize the @msgUrl attribute of the #LassoWsfProfile to the URL of the targetted web service.
182  *
183  * Return value: 0 if successful
184  */
185 gint
lasso_wsf_profile_set_msg_url_from_description(LassoWsfProfile * wsf_profile)186 lasso_wsf_profile_set_msg_url_from_description(LassoWsfProfile *wsf_profile)
187 {
188 	LassoDiscoDescription *description = NULL;
189 	int rc = 0;
190 
191 	g_return_val_if_fail(LASSO_IS_WSF_PROFILE(wsf_profile),
192 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
193 
194 	description = lasso_wsf_profile_get_description(wsf_profile);
195 	if (description->Endpoint != NULL) {
196 		lasso_assign_string(wsf_profile->msg_url, description->Endpoint);
197 	} else {
198 		rc = LASSO_WSF_PROFILE_ERROR_MISSING_ENDPOINT;
199 	}
200 	lasso_release_gobject(description);
201 	return rc;
202 }
203 
204 /* Documentation of g_list_find_custom say that list element is the first pointer,
205  * and user_data the second */
206 static gboolean
is_of_type(gconstpointer a,gconstpointer b)207 is_of_type(gconstpointer a, gconstpointer b)
208 {
209 	GType typeid = (GType)b;
210 
211 	if (a && G_IS_OBJECT(a)) {
212 		return G_OBJECT_TYPE(G_OBJECT(a)) == typeid;
213 	}
214 	return FALSE;
215 }
216 
217 /**
218  * lasso_wsf_profile_comply_with_saml_authentication:
219  * @profile: a #LassoWsfProfile
220  *
221  * Return value: 0 if an assertion was found and a signature corresponding to the
222  * key given as a subject confirmation in the assertion is generated, an error
223  * code otherwise.
224  */
225 static gint
lasso_wsf_profile_comply_with_saml_authentication(LassoWsfProfile * profile)226 lasso_wsf_profile_comply_with_saml_authentication(LassoWsfProfile *profile)
227 {
228 	LassoSoapEnvelope *soap = NULL;
229 	LassoSoapHeader *header = NULL;
230 	LassoWsSec1SecurityHeader *wsse_security = NULL;
231 	LassoSession *session = NULL;
232 	LassoDiscoDescription *description = NULL;
233 	GList *credentialRefs = NULL;
234 	gint rc = 0;
235 	GList *needle = NULL;
236 
237 	lasso_bad_param(WSF_PROFILE, profile);
238 	lasso_extract_node_or_fail(session, profile->session, SESSION, LASSO_PROFILE_ERROR_SESSION_NOT_FOUND);
239 	description = lasso_wsf_profile_get_description(profile);
240 	/* Lookup in the session the credential ref from the description and
241 	 * add them to the SOAP header wsse:Security. */
242 	/* FIXME: should we really add every credentials to the message, or only the one identifying
243 	 * us? */
244 	goto_cleanup_if_fail_with_rc(description != NULL, LASSO_WSF_PROFILE_ERROR_MISSING_DESCRIPTION);
245 	credentialRefs = description->CredentialRef;
246 	goto_cleanup_if_fail_with_rc(credentialRefs != NULL, LASSO_WSF_PROFILE_ERROR_MISSING_CREDENTIAL_REF);
247 	lasso_extract_node_or_fail(soap, profile->soap_envelope_request, SOAP_ENVELOPE, LASSO_SOAP_ERROR_MISSING_ENVELOPE);
248 	lasso_extract_node_or_fail(header, soap->Header, SOAP_HEADER, LASSO_SOAP_ERROR_MISSING_HEADER);
249 	needle = g_list_find_custom(header->Other, (gconstpointer)LASSO_TYPE_WSSE_SECURITY_HEADER,
250 			(GCompareFunc)is_of_type);
251 	if (needle) {
252 		lasso_assign_gobject(wsse_security, LASSO_WSSE_SECURITY_HEADER(needle->data));
253 	} else {
254 		wsse_security = lasso_wsse_security_header_new();
255 	}
256 	/* Comply with ID-WSF 1.0 specification */
257 	lasso_node_set_custom_namespace(LASSO_NODE(wsse_security), LASSO_WSSE_PREFIX,
258 			LASSO_WSSE_HREF);
259 
260 	while (credentialRefs) {
261 		char *ref = (char*)credentialRefs->data;
262 		xmlNode *assertion = lasso_session_get_assertion_by_id(session, ref);
263 		goto_cleanup_if_fail_with_rc(assertion != NULL, LASSO_WSF_PROFILE_ERROR_MISSING_CREDENTIAL_REF);
264 		/* add an exact copy of the assertion in order to keep the IdP signature valid */
265 		lasso_list_add_new_gobject(wsse_security->any, lasso_misc_text_node_new_with_xml_node(assertion));
266 		credentialRefs = g_list_next(credentialRefs);
267 		lasso_release_xml_node(assertion);
268 	}
269 	if (needle == NULL) {
270 		lasso_list_add_gobject(header->Other, wsse_security);
271 	}
272 cleanup:
273 	lasso_release_gobject(wsse_security);
274 	lasso_release_gobject(description);
275 	return rc;
276 }
277 
278 /**
279  * lasso_wsf_profile_comply_with_security_mechanism:
280  * @profile: a #LassoWsfProfile
281  *
282  * UNCOMPLETE.
283  *
284  * Return value: 0 if complyiing with the current security mechanism was
285  * successfull.
286  */
287 static gint
lasso_wsf_profile_comply_with_security_mechanism(LassoWsfProfile * profile)288 lasso_wsf_profile_comply_with_security_mechanism(LassoWsfProfile *profile)
289 {
290 	char *sec_mech_id;
291 
292 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
293 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
294 
295 	sec_mech_id = profile->private_data->security_mech_id;
296 	if (lasso_security_mech_id_is_saml_authentication(sec_mech_id)) {
297 		return lasso_wsf_profile_comply_with_saml_authentication(profile);
298 	}
299 	if (lasso_security_mech_id_is_bearer_authentication(sec_mech_id)) {
300 		/* Same as SAML auth, add the tokens to wss:Security header, the difference is that
301 		 * later we won't add our own signature to the header */
302 		return lasso_wsf_profile_comply_with_saml_authentication(profile);
303 	}
304 	if (lasso_security_mech_id_is_null_authentication(sec_mech_id)) {
305 		return 0;
306 	}
307 	return LASSO_WSF_PROFILE_ERROR_UNSUPPORTED_SECURITY_MECHANISM;
308 }
309 
310 static LassoSoapEnvelope*
lasso_wsf_profile_build_soap_envelope_internal(const char * refToMessageId,const char * providerId)311 lasso_wsf_profile_build_soap_envelope_internal(const char *refToMessageId, const char *providerId)
312 {
313 	LassoSoapEnvelope *envelope;
314 	LassoSoapHeader *header;
315 	LassoSoapBody *body;
316 	LassoSoapBindingCorrelation *correlation;
317 	gchar *messageId, *timestamp;
318 
319 	/* Body */
320 	body = lasso_soap_body_new();
321 	body->Id = lasso_build_unique_id(32);
322 	envelope = lasso_soap_envelope_new(body);
323 
324 	/* Header */
325 	header = lasso_soap_header_new();
326 	envelope->Header = header;
327 
328 	/* Correlation */
329 	messageId = lasso_build_unique_id(32);
330 	timestamp = lasso_get_current_time();
331 	correlation = lasso_soap_binding_correlation_new(messageId, timestamp);
332 	if (refToMessageId != NULL)
333 		correlation->refToMessageID = g_strdup(refToMessageId);
334 	header->Other = g_list_append(header->Other, correlation);
335 
336 	/* Provider */
337 	if (providerId) {
338 		LassoSoapBindingProvider *provider = lasso_soap_binding_provider_new(providerId);
339 		provider->id = lasso_build_unique_id(32);
340 		header->Other = g_list_append(header->Other, provider);
341 	}
342 
343 	return envelope;
344 }
345 
346 /*****************************************************************************/
347 /* public methods                                                            */
348 /*****************************************************************************/
349 
350 /**
351  * lasso_wsf_profile_move_credentials:
352  * @src: a #LassoWsfProfile containing the credentials
353  * @dest: the #LassoWsfProfile where to add the credentials
354  *
355  * @Deprecated: Since 2.2.1
356  *
357  * Return value: 0.
358  */
359 gint
lasso_wsf_profile_move_credentials(G_GNUC_UNUSED LassoWsfProfile * src,G_GNUC_UNUSED LassoWsfProfile * dest)360 lasso_wsf_profile_move_credentials(G_GNUC_UNUSED LassoWsfProfile *src, G_GNUC_UNUSED LassoWsfProfile *dest)
361 {
362 	return 0;
363 }
364 
365 /**
366  * lasso_wsf_profile_add_credential:
367  * @profile: a #LassoWsfProfile
368  * @credential: an #xmlNode containing credential informations
369  *
370  * @Deprecated: Since 2.2.1
371  *
372  * Return value: 0.
373  */
374 gint
lasso_wsf_profile_add_credential(G_GNUC_UNUSED LassoWsfProfile * profile,G_GNUC_UNUSED xmlNode * credential)375 lasso_wsf_profile_add_credential(G_GNUC_UNUSED LassoWsfProfile *profile, G_GNUC_UNUSED xmlNode *credential)
376 {
377 	return 0;
378 }
379 
380 /*
381  * lasso_wsf_profile_get_description_auto:
382  * @si: a #LassoDiscoServiceInstance
383  * @security_mech_id: the URI of a liberty security mechanism
384  *
385  * Traverse the service instance descriptions and find one which supports the
386  * given security mechanism.
387  *
388  * Return value: a #LassoDiscoDescription that supports security_mech_id, NULL
389  * otherwise.
390  */
391 static LassoDiscoDescription*
lasso_wsf_profile_get_description_auto(const LassoDiscoServiceInstance * si,const gchar * security_mech_id)392 lasso_wsf_profile_get_description_auto(const LassoDiscoServiceInstance *si,
393 	const gchar *security_mech_id)
394 {
395 	GList *iter, *iter2;
396 	LassoDiscoDescription *description;
397 
398 	g_return_val_if_fail(si, NULL);
399 	g_return_val_if_fail(security_mech_id, NULL);
400 
401 	iter = si->Description;
402 	while (iter) {
403 		description = LASSO_DISCO_DESCRIPTION(iter->data);
404 		iter2 = description->SecurityMechID;
405 		while (iter2) {
406 			if (strcmp(security_mech_id, iter2->data) == 0)
407 				return description;
408 			iter2 = iter2->next;
409 		}
410 		iter = iter->next;
411 	}
412 
413 	return NULL;
414 }
415 
416 /**
417  * lasso_wsf_profile_set_description_from_offering:
418  * @profile: a #LassoWsfProfile
419  * @offering: a #LassoDiscoResourceOffering containing descriptions
420  * @security_mech_id: an URL representing the wished security mechanism,
421  * if NULL take the first descriptions
422  *
423  * Setup the LassoWsfProfile for a given security mechanism.
424  *
425  * Return value: 0 if a corresponding description was found,
426  * LASSO_PROFILE_ERROR_MISSING_SERVICE_DESCRIPTION if no description with the
427  * given security mechanism was found.
428  */
429 gint
lasso_wsf_profile_set_description_from_offering(LassoWsfProfile * profile,const LassoDiscoResourceOffering * offering,const gchar * security_mech_id)430 lasso_wsf_profile_set_description_from_offering(
431 	LassoWsfProfile *profile,
432 	const LassoDiscoResourceOffering *offering,
433 	const gchar *security_mech_id)
434 {
435 	LassoDiscoDescription *description = NULL;
436 
437 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
438 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
439 	lasso_return_val_if_invalid_param(DISCO_RESOURCE_OFFERING, offering,
440 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
441 	if (security_mech_id == NULL) {
442 		if (offering->ServiceInstance &&
443 			offering->ServiceInstance->Description) {
444 			description = LASSO_DISCO_DESCRIPTION(
445 					offering->ServiceInstance->Description->data);
446 		}
447 	} else {
448 		description = lasso_wsf_profile_get_description_auto(offering->ServiceInstance,
449 				security_mech_id);
450 	}
451 	if (description == NULL) {
452 		return LASSO_PROFILE_ERROR_MISSING_SERVICE_DESCRIPTION;
453 	}
454 	lasso_wsf_profile_set_description(profile, description);
455 	return 0;
456 }
457 
458 /**
459  * lasso_wsf_profile_set_security_mech_id:
460  * @profile: the #LassoWsfProfile object
461  * @security_mech_id: a char* string representing the chosen security mech id.
462  *
463  * Set the security mechanism to use. Currently only SAML and NULL mechanism
464  * are supported for authentication. Transport is not handled by lasso so all
465  * are supported.
466  *
467  * List of supported mechanism ids:
468  * LASSO_SECURITY_MECH_NULL or "urn:liberty:security:2003-08:null:null"
469  * LASSO_SECURITY_MECH_SAML or "urn:liberty:security:2003-08:null:SAML"
470  * LASSO_SECURITY_MECH_TLS or "urn:liberty:security:2003-08:TLS:null"
471  * LASSO_SECURITY_MECH_TLS_SAML or "urn:liberty:security:2003-08:TLS:SAML"
472  * LASSO_SECURITY_MECH_CLIENT_TLS or "urn:liberty:security:2003-08:ClientTLS:null"
473  * LASSO_SECURITY_MECH_CLIENT_TLS_SAML or "urn:liberty:security:2003-08:ClientTLS:SAML"
474  *
475  * Return value: 0 if the security mechanism is supported by this #LassoWsfProfile
476  * object, an error code otherwise.
477  */
478 gint
lasso_wsf_profile_set_security_mech_id(LassoWsfProfile * profile,const char * security_mech_id)479 lasso_wsf_profile_set_security_mech_id(LassoWsfProfile *profile,
480 	const char *security_mech_id)
481 {
482 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
483 		LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
484 
485 	if (lasso_security_mech_id_is_saml_authentication(security_mech_id)
486 			|| lasso_security_mech_id_is_null_authentication(security_mech_id)) {
487 		lasso_assign_string(profile->private_data->security_mech_id, security_mech_id);
488 		if (profile->private_data->offering) {
489 			return lasso_wsf_profile_set_description_from_offering(
490 				profile,
491 				profile->private_data->offering,
492 				security_mech_id);
493 		}
494 	}
495 	return LASSO_WSF_PROFILE_ERROR_UNSUPPORTED_SECURITY_MECHANISM;
496 }
497 
498 /**
499  * lasso_wsf_profile_get_security_mech_id:
500  * @profile: the #LassoWsfProfile object
501  *
502  * Return value:(transfer none): the current security mechanism id for this object.
503  */
504 const char *
lasso_wsf_profile_get_security_mech_id(LassoWsfProfile * profile)505 lasso_wsf_profile_get_security_mech_id(LassoWsfProfile *profile)
506 {
507 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
508 		NULL);
509 
510 	return profile->private_data->security_mech_id;
511 }
512 
513 /**
514  * lasso_wsf_profile_set_description:
515  * @profile: the #LassoWsfProfile
516  * @description: a #LassoDiscoDescription
517  *
518  * Set the currently registered #LassoDiscoDescription, that permits to locate
519  * the endpoint and the security mechanism to use for the next ID-WSF request.
520  */
521 void
lasso_wsf_profile_set_description(LassoWsfProfile * profile,LassoDiscoDescription * description)522 lasso_wsf_profile_set_description(LassoWsfProfile *profile, LassoDiscoDescription *description)
523 {
524 	lasso_assign_gobject(profile->private_data->description, description);
525 }
526 
527 /**
528  * lasso_wsf_profile_get_description:
529  * @profile: a #LassoWsfProfile
530  *
531  * Returns the currently registered #LassoDiscoDescription, that permits to
532  * locate the endpoint and the security mechanism to use for the next ID-WSF
533  * request.
534  *
535  * Return value:(transfer full): a #LassoDiscoDescriptio or NULL if none is present.
536  */
537 LassoDiscoDescription *
lasso_wsf_profile_get_description(const LassoWsfProfile * profile)538 lasso_wsf_profile_get_description(const LassoWsfProfile *profile)
539 {
540 	return lasso_ref(profile->private_data->description);
541 }
542 
543 /**
544  * lasso_wsf_profile_get_resource_offering:
545  * @profile: the #LassoWsfProfile object
546  *
547  * Returns the ResourceOffering setupt with this profile object.
548  *
549  * Return value:(transfer full): a #LassoDiscoResourceOffering if one was setup during
550  * construction, NULL otherwise.
551  */
552 LassoDiscoResourceOffering *
lasso_wsf_profile_get_resource_offering(LassoWsfProfile * profile)553 lasso_wsf_profile_get_resource_offering(LassoWsfProfile *profile)
554 {
555 	return lasso_ref(profile->private_data->offering);
556 }
557 
558 /**
559  * lasso_wsf_profile_set_resource_offering:
560  * @profile: a #LassoWsfProfile
561  * @offering: a #LassoDiscoResourceOffering
562  *
563  * Set the Resssource Offering to setup this ID-WSF profile.
564  *
565  */
566 void
lasso_wsf_profile_set_resource_offering(LassoWsfProfile * profile,LassoDiscoResourceOffering * offering)567 lasso_wsf_profile_set_resource_offering(LassoWsfProfile *profile,
568 	LassoDiscoResourceOffering *offering)
569 {
570 	lasso_assign_gobject(profile->private_data->offering, offering);
571 }
572 
573 /**
574  * lasso_wsf_profile_build_soap_envelope:
575  * @refToMessageId: a char* string and the eventual MessageId of a SOAP request
576  * we are responding to.
577  * @providerId: a char* string and the eventual providerID of a web service
578  * provider we intend to send this soap message to.
579  *
580  * Build the a #LassoSoapEnvelope as a template for a future SOAP message
581  * containing the headers recommended by the ID-WSF 1.0 specification.
582  *
583  * Return value: a new #LassoSoapEnvelope if construction was successfull.
584  */
585 LassoSoapEnvelope*
lasso_wsf_profile_build_soap_envelope(const char * refToMessageId,const char * providerId)586 lasso_wsf_profile_build_soap_envelope(const char *refToMessageId, const char *providerId)
587 {
588 	return lasso_wsf_profile_build_soap_envelope_internal(refToMessageId, providerId);
589 }
590 
591 
592 /**
593  * lasso_wsf_profile_get_identity:
594  * @profile: a #LassoWsfProfile
595  *
596  * Gets the identity bound to @profile.
597  *
598  * Return value:(transfer none)(allow-none): the identity or NULL if it none was found.  The #LassoIdentity
599  *      object is internally allocated and must not be freed by the caller.
600  **/
601 LassoIdentity*
lasso_wsf_profile_get_identity(const LassoWsfProfile * profile)602 lasso_wsf_profile_get_identity(const LassoWsfProfile *profile)
603 {
604 	if (profile->identity && g_hash_table_size(profile->identity->federations))
605 		return profile->identity;
606 	return NULL;
607 }
608 
609 
610 /**
611  * lasso_wsf_profile_get_session:
612  * @profile: a #LassoWsfProfile
613  *
614  * Gets the session bound to @profile.
615  *
616  * Return value:(transfer none)(allow-none): the session or NULL if it none was found. The
617  * #LassoSession object is internally allocated and must not be freed by the caller.
618  **/
619 LassoSession*
lasso_wsf_profile_get_session(const LassoWsfProfile * profile)620 lasso_wsf_profile_get_session(const LassoWsfProfile *profile)
621 {
622 	if (profile->session == NULL)
623 		return NULL;
624 
625 	if (lasso_session_is_empty(profile->session))
626 		return NULL;
627 
628 	return profile->session;
629 }
630 
631 
632 /**
633  * lasso_wsf_profile_is_identity_dirty:
634  * @profile: a #LassoWsfProfile
635  *
636  * Checks whether identity has been modified (and should therefore be saved).
637  *
638  * Return value: %TRUE if identity has changed
639  **/
640 gboolean
lasso_wsf_profile_is_identity_dirty(const LassoWsfProfile * profile)641 lasso_wsf_profile_is_identity_dirty(const LassoWsfProfile *profile)
642 {
643 	return (profile->identity && profile->identity->is_dirty);
644 }
645 
646 
647 /**
648  * lasso_wsf_profile_is_session_dirty:
649  * @profile: a #LassoWsfProfile
650  *
651  * Checks whether session has been modified (and should therefore be saved).
652  *
653  * Return value: %TRUE if session has changed
654  **/
655 gboolean
lasso_wsf_profile_is_session_dirty(const LassoWsfProfile * profile)656 lasso_wsf_profile_is_session_dirty(const LassoWsfProfile *profile)
657 {
658 	return (profile->session && lasso_session_is_dirty(profile->session));
659 }
660 
661 
662 /**
663  * lasso_wsf_profile_set_identity_from_dump:
664  * @profile: a #LassoWsfProfile
665  * @dump: XML identity dump
666  *
667  * Builds a new #LassoIdentity object from XML dump and binds it to @profile.
668  *
669  * Return value: 0 on success; or a negative value otherwise.
670  **/
671 gint
lasso_wsf_profile_set_identity_from_dump(LassoWsfProfile * profile,const gchar * dump)672 lasso_wsf_profile_set_identity_from_dump(LassoWsfProfile *profile, const gchar *dump)
673 {
674 	g_return_val_if_fail(dump != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
675 
676 	profile->identity = lasso_identity_new_from_dump(dump);
677 	if (profile->identity == NULL)
678 		return critical_error(LASSO_PROFILE_ERROR_BAD_IDENTITY_DUMP);
679 
680 	return 0;
681 }
682 
683 
684 /**
685  * lasso_wsf_profile_set_session_from_dump:
686  * @profile: a #LassoWsfProfile
687  * @dump: XML session dump
688  *
689  * Builds a new #LassoSession object from XML dump and binds it to @profile.
690  *
691  * Return value: 0 on success; or a negative value otherwise.
692  **/
693 gint
lasso_wsf_profile_set_session_from_dump(LassoWsfProfile * profile,const gchar * dump)694 lasso_wsf_profile_set_session_from_dump(LassoWsfProfile *profile, const gchar  *dump)
695 {
696 	g_return_val_if_fail(dump != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
697 
698 	profile->session = lasso_session_new_from_dump(dump);
699 	if (profile->session == NULL)
700 		return critical_error(LASSO_PROFILE_ERROR_BAD_SESSION_DUMP);
701 
702 	return 0;
703 }
704 
705 /**
706  * lasso_wsf_profile_init_soap_request:
707  * @profile: a #LassoWsfProfile to initialize for a SOAP request
708  * @request: a #LassoNode object containing the body for the SOAP request, can be NULL.
709  *
710  * Build the SOAP envelope for a request to and ID-WSF 1.0 web service and set
711  * the body of the request to request. The reference to request is not stolen i.e
712  * the ref count of request is increased by one after this call.
713  *
714  * Return value: 0 if initialization was successfull.
715  **/
716 gint
lasso_wsf_profile_init_soap_request(LassoWsfProfile * profile,LassoNode * request)717 lasso_wsf_profile_init_soap_request(LassoWsfProfile *profile, LassoNode *request)
718 {
719 	LassoSoapEnvelope *envelope;
720 	char *providerID = NULL;
721 
722 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
723 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
724 
725 	if (profile->server) {
726 		providerID = profile->server->parent.ProviderID;
727 	}
728 	envelope = lasso_wsf_profile_build_soap_envelope_internal(NULL, providerID);
729 	lasso_assign_new_gobject(profile->soap_envelope_request, envelope);
730 	lasso_list_add_gobject(envelope->Body->any, request);
731 	lasso_assign_gobject(profile->request, request);
732 	return 0;
733 }
734 
735 /**
736  * lasso_wsf_profile_init_soap_response:
737  * @profile: a #LassoWsfProfile object
738  * @response: a #LassoNode object
739  *
740  * Build a new SOAP envelope containing response to current SOAP request
741  */
742 gint
lasso_wsf_profile_init_soap_response(LassoWsfProfile * profile,LassoNode * response)743 lasso_wsf_profile_init_soap_response(LassoWsfProfile *profile, LassoNode *response)
744 {
745 	char *providerID = NULL;
746 	LassoSoapEnvelope *envelope = NULL;
747 
748 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
749 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
750 
751 	if (profile->server) {
752 		providerID = profile->server->parent.ProviderID;
753 	}
754 	envelope = lasso_wsf_profile_build_soap_envelope_internal(lasso_wsf_profile_utils_get_message_id(profile->soap_envelope_request),
755 			providerID);
756 	lasso_assign_new_gobject(profile->soap_envelope_response, envelope);
757 	lasso_list_add_gobject(envelope->Body->any, response);
758 	lasso_assign_gobject(profile->response, response);
759 	return 0;
760 }
761 
762 /**
763  * lasso_wsf_profile_build_soap_request_msg:
764  * @profile: the #LassoWsfProfile object
765  *
766  * Create the char* string containing XML document for the SOAP ID-WSF request
767  * and eventually sign with the local public depending on the security
768  * mechanism requested.
769  *
770  * Return value: 0 if construction is successfull.
771  **/
772 gint
lasso_wsf_profile_build_soap_request_msg(LassoWsfProfile * wsf_profile)773 lasso_wsf_profile_build_soap_request_msg(LassoWsfProfile *wsf_profile)
774 {
775 	LassoSoapEnvelope *envelope;
776 	xmlOutputBuffer *buf;
777 	xmlCharEncodingHandler *handler;
778 	xmlDoc *doc = NULL;
779 	xmlNode *envelope_node = NULL;
780 	char *sec_mech_id = NULL;
781 	int rc = 0;
782 
783 	lasso_bad_param(WSF_PROFILE, wsf_profile);
784 	lasso_return_val_if_invalid_param(SOAP_ENVELOPE, wsf_profile->soap_envelope_request,
785 			LASSO_SOAP_ERROR_MISSING_ENVELOPE);
786 
787 	rc = lasso_wsf_profile_comply_with_security_mechanism(wsf_profile);
788 	goto_cleanup_if_fail(rc == 0);
789 	envelope = wsf_profile->soap_envelope_request;
790 	doc = xmlNewDoc((xmlChar*)"1.0");
791 	envelope_node = lasso_node_get_xmlNode(LASSO_NODE(envelope), FALSE);
792 	xmlDocSetRootElement(doc, envelope_node);
793 	/* Sign request if necessary */
794 	sec_mech_id = wsf_profile->private_data->security_mech_id;
795 	if (lasso_security_mech_id_is_saml_authentication(sec_mech_id)) {
796 		rc = lasso_wsf_profile_add_saml_signature(wsf_profile, doc);
797 		if (rc != 0) {
798 			goto cleanup;
799 		}
800 	} else if (lasso_security_mech_id_is_bearer_authentication(sec_mech_id)) {
801 		// Nothing to do
802 	} else if (lasso_security_mech_id_is_null_authentication(sec_mech_id) == FALSE) {
803 		rc = LASSO_WSF_PROFILE_ERROR_UNSUPPORTED_SECURITY_MECHANISM;
804 		goto cleanup;
805 	}
806 
807 	/* Dump soap request */
808 	handler = xmlFindCharEncodingHandler("utf-8");
809 	buf = xmlAllocOutputBuffer(handler);
810 	xmlNodeDumpOutput(buf, NULL, envelope_node, 0, 0, "utf-8");
811 	xmlOutputBufferFlush(buf);
812 	wsf_profile->msg_body = g_strdup(
813 		(char*)(buf->conv ? buf->conv->content : buf->buffer->content));
814 	lasso_release_output_buffer(buf);
815 	rc = lasso_wsf_profile_set_msg_url_from_description(wsf_profile);
816 
817 cleanup:
818 	lasso_release_doc(doc);
819 	return rc;
820 }
821 
822 /**
823  * lasso_wsf_profile_build_soap_response_msg:
824  * @wsf_profile: a #LassoWsfProfile object
825  *
826  * Create the char* string containing XML document for the SOAP ID-WSF
827  * response.
828  *
829  * Return value: 0 if construction is successfull.
830  **/
831 gint
lasso_wsf_profile_build_soap_response_msg(LassoWsfProfile * wsf_profile)832 lasso_wsf_profile_build_soap_response_msg(LassoWsfProfile *wsf_profile)
833 {
834 	LassoSoapEnvelope *envelope = NULL;
835 	LassoSoapFault *soap_fault = NULL;
836 	int rc = 0;
837 
838 	lasso_bad_param(WSF_PROFILE, wsf_profile);
839 	envelope = wsf_profile->soap_envelope_response;
840 	if (! LASSO_IS_SOAP_ENVELOPE(envelope)) {
841 		return LASSO_SOAP_ERROR_MISSING_ENVELOPE;
842 	}
843 
844 	/* If SOAP fault replace response by the SOAP fault */
845 	if ((soap_fault = lasso_wsf_profile_get_soap_fault(wsf_profile))) {
846 		LassoSoapBody *body = NULL;
847 		lasso_extract_node_or_fail(body, envelope->Body, SOAP_BODY, LASSO_SOAP_ERROR_MISSING_BODY);
848 		lasso_release_list_of_gobjects(body->any);
849 		lasso_list_add_gobject(body->any, soap_fault);
850 	}
851 
852 	lasso_assign_new_string(wsf_profile->msg_body,
853 			lasso_node_export_to_xml((LassoNode*)envelope));
854 cleanup:
855 	return rc;
856 }
857 
858 /** FIXME: add support for security mechanisms SAML and Bearer. */
859 /**
860  * lasso_wsf_profile_process_soap_request_msg:
861  * @profile: a #LassoWsfProfile object
862  * @message: a SOAP request message string
863  * @security_mech_id: the security mechanism to apply
864  *
865  * Process an ID-WSF SOAP request, extract headers information, and check compliance with the
866  * security mechanism.
867  *
868  * Return value: 0 if successful, an error code otherwise.
869  */
870 gint
lasso_wsf_profile_process_soap_request_msg(LassoWsfProfile * profile,const gchar * message,const gchar * security_mech_id)871 lasso_wsf_profile_process_soap_request_msg(LassoWsfProfile *profile, const gchar *message,
872 	const gchar *security_mech_id)
873 {
874 	LassoSoapBindingCorrelation *correlation = NULL;
875 	LassoSoapEnvelope *envelope = NULL;
876 	gchar *messageId = NULL;
877 	int rc = 0;
878 	xmlDoc *doc = NULL;
879 	GList *iter = NULL;
880 	GList *node_list = NULL;
881 
882 	lasso_bad_param(WSF_PROFILE, profile);
883 	lasso_null_param(message);
884 
885 	g_return_val_if_fail(profile->private_data, LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
886 	lasso_wsf_profile_set_soap_fault(profile, NULL);
887 
888 	doc = lasso_xml_parse_memory(message, strlen(message));
889 	goto_cleanup_if_fail_with_rc (doc != NULL, critical_error(LASSO_PROFILE_ERROR_INVALID_SOAP_MSG));
890 	/* Get soap request and his message id */
891 	envelope = LASSO_SOAP_ENVELOPE(lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc)));
892 	if (LASSO_IS_SOAP_ENVELOPE(envelope)) {
893 		lasso_assign_gobject(profile->soap_envelope_request, envelope);
894 	} else {
895 		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_SOAP_MSG);
896 	}
897 	goto_cleanup_if_fail_with_rc(envelope != NULL, LASSO_SOAP_ERROR_MISSING_ENVELOPE);
898 	goto_cleanup_if_fail_with_rc(envelope->Body != NULL, LASSO_SOAP_ERROR_MISSING_BODY);
899 	if (envelope->Body->any && LASSO_IS_NODE(envelope->Body->any->data)) {
900 		lasso_assign_gobject(profile->request, LASSO_NODE(envelope->Body->any->data));
901 	} else {
902 		profile->request = NULL;
903 		rc = LASSO_PROFILE_ERROR_MISSING_REQUEST;
904 	}
905 
906 	/* Get the correlation header */
907 	goto_cleanup_if_fail_with_rc(envelope->Header != NULL, LASSO_SOAP_ERROR_MISSING_HEADER);
908 	for (iter = envelope->Header->Other; iter != NULL; iter = iter->next) {
909 		if (LASSO_IS_SOAP_BINDING_CORRELATION(iter->data)) {
910 			correlation = LASSO_SOAP_BINDING_CORRELATION(iter->data);
911 			break;
912 		}
913 	}
914 	goto_cleanup_if_fail_with_rc (correlation != NULL && correlation->messageID != NULL,
915 		LASSO_WSF_PROFILE_ERROR_MISSING_CORRELATION);
916 	messageId = correlation->messageID;
917 
918 	/* Comply with security mechanism */
919 	if (lasso_security_mech_id_is_null_authentication(security_mech_id) == FALSE) {
920 		goto_cleanup_if_fail_with_rc(FALSE, LASSO_WSF_PROFILE_ERROR_UNSUPPORTED_SECURITY_MECHANISM);
921 	}
922 
923 	/* Extract the remote provider ID if present */
924 	if (LASSO_IS_SOAP_HEADER(envelope->Header)) {
925 		for (node_list = envelope->Header->Other;
926 				node_list; node_list = g_list_next(node_list)) {
927 			LassoSoapBindingProvider *node = node_list->data;
928 
929 			if (LASSO_IS_SOAP_BINDING_PROVIDER(node)) {
930 				lasso_assign_string(profile->private_data->remote_provider_id,
931 						node->providerID);
932 				break; /* Only treat the first one */
933 			}
934 		}
935 	}
936 
937 cleanup:
938 	lasso_release_gobject(envelope);
939 	lasso_release_doc(doc);
940 
941 	return rc;
942 }
943 
944 
945 /**
946  * lasso_wsf_profile_process_soap_response_msg:
947  * @profile: a #LassoWsfProfile object
948  * @message: the textual representaition of a SOAP message
949  *
950  * Parse a SOAP response from an ID-WSF 1.0 service,
951  * eventually signal a SOAP fault.
952  *
953  * Return value: 0 if the processing of this message was successful.
954  **/
955 gint
lasso_wsf_profile_process_soap_response_msg(LassoWsfProfile * profile,const gchar * message)956 lasso_wsf_profile_process_soap_response_msg(LassoWsfProfile *profile, const gchar *message)
957 {
958 	xmlDoc *doc = NULL;
959 	LassoSoapEnvelope *envelope = NULL;
960 	gint rc = 0;
961 
962 	lasso_bad_param(WSF_PROFILE, profile);
963 	lasso_null_param(message);
964 
965 	g_return_val_if_fail(profile->private_data, LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
966 	lasso_wsf_profile_set_soap_fault(profile, NULL);
967 
968 	doc = lasso_xml_parse_memory(message, strlen(message));
969 	goto_cleanup_if_fail_with_rc (doc != NULL, critical_error(LASSO_PROFILE_ERROR_INVALID_SOAP_MSG));
970 	envelope = (LassoSoapEnvelope*)lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc));
971 	if (LASSO_IS_SOAP_ENVELOPE(envelope)) {
972 		lasso_assign_gobject(profile->soap_envelope_response, envelope);
973 	} else {
974 		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_SOAP_MSG);
975 	}
976 	goto_cleanup_if_fail_with_rc(envelope->Body != NULL, LASSO_SOAP_ERROR_MISSING_BODY);
977 	if (envelope->Body->any && LASSO_IS_NODE(envelope->Body->any->data)) {
978 		lasso_assign_gobject(profile->response, envelope->Body->any->data);
979 	} else {
980 		lasso_release_gobject(profile->response);
981 		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_MISSING_RESPONSE);
982 	}
983 
984 	/* Check correlation header */
985 	goto_cleanup_if_fail_with_rc(
986 			lasso_wsf_profile_utils_get_header_correlation(
987 				profile->soap_envelope_response),
988 			LASSO_WSF_PROFILE_ERROR_MISSING_CORRELATION);
989 
990 	/* Check message ID */
991 	{
992 		const char *message_id =
993 			lasso_wsf_profile_utils_get_message_id(profile->soap_envelope_request);
994 		const char *ref_message_id =
995 			lasso_wsf_profile_utils_get_ref_message_id(profile->soap_envelope_response);
996 		goto_cleanup_if_fail_with_rc(lasso_strisequal(message_id, ref_message_id),
997 				LASSO_WSF_PROFILE_ERROR_INVALID_OR_MISSING_REFERENCE_TO_MESSAGE_ID);
998 	}
999 
1000 	/* Signal soap fault specifically,
1001 	 * find soap redirects. */
1002 	if (LASSO_IS_SOAP_FAULT(profile->response)) {
1003 		LassoSoapFault *fault = LASSO_SOAP_FAULT(profile->response);
1004 		if (LASSO_IS_SOAP_DETAIL(fault->Detail)) {
1005 		    LassoSoapDetail *detail = LASSO_SOAP_DETAIL(fault->Detail);
1006 		    GList *iter = detail->any;
1007 		    for (; iter; iter = g_list_next(iter)) {
1008 			if (LASSO_IS_IS_REDIRECT_REQUEST(iter->data)) {
1009 			    LassoIsRedirectRequest *redirect = LASSO_IS_REDIRECT_REQUEST(iter->data);
1010 			    lasso_assign_string(profile->msg_url, redirect->redirectURL);
1011 			    rc = LASSO_SOAP_ERROR_REDIRECT_REQUEST_FAULT;
1012 			}
1013 		    }
1014 
1015 		}
1016 		if (rc == 0) {
1017 			rc = LASSO_WSF_PROFILE_ERROR_SOAP_FAULT;
1018 		}
1019 	}
1020 cleanup:
1021 	lasso_release_gobject(envelope);
1022 	lasso_release_doc(doc);
1023 	return rc;
1024 }
1025 
1026 /**
1027  * lasso_wsf_profile_set_provider_soap_request:
1028  *
1029  * @Deprecated: Since 2.2.1
1030  *
1031  * Return value: NULL
1032  **/
1033 LassoSoapBindingProvider *
lasso_wsf_profile_set_provider_soap_request(G_GNUC_UNUSED LassoWsfProfile * profile,G_GNUC_UNUSED const char * providerId)1034 lasso_wsf_profile_set_provider_soap_request(G_GNUC_UNUSED LassoWsfProfile *profile,
1035 	G_GNUC_UNUSED const char *providerId)
1036 {
1037 	return NULL;
1038 }
1039 
1040 /*****************************************************************************/
1041 /* overrided parent class methods */
1042 /*****************************************************************************/
1043 
1044 static LassoNodeClass *parent_class = NULL;
1045 
1046 static void
dispose(GObject * object)1047 dispose(GObject *object)
1048 {
1049 	LassoWsfProfile *profile = LASSO_WSF_PROFILE(object);
1050 
1051 	if (profile->private_data->dispose_has_run == TRUE)
1052 		return;
1053 	lasso_release_string(profile->private_data->security_mech_id);
1054 	lasso_release_gobject(profile->private_data->offering);
1055 	lasso_release_gobject(profile->private_data->description);
1056 	lasso_release_string(profile->private_data->remote_provider_id);
1057 	lasso_release_gobject(profile->private_data->soap_fault);
1058 	lasso_release_string(profile->private_data->status_code);
1059 	profile->private_data->dispose_has_run = TRUE;
1060 
1061 	G_OBJECT_CLASS(parent_class)->dispose(object);
1062 }
1063 
1064 static void
finalize(GObject * object)1065 finalize(GObject *object)
1066 {
1067 	LassoWsfProfile *profile = LASSO_WSF_PROFILE(object);
1068 	lasso_release(profile->private_data);
1069 	profile->private_data = NULL;
1070 	G_OBJECT_CLASS(parent_class)->finalize(object);
1071 }
1072 
1073 /*****************************************************************************/
1074 /* instance and class init functions                                         */
1075 /*****************************************************************************/
1076 
1077 static void
instance_init(LassoWsfProfile * profile)1078 instance_init(LassoWsfProfile *profile)
1079 {
1080 	profile->server = NULL;
1081 	profile->request = NULL;
1082 	profile->response = NULL;
1083 	profile->soap_envelope_request = NULL;
1084 	profile->soap_envelope_response = NULL;
1085 	profile->msg_url = NULL;
1086 	profile->msg_body = NULL;
1087 
1088 	profile->private_data = g_new0(LassoWsfProfilePrivate, 1);
1089 }
1090 
1091 static void
class_init(LassoWsfProfileClass * klass,void * unused G_GNUC_UNUSED)1092 class_init(LassoWsfProfileClass *klass, void *unused G_GNUC_UNUSED)
1093 {
1094 	LassoNodeClass *nclass = LASSO_NODE_CLASS(klass);
1095 
1096 	parent_class = g_type_class_peek_parent(klass);
1097 	nclass->node_data = g_new0(LassoNodeClassData, 1);
1098 	lasso_node_class_set_nodename(nclass, "WsfProfile");
1099 	lasso_node_class_set_ns(nclass, LASSO_LASSO_HREF, LASSO_LASSO_PREFIX);
1100 	lasso_node_class_add_snippets(nclass, schema_snippets);
1101 
1102 	G_OBJECT_CLASS(klass)->dispose = dispose;
1103 	G_OBJECT_CLASS(klass)->finalize = finalize;
1104 }
1105 
1106 GType
lasso_wsf_profile_get_type()1107 lasso_wsf_profile_get_type()
1108 {
1109 	static GType this_type = 0;
1110 
1111 	if (!this_type) {
1112 		static const GTypeInfo this_info = {
1113 			sizeof(LassoWsfProfileClass),
1114 			NULL,
1115 			NULL,
1116 			(GClassInitFunc) class_init,
1117 			NULL,
1118 			NULL,
1119 			sizeof(LassoWsfProfile),
1120 			0,
1121 			(GInstanceInitFunc) instance_init,
1122 			NULL
1123 		};
1124 
1125 		this_type = g_type_register_static(LASSO_TYPE_NODE,
1126 				"LassoWsfProfile", &this_info, 0);
1127 	}
1128 	return this_type;
1129 }
1130 
1131 /**
1132  * lasso_wsf_profile_init:
1133  * @profile: the #LassoWsfProfile to initialize
1134  * @server: a #LassoServer object to resolve provider IDs.
1135  * @offering: a #LassoDiscoResourceOffering for the
1136  * targetted web service.
1137  *
1138  * Initialize a #LassoWsfProfile in order to handle or send
1139  * request to, an ID-WSF web service.
1140  *
1141  * Return: 0 if initialization was successfull.
1142  */
1143 gint
lasso_wsf_profile_init(LassoWsfProfile * profile,LassoServer * server,LassoDiscoResourceOffering * offering)1144 lasso_wsf_profile_init(LassoWsfProfile *profile,
1145 		LassoServer *server,
1146 		LassoDiscoResourceOffering *offering)
1147 {
1148 	lasso_return_val_if_invalid_param(WSF_PROFILE, profile,
1149 			LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1150 	/* FIXME: is a NULL server authorized ? */
1151 	lasso_assign_gobject(profile->server, server);
1152 	/* FIXME: is a NULL oferring authorized ? */
1153 	lasso_assign_gobject(profile->private_data->offering, offering);
1154 
1155 	return 0;
1156 }
1157 
1158 
1159 /**
1160  * lasso_wsf_profile_new:
1161  * @server: a #LassoServer object to lookup remote provider informations
1162  *
1163  * Create a new #WsfProfile with the given #LassoServer object.
1164  *
1165  * Return: a new #LassoWsfProfile if creation and initialization were
1166  * successfull, NULL otherwise.
1167  */
1168 LassoWsfProfile*
lasso_wsf_profile_new(LassoServer * server)1169 lasso_wsf_profile_new(LassoServer *server)
1170 {
1171 	return lasso_wsf_profile_new_full(server, NULL);
1172 }
1173 
1174 /**
1175  * lasso_wsf_profile_new_full:
1176  * @server: a #LassoServer object to lookup remote provider informations.
1177  * @offering: a #LassoDiscoResourceOffering for the requested service.
1178  *
1179  * Create a new #WsfProfile with the given #LassoServer object and the given
1180  * #LassoDiscoResourceOffering.
1181  *
1182  * Return: a new #LassoWsfProfile if creation and initialization were
1183  * successfull, NULL otherwise.
1184  */
1185 LassoWsfProfile*
lasso_wsf_profile_new_full(LassoServer * server,LassoDiscoResourceOffering * offering)1186 lasso_wsf_profile_new_full(LassoServer *server, LassoDiscoResourceOffering *offering)
1187 {
1188 	LassoWsfProfile *profile = NULL;
1189 
1190 	profile = g_object_new(LASSO_TYPE_WSF_PROFILE, NULL);
1191 	if (lasso_wsf_profile_init(profile, server, offering)) {
1192 		lasso_release_gobject(profile);
1193 	}
1194 	return profile;
1195 }
1196 
1197 /**
1198  * add_signature_template:
1199  * @server: a #LassoServer object
1200  * @doc: a #xmlDoc structure
1201  * @node a #xmlNode structure
1202  * @signature_ptr: an output argument for an #xmlNode structure
1203  *
1204  * Create a new XMLDSig template without any reference and return the created
1205  * Signature node. If node is not NULL add Signature as a last child to it. If @signature_ptr is not
1206  * NULL the template node is stored there.
1207  *
1208  * Return value: 0 if successful, LASSO_DS_ERROR_SIGNATURE_TMPL_CREATION_FAILED otherwise.
1209  */
1210 static gint
add_signature_template(LassoServer * server,xmlDoc * doc,xmlNode * node,xmlNode ** signature_ptr)1211 add_signature_template(LassoServer *server, xmlDoc *doc, xmlNode *node, xmlNode **signature_ptr) {
1212 	xmlNode *signature = NULL;
1213 	gint rc = 0;
1214 
1215 	switch (server->signature_method) {
1216 		case LASSO_SIGNATURE_METHOD_RSA_SHA1:
1217 			signature = xmlSecTmplSignatureCreate(doc,
1218 				xmlSecTransformExclC14NId,
1219 				xmlSecTransformRsaSha1Id,
1220 				NULL);
1221 			break;
1222 		case LASSO_SIGNATURE_METHOD_DSA_SHA1:
1223 			signature = xmlSecTmplSignatureCreate(doc,
1224 				xmlSecTransformExclC14NId,
1225 				xmlSecTransformDsaSha1Id,
1226 				NULL);
1227 			break;
1228 		default:
1229 			rc = LASSO_DS_ERROR_SIGNATURE_TMPL_CREATION_FAILED;
1230 			goto cleanup;
1231 
1232 	}
1233 
1234 	/* Last steps... */
1235 	if (signature_ptr) {
1236 		*signature_ptr = signature;
1237 	}
1238 	if (node) {
1239 		xmlAddChild(node, signature);
1240 	}
1241 cleanup:
1242 	return rc;
1243 }
1244 
1245 static gint
add_reference_to_non_enveloping_id(xmlNode * signature,xmlChar * id)1246 add_reference_to_non_enveloping_id(xmlNode *signature, xmlChar *id)
1247 {
1248 	gint rc = 0;
1249 	char *uri = NULL;
1250 	xmlNode *reference = NULL;
1251 
1252 	goto_cleanup_if_fail_with_rc(signature != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1253 	goto_cleanup_if_fail_with_rc(id != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1254 	uri = g_strdup_printf("#%s", id);
1255 	reference = xmlSecTmplSignatureAddReference(signature,
1256 			xmlSecTransformSha1Id, NULL, (xmlChar*)uri, NULL);
1257 	/* add exclusive C14N transform */
1258 	xmlSecTmplReferenceAddTransform(reference, xmlSecTransformExclC14NId);
1259 cleanup:
1260 	lasso_release(uri);
1261 	return rc;
1262 }
1263 
1264 static gint
create_signature_context(LassoServer * server,xmlSecDSigCtx ** ctx_ptr)1265 create_signature_context(LassoServer *server, xmlSecDSigCtx **ctx_ptr) {
1266 	xmlSecDSigCtx *dsig_ctx = NULL;
1267 	gint rc = 0;
1268 
1269 	lasso_bad_param(SERVER, server);
1270 	lasso_null_param(ctx_ptr);
1271 
1272 	/* Allocate an initialize the object */
1273 	dsig_ctx = xmlSecDSigCtxCreate(NULL);
1274 	/* Load the private key for the server object */
1275 	/* XXX: handle other formats */
1276 	/* XXX: handle password protected keys */
1277 	/* XXX: handle pkcs12 all-in-one files */
1278 	dsig_ctx->signKey = xmlSecCryptoAppKeyLoad(server->private_key,
1279 			xmlSecKeyDataFormatPem,
1280 			NULL, NULL, NULL);
1281 	goto_cleanup_if_fail_with_rc(dsig_ctx->signKey != NULL, LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED);
1282 	/* Load the certificate chain if needed */
1283 	if (server->certificate) {
1284 		gint ret = xmlSecCryptoAppKeyCertLoad(dsig_ctx->signKey,
1285 			server->certificate,
1286 			xmlSecKeyDataFormatPem);
1287 		goto_cleanup_if_fail_with_rc(ret >= 0, LASSO_DS_ERROR_CERTIFICATE_LOAD_FAILED);
1288 	}
1289 	/* Transfer the reference */
1290 	*ctx_ptr = dsig_ctx;
1291 	dsig_ctx = NULL;
1292 cleanup:
1293 	if (dsig_ctx) {
1294 		xmlSecDSigCtxDestroy(dsig_ctx);
1295 	}
1296 	return rc;
1297 
1298 }
1299 
1300 static xmlChar *
make_id_ref(xmlChar * id)1301 make_id_ref(xmlChar *id) {
1302 	char *res = NULL;
1303 
1304 	res = g_strdup_printf("#%s", (char*)id);
1305 	return (xmlChar*)res;
1306 }
1307 
1308 static void
add_key_info_security_token_reference(xmlDocPtr doc,xmlNode * signature,xmlChar * assertion_id)1309 add_key_info_security_token_reference(xmlDocPtr doc, xmlNode *signature, xmlChar *assertion_id) {
1310 	xmlNsPtr nsPtr = NULL;
1311 	xmlChar *value = NULL;
1312 	xmlNode *key_info = NULL, *security_token_reference = NULL, *reference = NULL;
1313 
1314 	/* Add key info */
1315 	key_info = xmlSecTmplSignatureEnsureKeyInfo(signature, NULL);
1316 	/* Free children */
1317 	xmlFreeNodeList(key_info->children);
1318 	key_info->children = NULL;
1319 	/* Create sec:SecurityTokenReferenceNode */
1320 	security_token_reference = xmlSecAddChild(key_info, (xmlChar*) "SecurityTokenReference",
1321 		(xmlChar*)LASSO_WSSE1_HREF);
1322 	nsPtr = xmlSearchNsByHref(doc, security_token_reference, (xmlChar*) LASSO_SEC_HREF);
1323 	if (nsPtr == NULL) {
1324 		nsPtr = xmlNewNs(security_token_reference, (xmlChar*) LASSO_SEC_HREF,
1325 			(xmlChar*) LASSO_SEC_PREFIX);
1326 	}
1327 	value = (xmlChar*) g_strdup_printf("%s:MessageAuthentication", nsPtr->prefix);
1328 	xmlSetProp(security_token_reference, (xmlChar*) "Usage", value);
1329 	lasso_release(value);
1330 	/* Create Reference */
1331 	reference = xmlSecAddChild(security_token_reference, (xmlChar*) "Reference",
1332 		(xmlChar*) LASSO_WSSE1_HREF);
1333 	value = make_id_ref(assertion_id);
1334 	xmlSetProp(reference, (xmlChar*) "URI", value);
1335 	lasso_release(value);
1336 }
1337 
1338 /**
1339  * lasso_wsf_profile_add_saml_signature:
1340  * @wsf_profile: a #LassoWsfProfile
1341  * @doc: the #xmlDoc document that contains the SOAP message to sign
1342  *
1343  * This function add the signature to comply with specification of the ID-WSF
1344  * SAML security mechanism.  In order to do that we must sign the headers
1345  * Provider, Correlation and eventually is:Interaction and also the Body of the
1346  * SOAP message.
1347  *
1348  * Return value: 0 if signature creation succeeded, an error code otherwise.
1349  */
1350 static gint
lasso_wsf_profile_add_saml_signature(LassoWsfProfile * wsf_profile,xmlDoc * doc)1351 lasso_wsf_profile_add_saml_signature(LassoWsfProfile *wsf_profile, xmlDoc *doc) {
1352 	xmlNode *envelope = NULL, *header = NULL, *body = NULL, *provider = NULL, *correlation = NULL;
1353 	xmlNode *interaction = NULL, *security = NULL, *assertion = NULL, *signature = NULL;
1354 	xmlChar *provider_id = NULL, *correlation_id = NULL, *interaction_id = NULL, *body_id = NULL;
1355 	xmlChar *assertion_id = NULL;
1356 	xmlSecDSigCtx *dsig_ctx = NULL;
1357 	const xmlChar* ids[] = {
1358 		(xmlChar*) "id",
1359 		(xmlChar*) "Id",
1360 		NULL
1361 	};
1362 	gint rc = 0, sec_ret = 0;
1363 
1364 
1365 	g_return_val_if_fail(LASSO_IS_WSF_PROFILE(wsf_profile),
1366 		LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1367 	g_return_val_if_fail(doc != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1368 
1369 	/* Lookup all referenced node and their Ids */
1370 	envelope = xmlDocGetRootElement(doc);
1371 	header = lasso_xml_soap11_get_header(envelope);
1372 
1373 	provider = xmlSecFindNode(header, (xmlChar*) "Provider",
1374 		(xmlChar*) LASSO_SOAP_BINDING_HREF);
1375 	correlation = xmlSecFindNode(header, (xmlChar*) "Correlation",
1376 		(xmlChar*) LASSO_SOAP_BINDING_HREF);
1377 	interaction = xmlSecFindNode(header, (xmlChar*) "UserInteraction",
1378 		(xmlChar*) LASSO_IS_HREF);
1379 	body = lasso_xml_soap11_get_body(envelope);
1380 	xmlSecAddIDs(doc, envelope, ids);
1381 	goto_cleanup_if_fail_with_rc(header != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1382 	goto_cleanup_if_fail_with_rc(provider != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1383 	goto_cleanup_if_fail_with_rc(correlation != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1384 	goto_cleanup_if_fail_with_rc(body != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1385 
1386 	provider_id = xmlGetProp(provider, (xmlChar*) "id");
1387 	correlation_id = xmlGetProp(correlation, (xmlChar*) "id");
1388 	if (interaction != NULL) {
1389 		interaction_id = xmlGetProp(interaction, (xmlChar*) "id");
1390 	}
1391 	body_id = xmlGetProp(body, (xmlChar*) "Id");
1392 	goto_cleanup_if_fail_with_rc(provider_id != NULL, LASSO_XML_ERROR_ATTR_NOT_FOUND);
1393 	goto_cleanup_if_fail_with_rc(correlation_id != NULL, LASSO_XML_ERROR_ATTR_NOT_FOUND);
1394 	goto_cleanup_if_fail_with_rc(body_id != NULL, LASSO_XML_ERROR_ATTR_NOT_FOUND);
1395 	goto_cleanup_if_fail_with_rc(interaction == NULL || interaction_id != NULL,
1396 		LASSO_XML_ERROR_ATTR_NOT_FOUND);
1397 
1398 	/* Lookup the assertion Id for the KeyInfo node generation */
1399 	security = xmlSecFindNode(header, (xmlChar*) "Security", (xmlChar*) LASSO_WSSE1_HREF);
1400 	goto_cleanup_if_fail_with_rc(security != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1401 	assertion = xmlSecFindNode(security, (xmlChar*) "Assertion", (xmlChar*) LASSO_SAML_ASSERTION_HREF);
1402 	goto_cleanup_if_fail_with_rc(assertion != NULL, LASSO_XML_ERROR_NODE_NOT_FOUND);
1403 	assertion_id = xmlGetProp(assertion, (xmlChar*)"AssertionID");
1404 	goto_cleanup_if_fail_with_rc(assertion_id != NULL, LASSO_XML_ERROR_ATTR_NOT_FOUND);
1405 
1406 	/* Create the signature template */
1407 	rc = add_signature_template(wsf_profile->server, doc, security, &signature);
1408 	if (rc != 0) {
1409 		goto cleanup;
1410 	}
1411 	rc = add_reference_to_non_enveloping_id(signature, provider_id);
1412 	if (rc != 0) {
1413 		goto cleanup;
1414 	}
1415 	rc = add_reference_to_non_enveloping_id(signature, correlation_id);
1416 	if (rc != 0) {
1417 		goto cleanup;
1418 	}
1419 	rc = add_reference_to_non_enveloping_id(signature, body_id);
1420 	if (rc != 0) {
1421 		goto cleanup;
1422 	}
1423 	if (interaction_id) {
1424 		rc = add_reference_to_non_enveloping_id(signature, interaction_id);
1425 		if (rc != 0) {
1426 			goto cleanup;
1427 		}
1428 	}
1429 	/* Create signature context */
1430 	xmlSetTreeDoc(envelope, doc);
1431 	rc = create_signature_context(wsf_profile->server, &dsig_ctx);
1432 	if (rc != 0)
1433 		goto cleanup;
1434 	/* Sign ! */
1435 	sec_ret = xmlSecDSigCtxSign(dsig_ctx, signature);
1436 	if (sec_ret < 0) {
1437 		rc = LASSO_DS_ERROR_SIGNATURE_FAILED;
1438 		goto cleanup;
1439 	}
1440 	add_key_info_security_token_reference(doc, signature, assertion_id);
1441 
1442 cleanup:
1443 	if (dsig_ctx) {
1444 		xmlSecDSigCtxDestroy(dsig_ctx);
1445 	}
1446 	lasso_release_xml_string(provider_id);
1447 	lasso_release_xml_string(correlation_id);
1448 	lasso_release_xml_string(interaction_id);
1449 	lasso_release_xml_string(body_id);
1450 	lasso_release_xml_string(assertion_id);
1451 	return rc;
1452 }
1453 
1454 /**
1455  * lasso_wsf_profile_get_remote_provider_id:
1456  * @wsf_profile: a #LassoWsfProfile object
1457  *
1458  * Return the remote provider id parsed in the last processing of a SOAP request or a SOAP response.
1459  *
1460  * Return value:(transfer none)(allow-none): the provider id string or NULL.
1461  */
1462 const char*
lasso_wsf_profile_get_remote_provider_id(LassoWsfProfile * wsf_profile)1463 lasso_wsf_profile_get_remote_provider_id(LassoWsfProfile *wsf_profile)
1464 {
1465 	lasso_return_val_if_invalid_param(WSF_PROFILE, wsf_profile, NULL);
1466 
1467 	return wsf_profile->private_data->remote_provider_id;
1468 }
1469 
1470 /**
1471  * lasso_wsf_profile_get_remote_provider:
1472  * @wsf_profile: a #LassoWsfProfile object
1473  * @provider:(transfer full): an output pointer to #LassoProvider object variable.
1474  *
1475  * Return the remote provider parsed in the last processing of a SOAP request or a SOAP response.
1476  *
1477  * Return value: 0 if successfull, LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if no provider id
1478  * is present in the SOAP headers, or LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the provider is
1479  * unknown to us.
1480  */
1481 gint
lasso_wsf_profile_get_remote_provider(LassoWsfProfile * wsf_profile,LassoProvider ** provider)1482 lasso_wsf_profile_get_remote_provider(LassoWsfProfile *wsf_profile, LassoProvider **provider)
1483 {
1484 	LassoProvider *_provider = NULL;
1485 
1486 	lasso_bad_param(WSF_PROFILE, wsf_profile);
1487 
1488 	if (! wsf_profile->private_data->remote_provider_id)
1489 		return LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID;
1490 
1491 	if (! LASSO_IS_SERVER(wsf_profile->server))
1492 		return LASSO_PROFILE_ERROR_MISSING_SERVER;
1493 
1494 	_provider = lasso_server_get_provider(wsf_profile->server, wsf_profile->private_data->remote_provider_id);
1495 	if (! _provider)
1496 		return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
1497 
1498 	if (provider) {
1499 		lasso_assign_gobject(*provider, _provider);
1500 	}
1501 	return 0;
1502 }
1503 
1504 /**
1505  * lasso_wsf_profile_get_fault:
1506  * @wsf_profile: a #LassoWsfProfile object
1507  *
1508  * If a fault is going to be returned as next response, return it.
1509  *
1510  * Return value:(transfer none)(allow-none): a #LassoSoapFault, or NULL if none is currently present in the object.
1511  */
1512 LassoSoapFault*
lasso_wsf_profile_get_soap_fault(LassoWsfProfile * wsf_profile)1513 lasso_wsf_profile_get_soap_fault(LassoWsfProfile *wsf_profile)
1514 {
1515 	lasso_return_val_if_invalid_param(WSF_PROFILE, wsf_profile, NULL);
1516 
1517 	if (wsf_profile->private_data)
1518 		return wsf_profile->private_data->soap_fault;
1519 	return NULL;
1520 }
1521 
1522 /**
1523  * lasso_wsf_profile_set_soap_fault:
1524  * @wsf_profile: a #LassoWsfProfile object
1525  * @soap_fault: a #LassoSoapFault object
1526  *
1527  * Set a SOAP fault to be returned in next SOAP response message. The SOAP fault is removed by
1528  * lasso_wsf_profile_init_soap_request.
1529  *
1530  * Return value: 0 if successful, an error code otherwise.
1531  */
1532 gint
lasso_wsf_profile_set_soap_fault(LassoWsfProfile * wsf_profile,LassoSoapFault * soap_fault)1533 lasso_wsf_profile_set_soap_fault(LassoWsfProfile *wsf_profile, LassoSoapFault *soap_fault)
1534 {
1535 	lasso_bad_param(WSF_PROFILE, wsf_profile);
1536 	if (! LASSO_IS_SOAP_FAULT(soap_fault) && soap_fault)
1537 		return LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ;
1538 	if (! wsf_profile->private_data)
1539 		return LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT;
1540 	lasso_assign_gobject(wsf_profile->private_data->soap_fault, soap_fault);
1541 	return 0;
1542 }
1543 
1544 /**
1545  * lasso_wsf_profile_set_status_code:
1546  * @wsf_profile: a #LassoWsfProfile
1547  * @status_code: a string representing the status code
1548  *
1549  * Set the status code to set in the next built response.
1550  *
1551  * Return value: 0 if successful, an error code otherwise.
1552  */
1553 gint
lasso_wsf_profile_set_status_code(LassoWsfProfile * wsf_profile,const char * status_code)1554 lasso_wsf_profile_set_status_code(LassoWsfProfile *wsf_profile, const char *status_code)
1555 {
1556 	lasso_bad_param(WSF_PROFILE, wsf_profile);
1557 	if (! wsf_profile->private_data)
1558 		return LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT;
1559 	lasso_assign_string(wsf_profile->private_data->status_code, status_code);
1560 	return 0;
1561 }
1562 
1563 /**
1564  * lasso_wsf_profile_get_status_code:
1565  * @wsf_profile: a #LassoWsfProfile object
1566  *
1567  * Return the actual status code for this protocol object.
1568  *
1569  * Return value:(transfer none)(allow-none): a string owned by the profile object or NULL.
1570  */
1571 const char*
lasso_wsf_profile_get_status_code(LassoWsfProfile * wsf_profile)1572 lasso_wsf_profile_get_status_code(LassoWsfProfile *wsf_profile) {
1573 	lasso_return_val_if_invalid_param(WSF_PROFILE, wsf_profile, NULL);
1574 
1575 	if (wsf_profile->private_data)
1576 		return wsf_profile->private_data->status_code;
1577 	return NULL;
1578 }
1579