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
|
/**
|
25
|
* SECTION:node
|
26
|
* @short_description: Base class for all Lasso objects
|
27
|
*
|
28
|
* #LassoNode is the base class for Lasso objects; just a step over GObject as
|
29
|
* defined in glib.
|
30
|
*
|
31
|
*/
|
32
|
|
33
|
#include "private.h"
|
34
|
#include <ctype.h>
|
35
|
#include <errno.h>
|
36
|
#include <string.h>
|
37
|
|
38
|
#include <xmlsec/base64.h>
|
39
|
#include <xmlsec/xmltree.h>
|
40
|
#include <xmlsec/xmldsig.h>
|
41
|
#include <xmlsec/templates.h>
|
42
|
#include <xmlsec/crypto.h>
|
43
|
#include <xmlsec/xmlenc.h>
|
44
|
#include <xmlsec/openssl/crypto.h>
|
45
|
#include <xmlsec/openssl/x509.h>
|
46
|
|
47
|
#include "xml.h"
|
48
|
#include "xml_enc.h"
|
49
|
#include "saml_name_identifier.h"
|
50
|
#include "../utils.h"
|
51
|
#include "../registry.h"
|
52
|
#include "../debug.h"
|
53
|
#include "soap-1.1/soap_envelope.h"
|
54
|
#include "soap-1.1/soap_body.h"
|
55
|
#include "misc_text_node.h"
|
56
|
#include "../lasso_config.h"
|
57
|
#ifdef LASSO_WSF_ENABLED
|
58
|
#include "idwsf_strings.h"
|
59
|
#include "id-wsf-2.0/idwsf2_strings.h"
|
60
|
#endif
|
61
|
|
62
|
/* Needed for ECP */
|
63
|
#include "saml-2.0/samlp2_idp_list.h"
|
64
|
#include "paos_request.h"
|
65
|
#include "ecp/ecp_request.h"
|
66
|
#include "ecp/ecp_response.h"
|
67
|
#include "ecp/ecp_relaystate.h"
|
68
|
|
69
|
#include "../key.h"
|
70
|
|
71
|
#define LOG_LEVEL_XML_DEBUG G_LOG_LEVEL_DEBUG /* change to G_LOG_LEVEL_WARNING so it shows in Apache log */
|
72
|
|
73
|
static void lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, xmlNode *xmlnode,
|
74
|
struct XmlSnippet *snippets, gboolean lasso_dump);
|
75
|
static struct XmlSnippet* find_xml_snippet_by_name(LassoNode *node, char *name, LassoNodeClass **class_p);
|
76
|
static gboolean set_value_at_path(LassoNode *node, char *path, char *query_value);
|
77
|
static char* get_value_by_path(LassoNode *node, char *path, struct XmlSnippet *xml_snippet);
|
78
|
static gboolean find_path(LassoNode *node, char *path, LassoNode **value_node,
|
79
|
LassoNodeClass **class_p, struct XmlSnippet **snippet);
|
80
|
|
81
|
static void lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
|
82
|
struct XmlSnippet *snippet_signature);
|
83
|
static void lasso_node_traversal(LassoNode *node, void (*do_to_node)(LassoNode *node, SnippetType type), SnippetType type);
|
84
|
|
85
|
static LassoNode* lasso_node_new_from_xmlNode_with_type(xmlNode *xmlnode, char *typename);
|
86
|
static void lasso_node_remove_original_xmlnode(LassoNode *node, SnippetType type);
|
87
|
|
88
|
GHashTable *dst_services_by_href = NULL; /* ID-WSF 1 extra DST services, indexed on href */
|
89
|
GHashTable *dst_services_by_prefix = NULL; /* ID-WSF 1 extra DST services, indexed on prefix */
|
90
|
|
91
|
GHashTable *idwsf2_dst_services_by_href = NULL; /* ID-WSF 2 DST services, indexed on href */
|
92
|
GHashTable *idwsf2_dst_services_by_prefix = NULL; /* ID-WSF 2 DST services, indexed on prefix */
|
93
|
|
94
|
/*****************************************************************************/
|
95
|
/* global methods */
|
96
|
/*****************************************************************************/
|
97
|
|
98
|
/**
|
99
|
* lasso_register_dst_service:
|
100
|
* @prefix: prefix of DST service
|
101
|
* @href: href of DST service
|
102
|
*
|
103
|
* Registers prefix and href of a custom data service template service.
|
104
|
**/
|
105
|
void
|
106
|
lasso_register_dst_service(const gchar *prefix, const gchar *href)
|
107
|
{
|
108
|
if (dst_services_by_href == NULL) {
|
109
|
dst_services_by_href = g_hash_table_new_full(
|
110
|
g_str_hash, g_str_equal, g_free, g_free);
|
111
|
dst_services_by_prefix = g_hash_table_new_full(
|
112
|
g_str_hash, g_str_equal, g_free, g_free);
|
113
|
}
|
114
|
g_hash_table_insert(dst_services_by_prefix, g_strdup(prefix), g_strdup(href));
|
115
|
g_hash_table_insert(dst_services_by_href, g_strdup(href), g_strdup(prefix));
|
116
|
}
|
117
|
|
118
|
void
|
119
|
lasso_register_idwsf2_dst_service(const gchar *prefix, const gchar *href)
|
120
|
{
|
121
|
if (idwsf2_dst_services_by_href == NULL) {
|
122
|
idwsf2_dst_services_by_href = g_hash_table_new_full(
|
123
|
g_str_hash, g_str_equal, g_free, g_free);
|
124
|
idwsf2_dst_services_by_prefix = g_hash_table_new_full(
|
125
|
g_str_hash, g_str_equal, g_free, g_free);
|
126
|
}
|
127
|
g_hash_table_insert(idwsf2_dst_services_by_prefix, g_strdup(prefix), g_strdup(href));
|
128
|
g_hash_table_insert(idwsf2_dst_services_by_href, g_strdup(href), g_strdup(prefix));
|
129
|
}
|
130
|
|
131
|
gchar*
|
132
|
lasso_get_prefix_for_dst_service_href(const gchar *href)
|
133
|
{
|
134
|
if (dst_services_by_href == NULL)
|
135
|
return NULL;
|
136
|
|
137
|
return g_strdup(g_hash_table_lookup(dst_services_by_href, href));
|
138
|
}
|
139
|
|
140
|
gchar*
|
141
|
lasso_get_prefix_for_idwsf2_dst_service_href(const gchar *href)
|
142
|
{
|
143
|
if (idwsf2_dst_services_by_href == NULL)
|
144
|
return NULL;
|
145
|
|
146
|
return g_strdup(g_hash_table_lookup(idwsf2_dst_services_by_href, href));
|
147
|
}
|
148
|
|
149
|
|
150
|
/*****************************************************************************/
|
151
|
/* virtual public methods */
|
152
|
/*****************************************************************************/
|
153
|
|
154
|
static char*
|
155
|
_lasso_node_export_to_xml(LassoNode *node, gboolean format, gboolean dump, int level)
|
156
|
{
|
157
|
xmlNode *xmlnode;
|
158
|
char *ret;
|
159
|
|
160
|
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
|
161
|
|
162
|
xmlnode = lasso_node_get_xmlNode(node, dump);
|
163
|
if (xmlnode == NULL) {
|
164
|
return NULL;
|
165
|
}
|
166
|
ret = lasso_xmlnode_to_string(xmlnode, format, level);
|
167
|
xmlFreeNode(xmlnode);
|
168
|
|
169
|
return ret;
|
170
|
}
|
171
|
|
172
|
/**
|
173
|
* lasso_node_dump:
|
174
|
* @node: a #LassoNode
|
175
|
*
|
176
|
* Dumps @node. All datas in object are dumped in an XML format.
|
177
|
*
|
178
|
* Return value:(transfer full): a full XML dump of @node. The string must be freed by the
|
179
|
* caller.
|
180
|
**/
|
181
|
char*
|
182
|
lasso_node_dump(LassoNode *node)
|
183
|
{
|
184
|
return _lasso_node_export_to_xml(node, FALSE, TRUE, 0);
|
185
|
}
|
186
|
|
187
|
/**
|
188
|
* lasso_node_debug:
|
189
|
* @node: a #LassoNode
|
190
|
* @level:(default 10): the indentation depth, i.e. the depth of the last nodes to be indented.
|
191
|
*
|
192
|
* Create a debug dump for @node, it is pretty printed so any contained signature will be
|
193
|
* uncheckable.
|
194
|
*
|
195
|
* Return value:(transfer full): a full indented and so human readable dump of @node. The string must be freed by
|
196
|
* the caller.
|
197
|
*/
|
198
|
char*
|
199
|
lasso_node_debug(LassoNode *node, int level)
|
200
|
{
|
201
|
return _lasso_node_export_to_xml(node, TRUE, TRUE, level);
|
202
|
}
|
203
|
|
204
|
/**
|
205
|
* lasso_node_destroy:
|
206
|
* @node: a #LassoNode
|
207
|
*
|
208
|
* Destroys the #LassoNode.
|
209
|
**/
|
210
|
void
|
211
|
lasso_node_destroy(LassoNode *node)
|
212
|
{
|
213
|
if (node == NULL) {
|
214
|
return;
|
215
|
}
|
216
|
if (LASSO_IS_NODE(node)) {
|
217
|
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
|
218
|
class->destroy(node);
|
219
|
}
|
220
|
}
|
221
|
|
222
|
/**
|
223
|
* lasso_node_export_to_base64:
|
224
|
* @node: a #LassoNode
|
225
|
*
|
226
|
* Exports @node to a base64-encoded message.
|
227
|
*
|
228
|
* Return value: a base64-encoded export of @node. The string must be freed by
|
229
|
* the caller.
|
230
|
**/
|
231
|
char*
|
232
|
lasso_node_export_to_base64(LassoNode *node)
|
233
|
{
|
234
|
char *str;
|
235
|
char *ret;
|
236
|
|
237
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
238
|
|
239
|
str = lasso_node_export_to_xml(node);
|
240
|
if (str == NULL)
|
241
|
return NULL;
|
242
|
ret = (char*)xmlSecBase64Encode(BAD_CAST str, strlen(str), 0);
|
243
|
lasso_release_string(str);
|
244
|
return ret;
|
245
|
}
|
246
|
|
247
|
/**
|
248
|
* lasso_node_export_to_ecp_soap_response:
|
249
|
* @node: a #LassoNode
|
250
|
*
|
251
|
* Exports @node to a ECP SOAP message.
|
252
|
*
|
253
|
* Return value: a ECP SOAP export of @node. The string must be freed by the
|
254
|
* caller.
|
255
|
**/
|
256
|
char*
|
257
|
lasso_node_export_to_ecp_soap_response(LassoNode *node, const char *assertionConsumerURL)
|
258
|
{
|
259
|
char *ret = NULL;
|
260
|
LassoNode *ecp_response = NULL;
|
261
|
GList *headers = NULL;
|
262
|
|
263
|
lasso_return_null_if_fail(LASSO_IS_NODE(node));
|
264
|
lasso_return_null_if_fail(assertionConsumerURL);
|
265
|
|
266
|
/* Build the soap header elements */
|
267
|
ecp_response = lasso_ecp_response_new(assertionConsumerURL);
|
268
|
goto_cleanup_if_fail(ecp_response);
|
269
|
lasso_list_add_new_gobject(headers, ecp_response);
|
270
|
|
271
|
/* Create soap envelope and serialize into an xml document */
|
272
|
ret = lasso_node_export_to_soap_with_headers(node, headers);
|
273
|
|
274
|
cleanup:
|
275
|
lasso_release_list_of_gobjects(headers);
|
276
|
return ret;
|
277
|
}
|
278
|
|
279
|
/**
|
280
|
* lasso_node_export_to_paos_request:
|
281
|
* @node: a #LassoNode
|
282
|
*
|
283
|
* Exports @node to a PAOS message.
|
284
|
*
|
285
|
* Deprecated, use lasso_node_export_to_paos_request_full() instead
|
286
|
*
|
287
|
* Return value: a PAOS export of @node. The string must be freed by the
|
288
|
* caller.
|
289
|
**/
|
290
|
char *
|
291
|
lasso_node_export_to_paos_request(LassoNode *node, const char *issuer,
|
292
|
const char *responseConsumerURL, const char *relay_state)
|
293
|
{
|
294
|
return lasso_node_export_to_paos_request_full(node, issuer, responseConsumerURL,
|
295
|
NULL, relay_state, TRUE, NULL, NULL);
|
296
|
}
|
297
|
|
298
|
/**
|
299
|
* lasso_node_export_to_paos_request_full:
|
300
|
* @node:
|
301
|
* @issuer:
|
302
|
* @responseConsumerURL:
|
303
|
* @message_id: (allow-none):
|
304
|
* @relay_state: (allow-none):
|
305
|
* @is_passive:
|
306
|
* @provider_name: (allow-none):
|
307
|
* @idp_list: (allow-none):
|
308
|
*
|
309
|
* Creates a new SOAP message. The SOAP headers include a PaosRequst,
|
310
|
* a EcpRequest and optionally a EcpRelayState. The SOAP body contains
|
311
|
* the @node parameters.
|
312
|
*
|
313
|
* Returns: string containing a PAOS request. The string must be freed
|
314
|
* by the caller.
|
315
|
**/
|
316
|
char *
|
317
|
lasso_node_export_to_paos_request_full(LassoNode *node, const char *issuer,
|
318
|
const char *responseConsumerURL, const char *message_id,
|
319
|
const char *relay_state, gboolean is_passive, gchar *provider_name,
|
320
|
LassoSamlp2IDPList *idp_list)
|
321
|
{
|
322
|
char *ret = NULL;
|
323
|
LassoNode *paos_request = NULL;
|
324
|
LassoNode *ecp_request = NULL;
|
325
|
LassoNode *ecp_relaystate = NULL;
|
326
|
GList *headers = NULL;
|
327
|
|
328
|
lasso_return_null_if_fail(LASSO_IS_NODE(node));
|
329
|
lasso_return_null_if_fail(issuer);
|
330
|
lasso_return_null_if_fail(responseConsumerURL);
|
331
|
|
332
|
/* Build the soap header elements */
|
333
|
paos_request = lasso_paos_request_new(responseConsumerURL, message_id);
|
334
|
goto_cleanup_if_fail(paos_request);
|
335
|
lasso_list_add_new_gobject(headers, paos_request);
|
336
|
|
337
|
ecp_request = lasso_ecp_request_new(issuer, is_passive, provider_name, idp_list);
|
338
|
goto_cleanup_if_fail(ecp_request);
|
339
|
lasso_list_add_new_gobject(headers, ecp_request);
|
340
|
|
341
|
if (relay_state) {
|
342
|
ecp_relaystate = lasso_ecp_relay_state_new(relay_state);
|
343
|
goto_cleanup_if_fail(ecp_relaystate);
|
344
|
lasso_list_add_new_gobject(headers, ecp_relaystate);
|
345
|
}
|
346
|
|
347
|
/* Create soap envelope and serialize into an xml document */
|
348
|
ret = lasso_node_export_to_soap_with_headers(node, headers);
|
349
|
|
350
|
cleanup:
|
351
|
lasso_release_list_of_gobjects(headers);
|
352
|
return ret;
|
353
|
}
|
354
|
|
355
|
/**
|
356
|
* lasso_node_export_to_query:
|
357
|
* @node: a #LassoNode
|
358
|
* @sign_method:(default 1): the Signature transform method
|
359
|
* @private_key_file:(allow-none): the path to the private key (may be NULL)
|
360
|
*
|
361
|
* Exports @node to a HTTP query string. If @private_key_file is NULL,
|
362
|
* query won't be signed.
|
363
|
*
|
364
|
* Return value: a HTTP query export of @node. The string must be freed by the
|
365
|
* caller.
|
366
|
**/
|
367
|
char*
|
368
|
lasso_node_export_to_query(LassoNode *node, LassoSignatureMethod sign_method,
|
369
|
const char *private_key_file)
|
370
|
{
|
371
|
return lasso_node_export_to_query_with_password(node, sign_method, private_key_file, NULL);
|
372
|
}
|
373
|
|
374
|
/**
|
375
|
* lasso_node_export_to_query_with_password:
|
376
|
* @node: a #LassoNode
|
377
|
* @sign_method:(default 1): the Signature transform method
|
378
|
* @private_key_file:(allow-none): the path to the private key (may be NULL)
|
379
|
* @private_key_file_password:(allow-none): the password needed to decrypt the private key
|
380
|
*
|
381
|
* Exports @node to a HTTP query string. If @private_key_file is NULL,
|
382
|
* query won't be signed.
|
383
|
*
|
384
|
* Return value: a HTTP query export of @node. The string must be freed by the
|
385
|
* caller.
|
386
|
**/
|
387
|
char*
|
388
|
lasso_node_export_to_query_with_password(LassoNode *node,
|
389
|
LassoSignatureMethod sign_method, const char *private_key_file,
|
390
|
const char *private_key_file_password)
|
391
|
{
|
392
|
char *unsigned_query, *query = NULL;
|
393
|
LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE;
|
394
|
|
395
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
396
|
|
397
|
context.signature_method = sign_method;
|
398
|
context.signature_key = lasso_xmlsec_load_private_key(private_key_file,
|
399
|
private_key_file_password, sign_method, NULL);
|
400
|
|
401
|
if (! context.signature_key) {
|
402
|
return NULL;
|
403
|
}
|
404
|
|
405
|
unsigned_query = lasso_node_build_query(node);
|
406
|
if (unsigned_query){
|
407
|
query = lasso_query_sign(unsigned_query, context);
|
408
|
if (query) {
|
409
|
lasso_release(unsigned_query);
|
410
|
unsigned_query = query;
|
411
|
}
|
412
|
}
|
413
|
lasso_release_sec_key(context.signature_key);
|
414
|
return unsigned_query;
|
415
|
}
|
416
|
|
417
|
/**
|
418
|
* lasso_node_export_to_xml:
|
419
|
* @node: a #LassoNode
|
420
|
*
|
421
|
* Exports @node to an xml message.
|
422
|
*
|
423
|
* Return value: an xml export of @node. The string must be freed by the
|
424
|
* caller.
|
425
|
**/
|
426
|
gchar*
|
427
|
lasso_node_export_to_xml(LassoNode *node)
|
428
|
{
|
429
|
return _lasso_node_export_to_xml(node, FALSE, FALSE, 0);
|
430
|
}
|
431
|
|
432
|
/**
|
433
|
* lasso_node_export_to_soap:
|
434
|
* @node: a #LassoNode
|
435
|
*
|
436
|
* Exports @node to a SOAP message.
|
437
|
*
|
438
|
* Return value: a SOAP export of @node. The string must be freed by the
|
439
|
* caller.
|
440
|
**/
|
441
|
char*
|
442
|
lasso_node_export_to_soap(LassoNode *node)
|
443
|
{
|
444
|
LassoSoapEnvelope *envelope;
|
445
|
LassoSoapBody *body;
|
446
|
char *ret;
|
447
|
|
448
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
449
|
|
450
|
body = lasso_soap_body_new();
|
451
|
envelope = lasso_soap_envelope_new(body);
|
452
|
lasso_list_add_gobject(body->any, node);
|
453
|
ret = lasso_node_export_to_xml((LassoNode*)envelope);
|
454
|
lasso_release_gobject(envelope);
|
455
|
lasso_release_gobject(body);
|
456
|
return ret;
|
457
|
}
|
458
|
|
459
|
/**
|
460
|
* lasso_node_export_to_soap_with_headers:
|
461
|
* @node: a #LassoNode, becomes the SOAP body
|
462
|
* @headers: (allow-none): #GList of #LassNode
|
463
|
*
|
464
|
* Exports @node to a SOAP message. The @node becomes the SOAP body.
|
465
|
* each header in the #headers list is added to the SOAP header if non-NULL.
|
466
|
* @headers is permitted to be an empty list (e.g. NULL).
|
467
|
*
|
468
|
* <example>
|
469
|
* <title>Create SOAP envelope with variable number of header nodes</title>
|
470
|
*
|
471
|
* <para>You need to form a SOAP message with authn_request as the body and
|
472
|
* paos_request, ecp_request and ecp_relaystate as SOAP header elements.
|
473
|
* It is possible one or more of these may be NULL and should be skipped.</para>
|
474
|
* <programlisting>
|
475
|
* char *text = NULL;
|
476
|
* LassoNode *paos_request = NULL;
|
477
|
* LassoNode *ecp_request = NULL;
|
478
|
* LassoNode *ecp_relaystate = NULL;
|
479
|
* GList *headers = NULL;
|
480
|
*
|
481
|
* paos_request = lasso_paos_request_new(responseConsumerURL, message_id);
|
482
|
* ecp_request = lasso_ecp_request_new(issuer, is_passive, provider_name, idp_list);
|
483
|
*
|
484
|
* lasso_list_add_new_gobject(headers, paos_request);
|
485
|
* lasso_list_add_new_gobject(headers, ecp_request);
|
486
|
* lasso_list_add_new_gobject(headers, ecp_relaystate);
|
487
|
*
|
488
|
* text = lasso_node_export_to_soap_with_headers(node, headers);
|
489
|
*
|
490
|
* lasso_release_list_of_gobjects(headers);
|
491
|
* </programlisting>
|
492
|
* </example>
|
493
|
*
|
494
|
* Return value: a SOAP export of @node. The string must be freed by the
|
495
|
* caller.
|
496
|
**/
|
497
|
char*
|
498
|
lasso_node_export_to_soap_with_headers(LassoNode *node, GList *headers)
|
499
|
{
|
500
|
GList *i;
|
501
|
LassoSoapEnvelope *envelope = NULL;
|
502
|
LassoNode *header = NULL;
|
503
|
char *ret = NULL;
|
504
|
|
505
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
506
|
|
507
|
envelope = lasso_soap_envelope_new_full();
|
508
|
lasso_list_add_gobject(envelope->Body->any, node);
|
509
|
|
510
|
lasso_foreach(i, headers) {
|
511
|
header = i->data;
|
512
|
if (!header) continue;
|
513
|
|
514
|
goto_cleanup_if_fail(LASSO_IS_NODE(header));
|
515
|
lasso_list_add_gobject(envelope->Header->Other, header); /* adds ref */
|
516
|
}
|
517
|
|
518
|
ret = lasso_node_export_to_xml((LassoNode*)envelope);
|
519
|
|
520
|
cleanup:
|
521
|
lasso_release_gobject(envelope);
|
522
|
return ret;
|
523
|
}
|
524
|
|
525
|
/**
|
526
|
* lasso_node_encrypt:
|
527
|
* @lasso_node: a #LassoNode to encrypt
|
528
|
* @encryption_public_key : RSA public key the node will be encrypted with
|
529
|
*
|
530
|
* Generate a DES key and encrypt it with the RSA key.
|
531
|
* Then encrypt @lasso_node with the DES key.
|
532
|
*
|
533
|
* Return value: an xmlNode which is the @node in an encrypted fashion.
|
534
|
* It must be freed by the caller.
|
535
|
**/
|
536
|
LassoSaml2EncryptedElement*
|
537
|
lasso_node_encrypt(LassoNode *lasso_node, xmlSecKey *encryption_public_key,
|
538
|
LassoEncryptionSymKeyType encryption_sym_key_type, const char *recipient)
|
539
|
{
|
540
|
xmlDocPtr doc = NULL;
|
541
|
xmlNodePtr orig_node = NULL;
|
542
|
LassoSaml2EncryptedElement *encrypted_element = NULL, *ret = NULL;
|
543
|
xmlSecKeysMngrPtr key_manager = NULL;
|
544
|
xmlNodePtr key_info_node = NULL;
|
545
|
xmlNodePtr encrypted_key_node = NULL;
|
546
|
xmlNodePtr encrypted_data = NULL;
|
547
|
xmlNodePtr key_info_node2 = NULL;
|
548
|
xmlSecEncCtxPtr enc_ctx = NULL;
|
549
|
xmlSecTransformId xmlsec_encryption_sym_key_type;
|
550
|
xmlSecKey *duplicate = NULL;
|
551
|
|
552
|
if (encryption_public_key == NULL || !xmlSecKeyIsValid(encryption_public_key)) {
|
553
|
message(G_LOG_LEVEL_WARNING, "Invalid encryption key");
|
554
|
goto cleanup;
|
555
|
}
|
556
|
|
557
|
/* Create a document to contain the node to encrypt */
|
558
|
doc = xmlNewDoc((xmlChar*)"1.0");
|
559
|
orig_node = lasso_node_get_xmlNode(lasso_node, FALSE);
|
560
|
xmlDocSetRootElement(doc, orig_node);
|
561
|
|
562
|
/* Get the symetric key type */
|
563
|
switch (encryption_sym_key_type) {
|
564
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_256:
|
565
|
xmlsec_encryption_sym_key_type = xmlSecTransformAes256CbcId;
|
566
|
break;
|
567
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_3DES:
|
568
|
xmlsec_encryption_sym_key_type = xmlSecTransformDes3CbcId;
|
569
|
break;
|
570
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_128:
|
571
|
default:
|
572
|
xmlsec_encryption_sym_key_type = xmlSecTransformAes128CbcId;
|
573
|
break;
|
574
|
}
|
575
|
|
576
|
/* Create encryption template for a specific symetric key type */
|
577
|
/* saml-core 2.2.4 line 498:
|
578
|
* The Type attribute SHOULD be present and, if present, MUST contain a value of
|
579
|
* http://www.w3.org/2001/04/xmlenc#Element. */
|
580
|
encrypted_data = xmlSecTmplEncDataCreate(doc,
|
581
|
xmlsec_encryption_sym_key_type, NULL, xmlSecTypeEncElement, NULL, NULL);
|
582
|
|
583
|
if (encrypted_data == NULL) {
|
584
|
message(G_LOG_LEVEL_WARNING, "Failed to create encryption template");
|
585
|
goto cleanup;
|
586
|
}
|
587
|
|
588
|
if (xmlSecTmplEncDataEnsureCipherValue(encrypted_data) == NULL) {
|
589
|
message(G_LOG_LEVEL_WARNING, "Failed to add CipherValue node");
|
590
|
goto cleanup;
|
591
|
}
|
592
|
|
593
|
/* create and initialize keys manager, we use a simple list based
|
594
|
* keys manager, implement your own xmlSecKeysStore klass if you need
|
595
|
* something more sophisticated
|
596
|
*/
|
597
|
key_manager = xmlSecKeysMngrCreate();
|
598
|
if (key_manager == NULL) {
|
599
|
message(G_LOG_LEVEL_WARNING, "Failed to create keys manager");
|
600
|
goto cleanup;
|
601
|
}
|
602
|
|
603
|
if (xmlSecCryptoAppDefaultKeysMngrInit(key_manager) < 0) {
|
604
|
message(G_LOG_LEVEL_WARNING, "Failed to initialize keys manager");
|
605
|
goto cleanup;
|
606
|
}
|
607
|
|
608
|
/* add key to keys manager, from now on keys manager is responsible
|
609
|
* for destroying key
|
610
|
*/
|
611
|
duplicate = xmlSecKeyDuplicate(encryption_public_key);
|
612
|
if (xmlSecCryptoAppDefaultKeysMngrAdoptKey(key_manager, duplicate) < 0) {
|
613
|
lasso_release_sec_key(duplicate);
|
614
|
goto cleanup;
|
615
|
}
|
616
|
|
617
|
/* add <dsig:KeyInfo/> */
|
618
|
key_info_node = xmlSecTmplEncDataEnsureKeyInfo(encrypted_data, NULL);
|
619
|
if (key_info_node == NULL) {
|
620
|
message(G_LOG_LEVEL_WARNING, "Failed to add key info");
|
621
|
goto cleanup;
|
622
|
}
|
623
|
|
624
|
/* add <enc:EncryptedKey/> to store the encrypted session key */
|
625
|
encrypted_key_node = xmlSecTmplKeyInfoAddEncryptedKey(key_info_node,
|
626
|
xmlSecTransformRsaPkcs1Id, NULL, NULL, (xmlChar*)recipient);
|
627
|
if (encrypted_key_node == NULL) {
|
628
|
message(G_LOG_LEVEL_WARNING, "Failed to add encrypted key");
|
629
|
goto cleanup;
|
630
|
}
|
631
|
|
632
|
/* we want to put encrypted key in the <enc:CipherValue/> node */
|
633
|
if (xmlSecTmplEncDataEnsureCipherValue(encrypted_key_node) == NULL) {
|
634
|
message(G_LOG_LEVEL_WARNING, "Failed to add CipherValue node");
|
635
|
goto cleanup;
|
636
|
}
|
637
|
|
638
|
/* add <dsig:KeyInfo/> and <dsig:KeyName/> nodes to <enc:EncryptedKey/> */
|
639
|
key_info_node2 = xmlSecTmplEncDataEnsureKeyInfo(encrypted_key_node, NULL);
|
640
|
if (key_info_node2 == NULL) {
|
641
|
message(G_LOG_LEVEL_WARNING, "Failed to add key info");
|
642
|
goto cleanup;
|
643
|
}
|
644
|
/* check id of the key */
|
645
|
if (xmlSecKeyGetData(encryption_public_key, xmlSecOpenSSLKeyDataRsaId) != 0) {
|
646
|
xmlNode *key_value = xmlSecTmplKeyInfoAddKeyValue(key_info_node2);
|
647
|
if (key_value == NULL) {
|
648
|
message(G_LOG_LEVEL_WARNING, "Failed to add key value");
|
649
|
goto cleanup;
|
650
|
}
|
651
|
} else { /* it must be a certificate */
|
652
|
xmlNodePtr x509_data;
|
653
|
x509_data = xmlSecTmplKeyInfoAddX509Data(key_info_node2);
|
654
|
if (x509_data == NULL) {
|
655
|
message(G_LOG_LEVEL_WARNING, "Failed to add X509 data");
|
656
|
goto cleanup;
|
657
|
}
|
658
|
}
|
659
|
|
660
|
|
661
|
|
662
|
|
663
|
/* create encryption context */
|
664
|
enc_ctx = (xmlSecEncCtxPtr)xmlSecEncCtxCreate(key_manager);
|
665
|
if (enc_ctx == NULL) {
|
666
|
message(G_LOG_LEVEL_WARNING, "Failed to create encryption context");
|
667
|
goto cleanup;
|
668
|
}
|
669
|
|
670
|
/* generate a symetric key */
|
671
|
switch (encryption_sym_key_type) {
|
672
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_256:
|
673
|
enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 256,
|
674
|
xmlSecKeyDataTypeSession);
|
675
|
break;
|
676
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_3DES:
|
677
|
enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataDesId, 192,
|
678
|
xmlSecKeyDataTypeSession);
|
679
|
break;
|
680
|
case LASSO_ENCRYPTION_SYM_KEY_TYPE_AES_128:
|
681
|
default:
|
682
|
enc_ctx->encKey = xmlSecKeyGenerate(xmlSecKeyDataAesId, 128,
|
683
|
xmlSecKeyDataTypeSession);
|
684
|
break;
|
685
|
}
|
686
|
|
687
|
if (enc_ctx->encKey == NULL) {
|
688
|
message(G_LOG_LEVEL_WARNING, "Failed to generate session des key");
|
689
|
goto cleanup;
|
690
|
}
|
691
|
|
692
|
|
693
|
/* encrypt the data */
|
694
|
if (xmlSecEncCtxXmlEncrypt(enc_ctx, encrypted_data, orig_node) < 0) {
|
695
|
message(G_LOG_LEVEL_WARNING, "Encryption failed");
|
696
|
goto cleanup;
|
697
|
}
|
698
|
|
699
|
|
700
|
/* Create a new EncryptedElement */
|
701
|
encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_saml2_encrypted_element_new());
|
702
|
lasso_assign_gobject(encrypted_element->original_data, lasso_node);
|
703
|
lasso_assign_xml_node(encrypted_element->EncryptedData, xmlDocGetRootElement(doc));
|
704
|
lasso_transfer_gobject(ret, encrypted_element);
|
705
|
|
706
|
cleanup:
|
707
|
lasso_release_key_manager(key_manager);
|
708
|
lasso_release_gobject(encrypted_element);
|
709
|
lasso_release_encrypt_context(enc_ctx);
|
710
|
lasso_release_doc(doc);
|
711
|
|
712
|
return ret;
|
713
|
}
|
714
|
|
715
|
|
716
|
/**
|
717
|
* lasso_node_init_from_query:
|
718
|
* @node: a #LassoNode (or derived class)
|
719
|
* @query: the query string
|
720
|
*
|
721
|
* Initialiazes @node fields with data from @query string.
|
722
|
*
|
723
|
* Return value: %TRUE if success
|
724
|
**/
|
725
|
gboolean
|
726
|
lasso_node_init_from_query(LassoNode *node, const char *query)
|
727
|
{
|
728
|
LassoNodeClass *class;
|
729
|
char **query_fields;
|
730
|
int i;
|
731
|
gboolean rc;
|
732
|
|
733
|
g_return_val_if_fail(LASSO_IS_NODE(node), FALSE);
|
734
|
class = LASSO_NODE_GET_CLASS(node);
|
735
|
|
736
|
query_fields = urlencoded_to_strings(query);
|
737
|
rc = class->init_from_query(node, query_fields);
|
738
|
for (i = 0; query_fields[i]; i++) {
|
739
|
xmlFree(query_fields[i]);
|
740
|
query_fields[i] = NULL;
|
741
|
}
|
742
|
lasso_release(query_fields);
|
743
|
return rc;
|
744
|
}
|
745
|
|
746
|
|
747
|
/**
|
748
|
* lasso_node_init_from_xml:
|
749
|
* @node: a #LassoNode (or derived class)
|
750
|
* @xmlnode: the libxml2 node
|
751
|
*
|
752
|
* Initialiazes @node fields with data from @xmlnode XML node.
|
753
|
*
|
754
|
* Return value: 0 on success; or a negative value otherwise.
|
755
|
**/
|
756
|
int
|
757
|
lasso_node_init_from_xml(LassoNode *node, xmlNode *xmlnode)
|
758
|
{
|
759
|
LassoNodeClass *class;
|
760
|
|
761
|
g_return_val_if_fail(LASSO_IS_NODE(node), LASSO_XML_ERROR_OBJECT_CONSTRUCTION_FAILED);
|
762
|
class = LASSO_NODE_GET_CLASS(node);
|
763
|
|
764
|
return class->init_from_xml(node, xmlnode);
|
765
|
}
|
766
|
|
767
|
/**
|
768
|
* lasso_node_build_query:
|
769
|
* @node: a #LassoNode
|
770
|
*
|
771
|
* Build an HTTP query from the given LassoNode, this is a pure virtual
|
772
|
* function, you must overload it in subclass.
|
773
|
*
|
774
|
* Return value: a newly allocated string containing the query if it succeed,
|
775
|
* or NULL otherwise.
|
776
|
*/
|
777
|
char*
|
778
|
lasso_node_build_query(LassoNode *node)
|
779
|
{
|
780
|
LassoNodeClass *class;
|
781
|
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
|
782
|
|
783
|
class = LASSO_NODE_GET_CLASS(node);
|
784
|
return class->build_query(node);
|
785
|
}
|
786
|
|
787
|
static LassoNodeClassData*
|
788
|
lasso_legacy_get_signature_node_data(LassoNode *node, LassoNodeClass **out_klass)
|
789
|
{
|
790
|
LassoNodeClass *klass = NULL;
|
791
|
LassoNodeClassData *node_data = NULL;
|
792
|
|
793
|
klass = LASSO_NODE_GET_CLASS(node);
|
794
|
/* find a klass defining a signature */
|
795
|
while (klass && LASSO_IS_NODE_CLASS(klass)) {
|
796
|
if (klass->node_data && klass->node_data->sign_type_offset) {
|
797
|
if (out_klass) {
|
798
|
*out_klass = klass;
|
799
|
}
|
800
|
node_data = klass->node_data;
|
801
|
break;
|
802
|
}
|
803
|
klass = g_type_class_peek_parent(klass);
|
804
|
}
|
805
|
|
806
|
return node_data;
|
807
|
}
|
808
|
|
809
|
static gboolean
|
810
|
lasso_legacy_extract_and_copy_signature_parameters(LassoNode *node, LassoNodeClassData *node_data)
|
811
|
{
|
812
|
LassoSignatureMethod signature_method = LASSO_SIGNATURE_METHOD_NONE;
|
813
|
char *private_key_file = NULL;
|
814
|
char *certificate_file = NULL;
|
815
|
|
816
|
if (! node_data) {
|
817
|
return FALSE;
|
818
|
}
|
819
|
signature_method = G_STRUCT_MEMBER(LassoSignatureMethod, node,
|
820
|
node_data->sign_method_offset);
|
821
|
private_key_file = G_STRUCT_MEMBER(char *, node, node_data->private_key_file_offset);
|
822
|
certificate_file = G_STRUCT_MEMBER(char *, node, node_data->certificate_file_offset);
|
823
|
if (! lasso_validate_signature_method(signature_method)) {
|
824
|
return FALSE;
|
825
|
}
|
826
|
if (lasso_node_set_signature(node,
|
827
|
lasso_make_signature_context_from_path_or_string(private_key_file, NULL,
|
828
|
signature_method, certificate_file)) != 0) {
|
829
|
return FALSE;
|
830
|
}
|
831
|
return TRUE;
|
832
|
}
|
833
|
|
834
|
/**
|
835
|
* lasso_node_get_xmlNode:
|
836
|
* @node: a #LassoNode
|
837
|
* @lasso_dump: whether to include lasso-specific nodes
|
838
|
*
|
839
|
* Builds an XML representation of @node.
|
840
|
*
|
841
|
* Return value: a new xmlNode. It must be freed by the caller.
|
842
|
**/
|
843
|
xmlNode*
|
844
|
lasso_node_get_xmlNode(LassoNode *node, gboolean lasso_dump)
|
845
|
{
|
846
|
xmlNode *xmlnode = NULL;
|
847
|
LassoSignatureContext context;
|
848
|
LassoNodeClassData *node_data;
|
849
|
|
850
|
g_return_val_if_fail (LASSO_IS_NODE(node), NULL);
|
851
|
xmlnode = LASSO_NODE_GET_CLASS(node)->get_xmlNode(node, lasso_dump);
|
852
|
node_data = lasso_legacy_get_signature_node_data(node, NULL);
|
853
|
context = lasso_node_get_signature(node);
|
854
|
/* support for legacy way to put a signature on a node */
|
855
|
if (! lasso_validate_signature_context(context)) {
|
856
|
if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data))
|
857
|
context = lasso_node_get_signature(node);
|
858
|
}
|
859
|
if (! lasso_dump && node_data && xmlnode && lasso_validate_signature_context(context)) {
|
860
|
int rc;
|
861
|
char *id_attribute = G_STRUCT_MEMBER(char*, node,
|
862
|
node_data->id_attribute_offset);
|
863
|
|
864
|
rc = lasso_sign_node(xmlnode, context, node_data->id_attribute_name,
|
865
|
id_attribute);
|
866
|
if (rc != 0) {
|
867
|
warning("Signing of %s:%s failed: %s", xmlnode->ns->prefix,
|
868
|
xmlnode->name, lasso_strerror(rc));
|
869
|
lasso_release_xml_node(xmlnode);
|
870
|
}
|
871
|
}
|
872
|
|
873
|
return xmlnode;
|
874
|
}
|
875
|
|
876
|
/**
|
877
|
* lasso_node_cleanup_original_xmlnodes:
|
878
|
*
|
879
|
* @node: a #LassoNode
|
880
|
*
|
881
|
* Traverse the #LassoNode tree starting at Node and remove keeped xmlNode if one is found.
|
882
|
*
|
883
|
* Return value: None
|
884
|
*/
|
885
|
void
|
886
|
lasso_node_cleanup_original_xmlnodes(LassoNode *node)
|
887
|
{
|
888
|
lasso_node_traversal(node, lasso_node_remove_original_xmlnode, 0);
|
889
|
}
|
890
|
|
891
|
static GQuark original_xmlnode_quark;
|
892
|
static GQuark custom_element_quark;
|
893
|
|
894
|
/**
|
895
|
* lasso_node_get_original_xmlnode:
|
896
|
* @node: a #LassoNode
|
897
|
*
|
898
|
* Retrieve the original xmlNode eventually associated to this #LassoNode.
|
899
|
*
|
900
|
* Return value:(transfer none): an #xmlNodePtr or NULL.
|
901
|
*/
|
902
|
xmlNodePtr
|
903
|
lasso_node_get_original_xmlnode(LassoNode *node)
|
904
|
{
|
905
|
return g_object_get_qdata(G_OBJECT(node), original_xmlnode_quark);
|
906
|
}
|
907
|
|
908
|
static void original_xmlnode_free(void *node) {
|
909
|
xmlNode *xnode = (xmlNode*)node;
|
910
|
|
911
|
|
912
|
if (node) {
|
913
|
if (lasso_flag_memory_debug) {
|
914
|
fprintf(stderr, "freeing original xmlnode %s (at %p)\n", xnode->name, xnode);
|
915
|
}
|
916
|
xmlFreeNode(xnode);
|
917
|
}
|
918
|
}
|
919
|
|
920
|
/**
|
921
|
* lasso_node_set_original_xmlnode:
|
922
|
* @node: the #LassoNode object
|
923
|
* @xmlnode: an #xmlNode
|
924
|
*
|
925
|
* Set the underlying XML representation of the object.
|
926
|
*
|
927
|
*/
|
928
|
void
|
929
|
lasso_node_set_original_xmlnode(LassoNode *node, xmlNode* xmlnode)
|
930
|
{
|
931
|
if (xmlnode) {
|
932
|
xmlNode *copy = NULL;
|
933
|
xmlNode *parent = xmlnode->parent;
|
934
|
|
935
|
copy = xmlCopyNode(xmlnode, 1);
|
936
|
/* excl-c14n can move some namespace declarations at the point where the document is
|
937
|
* cut, to simulate it we copy on the new node all namespaces from the parents of
|
938
|
* the node which are not shadowed by another declaration on this node or one of its
|
939
|
* parent. */
|
940
|
while (parent && parent->type == XML_ELEMENT_NODE) {
|
941
|
xmlNs *ns_def = parent->nsDef;
|
942
|
xmlNs *local_ns_def;
|
943
|
while (ns_def) {
|
944
|
int ok = 1;
|
945
|
local_ns_def = copy->nsDef;
|
946
|
while (local_ns_def) {
|
947
|
if (lasso_strisequal((char*)local_ns_def->prefix, (char*)ns_def->prefix)) {
|
948
|
ok = 0;
|
949
|
break;
|
950
|
}
|
951
|
local_ns_def = local_ns_def->next;
|
952
|
}
|
953
|
if (ok) {
|
954
|
xmlNewNs(copy, ns_def->href, ns_def->prefix);
|
955
|
}
|
956
|
ns_def = ns_def->next;
|
957
|
}
|
958
|
parent = parent->parent;
|
959
|
}
|
960
|
|
961
|
if (lasso_flag_memory_debug) {
|
962
|
fprintf(stderr, "setting original xmlnode (at %p) on node %s:%p\n", copy, G_OBJECT_TYPE_NAME (node), node);
|
963
|
}
|
964
|
g_object_set_qdata_full(G_OBJECT(node), original_xmlnode_quark, copy, (GDestroyNotify)original_xmlnode_free);
|
965
|
} else {
|
966
|
if (lasso_flag_memory_debug) {
|
967
|
fprintf(stderr, "clearing original xmlnode on node %p\n", node);
|
968
|
}
|
969
|
g_object_set_qdata_full(G_OBJECT(node), original_xmlnode_quark, NULL, (GDestroyNotify)original_xmlnode_free);
|
970
|
}
|
971
|
}
|
972
|
|
973
|
struct _CustomElement {
|
974
|
char *prefix;
|
975
|
char *href;
|
976
|
char *nodename;
|
977
|
GHashTable *namespaces;
|
978
|
LassoSignatureContext signature_context;
|
979
|
xmlSecKey *encryption_public_key;
|
980
|
LassoEncryptionSymKeyType encryption_sym_key_type;
|
981
|
};
|
982
|
|
983
|
static struct _CustomElement *
|
984
|
_lasso_node_new_custom_element()
|
985
|
{
|
986
|
struct _CustomElement *ret = g_new0(struct _CustomElement, 1);
|
987
|
ret->namespaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
988
|
return ret;
|
989
|
}
|
990
|
|
991
|
static void
|
992
|
_lasso_node_free_custom_element(struct _CustomElement *custom_element)
|
993
|
{
|
994
|
if (custom_element) {
|
995
|
lasso_release_string(custom_element->prefix);
|
996
|
lasso_release_string(custom_element->href);
|
997
|
lasso_release_string(custom_element->nodename);
|
998
|
lasso_release_ghashtable(custom_element->namespaces);
|
999
|
lasso_release_sec_key(custom_element->encryption_public_key);
|
1000
|
lasso_release_sec_key(custom_element->signature_context.signature_key);
|
1001
|
}
|
1002
|
lasso_release(custom_element);
|
1003
|
}
|
1004
|
|
1005
|
/**
|
1006
|
* _lasso_node_get_custom_element:
|
1007
|
* @node: a #LassoNode object
|
1008
|
*
|
1009
|
* Return the eventually attached custom namespace object
|
1010
|
*
|
1011
|
* Return value: NULL or an #_CustomElement structure.
|
1012
|
*/
|
1013
|
static struct _CustomElement*
|
1014
|
_lasso_node_get_custom_element(LassoNode *node)
|
1015
|
{
|
1016
|
if (! LASSO_NODE(node))
|
1017
|
return NULL;
|
1018
|
return g_object_get_qdata((GObject*)node, custom_element_quark);
|
1019
|
}
|
1020
|
|
1021
|
static struct _CustomElement*
|
1022
|
_lasso_node_get_custom_element_or_create(LassoNode *node)
|
1023
|
{
|
1024
|
struct _CustomElement *custom_element;
|
1025
|
|
1026
|
if (! LASSO_IS_NODE(node))
|
1027
|
return NULL;
|
1028
|
|
1029
|
custom_element = _lasso_node_get_custom_element(node);
|
1030
|
if (! custom_element) {
|
1031
|
custom_element = _lasso_node_new_custom_element();
|
1032
|
g_object_set_qdata_full((GObject*)node, custom_element_quark,
|
1033
|
custom_element,
|
1034
|
(GDestroyNotify)_lasso_node_free_custom_element);
|
1035
|
}
|
1036
|
return custom_element;
|
1037
|
}
|
1038
|
|
1039
|
|
1040
|
/**
|
1041
|
* lasso_node_set_custom_namespace:
|
1042
|
* @node: a #LassoNode object
|
1043
|
* @prefix: the prefix to use for the definition
|
1044
|
* @href: the URI of the namespace
|
1045
|
*
|
1046
|
* Set a custom namespace for an object instance, use it with object existing a lot of revision of
|
1047
|
* the nearly same namespace.
|
1048
|
*/
|
1049
|
void
|
1050
|
lasso_node_set_custom_namespace(LassoNode *node, const char *prefix, const char *href)
|
1051
|
{
|
1052
|
struct _CustomElement *custom_element;
|
1053
|
|
1054
|
custom_element = _lasso_node_get_custom_element_or_create(node);
|
1055
|
g_return_if_fail (custom_element != NULL);
|
1056
|
|
1057
|
lasso_assign_string(custom_element->prefix, prefix);
|
1058
|
lasso_assign_string(custom_element->href, href);
|
1059
|
}
|
1060
|
|
1061
|
/**
|
1062
|
* lasso_node_set_signature:
|
1063
|
* @node: a #LassoNode object
|
1064
|
* @signature_context: a #LassoSignatureContext structure
|
1065
|
*
|
1066
|
* Setup a signature on @node.
|
1067
|
*
|
1068
|
* Return value: 0 if successful, an error code otherwise.
|
1069
|
*/
|
1070
|
int
|
1071
|
lasso_node_set_signature(LassoNode *node, LassoSignatureContext context)
|
1072
|
{
|
1073
|
struct _CustomElement *custom_element;
|
1074
|
int rc = 0;
|
1075
|
|
1076
|
lasso_bad_param(NODE, node);
|
1077
|
custom_element = _lasso_node_get_custom_element_or_create(node);
|
1078
|
g_return_val_if_fail (custom_element != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
1079
|
|
1080
|
if (custom_element->signature_context.signature_key) {
|
1081
|
lasso_release_sec_key(custom_element->signature_context.signature_key);
|
1082
|
}
|
1083
|
custom_element->signature_context.signature_method = context.signature_method;
|
1084
|
lasso_assign_new_sec_key(custom_element->signature_context.signature_key,
|
1085
|
context.signature_key);
|
1086
|
return rc;
|
1087
|
}
|
1088
|
|
1089
|
/**
|
1090
|
* lasso_node_get_signature:
|
1091
|
* @node: a #LassoNode object
|
1092
|
* @type: an output for the signature type
|
1093
|
* @method: an output for the signature method
|
1094
|
* @private_key: an output for the private key
|
1095
|
* @private_key_password: an output for the private key password
|
1096
|
* @certificate: an output for the certificate
|
1097
|
*
|
1098
|
* Return signature parameters stored with this node.
|
1099
|
*/
|
1100
|
LassoSignatureContext
|
1101
|
lasso_node_get_signature(LassoNode *node)
|
1102
|
{
|
1103
|
struct _CustomElement *custom_element;
|
1104
|
|
1105
|
g_return_val_if_fail (LASSO_IS_NODE(node), LASSO_SIGNATURE_CONTEXT_NONE);
|
1106
|
custom_element = _lasso_node_get_custom_element(node);
|
1107
|
if (! custom_element) {
|
1108
|
return LASSO_SIGNATURE_CONTEXT_NONE;
|
1109
|
}
|
1110
|
return custom_element->signature_context;
|
1111
|
}
|
1112
|
|
1113
|
/**
|
1114
|
* lasso_node_set_encryption:
|
1115
|
* @node: a @LassoNode object
|
1116
|
* @encryption_public_key: an #xmlSecKey used to crypt the session key
|
1117
|
* @encryption_sym_key_type: the kind of session key to use
|
1118
|
*
|
1119
|
* Setup a node for future encryption. It is read by saml2:EncryptedElement for eventually
|
1120
|
* encrypting nodes.
|
1121
|
*
|
1122
|
* Return value: 0 if successful, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if node is not a
|
1123
|
* #LassoNode.
|
1124
|
*/
|
1125
|
void
|
1126
|
lasso_node_set_encryption(LassoNode *node, xmlSecKey *encryption_public_key,
|
1127
|
LassoEncryptionSymKeyType encryption_sym_key_type)
|
1128
|
{
|
1129
|
struct _CustomElement *custom_element;
|
1130
|
|
1131
|
g_return_if_fail(LASSO_IS_NODE(node));
|
1132
|
if (encryption_public_key) {
|
1133
|
custom_element = _lasso_node_get_custom_element_or_create(node);
|
1134
|
if (! custom_element) {
|
1135
|
return;
|
1136
|
}
|
1137
|
} else {
|
1138
|
custom_element = _lasso_node_get_custom_element(node);
|
1139
|
if (! custom_element) {
|
1140
|
return;
|
1141
|
}
|
1142
|
lasso_release_sec_key(custom_element->encryption_public_key);
|
1143
|
return;
|
1144
|
}
|
1145
|
lasso_assign_sec_key(custom_element->encryption_public_key,
|
1146
|
encryption_public_key);
|
1147
|
if (encryption_sym_key_type < LASSO_ENCRYTPION_SYM_KEY_TYPE_LAST) {
|
1148
|
custom_element->encryption_sym_key_type = encryption_sym_key_type;
|
1149
|
} else {
|
1150
|
custom_element->encryption_sym_key_type = LASSO_ENCRYPTION_SYM_KEY_TYPE_DEFAULT;
|
1151
|
}
|
1152
|
}
|
1153
|
|
1154
|
/**
|
1155
|
* lasso_node_get_encryption:
|
1156
|
* @node: a #LassoNode object
|
1157
|
* @encryption_public_key_ptr: a pointer on a pointer to an #xmlSecKey object, to hold the the
|
1158
|
* public key used to encrypt the session key
|
1159
|
* @encryption_sym_key_type: a pointer on a #LassoEncryptionSymKeyType
|
1160
|
*
|
1161
|
* Lookup eventual configuration for encrypting the given node.
|
1162
|
*/
|
1163
|
void
|
1164
|
lasso_node_get_encryption(LassoNode *node, xmlSecKey **encryption_public_key,
|
1165
|
LassoEncryptionSymKeyType *encryption_sym_key_type)
|
1166
|
{
|
1167
|
struct _CustomElement *custom_element;
|
1168
|
|
1169
|
g_return_if_fail(LASSO_IS_NODE(node));
|
1170
|
custom_element = _lasso_node_get_custom_element(node);
|
1171
|
if (custom_element && custom_element->encryption_public_key) {
|
1172
|
lasso_assign_sec_key(*encryption_public_key,
|
1173
|
custom_element->encryption_public_key);
|
1174
|
*encryption_sym_key_type = custom_element->encryption_sym_key_type;
|
1175
|
}
|
1176
|
}
|
1177
|
|
1178
|
/**
|
1179
|
* lasso_node_set_custom_nodename:
|
1180
|
* @node: a #LassoNode object
|
1181
|
* @nodename: the name to use for the node
|
1182
|
*
|
1183
|
* Set a custom nodename for an object instance, use it with object implement a schema type and not
|
1184
|
* a real element.
|
1185
|
*/
|
1186
|
void
|
1187
|
lasso_node_set_custom_nodename(LassoNode *node, const char *nodename)
|
1188
|
{
|
1189
|
struct _CustomElement *custom_element;
|
1190
|
|
1191
|
custom_element = _lasso_node_get_custom_element_or_create(node);
|
1192
|
g_return_if_fail (custom_element != NULL);
|
1193
|
|
1194
|
lasso_assign_string(custom_element->nodename, nodename);
|
1195
|
}
|
1196
|
|
1197
|
/**
|
1198
|
* lasso_node_add_custom_namespace:
|
1199
|
* @prefix: prefix name
|
1200
|
* @href: href url
|
1201
|
*
|
1202
|
* Add a custom namespace declaration at this node level
|
1203
|
*/
|
1204
|
void
|
1205
|
lasso_node_add_custom_namespace(LassoNode *node, const char *prefix,
|
1206
|
const char *href)
|
1207
|
{
|
1208
|
struct _CustomElement *custom_element;
|
1209
|
|
1210
|
custom_element = _lasso_node_get_custom_element_or_create(node);
|
1211
|
g_return_if_fail(custom_element != NULL);
|
1212
|
|
1213
|
g_hash_table_insert(custom_element->namespaces, g_strdup(prefix), g_strdup(href));
|
1214
|
}
|
1215
|
|
1216
|
/*****************************************************************************/
|
1217
|
/* implementation methods */
|
1218
|
/*****************************************************************************/
|
1219
|
|
1220
|
static void
|
1221
|
lasso_node_remove_original_xmlnode(LassoNode *node, SnippetType type) {
|
1222
|
LassoNodeClass *class;
|
1223
|
class = LASSO_NODE_GET_CLASS(node);
|
1224
|
|
1225
|
if (class->node_data->keep_xmlnode || type & SNIPPET_KEEP_XMLNODE) {
|
1226
|
lasso_node_set_original_xmlnode(node, NULL);
|
1227
|
}
|
1228
|
}
|
1229
|
|
1230
|
static void
|
1231
|
lasso_node_traversal(LassoNode *node, void (*do_to_node)(LassoNode *node, SnippetType type), SnippetType type) {
|
1232
|
LassoNodeClass *class;
|
1233
|
struct XmlSnippet *snippet;
|
1234
|
|
1235
|
if (node == NULL || do_to_node == NULL) {
|
1236
|
return;
|
1237
|
}
|
1238
|
class = LASSO_NODE_GET_CLASS(node);
|
1239
|
do_to_node(node, type);
|
1240
|
|
1241
|
while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
|
1242
|
GType g_type = G_TYPE_FROM_CLASS(class);
|
1243
|
snippet = class->node_data->snippets;
|
1244
|
while (snippet->name != NULL) {
|
1245
|
SnippetType type;
|
1246
|
void **value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
|
1247
|
|
1248
|
type = snippet->type & 0xff;
|
1249
|
switch (type) {
|
1250
|
case SNIPPET_NODE:
|
1251
|
case SNIPPET_NODE_IN_CHILD:
|
1252
|
lasso_node_traversal(*value, do_to_node, snippet->type);
|
1253
|
break;
|
1254
|
case SNIPPET_LIST_NODES:
|
1255
|
{
|
1256
|
GList *list = *value;
|
1257
|
while (list != NULL) {
|
1258
|
if (list->data) {
|
1259
|
lasso_node_traversal(LASSO_NODE(list->data), do_to_node, snippet->type);
|
1260
|
}
|
1261
|
list = g_list_next(list);
|
1262
|
}
|
1263
|
}
|
1264
|
break;
|
1265
|
case SNIPPET_UNUSED1:
|
1266
|
g_assert_not_reached();
|
1267
|
default:
|
1268
|
break;
|
1269
|
}
|
1270
|
snippet++;
|
1271
|
}
|
1272
|
class = g_type_class_peek_parent(class);
|
1273
|
}
|
1274
|
}
|
1275
|
|
1276
|
static void
|
1277
|
lasso_node_impl_destroy(LassoNode *node)
|
1278
|
{
|
1279
|
g_object_unref(G_OBJECT(node));
|
1280
|
}
|
1281
|
#define trace_snippet(format, args...) \
|
1282
|
lasso_trace(format "%s.%s\n", ## args, G_OBJECT_TYPE_NAME(node), snippet->name)
|
1283
|
|
1284
|
/**
|
1285
|
* _lasso_node_collect_namespaces:
|
1286
|
* @namespaces: a pointer to a pointer on a #GHashTable
|
1287
|
* @node: an #xmlNode pointer
|
1288
|
*
|
1289
|
* Follow the parent link of the @node to collect all declared namespaces, it is usefull for content
|
1290
|
* that need to be interpreted with respect to declared namespaces (XPath for example).
|
1291
|
*/
|
1292
|
void
|
1293
|
_lasso_node_collect_namespaces(GHashTable **namespaces, xmlNode *node)
|
1294
|
{
|
1295
|
if (*namespaces == NULL) {
|
1296
|
*namespaces = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free);
|
1297
|
}
|
1298
|
while (node) {
|
1299
|
if (node->type == XML_ELEMENT_NODE) {
|
1300
|
xmlNs *nsDef = node->nsDef;
|
1301
|
while (nsDef) {
|
1302
|
if (nsDef->prefix && nsDef->href) {
|
1303
|
g_hash_table_insert(*namespaces, g_strdup((char*)nsDef->prefix),
|
1304
|
g_strdup((char*)nsDef->href));
|
1305
|
}
|
1306
|
nsDef = nsDef->next;
|
1307
|
}
|
1308
|
}
|
1309
|
node = node->parent;
|
1310
|
}
|
1311
|
}
|
1312
|
|
1313
|
gboolean
|
1314
|
lasso_get_integer_attribute(xmlNode *node, xmlChar *attribute_name, xmlChar *ns_href, int *integer, long int low, long int high) {
|
1315
|
xmlChar *content = NULL;
|
1316
|
gboolean rc = FALSE;
|
1317
|
long int what;
|
1318
|
|
1319
|
g_assert (integer);
|
1320
|
content = xmlGetNsProp(node, attribute_name, ns_href);
|
1321
|
if (! content)
|
1322
|
goto cleanup;
|
1323
|
if (! lasso_string_to_xsd_integer((char*)content, &what))
|
1324
|
goto cleanup;
|
1325
|
if (what < low || what >= high)
|
1326
|
goto cleanup;
|
1327
|
*integer = what;
|
1328
|
rc = TRUE;
|
1329
|
cleanup:
|
1330
|
lasso_release_xml_string(content);
|
1331
|
return rc;
|
1332
|
}
|
1333
|
|
1334
|
static inline gboolean
|
1335
|
lasso_equal_namespace(xmlNs *t1, xmlNs *t2) {
|
1336
|
return t1 && t2 && (t1 == t2 ||
|
1337
|
lasso_strisequal((char*)t1->href, (char*)t2->href));
|
1338
|
}
|
1339
|
|
1340
|
static void
|
1341
|
snippet_set_value(LassoNode *node, LassoNodeClass *class, struct XmlSnippet *snippet, xmlChar *content) {
|
1342
|
void *value;
|
1343
|
GType g_type = G_TYPE_FROM_CLASS(class);
|
1344
|
|
1345
|
/* If not offset, it means it is handled by an adhoc init_from_xml */
|
1346
|
if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE)) {
|
1347
|
return;
|
1348
|
}
|
1349
|
value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
|
1350
|
if (snippet->type & SNIPPET_INTEGER) {
|
1351
|
int val = strtol((char*)content, NULL, 10);
|
1352
|
if (((val == INT_MIN || val == INT_MAX) && errno == ERANGE)
|
1353
|
|| errno == EINVAL || val < 0) {
|
1354
|
if (snippet->type & SNIPPET_OPTIONAL_NEG) {
|
1355
|
val = -1;
|
1356
|
} else {
|
1357
|
val = 0;
|
1358
|
}
|
1359
|
}
|
1360
|
(*(int*)value) = val;
|
1361
|
} else if (snippet->type & SNIPPET_BOOLEAN) {
|
1362
|
int val = 0;
|
1363
|
if (strcmp((char*)content, "true") == 0) {
|
1364
|
val = 1;
|
1365
|
} else if (strcmp((char*)content, "1") == 0) {
|
1366
|
val = 1;
|
1367
|
}
|
1368
|
(*(int*)value) = val;
|
1369
|
} else {
|
1370
|
lasso_assign_string((*(char**)value), (char*)content);
|
1371
|
if (lasso_flag_memory_debug == TRUE) {
|
1372
|
fprintf(stderr, " setting prop %s/%s to value %p: %s\n",
|
1373
|
G_OBJECT_TYPE_NAME(node), snippet->name, *(void**)value, (char*)content);
|
1374
|
}
|
1375
|
}
|
1376
|
}
|
1377
|
|
1378
|
gboolean
|
1379
|
next_node_snippet(GSList **class_iter_p, struct XmlSnippet **snippet_p)
|
1380
|
{
|
1381
|
while (*class_iter_p) {
|
1382
|
if (*snippet_p) {
|
1383
|
if ((*snippet_p)->name) {
|
1384
|
SnippetType type = (*snippet_p)->type;
|
1385
|
/* special case for ArtifactResponse */
|
1386
|
if (type & SNIPPET_ANY && (type & 0xff) == SNIPPET_NODE)
|
1387
|
return TRUE;
|
1388
|
if (! (type & SNIPPET_ANY) && (*snippet_p)->name[0] != '\0') {
|
1389
|
switch (type & 0xff) {
|
1390
|
case SNIPPET_NODE:
|
1391
|
case SNIPPET_NODE_IN_CHILD:
|
1392
|
case SNIPPET_LIST_XMLNODES:
|
1393
|
case SNIPPET_LIST_CONTENT:
|
1394
|
case SNIPPET_LIST_NODES:
|
1395
|
case SNIPPET_EXTENSION:
|
1396
|
case SNIPPET_XMLNODE:
|
1397
|
case SNIPPET_CONTENT:
|
1398
|
case SNIPPET_SIGNATURE:
|
1399
|
return TRUE;
|
1400
|
default:
|
1401
|
break;
|
1402
|
}
|
1403
|
}
|
1404
|
++*snippet_p;
|
1405
|
} else {
|
1406
|
*class_iter_p = g_slist_next(*class_iter_p);
|
1407
|
*snippet_p = NULL;
|
1408
|
}
|
1409
|
} else {
|
1410
|
*snippet_p = ((LassoNodeClass*)(*class_iter_p)->data)
|
1411
|
->node_data->snippets;
|
1412
|
}
|
1413
|
}
|
1414
|
return FALSE;
|
1415
|
}
|
1416
|
|
1417
|
static inline gboolean
|
1418
|
is_snippet_type(struct XmlSnippet *snippet, SnippetType simple_type) {
|
1419
|
return (snippet->type & 0xff) == simple_type;
|
1420
|
}
|
1421
|
|
1422
|
static inline gboolean
|
1423
|
is_snippet_mandatory(struct XmlSnippet *snippet)
|
1424
|
{
|
1425
|
return snippet->type & SNIPPET_MANDATORY ? TRUE : FALSE;
|
1426
|
}
|
1427
|
|
1428
|
static inline gboolean
|
1429
|
is_snippet_multiple(struct XmlSnippet *snippet)
|
1430
|
{
|
1431
|
switch (snippet->type & 0xff) {
|
1432
|
case SNIPPET_LIST_XMLNODES:
|
1433
|
case SNIPPET_LIST_CONTENT:
|
1434
|
case SNIPPET_LIST_NODES:
|
1435
|
case SNIPPET_EXTENSION:
|
1436
|
return TRUE;
|
1437
|
default:
|
1438
|
return FALSE;
|
1439
|
}
|
1440
|
}
|
1441
|
|
1442
|
static inline gboolean
|
1443
|
node_match_snippet(xmlNode *parent, xmlNode *node, struct XmlSnippet *snippet)
|
1444
|
{
|
1445
|
/* special case of ArtifactResponse */
|
1446
|
if (snippet->type & SNIPPET_ANY) {
|
1447
|
message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs SNIPPET_ANY: SUCCESS", node->name);
|
1448
|
return TRUE;
|
1449
|
} else {
|
1450
|
if (!lasso_strisequal(snippet->name, (char*)node->name)) {
|
1451
|
message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: FAILURE names don't match", node->name, snippet->name);
|
1452
|
return FALSE;
|
1453
|
}
|
1454
|
|
1455
|
if ((snippet->ns_uri == NULL) && lasso_equal_namespace(parent->ns, node->ns)) {
|
1456
|
message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: SUCCESS namespace prefixes match", node->name, snippet->name);
|
1457
|
return TRUE;
|
1458
|
}
|
1459
|
|
1460
|
if ((node->ns != NULL) && lasso_strisequal((char*)node->ns->href, snippet->ns_uri)) {
|
1461
|
message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: SUCCESS namespace URIs match", node->name, snippet->name);
|
1462
|
return TRUE;
|
1463
|
}
|
1464
|
|
1465
|
message(LOG_LEVEL_XML_DEBUG, "Matching node %s vs snippet %s: FAILURE", node->name, snippet->name);
|
1466
|
return FALSE;
|
1467
|
}
|
1468
|
}
|
1469
|
|
1470
|
/** FIXME: return a real error code */
|
1471
|
static int
|
1472
|
lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode)
|
1473
|
{
|
1474
|
struct XmlSnippet *snippet;
|
1475
|
xmlNode *t;
|
1476
|
LassoNodeClass *class;
|
1477
|
void *value;
|
1478
|
SnippetType type;
|
1479
|
struct XmlSnippet *snippet_any = NULL;
|
1480
|
struct XmlSnippet *snippet_any_attribute = NULL;
|
1481
|
GType g_type_collect_namespaces = 0, g_type_any = 0, g_type_any_attribute = 0;
|
1482
|
struct XmlSnippet *snippet_collect_namespaces = NULL;
|
1483
|
struct XmlSnippet *snippet_signature = NULL;
|
1484
|
gboolean keep_xmlnode = FALSE;
|
1485
|
GSList *class_list = NULL;
|
1486
|
GSList *class_iter = NULL;
|
1487
|
xmlAttr *attr = NULL;
|
1488
|
GType g_type = 0;
|
1489
|
LassoNodeClass *node_class;
|
1490
|
gint rc = 0;
|
1491
|
|
1492
|
message(LOG_LEVEL_XML_DEBUG, "lasso_node_impl_init_from_xml <%s>", xmlnode->name);
|
1493
|
|
1494
|
if (! xmlnode) {
|
1495
|
rc = 1;
|
1496
|
goto cleanup;
|
1497
|
}
|
1498
|
|
1499
|
node_class = class = LASSO_NODE_GET_CLASS(node);
|
1500
|
/* No node_data no initialization possible */
|
1501
|
if (! class->node_data) {
|
1502
|
message(G_LOG_LEVEL_WARNING, "Class %s has no node_data so no initialization "
|
1503
|
"is possible", G_OBJECT_CLASS_NAME(class));
|
1504
|
rc = 1;
|
1505
|
goto cleanup;
|
1506
|
}
|
1507
|
|
1508
|
/* Collect special snippets like SNIPPET_COLLECT_NAMESPACES, SNIPPET_ANY, SNIPPET_ATTRIBUTE
|
1509
|
* or SNIPPET_SIGNATURE, and initialize class_list in reverse. */
|
1510
|
while (class && LASSO_IS_NODE_CLASS(class)) {
|
1511
|
if (class->node_data) {
|
1512
|
GType g_type = G_TYPE_FROM_CLASS(class);
|
1513
|
keep_xmlnode |= class->node_data->keep_xmlnode;
|
1514
|
if (class->node_data->snippets)
|
1515
|
class_list = g_slist_prepend(class_list, class);
|
1516
|
for (snippet = class->node_data->snippets; snippet && snippet->name; snippet++) {
|
1517
|
type = snippet->type & 0xff;
|
1518
|
|
1519
|
if (snippet->name && snippet->name[0] == '\0' && type ==
|
1520
|
SNIPPET_COLLECT_NAMESPACES) {
|
1521
|
snippet_collect_namespaces = snippet;
|
1522
|
g_type_collect_namespaces = g_type;
|
1523
|
} else if (type == SNIPPET_SIGNATURE) {
|
1524
|
snippet_signature = snippet;
|
1525
|
} else if (type == SNIPPET_ATTRIBUTE && snippet->type & SNIPPET_ANY) {
|
1526
|
g_type_any_attribute = g_type;
|
1527
|
snippet_any_attribute = snippet;
|
1528
|
} else if (type == SNIPPET_TEXT_CHILD) {
|
1529
|
xmlChar *tmp = xmlNodeGetContent(xmlnode);
|
1530
|
snippet_set_value(node, class, snippet, tmp);
|
1531
|
lasso_release_xml_string(tmp);
|
1532
|
} else if (type != SNIPPET_ATTRIBUTE && type != SNIPPET_NODE && snippet->type & SNIPPET_ANY) {
|
1533
|
if (! snippet_any) {
|
1534
|
g_type_any = g_type;
|
1535
|
snippet_any = snippet;
|
1536
|
} else {
|
1537
|
message(G_LOG_LEVEL_CRITICAL, "Two 'any' node snippet for class %s",
|
1538
|
g_type_name(G_TYPE_FROM_INSTANCE(node)));
|
1539
|
}
|
1540
|
}
|
1541
|
}
|
1542
|
}
|
1543
|
class = g_type_class_peek_parent(class);
|
1544
|
}
|
1545
|
|
1546
|
/* If any class asked for keeping the xmlNode, keep it around */
|
1547
|
if (keep_xmlnode) {
|
1548
|
lasso_node_set_original_xmlnode(node, xmlnode);
|
1549
|
}
|
1550
|
|
1551
|
/** Collect attributes */
|
1552
|
for (attr = xmlnode->properties; attr; attr = attr->next) {
|
1553
|
xmlChar *content;
|
1554
|
content = xmlNodeGetContent((xmlNode*)attr);
|
1555
|
int ok = 0;
|
1556
|
|
1557
|
/* Skip xsi:type if it was used to find the node class */
|
1558
|
if (attr->ns && lasso_strisequal((char*)attr->name, "type") &&
|
1559
|
lasso_strisequal((char*)attr->ns->href, LASSO_XSI_HREF)) {
|
1560
|
char *colon = strchr((char*)content, ':');
|
1561
|
if (colon) {
|
1562
|
xmlNs *ns;
|
1563
|
*colon = '\0';
|
1564
|
ns = xmlSearchNs(NULL, xmlnode, content);
|
1565
|
*colon = ':';
|
1566
|
if (ns && lasso_strisequal((char*)ns->href, (char*)node_class->node_data->ns->href)
|
1567
|
&& lasso_strisequal(&colon[1], node_class->node_data->node_name)) {
|
1568
|
lasso_release_xml_string(content);
|
1569
|
continue;
|
1570
|
}
|
1571
|
}
|
1572
|
}
|
1573
|
|
1574
|
for (class_iter = class_list; class_iter; class_iter = class_iter->next) {
|
1575
|
class = class_iter->data;
|
1576
|
for (snippet = class->node_data->snippets;
|
1577
|
snippet && snippet->name; snippet++) {
|
1578
|
type = snippet->type & 0xff;
|
1579
|
/* assign attribute content if attribute has the same name as the
|
1580
|
* snippet and:
|
1581
|
* - the snippet and the attribute have no namespace
|
1582
|
* - the snippet has no namespace but the attribute has the same
|
1583
|
* namespace as the node
|
1584
|
* - the snippet and the node have a namespace, which are equal.
|
1585
|
*/
|
1586
|
if (type != SNIPPET_ATTRIBUTE)
|
1587
|
continue;
|
1588
|
if (! lasso_strisequal((char*)attr->name, (char*)snippet->name))
|
1589
|
continue;
|
1590
|
if (attr->ns) {
|
1591
|
gboolean same_namespace, given_namespace;
|
1592
|
|
1593
|
same_namespace = lasso_equal_namespace(attr->ns,
|
1594
|
xmlnode->ns) && ! snippet->ns_uri;
|
1595
|
given_namespace = snippet->ns_uri &&
|
1596
|
lasso_strisequal((char*)attr->ns->href,
|
1597
|
snippet->ns_uri);
|
1598
|
if (! same_namespace && ! given_namespace)
|
1599
|
break;
|
1600
|
}
|
1601
|
snippet_set_value(node, class, snippet, content);
|
1602
|
ok = 1;
|
1603
|
break;
|
1604
|
}
|
1605
|
}
|
1606
|
if (! ok && attr->ns && snippet_any_attribute) {
|
1607
|
GHashTable **any_attribute;
|
1608
|
gchar *key;
|
1609
|
|
1610
|
any_attribute = SNIPPET_STRUCT_MEMBER_P(node, g_type_any_attribute,
|
1611
|
snippet_any_attribute);
|
1612
|
if (*any_attribute == NULL) {
|
1613
|
*any_attribute = g_hash_table_new_full(g_str_hash, g_str_equal,
|
1614
|
g_free, g_free);
|
1615
|
}
|
1616
|
if (lasso_equal_namespace(attr->ns, xmlnode->ns)) {
|
1617
|
key = g_strdup((char*)attr->name);
|
1618
|
} else {
|
1619
|
key = g_strdup_printf("{%s}%s", attr->ns->href, attr->name);
|
1620
|
}
|
1621
|
g_hash_table_insert(*any_attribute, key, g_strdup((char*)content));
|
1622
|
lasso_release_xml_string(content);
|
1623
|
} else if (! ok) {
|
1624
|
warning("lasso_node_impl_init_from_xml: Unexpected attribute: {%s}%s = %s",
|
1625
|
attr->ns ? attr->ns->href : NULL, attr->name, content);
|
1626
|
}
|
1627
|
lasso_release_xml_string(content);
|
1628
|
}
|
1629
|
|
1630
|
/* Collect children nodes in reverse order of class parents (older parent first), skip non
|
1631
|
* node and ANY snippets) */
|
1632
|
class_iter = class_list;
|
1633
|
snippet = ((LassoNodeClass*)class_iter->data)->node_data->snippets;
|
1634
|
next_node_snippet(&class_iter, &snippet);
|
1635
|
for (t = xmlnode->children; t && class_iter && snippet; t = t->next) {
|
1636
|
/* Only collect text node if:
|
1637
|
* - there is a LIST_XMLNODES any snippet
|
1638
|
* - there is a LIST_NODES any snippet with the ALLOW_TEXT modifier
|
1639
|
*/
|
1640
|
if (t->type == XML_TEXT_NODE && snippet_any &&
|
1641
|
(is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)
|
1642
|
|| (is_snippet_type(snippet_any, SNIPPET_LIST_NODES) &&
|
1643
|
(snippet_any->type & SNIPPET_ALLOW_TEXT)))) {
|
1644
|
GList **location = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
|
1645
|
if (is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)) {
|
1646
|
lasso_list_add_xml_node(*location, t);
|
1647
|
} else {
|
1648
|
lasso_list_add_new_gobject(*location,
|
1649
|
lasso_node_new_from_xmlNode_with_type(t,
|
1650
|
"LassoMiscTextNode"));
|
1651
|
}
|
1652
|
} else if (t->type == XML_COMMENT_NODE || t->type == XML_PI_NODE || t->type == XML_TEXT_NODE) {
|
1653
|
/* ignore comments */
|
1654
|
continue;
|
1655
|
} else if (t->type == XML_ELEMENT_NODE) {
|
1656
|
LassoNode *subnode = NULL;
|
1657
|
xmlNode *first_child = NULL;
|
1658
|
GList **list = NULL;
|
1659
|
xmlChar *content = NULL;
|
1660
|
gboolean match = FALSE;
|
1661
|
struct XmlSnippet *matched_snippet = NULL;
|
1662
|
|
1663
|
#define ADVANCE_MATCH \
|
1664
|
if (snippet->type & SNIPPET_JUMP_ON_MATCH) { \
|
1665
|
snippet += (ptrdiff_t)SNIPPET_JUMP_OFFSET(snippet->type); \
|
1666
|
} else { \
|
1667
|
snippet++; \
|
1668
|
} \
|
1669
|
next_node_snippet(&class_iter, &snippet);
|
1670
|
#define ADVANCE_MISS \
|
1671
|
if (snippet->type & SNIPPET_JUMP_ON_MISS) { \
|
1672
|
snippet += (ptrdiff_t)SNIPPET_JUMP_OFFSET(snippet->type); \
|
1673
|
} else { \
|
1674
|
snippet++; \
|
1675
|
} \
|
1676
|
next_node_snippet(&class_iter, &snippet);
|
1677
|
#define ERROR \
|
1678
|
message(G_LOG_LEVEL_CRITICAL, "Element <%s:%s> was not expected at this location inside element <%s>. " \
|
1679
|
"Please ensure the XML correctly follows XML schema", \
|
1680
|
(t->ns == NULL) ? "<noprefix>" : ((t->ns->prefix == NULL)? (char*)t->ns->href : (char*)t->ns->prefix), \
|
1681
|
t->name, \
|
1682
|
xmlnode->name); \
|
1683
|
rc = 1; \
|
1684
|
goto cleanup;
|
1685
|
/* Find a matching snippet */
|
1686
|
while (class_iter && snippet) {
|
1687
|
gboolean mandatory = is_snippet_mandatory(snippet);
|
1688
|
gboolean multiple = is_snippet_multiple(snippet);
|
1689
|
|
1690
|
if ((match = node_match_snippet(xmlnode, t, snippet))) {
|
1691
|
matched_snippet = snippet;
|
1692
|
class = class_iter->data;
|
1693
|
g_type = G_TYPE_FROM_CLASS(class);
|
1694
|
value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet);
|
1695
|
list = value;
|
1696
|
if (! multiple || (snippet->type & SNIPPET_JUMP_ON_MATCH)) {
|
1697
|
ADVANCE_MATCH;
|
1698
|
}
|
1699
|
break;
|
1700
|
} else {
|
1701
|
if (mandatory) {
|
1702
|
break;
|
1703
|
} else {
|
1704
|
ADVANCE_MISS;
|
1705
|
}
|
1706
|
}
|
1707
|
}
|
1708
|
if (! match) {
|
1709
|
ERROR;
|
1710
|
}
|
1711
|
#undef ADVANCE
|
1712
|
#undef ERROR
|
1713
|
|
1714
|
if (matched_snippet->offset || (matched_snippet->type & SNIPPET_PRIVATE)) {
|
1715
|
switch (matched_snippet->type & 0xff) {
|
1716
|
case SNIPPET_LIST_NODES:
|
1717
|
case SNIPPET_NODE:
|
1718
|
subnode = lasso_node_new_from_xmlNode_with_type(t,
|
1719
|
matched_snippet->class_name);
|
1720
|
if (subnode == NULL) {
|
1721
|
message(G_LOG_LEVEL_CRITICAL, "Failed to create LassoNode from XML node");
|
1722
|
}
|
1723
|
else {
|
1724
|
if (is_snippet_type(matched_snippet, SNIPPET_NODE)) {
|
1725
|
lasso_assign_new_gobject(*(LassoNode**)value, subnode);
|
1726
|
}
|
1727
|
else {
|
1728
|
lasso_list_add_new_gobject(*list, subnode);
|
1729
|
}
|
1730
|
}
|
1731
|
break;
|
1732
|
case SNIPPET_NODE_IN_CHILD:
|
1733
|
first_child = xmlSecGetNextElementNode(t->children);
|
1734
|
if (first_child) {
|
1735
|
subnode = lasso_node_new_from_xmlNode_with_type(first_child,
|
1736
|
matched_snippet->class_name);
|
1737
|
lasso_assign_new_gobject(*(LassoNode**)value, subnode);
|
1738
|
}
|
1739
|
break;
|
1740
|
case SNIPPET_XMLNODE:
|
1741
|
lasso_assign_xml_node(*(xmlNode**)value, t);
|
1742
|
break;
|
1743
|
case SNIPPET_LIST_XMLNODES:
|
1744
|
case SNIPPET_EXTENSION:
|
1745
|
lasso_list_add_xml_node(*list, t);
|
1746
|
break;
|
1747
|
case SNIPPET_CONTENT:
|
1748
|
case SNIPPET_LIST_CONTENT:
|
1749
|
content = xmlNodeGetContent(t);
|
1750
|
if (is_snippet_type(matched_snippet, SNIPPET_CONTENT)) {
|
1751
|
snippet_set_value(node, class, matched_snippet, content);
|
1752
|
} else { /* only list of string-like xsd:type supported */
|
1753
|
lasso_list_add_string(*list, (char*)content);
|
1754
|
}
|
1755
|
lasso_release_xml_string(content);
|
1756
|
break;
|
1757
|
case SNIPPET_SIGNATURE:
|
1758
|
/* We ignore it */
|
1759
|
break;
|
1760
|
default:
|
1761
|
g_assert_not_reached();
|
1762
|
|
1763
|
}
|
1764
|
}
|
1765
|
/* When creating a new LassoNode and option KEEP_XMLNODE is present,
|
1766
|
* we attached the xmlNode to the LassoNode */
|
1767
|
if (subnode && (matched_snippet->type & SNIPPET_KEEP_XMLNODE)) {
|
1768
|
lasso_node_set_original_xmlnode(subnode, t);
|
1769
|
}
|
1770
|
} else {
|
1771
|
g_assert_not_reached();
|
1772
|
}
|
1773
|
}
|
1774
|
if (t) { /* t is an ELEMENT that dont match any snippet, when taken in order */
|
1775
|
if (snippet_any && is_snippet_type(snippet_any, SNIPPET_LIST_XMLNODES)) {
|
1776
|
value = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
|
1777
|
GList **list = value;
|
1778
|
for (; t; t = t->next) {
|
1779
|
lasso_list_add_xml_node(*list, t);
|
1780
|
}
|
1781
|
} else if (snippet_any && is_snippet_type(snippet_any, SNIPPET_LIST_NODES)) {
|
1782
|
value = SNIPPET_STRUCT_MEMBER_P(node, g_type_any, snippet_any);
|
1783
|
GList **list = value;
|
1784
|
for (; t; t = t->next) {
|
1785
|
LassoNode *subnode = NULL;
|
1786
|
|
1787
|
if (t->type == XML_TEXT_NODE && (snippet_any->type &
|
1788
|
SNIPPET_ALLOW_TEXT)) {
|
1789
|
lasso_list_add_new_gobject(*list,
|
1790
|
lasso_node_new_from_xmlNode_with_type(t,
|
1791
|
"LassoMiscTextNode"));
|
1792
|
} else if (t->type == XML_ELEMENT_NODE) {
|
1793
|
subnode = lasso_node_new_from_xmlNode_with_type(t,
|
1794
|
snippet_any->class_name);
|
1795
|
if (subnode && (snippet_any->type & SNIPPET_KEEP_XMLNODE)) {
|
1796
|
lasso_node_set_original_xmlnode(subnode, t);
|
1797
|
}
|
1798
|
if (! subnode) {
|
1799
|
subnode = (LassoNode*)
|
1800
|
lasso_misc_text_node_new_with_xml_node(t);
|
1801
|
}
|
1802
|
lasso_list_add_new_gobject(*list, subnode);
|
1803
|
}
|
1804
|
}
|
1805
|
} else if (snippet_any) {
|
1806
|
g_assert_not_reached();
|
1807
|
} else {
|
1808
|
for (; t; t = t->next) {
|
1809
|
if (t->type == XML_ELEMENT_NODE) {
|
1810
|
critical("lasso_node_impl_init_from_xml: Cannot match "
|
1811
|
"element {%s}%s with a snippet of "
|
1812
|
"class %s",
|
1813
|
t->ns ? t->ns->href : NULL, t->name,
|
1814
|
g_type_name(G_TYPE_FROM_INSTANCE(node)));
|
1815
|
rc = 1;
|
1816
|
goto cleanup;
|
1817
|
}
|
1818
|
}
|
1819
|
}
|
1820
|
}
|
1821
|
|
1822
|
/* Collect namespaces on the current node */
|
1823
|
if (snippet_collect_namespaces) {
|
1824
|
void *value = SNIPPET_STRUCT_MEMBER_P(node, g_type_collect_namespaces,
|
1825
|
snippet_collect_namespaces);
|
1826
|
_lasso_node_collect_namespaces(value, xmlnode);
|
1827
|
}
|
1828
|
|
1829
|
/* Collect signature parameters */
|
1830
|
{
|
1831
|
LassoSignatureMethod method = 0;
|
1832
|
xmlChar *private_key = NULL;
|
1833
|
xmlChar *private_key_password = NULL;
|
1834
|
xmlChar *certificate = NULL;
|
1835
|
LassoSignatureContext signature_context = LASSO_SIGNATURE_CONTEXT_NONE;
|
1836
|
|
1837
|
while (snippet_signature) {
|
1838
|
int what;
|
1839
|
if (! lasso_get_integer_attribute(xmlnode, LASSO_SIGNATURE_METHOD_ATTRIBUTE,
|
1840
|
BAD_CAST LASSO_LIB_HREF, &what,
|
1841
|
LASSO_SIGNATURE_METHOD_RSA_SHA1,
|
1842
|
LASSO_SIGNATURE_METHOD_LAST))
|
1843
|
break;
|
1844
|
method = what;
|
1845
|
if (! lasso_get_integer_attribute(xmlnode, LASSO_SIGNATURE_METHOD_ATTRIBUTE,
|
1846
|
BAD_CAST LASSO_LIB_HREF, &what, LASSO_SIGNATURE_TYPE_NONE+1,
|
1847
|
LASSO_SIGNATURE_TYPE_LAST))
|
1848
|
break;
|
1849
|
private_key_password = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_PASSWORD_ATTRIBUTE,
|
1850
|
BAD_CAST LASSO_LIB_HREF);
|
1851
|
if (! private_key)
|
1852
|
break;
|
1853
|
private_key = xmlGetNsProp(xmlnode, LASSO_PRIVATE_KEY_ATTRIBUTE, BAD_CAST
|
1854
|
LASSO_LIB_HREF);
|
1855
|
certificate = xmlGetNsProp(xmlnode, LASSO_CERTIFICATE_ATTRIBUTE, BAD_CAST
|
1856
|
LASSO_LIB_HREF);
|
1857
|
|
1858
|
signature_context.signature_method = method;
|
1859
|
signature_context.signature_key = lasso_xmlsec_load_private_key((char*) private_key,
|
1860
|
(char*) private_key_password, method, (char*) certificate);
|
1861
|
lasso_node_set_signature(node, signature_context);
|
1862
|
break;
|
1863
|
}
|
1864
|
lasso_release_xml_string(private_key);
|
1865
|
lasso_release_xml_string(private_key_password);
|
1866
|
lasso_release_xml_string(certificate);
|
1867
|
}
|
1868
|
cleanup:
|
1869
|
lasso_release_slist(class_list);
|
1870
|
message(LOG_LEVEL_XML_DEBUG, "lasso_node_impl_init_from_xml </%s> rc=%d", xmlnode->name, rc);
|
1871
|
return rc;
|
1872
|
}
|
1873
|
#undef trace_snippet
|
1874
|
|
1875
|
/**
|
1876
|
* lasso_node_remove_signature:
|
1877
|
* @node: a #LassoNode object
|
1878
|
*
|
1879
|
* Remove any signature setup on this node.
|
1880
|
*/
|
1881
|
void
|
1882
|
lasso_node_remove_signature(LassoNode *node) {
|
1883
|
LassoNodeClass *klass;
|
1884
|
|
1885
|
if (! LASSO_IS_NODE(node))
|
1886
|
return;
|
1887
|
klass = LASSO_NODE_GET_CLASS(node);
|
1888
|
/* follow the class parenting chain */
|
1889
|
while (klass && LASSO_IS_NODE_CLASS(klass)) {
|
1890
|
if (klass && klass->node_data && klass->node_data->sign_type_offset != 0) {
|
1891
|
G_STRUCT_MEMBER(LassoSignatureType, node, klass->node_data->sign_type_offset) =
|
1892
|
LASSO_SIGNATURE_TYPE_NONE;
|
1893
|
}
|
1894
|
klass = g_type_class_peek_parent(klass);
|
1895
|
}
|
1896
|
lasso_node_set_signature(node, LASSO_SIGNATURE_CONTEXT_NONE);
|
1897
|
}
|
1898
|
|
1899
|
/*****************************************************************************/
|
1900
|
/* private methods */
|
1901
|
/*****************************************************************************/
|
1902
|
|
1903
|
static void
|
1904
|
_xmlnode_add_custom_namespace(const char *prefix, const char *href, xmlNode *xmlnode)
|
1905
|
{
|
1906
|
xmlNs *existing = NULL;
|
1907
|
|
1908
|
existing = xmlSearchNs(NULL, xmlnode, BAD_CAST prefix);
|
1909
|
if (existing) {
|
1910
|
if (lasso_strisnotequal((char *)existing->href,href)) {
|
1911
|
message(G_LOG_LEVEL_CRITICAL, "Cannot add namespace %s='%s' to node %s, "
|
1912
|
"namespace already exists with another href", prefix, href,
|
1913
|
(char*)xmlnode->name);
|
1914
|
}
|
1915
|
return;
|
1916
|
}
|
1917
|
xmlNewNs(xmlnode, BAD_CAST href, BAD_CAST prefix);
|
1918
|
}
|
1919
|
|
1920
|
static char*
|
1921
|
lasso_node_impl_build_query(LassoNode *node)
|
1922
|
{
|
1923
|
return lasso_node_build_query_from_snippets(node);
|
1924
|
}
|
1925
|
|
1926
|
static xmlNode*
|
1927
|
lasso_node_impl_get_xmlNode(LassoNode *node, gboolean lasso_dump)
|
1928
|
{
|
1929
|
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
|
1930
|
LassoNodeClass *version_class = NULL;
|
1931
|
xmlNode *xmlnode;
|
1932
|
xmlNs *ns = NULL;
|
1933
|
GSList *list_classes = NULL, *iter_classes = NULL;
|
1934
|
LassoNode *value_node;
|
1935
|
struct XmlSnippet *version_snippet;
|
1936
|
struct _CustomElement *custom_element;
|
1937
|
LassoNodeClass *xsi_sub_type_data_class = NULL;
|
1938
|
LassoNodeClass *node_name_class = class;
|
1939
|
|
1940
|
while (node_name_class->node_data->xsi_sub_type) {
|
1941
|
node_name_class= g_type_class_peek_parent(node_name_class);
|
1942
|
}
|
1943
|
if (node_name_class != class) {
|
1944
|
xsi_sub_type_data_class = class;
|
1945
|
}
|
1946
|
g_assert(node_name_class && node_name_class->node_data &&
|
1947
|
node_name_class->node_data->node_name);
|
1948
|
|
1949
|
/* Create node in its namespace */
|
1950
|
xmlnode = xmlNewNode(NULL, (xmlChar*)node_name_class->node_data->node_name);
|
1951
|
if (node_name_class->node_data->ns) {
|
1952
|
ns = get_or_define_ns(xmlnode, node_name_class->node_data->ns->href,
|
1953
|
node_name_class->node_data->ns->prefix);
|
1954
|
xmlSetNs(xmlnode, ns);
|
1955
|
}
|
1956
|
/* If subtype, set an xsi:type attribute */
|
1957
|
if (xsi_sub_type_data_class) {
|
1958
|
set_xsi_type(xmlnode,
|
1959
|
xsi_sub_type_data_class->node_data->ns->prefix,
|
1960
|
xsi_sub_type_data_class->node_data->ns->href,
|
1961
|
BAD_CAST xsi_sub_type_data_class->node_data->node_name);
|
1962
|
}
|
1963
|
custom_element = _lasso_node_get_custom_element(node);
|
1964
|
|
1965
|
/* collect all classes in reverse order */
|
1966
|
while (class && LASSO_IS_NODE_CLASS(class)) {
|
1967
|
if (class->node_data && class->node_data->snippets)
|
1968
|
list_classes = g_slist_prepend(list_classes, class);
|
1969
|
class = g_type_class_peek_parent(class);
|
1970
|
}
|
1971
|
|
1972
|
/* set a custom namespace if one is found */
|
1973
|
if (custom_element != NULL) {
|
1974
|
if (custom_element->href) {
|
1975
|
xmlChar *prefix = BAD_CAST (custom_element->prefix);
|
1976
|
xmlNs *ns = NULL, *oldns = NULL;
|
1977
|
|
1978
|
oldns = xmlSearchNs(NULL, xmlnode, prefix);
|
1979
|
if (prefix && oldns) {
|
1980
|
prefix = NULL;
|
1981
|
}
|
1982
|
// remove existing default namespace
|
1983
|
if (prefix == NULL) {
|
1984
|
xmlNs *cur = xmlnode->nsDef, *last = NULL;
|
1985
|
while (cur) {
|
1986
|
if (cur->prefix == NULL) {
|
1987
|
if (last) {
|
1988
|
last->next = cur->next;
|
1989
|
} else {
|
1990
|
xmlnode->nsDef = cur->next;
|
1991
|
}
|
1992
|
xmlFreeNs(cur);
|
1993
|
}
|
1994
|
last = cur;
|
1995
|
cur = cur->next;
|
1996
|
}
|
1997
|
}
|
1998
|
ns = xmlNewNs(xmlnode, (xmlChar*)custom_element->href,
|
1999
|
(xmlChar*)custom_element->prefix);
|
2000
|
/* skip the base class namespace, it is replaced by the custom one */
|
2001
|
xmlSetNs(xmlnode, ns);
|
2002
|
}
|
2003
|
if (custom_element->nodename) {
|
2004
|
xmlNodeSetName(xmlnode, BAD_CAST (custom_element->nodename));
|
2005
|
}
|
2006
|
g_hash_table_foreach(custom_element->namespaces,
|
2007
|
(GHFunc)_xmlnode_add_custom_namespace, xmlnode);
|
2008
|
}
|
2009
|
|
2010
|
|
2011
|
for (iter_classes = list_classes; iter_classes; iter_classes = g_slist_next(iter_classes)) {
|
2012
|
class = iter_classes->data;
|
2013
|
lasso_node_build_xmlNode_from_snippets(node,
|
2014
|
(LassoNodeClass*)class, xmlnode,
|
2015
|
class->node_data->snippets,
|
2016
|
lasso_dump);
|
2017
|
}
|
2018
|
|
2019
|
xmlCleanNs(xmlnode);
|
2020
|
|
2021
|
/* backward compatibility with Liberty ID-FF 1.1; */
|
2022
|
if (find_path(node, "MajorVersion", &value_node, &version_class, &version_snippet) == TRUE) {
|
2023
|
int *value;
|
2024
|
int major_version, minor_version;
|
2025
|
|
2026
|
value = SNIPPET_STRUCT_MEMBER_P(value_node, G_TYPE_FROM_CLASS(version_class),
|
2027
|
version_snippet);
|
2028
|
major_version = *value;
|
2029
|
|
2030
|
if (find_path(node, "MinorVersion", &value_node, &version_class, &version_snippet) == TRUE) {
|
2031
|
value = SNIPPET_STRUCT_MEMBER_P(value_node, G_TYPE_FROM_CLASS(version_class),
|
2032
|
version_snippet);
|
2033
|
minor_version = *value;
|
2034
|
} else {
|
2035
|
minor_version = 0;
|
2036
|
}
|
2037
|
|
2038
|
if (strcmp((char*)xmlnode->ns->href, LASSO_LIB_HREF) == 0) {
|
2039
|
if (major_version == 1 && minor_version == 0) {
|
2040
|
xmlFree((xmlChar*)xmlnode->ns->href); /* warning: discard const */
|
2041
|
xmlnode->ns->href = xmlStrdup((xmlChar*)
|
2042
|
"http://projectliberty.org/schemas/core/2002/12");
|
2043
|
}
|
2044
|
}
|
2045
|
}
|
2046
|
|
2047
|
g_slist_free(list_classes);
|
2048
|
return xmlnode;
|
2049
|
}
|
2050
|
|
2051
|
/*****************************************************************************/
|
2052
|
/* overridden parent class methods */
|
2053
|
/*****************************************************************************/
|
2054
|
|
2055
|
static GObjectClass *parent_class = NULL;
|
2056
|
|
2057
|
static void
|
2058
|
lasso_node_dispose(GObject *object)
|
2059
|
{
|
2060
|
LassoNodeClass *class;
|
2061
|
struct XmlSnippet *snippet;
|
2062
|
SnippetType type;
|
2063
|
|
2064
|
if (lasso_flag_memory_debug == TRUE) {
|
2065
|
fprintf(stderr, "dispose of %s (at %p)\n", G_OBJECT_TYPE_NAME(object), object);
|
2066
|
}
|
2067
|
|
2068
|
class = LASSO_NODE_GET_CLASS(object);
|
2069
|
|
2070
|
while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
|
2071
|
for (snippet = class->node_data->snippets; snippet && snippet->name; snippet++) {
|
2072
|
void **value = SNIPPET_STRUCT_MEMBER_P(object, G_TYPE_FROM_CLASS(class), snippet);
|
2073
|
type = snippet->type & 0xff;
|
2074
|
|
2075
|
if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE))
|
2076
|
continue;
|
2077
|
if (snippet->type & SNIPPET_BOOLEAN)
|
2078
|
continue;
|
2079
|
if (snippet->type & SNIPPET_INTEGER)
|
2080
|
continue;
|
2081
|
|
2082
|
if (*value == NULL)
|
2083
|
continue;
|
2084
|
|
2085
|
if (lasso_flag_memory_debug == TRUE) {
|
2086
|
fprintf(stderr, " freeing %s/%s (at %p)\n",
|
2087
|
G_OBJECT_TYPE_NAME(object), snippet->name, *value);
|
2088
|
}
|
2089
|
switch (type) {
|
2090
|
case SNIPPET_NODE:
|
2091
|
case SNIPPET_NODE_IN_CHILD:
|
2092
|
lasso_release_gobject(*value);
|
2093
|
break;
|
2094
|
case SNIPPET_XMLNODE:
|
2095
|
xmlFreeNode(*value);
|
2096
|
break;
|
2097
|
case SNIPPET_LIST_NODES:
|
2098
|
lasso_release_list_of_gobjects((*(GList**)value));
|
2099
|
break;
|
2100
|
case SNIPPET_EXTENSION:
|
2101
|
case SNIPPET_LIST_XMLNODES:
|
2102
|
lasso_release_list_of_xml_node(*(GList**)value);
|
2103
|
break;
|
2104
|
case SNIPPET_LIST_CONTENT:
|
2105
|
lasso_release_list_of_strings(*(GList**)value);
|
2106
|
break;
|
2107
|
case SNIPPET_CONTENT:
|
2108
|
case SNIPPET_TEXT_CHILD:
|
2109
|
case SNIPPET_ATTRIBUTE: {
|
2110
|
if (snippet->type & SNIPPET_ANY) {
|
2111
|
if (*value) {
|
2112
|
lasso_release_ghashtable(*value);
|
2113
|
}
|
2114
|
} else {
|
2115
|
lasso_release_string(*(char**)value);
|
2116
|
}
|
2117
|
} break;
|
2118
|
case SNIPPET_SIGNATURE:
|
2119
|
break; /* no real element here */
|
2120
|
case SNIPPET_COLLECT_NAMESPACES:
|
2121
|
if (*value) {
|
2122
|
lasso_release_ghashtable(*value);
|
2123
|
}
|
2124
|
break;
|
2125
|
default:
|
2126
|
fprintf(stderr, "%d\n", type);
|
2127
|
g_assert_not_reached();
|
2128
|
}
|
2129
|
|
2130
|
if (type != SNIPPET_SIGNATURE) {
|
2131
|
/* Signature snippet is not something to free,
|
2132
|
* so don't set the value to NULL */
|
2133
|
*value = NULL;
|
2134
|
}
|
2135
|
}
|
2136
|
class = g_type_class_peek_parent(class);
|
2137
|
}
|
2138
|
|
2139
|
parent_class->dispose(object);
|
2140
|
}
|
2141
|
|
2142
|
/*****************************************************************************/
|
2143
|
/* instance and class init functions */
|
2144
|
/*****************************************************************************/
|
2145
|
|
2146
|
static gboolean
|
2147
|
init_from_query(LassoNode *node, char **query_fields)
|
2148
|
{
|
2149
|
return lasso_node_init_from_query_fields(node, query_fields);
|
2150
|
}
|
2151
|
|
2152
|
static void
|
2153
|
class_init(LassoNodeClass *class)
|
2154
|
{
|
2155
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
2156
|
|
2157
|
parent_class = g_type_class_peek_parent(class);
|
2158
|
/* virtual public methods */
|
2159
|
class->destroy = lasso_node_impl_destroy;
|
2160
|
class->init_from_query = init_from_query;
|
2161
|
class->init_from_xml = lasso_node_impl_init_from_xml;
|
2162
|
|
2163
|
/* virtual private methods */
|
2164
|
class->build_query = lasso_node_impl_build_query;
|
2165
|
class->get_xmlNode = lasso_node_impl_get_xmlNode;
|
2166
|
|
2167
|
/* override */
|
2168
|
gobject_class->dispose = lasso_node_dispose;
|
2169
|
|
2170
|
original_xmlnode_quark = g_quark_from_static_string("lasso_original_xmlnode");
|
2171
|
custom_element_quark = g_quark_from_static_string("lasso_custom_element");
|
2172
|
class->node_data = NULL;
|
2173
|
}
|
2174
|
|
2175
|
static void
|
2176
|
base_class_finalize(LassoNodeClass *class)
|
2177
|
{
|
2178
|
if (class->node_data) {
|
2179
|
LassoNodeClassData *data = class->node_data;
|
2180
|
|
2181
|
if (data->ns) {
|
2182
|
xmlFreeNs(data->ns);
|
2183
|
}
|
2184
|
if (data->node_name) {
|
2185
|
lasso_release(data->node_name);
|
2186
|
}
|
2187
|
lasso_release(class->node_data);
|
2188
|
class->node_data = NULL;
|
2189
|
}
|
2190
|
}
|
2191
|
|
2192
|
GType
|
2193
|
lasso_node_get_type()
|
2194
|
{
|
2195
|
static GType this_type = 0;
|
2196
|
|
2197
|
if (!this_type) {
|
2198
|
static const GTypeInfo this_info = {
|
2199
|
sizeof (LassoNodeClass),
|
2200
|
NULL,
|
2201
|
(GBaseFinalizeFunc) base_class_finalize,
|
2202
|
(GClassInitFunc) class_init,
|
2203
|
NULL,
|
2204
|
NULL,
|
2205
|
sizeof(LassoNode),
|
2206
|
0,
|
2207
|
NULL,
|
2208
|
NULL,
|
2209
|
};
|
2210
|
|
2211
|
this_type = g_type_register_static(G_TYPE_OBJECT , "LassoNode", &this_info, 0);
|
2212
|
}
|
2213
|
return this_type;
|
2214
|
}
|
2215
|
|
2216
|
/**
|
2217
|
* lasso_node_new:
|
2218
|
*
|
2219
|
* Creates a new #LassoNode.
|
2220
|
*
|
2221
|
* Return value: a newly created #LassoNode object
|
2222
|
**/
|
2223
|
LassoNode*
|
2224
|
lasso_node_new()
|
2225
|
{
|
2226
|
return g_object_new(LASSO_TYPE_NODE, NULL);
|
2227
|
}
|
2228
|
|
2229
|
/**
|
2230
|
* lasso_node_new_from_dump:
|
2231
|
* @dump: XML object dump
|
2232
|
*
|
2233
|
* Restores the @dump to a new #LassoNode subclass.
|
2234
|
*
|
2235
|
* Return value: a newly created object; or NULL if an error occured.
|
2236
|
**/
|
2237
|
LassoNode*
|
2238
|
lasso_node_new_from_dump(const char *dump)
|
2239
|
{
|
2240
|
LassoNode *node;
|
2241
|
xmlDoc *doc;
|
2242
|
|
2243
|
if (dump == NULL)
|
2244
|
return NULL;
|
2245
|
|
2246
|
doc = lasso_xml_parse_memory(dump, strlen(dump));
|
2247
|
if (doc == NULL)
|
2248
|
return NULL;
|
2249
|
|
2250
|
node = lasso_node_new_from_xmlNode(xmlDocGetRootElement(doc));
|
2251
|
|
2252
|
lasso_release_doc(doc);
|
2253
|
return node;
|
2254
|
}
|
2255
|
|
2256
|
|
2257
|
/**
|
2258
|
* lasso_node_new_from_soap:
|
2259
|
* @soap: the SOAP message
|
2260
|
*
|
2261
|
* Parses SOAP message and creates a new Lasso object with the right class.
|
2262
|
*
|
2263
|
* Return value: node if success; NULL otherwise
|
2264
|
**/
|
2265
|
LassoNode*
|
2266
|
lasso_node_new_from_soap(const char *soap)
|
2267
|
{
|
2268
|
xmlDoc *doc;
|
2269
|
xmlNode *xmlnode;
|
2270
|
LassoNode *node = NULL;
|
2271
|
|
2272
|
doc = lasso_xml_parse_memory(soap, strlen(soap));
|
2273
|
if (doc == NULL) {
|
2274
|
return NULL;
|
2275
|
}
|
2276
|
xmlnode = lasso_xml_get_soap_content(xmlDocGetRootElement(doc));
|
2277
|
if (xmlnode == NULL) {
|
2278
|
return NULL;
|
2279
|
}
|
2280
|
node = lasso_node_new_from_xmlNode(xmlnode);
|
2281
|
|
2282
|
lasso_release_doc(doc);
|
2283
|
|
2284
|
return node;
|
2285
|
}
|
2286
|
|
2287
|
/* How finding a typename from an xmlNode works ?
|
2288
|
*
|
2289
|
* There is three way to get to a typename:
|
2290
|
* 1. by an xsi:type QName attribute, that we resolve
|
2291
|
* 2. by constructing a QName from the namespace of the xsi:type and the name of the node
|
2292
|
* 3. by resolving the QName of the node
|
2293
|
*
|
2294
|
* To resolve a typename you must map the QName using the default registry object, or use
|
2295
|
* prefix_from_href_and_nodename() to mat the QName to a prefix used to build the typename with this
|
2296
|
* template: typename = "Lasso" + prefix + name_part(QName).
|
2297
|
*
|
2298
|
* The resolving algorithm is in the function _type_name_from_href_and_nodename().
|
2299
|
*
|
2300
|
* The prefix extraction in prefix_from_href_and_nodename().
|
2301
|
*
|
2302
|
*/
|
2303
|
static const char *
|
2304
|
prefix_from_href_and_nodename(const xmlChar *href, G_GNUC_UNUSED const xmlChar *nodename) {
|
2305
|
char *prefix = NULL;
|
2306
|
#ifdef LASSO_WSF_ENABLED
|
2307
|
char *tmp = NULL;
|
2308
|
#endif
|
2309
|
|
2310
|
if (strcmp((char*)href, LASSO_LASSO_HREF) == 0)
|
2311
|
prefix = "";
|
2312
|
else if (strcmp((char*)href, LASSO_SAML_ASSERTION_HREF) == 0)
|
2313
|
prefix = "Saml";
|
2314
|
else if (strcmp((char*)href, LASSO_SAML_PROTOCOL_HREF) == 0)
|
2315
|
prefix = "Samlp";
|
2316
|
else if (strcmp((char*)href, LASSO_LIB_HREF) == 0)
|
2317
|
prefix = "Lib";
|
2318
|
else if (strcmp((char*)href, LASSO_SAML2_ASSERTION_HREF) == 0)
|
2319
|
prefix = "Saml2";
|
2320
|
else if (strcmp((char*)href, LASSO_SAML2_PROTOCOL_HREF) == 0)
|
2321
|
prefix = "Samlp2";
|
2322
|
else if (strcmp((char*)href, LASSO_ECP_HREF) == 0)
|
2323
|
prefix = "Ecp";
|
2324
|
else if (strcmp((char*)href, LASSO_PAOS_HREF) == 0)
|
2325
|
prefix = "Paos";
|
2326
|
else if (strcmp((char*)href, LASSO_SOAP_ENV_HREF) == 0)
|
2327
|
prefix = "Soap";
|
2328
|
else if (strcmp((char*)href, LASSO_DS_HREF) == 0)
|
2329
|
prefix = "Ds";
|
2330
|
#ifdef LASSO_WSF_ENABLED
|
2331
|
else if (strcmp((char*)href, LASSO_SOAP_BINDING_HREF) == 0)
|
2332
|
prefix = "SoapBinding";
|
2333
|
else if (strcmp((char*)href, LASSO_SOAP_BINDING_EXT_HREF) == 0)
|
2334
|
prefix = "SoapBindingExt";
|
2335
|
else if (strcmp((char*)href, LASSO_DISCO_HREF) == 0)
|
2336
|
prefix = "Disco";
|
2337
|
else if (strcmp((char*)href, LASSO_IS_HREF) == 0)
|
2338
|
prefix = "Is";
|
2339
|
else if (strcmp((char*)href, LASSO_SA_HREF) == 0)
|
2340
|
prefix = "Sa";
|
2341
|
else if (strcmp((char*)href, LASSO_WSSE_HREF) == 0)
|
2342
|
prefix = "WsSec1";
|
2343
|
else if (strcmp((char*)href, LASSO_WSSE1_HREF) == 0)
|
2344
|
prefix = "WsSec1";
|
2345
|
else if (strcmp((char*)href, LASSO_IDWSF2_DISCOVERY_HREF) == 0)
|
2346
|
prefix = "IdWsf2Disco";
|
2347
|
else if (strcmp((char*)href, LASSO_IDWSF2_SBF_HREF) == 0)
|
2348
|
prefix = "IdWsf2Sbf";
|
2349
|
else if (strcmp((char*)href, LASSO_IDWSF2_SB2_HREF) == 0)
|
2350
|
prefix = "IdWsf2Sb2";
|
2351
|
else if (strcmp((char*)href, LASSO_IDWSF2_UTIL_HREF) == 0)
|
2352
|
prefix = "IdWsf2Util";
|
2353
|
else if (strcmp((char*)href, LASSO_IDWSF2_SEC_HREF) == 0)
|
2354
|
prefix = "IdWsf2Sec";
|
2355
|
else if (strcmp((char*)href, LASSO_IDWSF2_IMS_HREF) == 0)
|
2356
|
prefix = "IdWsf2Ims";
|
2357
|
else if (strcmp((char*)href, LASSO_IDWSF2_IS_HREF) == 0)
|
2358
|
prefix = "IdWsf2Is";
|
2359
|
else if (strcmp((char*)href, LASSO_IDWSF2_PS_HREF) == 0)
|
2360
|
prefix = "IdWsf2Ps";
|
2361
|
else if (strcmp((char*)href, LASSO_IDWSF2_SUBS_HREF) == 0)
|
2362
|
prefix = "IdWsf2Subs";
|
2363
|
else if (strcmp((char*)href, LASSO_IDWSF2_SUBSREF_HREF) == 0)
|
2364
|
prefix = "IdWsf2SubsRef";
|
2365
|
else if (strcmp((char*)href, LASSO_WSA_HREF) == 0)
|
2366
|
prefix = "WsAddr";
|
2367
|
#if 0 /* Desactivate DGME lib special casing */
|
2368
|
else if (strcmp((char*)href, "urn:dgme:msp:ed:2007-01") == 0)
|
2369
|
/* FIXME: new namespaces should be possible to add from another library than lasso */
|
2370
|
prefix = "DgmeMspEd";
|
2371
|
#endif
|
2372
|
else if ((tmp = lasso_get_prefix_for_idwsf2_dst_service_href((char*)href))
|
2373
|
!= NULL) {
|
2374
|
/* ID-WSF 2 Profile */
|
2375
|
prefix = "IdWsf2DstRef";
|
2376
|
lasso_release_string(tmp);
|
2377
|
} else if ((tmp = lasso_get_prefix_for_dst_service_href((char*)href))
|
2378
|
!= NULL) {
|
2379
|
/* ID-WSF 1 Profile */
|
2380
|
prefix = "Dst";
|
2381
|
lasso_release_string(tmp);
|
2382
|
}
|
2383
|
|
2384
|
if (prefix != NULL && strcmp(prefix, "Dst") == 0 && strcmp((char*)nodename, "Status") == 0)
|
2385
|
prefix = "Utility";
|
2386
|
else if (prefix != NULL && strcmp(prefix, "Disco") == 0 && strcmp((char*)nodename, "Status") == 0)
|
2387
|
prefix = "Utility";
|
2388
|
else if (prefix != NULL && strcmp(prefix, "Sa") == 0 && strcmp((char*)nodename, "Status") == 0)
|
2389
|
prefix = "Utility";
|
2390
|
#endif
|
2391
|
|
2392
|
return prefix;
|
2393
|
}
|
2394
|
|
2395
|
/*
|
2396
|
* _type_name_from_href_and_nodename:
|
2397
|
* @href: the href part of a QName
|
2398
|
* @nodename: the name part of a QName
|
2399
|
*
|
2400
|
* Return value: a typename string if one if found that exists, NULL otherwise.
|
2401
|
*/
|
2402
|
static char*
|
2403
|
_type_name_from_href_and_nodename(char *href, char *nodename) {
|
2404
|
const char *prefix = prefix_from_href_and_nodename(BAD_CAST (href), BAD_CAST (nodename));
|
2405
|
char *typename = NULL;
|
2406
|
|
2407
|
if (!href || !nodename)
|
2408
|
return NULL;
|
2409
|
|
2410
|
/* FIXME: hardcoded mappings */
|
2411
|
if (strcmp(nodename, "SvcMD") == 0) {
|
2412
|
typename = g_strdup("LassoIdWsf2DiscoSvcMetadata");
|
2413
|
} else if (prefix != NULL && strcmp(prefix, "IdWsf2DstRef") == 0 && strcmp(nodename, "Status") == 0) {
|
2414
|
typename = g_strdup("LassoIdWsf2UtilStatus");
|
2415
|
} else if (prefix != NULL && strcmp(prefix, "WsSec1") == 0 && strcmp(nodename, "Security") == 0) {
|
2416
|
typename = g_strdup("LassoWsSec1SecurityHeader");
|
2417
|
} else if (prefix != NULL && strcmp(prefix, "Soap") == 0 && strcmp(nodename, "detail") == 0) {
|
2418
|
typename = g_strdup("LassoSoapDetail");
|
2419
|
} else {
|
2420
|
/* first try with registered mappings */
|
2421
|
const char *ctypename = lasso_registry_default_get_mapping(href, nodename, LASSO_LASSO_HREF);
|
2422
|
if (ctypename) {
|
2423
|
typename = g_strdup(ctypename);
|
2424
|
}
|
2425
|
/* finally try the default behaviour */
|
2426
|
if (prefix != NULL && typename == NULL) {
|
2427
|
typename = g_strdup_printf("Lasso%s%s", prefix, nodename);
|
2428
|
}
|
2429
|
}
|
2430
|
|
2431
|
/* Does it really exist ? */
|
2432
|
if (typename && g_type_from_name (typename) == 0) {
|
2433
|
lasso_release_string(typename);
|
2434
|
}
|
2435
|
|
2436
|
return typename;
|
2437
|
}
|
2438
|
|
2439
|
/**
|
2440
|
* _lasso_node_new_from_xmlNode:
|
2441
|
* @node: an xmlNode
|
2442
|
*
|
2443
|
* Builds a new #LassoNode from an xmlNode.
|
2444
|
*
|
2445
|
* Return value: a new node
|
2446
|
**/
|
2447
|
static LassoNode*
|
2448
|
_lasso_node_new_from_xmlNode(xmlNode *xmlnode)
|
2449
|
{
|
2450
|
char *typename = NULL;
|
2451
|
xmlChar *xsitype = NULL;
|
2452
|
LassoNode *node = NULL;
|
2453
|
gboolean fromXsi = FALSE;
|
2454
|
|
2455
|
xsitype = xmlGetNsProp(xmlnode, (xmlChar*)"type", (xmlChar*)LASSO_XSI_HREF);
|
2456
|
if (xsitype) {
|
2457
|
xmlChar *xmlPrefix, *separator;
|
2458
|
xmlNsPtr xsiNs = NULL;
|
2459
|
char *xsiNodeName = NULL;
|
2460
|
|
2461
|
/** Honor xsi:type */
|
2462
|
xmlPrefix = (xmlChar*)xsitype;
|
2463
|
separator = (xmlChar*)strchr((char*)xsitype, ':');
|
2464
|
if (separator != NULL) {
|
2465
|
xmlPrefix = (xmlChar*)g_strndup((char*)xmlPrefix, (size_t)(separator - xmlPrefix));
|
2466
|
xsiNs = xmlSearchNs(NULL, xmlnode, xmlPrefix);
|
2467
|
if (xsiNs != NULL) {
|
2468
|
xsiNodeName = g_strdup((char*)(separator+1));
|
2469
|
if (strcmp((char*)xsiNs->href, LASSO_LASSO_HREF) == 0) {
|
2470
|
typename = g_strdup(xsiNodeName);
|
2471
|
}
|
2472
|
}
|
2473
|
lasso_release(xmlPrefix);
|
2474
|
}
|
2475
|
if (! typename && xsiNs && xsiNodeName) {
|
2476
|
typename = _type_name_from_href_and_nodename ((char*)xsiNs->href, xsiNodeName);
|
2477
|
}
|
2478
|
if (! typename && xsiNs) {
|
2479
|
typename = _type_name_from_href_and_nodename ((char*)xsiNs->href, (char*)xmlnode->name);
|
2480
|
}
|
2481
|
lasso_release_xml_string(xsitype);
|
2482
|
if (xsiNodeName)
|
2483
|
lasso_release_string(xsiNodeName);
|
2484
|
if (typename)
|
2485
|
fromXsi = TRUE;
|
2486
|
}
|
2487
|
|
2488
|
if (typename == NULL && xmlnode->ns && xmlnode->ns->href) {
|
2489
|
typename = _type_name_from_href_and_nodename ((char*)xmlnode->ns->href, (char*)xmlnode->name);
|
2490
|
}
|
2491
|
|
2492
|
if (typename) {
|
2493
|
node = lasso_node_new_from_xmlNode_with_type(xmlnode, typename);
|
2494
|
}
|
2495
|
if (! node) {
|
2496
|
goto cleanup;
|
2497
|
}
|
2498
|
if (! fromXsi) {
|
2499
|
/* if the typename was not obtained via xsi:type but through mapping of the element
|
2500
|
* name then keep the element name */
|
2501
|
if (LASSO_NODE_GET_CLASS(node)->node_data &&
|
2502
|
LASSO_NODE_GET_CLASS(node)->node_data->node_name &&
|
2503
|
lasso_strisnotequal((char*)xmlnode->name,
|
2504
|
LASSO_NODE_GET_CLASS(node)->node_data->node_name))
|
2505
|
{
|
2506
|
lasso_node_set_custom_nodename(node, (char*)xmlnode->name);
|
2507
|
}
|
2508
|
|
2509
|
if (xmlnode->ns && (LASSO_NODE_GET_CLASS(node)->node_data == NULL ||
|
2510
|
LASSO_NODE_GET_CLASS(node)->node_data->ns == NULL ||
|
2511
|
lasso_xmlstrisnotequal(xmlnode->ns->href,
|
2512
|
LASSO_NODE_GET_CLASS(node)->node_data->ns->href)))
|
2513
|
{
|
2514
|
lasso_node_set_custom_namespace(node, (char*)xmlnode->ns->prefix,
|
2515
|
(char*)xmlnode->ns->href);
|
2516
|
}
|
2517
|
|
2518
|
|
2519
|
}
|
2520
|
cleanup:
|
2521
|
lasso_release(typename);
|
2522
|
|
2523
|
return node;
|
2524
|
}
|
2525
|
|
2526
|
/**
|
2527
|
* lasso_node_new_from_xmlNode:
|
2528
|
* @node: an xmlNode
|
2529
|
*
|
2530
|
* Builds a new #LassoNode from an xmlNode.
|
2531
|
*
|
2532
|
* Return value: a new node
|
2533
|
**/
|
2534
|
LassoNode*
|
2535
|
lasso_node_new_from_xmlNode(xmlNode *xmlnode)
|
2536
|
{
|
2537
|
if (xmlnode == NULL || xmlnode->ns == NULL) {
|
2538
|
message(G_LOG_LEVEL_CRITICAL, "Unable to build a LassoNode from a xmlNode");
|
2539
|
return NULL;
|
2540
|
}
|
2541
|
return _lasso_node_new_from_xmlNode(xmlnode);
|
2542
|
}
|
2543
|
|
2544
|
static LassoNode*
|
2545
|
lasso_node_new_from_xmlNode_with_type(xmlNode *xmlnode, char *typename)
|
2546
|
{
|
2547
|
GType gtype;
|
2548
|
LassoNode *node;
|
2549
|
int rc = 0;
|
2550
|
|
2551
|
message(LOG_LEVEL_XML_DEBUG, "Processing node '%s' with type '%s'", xmlnode->name, typename);
|
2552
|
|
2553
|
if (typename == NULL) {
|
2554
|
return _lasso_node_new_from_xmlNode(xmlnode); /* will auto-detect */
|
2555
|
}
|
2556
|
|
2557
|
gtype = g_type_from_name(typename);
|
2558
|
if (gtype == 0) {
|
2559
|
message(G_LOG_LEVEL_CRITICAL, "Unable to get g_type from name '%s'", typename);
|
2560
|
return NULL;
|
2561
|
}
|
2562
|
|
2563
|
|
2564
|
node = g_object_new(gtype, NULL);
|
2565
|
if (lasso_flag_memory_debug == TRUE) {
|
2566
|
fprintf(stderr, "allocation of %s (for xmlNode %p) : %p\n", g_type_name(gtype), xmlnode, node);
|
2567
|
}
|
2568
|
rc = lasso_node_init_from_xml(node, xmlnode);
|
2569
|
if (rc) {
|
2570
|
message(G_LOG_LEVEL_CRITICAL, "Lasso node initialization failed for node '%s', type '%s': error %d", xmlnode->name, typename, rc);
|
2571
|
lasso_node_destroy(node);
|
2572
|
return NULL;
|
2573
|
}
|
2574
|
|
2575
|
return node;
|
2576
|
}
|
2577
|
|
2578
|
static gboolean
|
2579
|
is_base64(const char *message)
|
2580
|
{
|
2581
|
const char *c;
|
2582
|
|
2583
|
c = message;
|
2584
|
while (*c != 0 && (isalnum((int)*c) || *c == '+' || *c == '/' || *c == '\n' || *c == '\r')) c++;
|
2585
|
while (*c == '=' || *c == '\n' || *c == '\r') c++; /* trailing = */
|
2586
|
|
2587
|
if (*c == 0)
|
2588
|
return TRUE;
|
2589
|
|
2590
|
return FALSE;
|
2591
|
}
|
2592
|
|
2593
|
|
2594
|
/**
|
2595
|
* lasso_node_init_from_message_with_format:
|
2596
|
* @node: a #LassoNode (or derived class)
|
2597
|
* @message: a Liberty message
|
2598
|
* @constraint: LASSO_MESSAGE_FORMAT_UNKNOWN or the format the message must be in
|
2599
|
* @doc_out: a pointer to store the resulting #xmlDoc structure
|
2600
|
* @node_out: a pointer to store the resulting content #xmlNode
|
2601
|
*
|
2602
|
* Parses @message and initialiazes @node fields with data from it. Message type may be base64,
|
2603
|
* SOAP, XML or query string, correct type is found automatically if contraint is
|
2604
|
* LASSO_MESSAGE_FORMAT_UNKNOWN or is limited to the value given.
|
2605
|
* If the format is one of LASSO_MESSAGE_FORMAT_XML or LASSO_MESSAGE_FORMAT_XML or
|
2606
|
* LASSO_MESSAGE_FORMAT_BASE64 the resulting #xmlDoc and #xmlNode of the message can be retrieved.
|
2607
|
*
|
2608
|
* Return value: a #LassoMessageFormat value.
|
2609
|
**/
|
2610
|
LassoMessageFormat
|
2611
|
lasso_node_init_from_message_with_format(LassoNode *node, const char *message, LassoMessageFormat constraint, xmlDoc **doc_out, xmlNode **root_out)
|
2612
|
{
|
2613
|
char *msg = NULL;
|
2614
|
gboolean b64 = FALSE;
|
2615
|
LassoMessageFormat rc = LASSO_MESSAGE_FORMAT_ERROR;
|
2616
|
xmlDoc *doc = NULL;
|
2617
|
xmlNode *root = NULL;
|
2618
|
gboolean any = constraint == LASSO_MESSAGE_FORMAT_UNKNOWN;
|
2619
|
|
2620
|
msg = (char*)message;
|
2621
|
|
2622
|
/* BASE64 case */
|
2623
|
if (any || constraint == LASSO_MESSAGE_FORMAT_BASE64) {
|
2624
|
if (message[0] != 0 && is_base64(message)) {
|
2625
|
int rc = 0;
|
2626
|
|
2627
|
msg = g_malloc(strlen(message));
|
2628
|
rc = xmlSecBase64Decode((xmlChar*)message, (xmlChar*)msg, strlen(message));
|
2629
|
if (rc >= 0) {
|
2630
|
b64 = TRUE;
|
2631
|
} else {
|
2632
|
lasso_release(msg);
|
2633
|
msg = (char*)message;
|
2634
|
}
|
2635
|
}
|
2636
|
}
|
2637
|
|
2638
|
/* XML case */
|
2639
|
if (any || constraint == LASSO_MESSAGE_FORMAT_XML ||
|
2640
|
constraint == LASSO_MESSAGE_FORMAT_BASE64 ||
|
2641
|
constraint == LASSO_MESSAGE_FORMAT_SOAP) {
|
2642
|
if (strchr(msg, '<')) {
|
2643
|
doc = lasso_xml_parse_memory(msg, strlen(msg));
|
2644
|
if (doc == NULL) {
|
2645
|
rc = LASSO_MESSAGE_FORMAT_UNKNOWN;
|
2646
|
goto cleanup;
|
2647
|
}
|
2648
|
root = xmlDocGetRootElement(doc);
|
2649
|
|
2650
|
if (any || constraint == LASSO_MESSAGE_FORMAT_SOAP) {
|
2651
|
gboolean is_soap = FALSE;
|
2652
|
|
2653
|
is_soap = lasso_xml_is_soap(root);
|
2654
|
if (is_soap) {
|
2655
|
root = lasso_xml_get_soap_content(root);
|
2656
|
}
|
2657
|
rc = lasso_node_init_from_xml(node, root);
|
2658
|
if (rc != 0) {
|
2659
|
rc = LASSO_MESSAGE_FORMAT_XSCHEMA_ERROR;
|
2660
|
goto cleanup;
|
2661
|
|
2662
|
}
|
2663
|
if (is_soap) {
|
2664
|
rc = LASSO_MESSAGE_FORMAT_SOAP;
|
2665
|
goto cleanup;
|
2666
|
}
|
2667
|
if (b64) {
|
2668
|
lasso_release(msg);
|
2669
|
rc = LASSO_MESSAGE_FORMAT_BASE64;
|
2670
|
goto cleanup;
|
2671
|
}
|
2672
|
rc = LASSO_MESSAGE_FORMAT_XML;
|
2673
|
goto cleanup;
|
2674
|
}
|
2675
|
}
|
2676
|
}
|
2677
|
|
2678
|
/* HTTP query CASE */
|
2679
|
if (any || constraint == LASSO_MESSAGE_FORMAT_QUERY) {
|
2680
|
if (strchr(msg, '&') || strchr(msg, '=')) {
|
2681
|
/* XXX: detect SAML artifact messages to return a different status code ? */
|
2682
|
if (lasso_node_init_from_query(node, msg) == FALSE) {
|
2683
|
goto cleanup;
|
2684
|
}
|
2685
|
rc = LASSO_MESSAGE_FORMAT_QUERY;
|
2686
|
goto cleanup;
|
2687
|
}
|
2688
|
}
|
2689
|
|
2690
|
cleanup:
|
2691
|
if (doc_out) {
|
2692
|
*doc_out = doc;
|
2693
|
if (root_out) {
|
2694
|
*root_out = root;
|
2695
|
}
|
2696
|
} else {
|
2697
|
lasso_release_doc(doc);
|
2698
|
}
|
2699
|
return rc;
|
2700
|
}
|
2701
|
|
2702
|
/**
|
2703
|
* lasso_node_init_from_message:
|
2704
|
* @node: a #LassoNode (or derived class)
|
2705
|
* @message: a Liberty message
|
2706
|
*
|
2707
|
* Parses @message and initialiazes @node fields with data from it. Message
|
2708
|
* type may be base64, SOAP, XML or query string, correct type is found
|
2709
|
* automatically.
|
2710
|
*
|
2711
|
* Return value: a #LassoMessageFormat value.
|
2712
|
**/
|
2713
|
LassoMessageFormat
|
2714
|
lasso_node_init_from_message(LassoNode *node, const char *message)
|
2715
|
{
|
2716
|
return lasso_node_init_from_message_with_format(node, message, LASSO_MESSAGE_FORMAT_UNKNOWN, NULL, NULL);
|
2717
|
}
|
2718
|
|
2719
|
/**
|
2720
|
* lasso_node_class_add_snippets:
|
2721
|
* @klass: object class
|
2722
|
* @snippets: array of XmlSnippet (NULL terminated)
|
2723
|
**/
|
2724
|
void
|
2725
|
lasso_node_class_add_snippets(LassoNodeClass *klass, struct XmlSnippet *snippets)
|
2726
|
{
|
2727
|
klass->node_data->snippets = snippets;
|
2728
|
}
|
2729
|
|
2730
|
|
2731
|
/**
|
2732
|
* lasso_node_class_add_query_snippets:
|
2733
|
* @klass: object class
|
2734
|
* @snippets: array of QuerySnippet (NULL terminated)
|
2735
|
**/
|
2736
|
void
|
2737
|
lasso_node_class_add_query_snippets(LassoNodeClass *klass, struct QuerySnippet *snippets)
|
2738
|
{
|
2739
|
klass->node_data->query_snippets = snippets;
|
2740
|
}
|
2741
|
|
2742
|
/**
|
2743
|
* lasso_node_class_set_nodename:
|
2744
|
* @klass: object class
|
2745
|
* @name: name for element node
|
2746
|
**/
|
2747
|
void
|
2748
|
lasso_node_class_set_nodename(LassoNodeClass *klass, char *name)
|
2749
|
{
|
2750
|
if (klass->node_data->node_name)
|
2751
|
lasso_release(klass->node_data->node_name);
|
2752
|
klass->node_data->node_name = g_strdup(name);
|
2753
|
}
|
2754
|
|
2755
|
|
2756
|
/**
|
2757
|
* lasso_node_class_set_ns:
|
2758
|
* @klass: object class
|
2759
|
* @href: namespace uri
|
2760
|
* @prefix: namespace prefix
|
2761
|
**/
|
2762
|
void
|
2763
|
lasso_node_class_set_ns(LassoNodeClass *klass, char *href, char *prefix)
|
2764
|
{
|
2765
|
if (klass->node_data->ns)
|
2766
|
xmlFreeNs(klass->node_data->ns);
|
2767
|
klass->node_data->ns = xmlNewNs(NULL, (xmlChar*)href, (xmlChar*)prefix);
|
2768
|
}
|
2769
|
|
2770
|
static void
|
2771
|
snippet_dump_any(gchar *key, gchar *value, xmlNode *xmlnode)
|
2772
|
{
|
2773
|
if (! key)
|
2774
|
return;
|
2775
|
if (! value)
|
2776
|
return;
|
2777
|
/* element tree syntax for setting namespaces */
|
2778
|
if (key && key[0] == '{') {
|
2779
|
char *end = strchr(key, '}');
|
2780
|
char *ns_uri;
|
2781
|
xmlNs *ns;
|
2782
|
if (! end) {
|
2783
|
message(G_LOG_LEVEL_WARNING, "Invalid attribute name: %s", key);
|
2784
|
return;
|
2785
|
}
|
2786
|
ns_uri = g_strndup(key+1, end-(key+1));
|
2787
|
ns = get_or_define_ns(xmlnode, BAD_CAST ns_uri, NULL);
|
2788
|
xmlSetNsProp(xmlnode, ns, BAD_CAST &end[1], BAD_CAST value);
|
2789
|
} else {
|
2790
|
xmlSetProp(xmlnode, BAD_CAST key, BAD_CAST value);
|
2791
|
}
|
2792
|
}
|
2793
|
|
2794
|
static void
|
2795
|
apply_snippet_ns(struct XmlSnippet *snippet, xmlNode *xmlnode)
|
2796
|
{
|
2797
|
xmlNs *ns;
|
2798
|
|
2799
|
if (! xmlnode)
|
2800
|
return;
|
2801
|
if (snippet->ns_uri) {
|
2802
|
if (! xmlnode->ns || !lasso_strisequal((char*)xmlnode->ns->href, (char*)snippet->ns_uri)) {
|
2803
|
ns = get_or_define_ns(xmlnode, BAD_CAST snippet->ns_uri, BAD_CAST snippet->ns_name);
|
2804
|
xmlSetNs(xmlnode, ns);
|
2805
|
}
|
2806
|
/* If not a any snippet, apply given Name, what about xsi:type ? */
|
2807
|
}
|
2808
|
if (! (snippet->type & SNIPPET_ANY) && ! lasso_strisempty(snippet->name) &&
|
2809
|
lasso_strisnotequal((char*)xmlnode->name, (char*)snippet->name))
|
2810
|
xmlNodeSetName(xmlnode, BAD_CAST snippet->name);
|
2811
|
}
|
2812
|
|
2813
|
static void
|
2814
|
lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, xmlNode *xmlnode,
|
2815
|
struct XmlSnippet *snippets, gboolean lasso_dump)
|
2816
|
{
|
2817
|
struct XmlSnippet *snippet;
|
2818
|
GType g_type;
|
2819
|
xmlNode *t;
|
2820
|
GList *elem;
|
2821
|
struct XmlSnippet *snippet_any_attribute = NULL;
|
2822
|
|
2823
|
g_type = G_TYPE_FROM_CLASS(class);
|
2824
|
|
2825
|
snippet = snippets;
|
2826
|
while (snippet && snippet->name) {
|
2827
|
void *value = NULL;
|
2828
|
int int_value = 0;
|
2829
|
gboolean bool_value = FALSE;
|
2830
|
char *str = NULL;
|
2831
|
gboolean optional = snippet->type & SNIPPET_OPTIONAL;
|
2832
|
gboolean optional_neg = snippet->type & SNIPPET_OPTIONAL_NEG;
|
2833
|
gboolean multiple = is_snippet_multiple(snippet);
|
2834
|
|
2835
|
if (! snippet->offset && ! (snippet->type & SNIPPET_PRIVATE)) {
|
2836
|
goto advance;
|
2837
|
}
|
2838
|
if (lasso_dump == FALSE && snippet->type & SNIPPET_LASSO_DUMP) {
|
2839
|
goto advance;
|
2840
|
}
|
2841
|
if ((snippet->type & 0xff) == SNIPPET_ATTRIBUTE && (snippet->type & SNIPPET_ANY)) {
|
2842
|
snippet_any_attribute = snippet;
|
2843
|
goto advance;
|
2844
|
}
|
2845
|
/* special treatment for 1-* list of nodes, without we would serialize them twice */
|
2846
|
if (multiple && (snippet->type & SNIPPET_JUMP_ON_MATCH && SNIPPET_JUMP_OFFSET(snippet->type) > 0)) {
|
2847
|
snippet++;
|
2848
|
continue;
|
2849
|
}
|
2850
|
|
2851
|
// convert input type to string if needed
|
2852
|
if (snippet->type & SNIPPET_INTEGER) {
|
2853
|
int_value = SNIPPET_STRUCT_MEMBER(int, node, g_type, snippet);
|
2854
|
if (int_value == 0 && optional) {
|
2855
|
goto advance;
|
2856
|
}
|
2857
|
if (int_value == -1 && optional_neg) {
|
2858
|
goto advance;
|
2859
|
}
|
2860
|
str = g_strdup_printf("%i", int_value);
|
2861
|
} else if (snippet->type & SNIPPET_BOOLEAN) {
|
2862
|
bool_value = SNIPPET_STRUCT_MEMBER(gboolean, node, g_type, snippet);
|
2863
|
if (bool_value == FALSE && optional) {
|
2864
|
goto advance;
|
2865
|
}
|
2866
|
str = bool_value ? "true" : "false";
|
2867
|
} else {
|
2868
|
value = SNIPPET_STRUCT_MEMBER(void *, node, g_type, snippet);
|
2869
|
if (value == NULL) {
|
2870
|
goto advance;
|
2871
|
}
|
2872
|
str = value;
|
2873
|
}
|
2874
|
|
2875
|
// output type
|
2876
|
switch (snippet->type & 0xff) {
|
2877
|
case SNIPPET_ATTRIBUTE:
|
2878
|
if (snippet->ns_name) {
|
2879
|
xmlNsPtr ns;
|
2880
|
|
2881
|
ns = xmlNewNs(xmlnode, (xmlChar*)snippet->ns_uri, (xmlChar*)snippet->ns_name);
|
2882
|
xmlSetNsProp(xmlnode, ns, (xmlChar*)snippet->name, (xmlChar*)str);
|
2883
|
} else {
|
2884
|
xmlSetProp(xmlnode, (xmlChar*)snippet->name, (xmlChar*)str);
|
2885
|
}
|
2886
|
break;
|
2887
|
case SNIPPET_TEXT_CHILD:
|
2888
|
xmlAddChild(xmlnode, xmlNewText((xmlChar*)str));
|
2889
|
break;
|
2890
|
case SNIPPET_NODE:
|
2891
|
{
|
2892
|
xmlNode *t2;
|
2893
|
t2 = lasso_node_get_xmlNode(LASSO_NODE(value), lasso_dump);
|
2894
|
apply_snippet_ns(snippet, t2);
|
2895
|
xmlAddChild(xmlnode, t2);
|
2896
|
} break;
|
2897
|
case SNIPPET_CONTENT:
|
2898
|
xmlNewTextChild(xmlnode, NULL,
|
2899
|
(xmlChar*)snippet->name, (xmlChar*)str);
|
2900
|
break;
|
2901
|
case SNIPPET_NODE_IN_CHILD:
|
2902
|
t = xmlNewTextChild(xmlnode, NULL, (xmlChar*)snippet->name, NULL);
|
2903
|
xmlAddChild(t, lasso_node_get_xmlNode(
|
2904
|
LASSO_NODE(value), lasso_dump));
|
2905
|
break;
|
2906
|
case SNIPPET_LIST_NODES:
|
2907
|
elem = (GList *)value;
|
2908
|
while (elem) {
|
2909
|
xmlNode *subnode = lasso_node_get_xmlNode(
|
2910
|
LASSO_NODE(elem->data), lasso_dump);
|
2911
|
if (subnode) {
|
2912
|
apply_snippet_ns(snippet, subnode);
|
2913
|
xmlAddChild(xmlnode, subnode);
|
2914
|
}
|
2915
|
elem = g_list_next(elem);
|
2916
|
}
|
2917
|
break;
|
2918
|
case SNIPPET_LIST_CONTENT:
|
2919
|
/* sequence of simple elements (no children,
|
2920
|
* no attrs, just content) */
|
2921
|
elem = (GList *)value;
|
2922
|
while (elem) {
|
2923
|
xmlNode *subnode;
|
2924
|
subnode = xmlNewTextChild(xmlnode, NULL,
|
2925
|
(xmlChar*)snippet->name,
|
2926
|
(xmlChar*)(elem->data));
|
2927
|
apply_snippet_ns(snippet, subnode);
|
2928
|
elem = g_list_next(elem);
|
2929
|
}
|
2930
|
break;
|
2931
|
case SNIPPET_LIST_XMLNODES:
|
2932
|
case SNIPPET_EXTENSION:
|
2933
|
elem = (GList *)value;
|
2934
|
while (elem) {
|
2935
|
xmlAddChild(xmlnode, xmlCopyNode(elem->data, 1));
|
2936
|
elem = g_list_next(elem);
|
2937
|
}
|
2938
|
break;
|
2939
|
case SNIPPET_XMLNODE:
|
2940
|
xmlAddChild(xmlnode, xmlCopyNode((xmlNode *)value, 1));
|
2941
|
break;
|
2942
|
case SNIPPET_SIGNATURE:
|
2943
|
lasso_node_add_signature_template(node, xmlnode, snippet);
|
2944
|
break;
|
2945
|
case SNIPPET_COLLECT_NAMESPACES:
|
2946
|
break;
|
2947
|
case SNIPPET_UNUSED1:
|
2948
|
g_assert_not_reached();
|
2949
|
}
|
2950
|
if (snippet->type & SNIPPET_INTEGER) {
|
2951
|
lasso_release(str);
|
2952
|
}
|
2953
|
advance:
|
2954
|
if ((snippet->type & SNIPPET_JUMP_ON_MATCH) && SNIPPET_JUMP_OFFSET(snippet->type) > 0 && value) {
|
2955
|
snippet += SNIPPET_JUMP_OFFSET(snippet->type);
|
2956
|
} else if (!value && (snippet->type & SNIPPET_JUMP_ON_MISS) && SNIPPET_JUMP_OFFSET(snippet->type) > 0 && value) {
|
2957
|
snippet += SNIPPET_JUMP_OFFSET(snippet->type);
|
2958
|
} else {
|
2959
|
snippet++;
|
2960
|
}
|
2961
|
}
|
2962
|
|
2963
|
if (snippet_any_attribute) {
|
2964
|
GHashTable *value = SNIPPET_STRUCT_MEMBER(GHashTable *, node, g_type,
|
2965
|
snippet_any_attribute);
|
2966
|
if (value) {
|
2967
|
g_hash_table_foreach(value, (GHFunc)snippet_dump_any, xmlnode);
|
2968
|
}
|
2969
|
}
|
2970
|
}
|
2971
|
|
2972
|
static void
|
2973
|
lasso_node_add_signature_template(LassoNode *node, xmlNode *xmlnode,
|
2974
|
struct XmlSnippet *snippet_signature)
|
2975
|
{
|
2976
|
LassoNodeClass *klass = NULL;
|
2977
|
LassoNodeClassData *node_data = NULL;
|
2978
|
LassoSignatureContext context;
|
2979
|
char *id = NULL;
|
2980
|
|
2981
|
node_data = lasso_legacy_get_signature_node_data(node, &klass);
|
2982
|
if (! node_data)
|
2983
|
return;
|
2984
|
|
2985
|
if (node_data->sign_type_offset == 0)
|
2986
|
return;
|
2987
|
|
2988
|
context = lasso_node_get_signature(node);
|
2989
|
if (! lasso_validate_signature_context(context))
|
2990
|
if (lasso_legacy_extract_and_copy_signature_parameters(node, node_data))
|
2991
|
context = lasso_node_get_signature(node);
|
2992
|
|
2993
|
if (snippet_signature->offset) {
|
2994
|
id = SNIPPET_STRUCT_MEMBER(char *, node, G_TYPE_FROM_CLASS(klass), snippet_signature);
|
2995
|
}
|
2996
|
|
2997
|
lasso_xmlnode_add_saml2_signature_template(xmlnode, context, id);
|
2998
|
}
|
2999
|
|
3000
|
static struct XmlSnippet*
|
3001
|
find_xml_snippet_by_name(LassoNode *node, char *name, LassoNodeClass **class_p)
|
3002
|
{
|
3003
|
LassoNodeClass *class;
|
3004
|
struct XmlSnippet *snippet;
|
3005
|
|
3006
|
class = LASSO_NODE_GET_CLASS(node);
|
3007
|
while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
|
3008
|
for (snippet = class->node_data->snippets;
|
3009
|
snippet && snippet->name && strcmp(snippet->name, name) != 0;
|
3010
|
snippet++) ;
|
3011
|
if (snippet && snippet->name) {
|
3012
|
*class_p = class;
|
3013
|
return snippet;
|
3014
|
}
|
3015
|
class = g_type_class_peek_parent(class);
|
3016
|
}
|
3017
|
*class_p = NULL;
|
3018
|
return NULL;
|
3019
|
}
|
3020
|
|
3021
|
static gboolean
|
3022
|
find_path(LassoNode *node, char *path, LassoNode **value_node, LassoNodeClass **class_p, struct XmlSnippet **snippet)
|
3023
|
{
|
3024
|
char *s, *t;
|
3025
|
struct XmlSnippet *tsnippet = NULL;
|
3026
|
LassoNode *tnode = node;
|
3027
|
|
3028
|
*class_p = NULL;
|
3029
|
s = path;
|
3030
|
while (s) {
|
3031
|
t = strchr(s, '/');
|
3032
|
if (t) *t = 0;
|
3033
|
tsnippet = find_xml_snippet_by_name(tnode, s, class_p);
|
3034
|
if (t) {
|
3035
|
tnode = SNIPPET_STRUCT_MEMBER(LassoNode *, tnode, G_TYPE_FROM_CLASS(*class_p),
|
3036
|
tsnippet);
|
3037
|
if (tnode == NULL)
|
3038
|
return FALSE;
|
3039
|
|
3040
|
s = t+1;
|
3041
|
} else {
|
3042
|
s = NULL;
|
3043
|
}
|
3044
|
}
|
3045
|
|
3046
|
if (tsnippet == NULL)
|
3047
|
return FALSE;
|
3048
|
|
3049
|
*snippet = tsnippet;
|
3050
|
*value_node = tnode;
|
3051
|
return TRUE;
|
3052
|
}
|
3053
|
|
3054
|
|
3055
|
static char*
|
3056
|
get_value_by_path(LassoNode *node, char *path, struct XmlSnippet *xml_snippet)
|
3057
|
{
|
3058
|
struct XmlSnippet *snippet;
|
3059
|
LassoNode *value_node;
|
3060
|
LassoNodeClass *class;
|
3061
|
GType g_type;
|
3062
|
|
3063
|
if (find_path(node, path, &value_node, &class, &snippet) != TRUE)
|
3064
|
return NULL;
|
3065
|
g_type = G_TYPE_FROM_CLASS(class);
|
3066
|
|
3067
|
*xml_snippet = *snippet;
|
3068
|
|
3069
|
if (snippet->type & SNIPPET_BOOLEAN) {
|
3070
|
gboolean v = SNIPPET_STRUCT_MEMBER(gboolean, value_node, g_type, snippet);
|
3071
|
return v ? g_strdup("true") : g_strdup("false");
|
3072
|
} else if (snippet->type & SNIPPET_INTEGER) {
|
3073
|
int v = SNIPPET_STRUCT_MEMBER(int, value_node, g_type, snippet);
|
3074
|
return g_strdup_printf("%d", v);
|
3075
|
} else if (snippet->type == SNIPPET_NODE) {
|
3076
|
LassoNode *value = SNIPPET_STRUCT_MEMBER(LassoNode *, value_node, g_type, snippet);
|
3077
|
return lasso_node_build_query(value);
|
3078
|
} else if (snippet->type == SNIPPET_EXTENSION) {
|
3079
|
/* convert all of the <lib:Extension> into a string, already
|
3080
|
* escaped for URI usage */
|
3081
|
GList *value = SNIPPET_STRUCT_MEMBER(GList *, value_node, g_type, snippet);
|
3082
|
xmlChar *s, *s2;
|
3083
|
GString *result = g_string_new("");
|
3084
|
while (value) {
|
3085
|
xmlNode *t = value->data;
|
3086
|
xmlNode *c;
|
3087
|
|
3088
|
/* attributes */
|
3089
|
#if 0
|
3090
|
xmlAttr *a;
|
3091
|
for (a = t->properties; a; a = a->next) {
|
3092
|
if (result->len)
|
3093
|
g_string_append(result, "&");
|
3094
|
s = xmlGetProp(t, a->name);
|
3095
|
g_string_append(result, a->name);
|
3096
|
g_string_append(result, "=");
|
3097
|
s2 = xmlURIEscapeStr(s, NULL);
|
3098
|
g_string_append(result, s2);
|
3099
|
xmlFree(s2);
|
3100
|
xmlFree(s);
|
3101
|
}
|
3102
|
#endif
|
3103
|
|
3104
|
/* children (only simple ones and 1-level deep) */
|
3105
|
for (c = t->children; c; c = c->next) {
|
3106
|
if (c->type != XML_ELEMENT_NODE)
|
3107
|
continue;
|
3108
|
if (c->children->type != XML_TEXT_NODE)
|
3109
|
continue;
|
3110
|
if (c->properties != NULL)
|
3111
|
continue;
|
3112
|
if (result->len)
|
3113
|
g_string_append(result, "&");
|
3114
|
g_string_append(result, (char*)c->name);
|
3115
|
g_string_append(result, "=");
|
3116
|
s = xmlNodeGetContent(c);
|
3117
|
s2 = xmlURIEscapeStr(s, NULL);
|
3118
|
g_string_append(result, (char*)s2);
|
3119
|
xmlFree(s2);
|
3120
|
xmlFree(s);
|
3121
|
}
|
3122
|
|
3123
|
value = g_list_next(value);
|
3124
|
}
|
3125
|
if (result->len == 0) {
|
3126
|
lasso_release_gstring(result, TRUE);
|
3127
|
return NULL;
|
3128
|
}
|
3129
|
return g_string_free(result, FALSE);
|
3130
|
} else if (snippet->type == SNIPPET_LIST_CONTENT) {
|
3131
|
/* not clear in spec; concat values with spaces */
|
3132
|
GList *value = SNIPPET_STRUCT_MEMBER(GList *, value_node, g_type, snippet);
|
3133
|
GString *result = g_string_new("");
|
3134
|
while (value) {
|
3135
|
result = g_string_append(result, (char*)value->data);
|
3136
|
if (value->next)
|
3137
|
result = g_string_append(result, " ");
|
3138
|
value = value->next;
|
3139
|
}
|
3140
|
if (result->len == 0) {
|
3141
|
lasso_release_gstring(result, TRUE);
|
3142
|
return NULL;
|
3143
|
}
|
3144
|
return g_string_free(result, FALSE);
|
3145
|
} else {
|
3146
|
char *value = SNIPPET_STRUCT_MEMBER(char *, value_node, g_type, snippet);
|
3147
|
if (value == NULL) return NULL;
|
3148
|
return g_strdup(value);
|
3149
|
}
|
3150
|
return NULL;
|
3151
|
}
|
3152
|
|
3153
|
static gboolean
|
3154
|
set_value_at_path(LassoNode *node, char *path, char *query_value)
|
3155
|
{
|
3156
|
struct XmlSnippet *snippet;
|
3157
|
LassoNode *value_node;
|
3158
|
LassoNodeClass *class;
|
3159
|
GType g_type;
|
3160
|
void *value;
|
3161
|
|
3162
|
if (find_path(node, path, &value_node, &class, &snippet) != TRUE)
|
3163
|
return FALSE;
|
3164
|
g_type = G_TYPE_FROM_CLASS(class);
|
3165
|
|
3166
|
value = SNIPPET_STRUCT_MEMBER_P(value_node, g_type, snippet);
|
3167
|
|
3168
|
if (snippet->type & SNIPPET_INTEGER) {
|
3169
|
int val = atoi(query_value);
|
3170
|
(*(int*)value) = val;
|
3171
|
} else if (snippet->type & SNIPPET_BOOLEAN) {
|
3172
|
int val = (strcmp(query_value, "true") == 0);
|
3173
|
(*(int*)value) = val;
|
3174
|
} else if (snippet->type == SNIPPET_NODE) {
|
3175
|
LassoNode *v = *(LassoNode**)value;
|
3176
|
if (v == NULL) {
|
3177
|
message(G_LOG_LEVEL_CRITICAL, "building node from query; unknown subnode");
|
3178
|
g_assert_not_reached();
|
3179
|
}
|
3180
|
LASSO_NODE_GET_CLASS(v)->init_from_query(v, &query_value);
|
3181
|
} else if (snippet->type == SNIPPET_LIST_CONTENT) {
|
3182
|
char **elems = g_strsplit(query_value, " ", 0);
|
3183
|
int i;
|
3184
|
GList *l = NULL;
|
3185
|
for (i = 0; elems[i]; i++) {
|
3186
|
l = g_list_append(l, g_strdup(elems[i]));
|
3187
|
}
|
3188
|
g_strfreev(elems);
|
3189
|
(*(GList**)value) = l;
|
3190
|
} else {
|
3191
|
(*(char**)value) = g_strdup(query_value);
|
3192
|
}
|
3193
|
|
3194
|
return TRUE;
|
3195
|
}
|
3196
|
|
3197
|
|
3198
|
gchar*
|
3199
|
lasso_node_build_query_from_snippets(LassoNode *node)
|
3200
|
{
|
3201
|
int i;
|
3202
|
char path[100];
|
3203
|
char *v;
|
3204
|
GString *s;
|
3205
|
xmlChar *t;
|
3206
|
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
|
3207
|
struct QuerySnippet *query_snippets = NULL;
|
3208
|
struct XmlSnippet xml_snippet;
|
3209
|
|
3210
|
while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
|
3211
|
if (class->node_data && class->node_data->query_snippets) {
|
3212
|
query_snippets = class->node_data->query_snippets;
|
3213
|
break;
|
3214
|
}
|
3215
|
class = g_type_class_peek_parent(class);
|
3216
|
}
|
3217
|
if (query_snippets == NULL)
|
3218
|
return NULL;
|
3219
|
|
3220
|
s = g_string_sized_new(2000);
|
3221
|
|
3222
|
for (i=0; query_snippets[i].path; i++) {
|
3223
|
g_strlcpy(path, query_snippets[i].path, 100);
|
3224
|
v = get_value_by_path(node, path, &xml_snippet);
|
3225
|
if (v && xml_snippet.type == SNIPPET_EXTENSION) {
|
3226
|
if (s->len)
|
3227
|
g_string_append(s, "&");
|
3228
|
g_string_append(s, v);
|
3229
|
lasso_release(v);
|
3230
|
continue;
|
3231
|
}
|
3232
|
if (v) {
|
3233
|
char *field_name = query_snippets[i].field_name;
|
3234
|
if (field_name == NULL)
|
3235
|
field_name = query_snippets[i].path;
|
3236
|
if (s->len)
|
3237
|
g_string_append(s, "&");
|
3238
|
g_string_append(s, field_name);
|
3239
|
g_string_append(s, "=");
|
3240
|
t = xmlURIEscapeStr((xmlChar*)v, NULL);
|
3241
|
g_string_append(s, (char*)t);
|
3242
|
xmlFree(t);
|
3243
|
}
|
3244
|
if (v)
|
3245
|
lasso_release(v);
|
3246
|
}
|
3247
|
|
3248
|
return g_string_free(s, FALSE);
|
3249
|
}
|
3250
|
|
3251
|
|
3252
|
gboolean
|
3253
|
lasso_node_init_from_query_fields(LassoNode *node, char **query_fields)
|
3254
|
{
|
3255
|
int i, j;
|
3256
|
char *field, *t;
|
3257
|
LassoNodeClass *class = LASSO_NODE_GET_CLASS(node);
|
3258
|
struct QuerySnippet *query_snippets = NULL;
|
3259
|
gboolean has_extension = FALSE;
|
3260
|
|
3261
|
while (class && LASSO_IS_NODE_CLASS(class) && class->node_data) {
|
3262
|
if (class->node_data && class->node_data->query_snippets) {
|
3263
|
query_snippets = class->node_data->query_snippets;
|
3264
|
break;
|
3265
|
}
|
3266
|
class = g_type_class_peek_parent(class);
|
3267
|
}
|
3268
|
if (query_snippets == NULL)
|
3269
|
return FALSE;
|
3270
|
|
3271
|
for (i = 0; (field = query_fields[i]); i++) {
|
3272
|
t = strchr(field, '=');
|
3273
|
if (t == NULL)
|
3274
|
continue;
|
3275
|
*t = 0;
|
3276
|
|
3277
|
for (j=0; query_snippets[j].path; j++) {
|
3278
|
char *field_name = query_snippets[j].field_name;
|
3279
|
char path[100];
|
3280
|
|
3281
|
g_strlcpy(path, query_snippets[j].path, 100);
|
3282
|
|
3283
|
if (field_name == NULL)
|
3284
|
field_name = query_snippets[j].path;
|
3285
|
if (strcmp(field_name, "Extension") == 0) {
|
3286
|
has_extension = TRUE;
|
3287
|
continue;
|
3288
|
}
|
3289
|
if (strcmp(field, field_name) != 0)
|
3290
|
continue;
|
3291
|
set_value_at_path(node, path, t+1);
|
3292
|
break;
|
3293
|
}
|
3294
|
if (query_snippets[j].path == NULL && has_extension &&
|
3295
|
strcmp(field, "SigAlg") != 0 && strcmp(field, "Signature") != 0) {
|
3296
|
/* got to the end without finding anything; and has
|
3297
|
* Extension; build it */
|
3298
|
struct XmlSnippet *extension_snippet;
|
3299
|
LassoNode *value_node;
|
3300
|
LassoNodeClass *class;
|
3301
|
GList **value;
|
3302
|
xmlNode *xmlnode, *xmlchild;
|
3303
|
if (find_path(node, "Extension", &value_node, &class, &extension_snippet) == TRUE) {
|
3304
|
GType g_type = G_TYPE_FROM_CLASS(class);
|
3305
|
value = SNIPPET_STRUCT_MEMBER_P(value_node, g_type,
|
3306
|
extension_snippet);
|
3307
|
if (*value) {
|
3308
|
xmlnode = (*value)->data;
|
3309
|
} else {
|
3310
|
xmlnode = xmlNewNode(xmlNewNs(NULL,
|
3311
|
(xmlChar*)LASSO_LIB_HREF,
|
3312
|
(xmlChar*)LASSO_LIB_PREFIX),
|
3313
|
(xmlChar*)"Extension");
|
3314
|
}
|
3315
|
xmlchild = xmlNewNode(NULL, (xmlChar*)field);
|
3316
|
xmlAddChild(xmlchild, xmlNewText((xmlChar*)t+1));
|
3317
|
xmlAddChild(xmlnode, xmlchild);
|
3318
|
if (! *value)
|
3319
|
*value = g_list_append(*value, xmlnode);
|
3320
|
}
|
3321
|
}
|
3322
|
*t = '=';
|
3323
|
}
|
3324
|
|
3325
|
return TRUE;
|
3326
|
}
|
3327
|
|
3328
|
gboolean
|
3329
|
lasso_node_init_from_saml2_query_fields(LassoNode *node, char **query_fields, G_GNUC_UNUSED char **relay_state)
|
3330
|
{
|
3331
|
int i;
|
3332
|
char *field, *t;
|
3333
|
char *req = NULL;
|
3334
|
char *enc = NULL;
|
3335
|
gboolean rc;
|
3336
|
|
3337
|
for (i=0; (field=query_fields[i]); i++) {
|
3338
|
t = strchr(field, '=');
|
3339
|
if (t == NULL)
|
3340
|
continue;
|
3341
|
*t = 0;
|
3342
|
if (strcmp(field, LASSO_SAML2_FIELD_ENCODING) == 0) {
|
3343
|
enc = t+1;
|
3344
|
continue;
|
3345
|
}
|
3346
|
if (strcmp(field, LASSO_SAML2_FIELD_REQUEST) == 0 || strcmp(field, LASSO_SAML2_FIELD_RESPONSE) == 0) {
|
3347
|
req = t+1;
|
3348
|
continue;
|
3349
|
}
|
3350
|
}
|
3351
|
|
3352
|
if (enc && strcmp(enc, LASSO_SAML2_DEFLATE_ENCODING) != 0) {
|
3353
|
/* unknown encoding */
|
3354
|
message(G_LOG_LEVEL_CRITICAL, "Unknown URL encoding: %s", enc);
|
3355
|
return FALSE;
|
3356
|
}
|
3357
|
|
3358
|
if (req == NULL) {
|
3359
|
return FALSE;
|
3360
|
}
|
3361
|
|
3362
|
rc = lasso_node_init_from_deflated_query_part(node, req);
|
3363
|
if (rc == FALSE) {
|
3364
|
return rc;
|
3365
|
}
|
3366
|
|
3367
|
return TRUE;
|
3368
|
}
|
3369
|
|
3370
|
static void
|
3371
|
xmlDeclareNs(xmlNode *root_node, xmlNode *node)
|
3372
|
{
|
3373
|
xmlNs *ns;
|
3374
|
xmlNode *t;
|
3375
|
|
3376
|
if (strcmp((char*)node->name, "Signature") == 0)
|
3377
|
return;
|
3378
|
|
3379
|
for (ns = node->nsDef; ns; ns = ns->next) {
|
3380
|
if (ns->prefix && strcmp((char*)ns->prefix, "xsi") != 0) {
|
3381
|
xmlNewNs(root_node, ns->href, ns->prefix);
|
3382
|
}
|
3383
|
}
|
3384
|
for (t = node->children; t; t = t->next) {
|
3385
|
if (t->type == XML_ELEMENT_NODE) {
|
3386
|
xmlDeclareNs(root_node, t);
|
3387
|
}
|
3388
|
}
|
3389
|
}
|
3390
|
|
3391
|
static inline int
|
3392
|
sameNs(xmlNs *ns1, xmlNs *ns2)
|
3393
|
{
|
3394
|
/* this checks ns->prefix instead of ns->href so it is possible to
|
3395
|
* merge down to an earlier version of liberty namespace
|
3396
|
*/
|
3397
|
return (ns1 == NULL && ns2 == NULL) || (
|
3398
|
ns1 && ns2 && ns1->prefix && ns2->prefix &&
|
3399
|
strcmp((char*)ns1->prefix, (char*)ns2->prefix) == 0 &&
|
3400
|
strcmp((char*)ns1->href, (char*)ns2->href) == 0);
|
3401
|
}
|
3402
|
|
3403
|
static void
|
3404
|
xmlPropUseNsDef(xmlNs *ns, xmlNode *node)
|
3405
|
{
|
3406
|
xmlAttr *attr;
|
3407
|
|
3408
|
for (attr = node->properties; attr; attr = attr->next) {
|
3409
|
if (sameNs(ns, attr->ns)) {
|
3410
|
attr->ns = ns;
|
3411
|
}
|
3412
|
}
|
3413
|
}
|
3414
|
|
3415
|
static void
|
3416
|
xmlUseNsDef(xmlNs *ns, xmlNode *node)
|
3417
|
{
|
3418
|
xmlNode *t;
|
3419
|
xmlNs *ns2;
|
3420
|
xmlNs *ns3 = NULL;
|
3421
|
|
3422
|
xmlPropUseNsDef(ns, node);
|
3423
|
if (sameNs(ns, node->ns)) {
|
3424
|
node->ns = ns;
|
3425
|
}
|
3426
|
|
3427
|
for (t = node->children; t; t = t->next) {
|
3428
|
if (t->type == XML_ELEMENT_NODE)
|
3429
|
xmlUseNsDef(ns, t);
|
3430
|
}
|
3431
|
|
3432
|
if (sameNs(node->nsDef, ns)) {
|
3433
|
ns3 = node->nsDef;
|
3434
|
node->nsDef = node->nsDef->next;
|
3435
|
xmlFreeNs(ns3);
|
3436
|
} else if (node->nsDef) {
|
3437
|
for (ns2 = node->nsDef; ns2->next; ns2 = ns2->next) {
|
3438
|
if (sameNs(ns2->next, ns)) {
|
3439
|
ns3 = ns2->next;
|
3440
|
ns2->next = ns2->next->next;
|
3441
|
xmlFreeNs(ns3);
|
3442
|
if (ns2->next == NULL)
|
3443
|
break;
|
3444
|
}
|
3445
|
}
|
3446
|
}
|
3447
|
}
|
3448
|
|
3449
|
/**
|
3450
|
* xmlCleanNs
|
3451
|
* @root_node: the root #xmlNode where to start the cleaning.
|
3452
|
*
|
3453
|
* xmlCleanNs removes duplicate xml namespace declarations and merge them on
|
3454
|
* the @root_node.
|
3455
|
**/
|
3456
|
void
|
3457
|
xmlCleanNs(xmlNode *root_node)
|
3458
|
{
|
3459
|
xmlNs *ns;
|
3460
|
xmlNode *t;
|
3461
|
|
3462
|
for (t = root_node->children; t; t = t->next)
|
3463
|
if (t->type == XML_ELEMENT_NODE)
|
3464
|
xmlDeclareNs(root_node, t);
|
3465
|
|
3466
|
for (ns = root_node->nsDef; ns; ns = ns->next) {
|
3467
|
for (t = root_node->children; t; t = t->next)
|
3468
|
if (t->type == XML_ELEMENT_NODE)
|
3469
|
xmlUseNsDef(ns, t);
|
3470
|
}
|
3471
|
}
|
3472
|
|
3473
|
void
|
3474
|
xml_insure_namespace(xmlNode *xmlnode, xmlNs *ns, gboolean force, gchar *ns_href, gchar *ns_prefix)
|
3475
|
{
|
3476
|
xmlNode *t = xmlnode->children;
|
3477
|
|
3478
|
if (ns == NULL) {
|
3479
|
for (ns = xmlnode->nsDef; ns; ns = ns->next) {
|
3480
|
if (ns->href && lasso_strisequal((gchar *)ns->href,ns_href)) {
|
3481
|
break;
|
3482
|
}
|
3483
|
}
|
3484
|
if (ns == NULL) {
|
3485
|
ns = xmlNewNs(xmlnode, (xmlChar*)ns_href, (xmlChar*)ns_prefix);
|
3486
|
}
|
3487
|
}
|
3488
|
|
3489
|
xmlSetNs(xmlnode, ns);
|
3490
|
while (t) {
|
3491
|
if (t->type == XML_ELEMENT_NODE && (force == TRUE || t->ns == NULL)) {
|
3492
|
xml_insure_namespace(t, ns, force, NULL, NULL);
|
3493
|
}
|
3494
|
t = t->next;
|
3495
|
}
|
3496
|
}
|
3497
|
|
3498
|
/**
|
3499
|
* lasso_node_get_xmlnode_for_any_type:
|
3500
|
* @node: a #LassoNode.
|
3501
|
* @xmlnode: the #xmlNode returned.
|
3502
|
*
|
3503
|
* Return value: a xmlNode completed with the content of the produced by the get_xmlNode virtual
|
3504
|
* method of the parent class.
|
3505
|
*/
|
3506
|
xmlNode*
|
3507
|
lasso_node_get_xmlnode_for_any_type(LassoNode *node, xmlNode *cur)
|
3508
|
{
|
3509
|
xmlNode *original_xmlnode;
|
3510
|
|
3511
|
original_xmlnode = lasso_node_get_original_xmlnode(node);
|
3512
|
if (cur) {
|
3513
|
if (original_xmlnode) {
|
3514
|
xmlNode *children = xmlCopyNodeList(original_xmlnode->children);
|
3515
|
xmlAttr *attrs = xmlCopyPropList(cur, original_xmlnode->properties);
|
3516
|
if (cur->properties == NULL) {
|
3517
|
cur->properties = attrs;
|
3518
|
} else {
|
3519
|
xmlAttr *it = cur->properties;
|
3520
|
while (it->next) {
|
3521
|
it = it->next;
|
3522
|
}
|
3523
|
it->next = attrs;
|
3524
|
}
|
3525
|
xmlAddChildList(cur, children);
|
3526
|
return cur;
|
3527
|
} else {
|
3528
|
return cur;
|
3529
|
}
|
3530
|
} else {
|
3531
|
if (original_xmlnode) {
|
3532
|
return xmlCopyNode(original_xmlnode, 1);
|
3533
|
} else {
|
3534
|
return cur;
|
3535
|
}
|
3536
|
}
|
3537
|
}
|
3538
|
|
3539
|
/**
|
3540
|
* lasso_node_get_name:
|
3541
|
* @node: a #LassoNode
|
3542
|
*
|
3543
|
* Return the XML element name for this object, the one that would be used in the XML dump of this
|
3544
|
* object.
|
3545
|
*
|
3546
|
* Return value: the name of the object, the value must not be stored.
|
3547
|
*/
|
3548
|
const char*
|
3549
|
lasso_node_get_name(LassoNode *node)
|
3550
|
{
|
3551
|
struct _CustomElement *custom_element;
|
3552
|
LassoNodeClass *klass;
|
3553
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
3554
|
|
3555
|
custom_element = _lasso_node_get_custom_element(node);
|
3556
|
if (custom_element && custom_element->nodename) {
|
3557
|
return custom_element->nodename;
|
3558
|
}
|
3559
|
klass = LASSO_NODE_GET_CLASS(node);
|
3560
|
return klass->node_data->node_name;
|
3561
|
}
|
3562
|
|
3563
|
/**
|
3564
|
* lasso_node_get_name:
|
3565
|
* @node: a #LassoNode
|
3566
|
*
|
3567
|
* Return the XML element name for this object, the one that would be used in the XML dump of this
|
3568
|
* object.
|
3569
|
*
|
3570
|
* Return value: the name of the object, the value must not be stored.
|
3571
|
*/
|
3572
|
const char*
|
3573
|
lasso_node_get_namespace(LassoNode *node)
|
3574
|
{
|
3575
|
struct _CustomElement *custom_element;
|
3576
|
LassoNodeClass *klass;
|
3577
|
g_return_val_if_fail(LASSO_IS_NODE(node), NULL);
|
3578
|
|
3579
|
custom_element = _lasso_node_get_custom_element(node);
|
3580
|
if (custom_element && custom_element->nodename) {
|
3581
|
return custom_element->href;
|
3582
|
}
|
3583
|
klass = LASSO_NODE_GET_CLASS(node);
|
3584
|
if (klass->node_data && klass->node_data->ns)
|
3585
|
return (const char*)klass->node_data->ns->href;
|
3586
|
return NULL;
|
3587
|
}
|
3588
|
|
3589
|
|
3590
|
/**
|
3591
|
* lasso_node_export_to_saml2_query:
|
3592
|
* @node: the #LassoNode object to pass as a query
|
3593
|
* @param_name: the key value for the query string parameter
|
3594
|
* @url:(allow-none): an optional URL to prepend to the query string
|
3595
|
* @key:(allow-none): a #LassoKey object
|
3596
|
*
|
3597
|
* Export a node as signed query string, the node must support serialization as a query.
|
3598
|
*
|
3599
|
* Return value: an HTTP URL or query string if successful, NULL otherwise.
|
3600
|
*/
|
3601
|
char*
|
3602
|
lasso_node_export_to_saml2_query(LassoNode *node, const char *param_name, const char *url,
|
3603
|
LassoKey *key)
|
3604
|
{
|
3605
|
char *value = NULL, *query = NULL, *signed_query = NULL, *result = NULL;
|
3606
|
xmlChar *encoded_param = NULL;
|
3607
|
|
3608
|
value = lasso_node_build_deflated_query(node);
|
3609
|
if (! value)
|
3610
|
goto cleanup;
|
3611
|
encoded_param = xmlURIEscapeStr(BAD_CAST param_name, NULL);
|
3612
|
if (! encoded_param)
|
3613
|
goto cleanup;
|
3614
|
query = g_strdup_printf("%s=%s", encoded_param, value);
|
3615
|
if (! query)
|
3616
|
goto cleanup;
|
3617
|
if (LASSO_IS_KEY(key)) {
|
3618
|
signed_query = lasso_key_query_sign(key, query);
|
3619
|
} else {
|
3620
|
lasso_transfer_string(signed_query, query);
|
3621
|
}
|
3622
|
if (! signed_query)
|
3623
|
goto cleanup;
|
3624
|
if (url) {
|
3625
|
result = lasso_concat_url_query(url, signed_query);
|
3626
|
} else {
|
3627
|
lasso_transfer_string(result, signed_query);
|
3628
|
}
|
3629
|
|
3630
|
cleanup:
|
3631
|
lasso_release_string(value);
|
3632
|
lasso_release_xml_string(encoded_param);
|
3633
|
lasso_release_string(query);
|
3634
|
lasso_release_string(signed_query);
|
3635
|
return result;
|
3636
|
}
|
3637
|
|
3638
|
/**
|
3639
|
* lasso_node_new_from_saml2_query:
|
3640
|
* @url_or_qs: an URL containing a query string or a query string only
|
3641
|
* @param_name: the key value for the query string parameter to extract as a #LassoNode.
|
3642
|
* @key:(allow-none): a #LassoKey object
|
3643
|
*
|
3644
|
* Verify the signature on a SAML-2 encoded query string and return the encoded node.
|
3645
|
*
|
3646
|
* Return value: a newly build #LassoNode if successful, NULL otherwise.
|
3647
|
*/
|
3648
|
LassoNode*
|
3649
|
lasso_node_new_from_saml2_query(const char *url_or_qs, const char *param_name, LassoKey *key)
|
3650
|
{
|
3651
|
char *needle = NULL;
|
3652
|
LassoNode *result = NULL;
|
3653
|
|
3654
|
if (! url_or_qs || ! param_name)
|
3655
|
return NULL;
|
3656
|
needle = strchr(url_or_qs, '?');
|
3657
|
if (needle) {
|
3658
|
url_or_qs = (const char*)(needle+1);
|
3659
|
}
|
3660
|
if (key) {
|
3661
|
goto_cleanup_if_fail(lasso_key_query_verify(key, url_or_qs) == 0);
|
3662
|
}
|
3663
|
cleanup:
|
3664
|
return result;
|
3665
|
}
|