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