~ubuntu-branches/ubuntu/gutsy/lasso/gutsy

« back to all changes in this revision

Viewing changes to lasso/id-ff/provider.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2005-09-16 02:16:49 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050916021649-lr5tuka6pfmmks44
Tags: 0.6.2-3ubuntu1
* debian/control: removed hardcoded php dependency, added php:Depends
  substvar
* debian/rules: added phpapiver, added substitution of php:Depends

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: provider.c,v 1.57 2005/05/25 11:09:40 fpeters Exp $
 
2
 *
 
3
 * Lasso - A free implementation of the Liberty Alliance specifications.
 
4
 *
 
5
 * Copyright (C) 2004, 2005 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, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 */
 
24
 
 
25
#include <libxml/xpath.h>
 
26
#include <libxml/xpathInternals.h>
 
27
 
 
28
#include <xmlsec/base64.h>
 
29
#include <xmlsec/xmldsig.h>
 
30
#include <xmlsec/xmltree.h>
 
31
 
 
32
#include <lasso/id-ff/provider.h>
 
33
#include <lasso/id-ff/providerprivate.h>
 
34
 
 
35
struct _LassoProviderPrivate
 
36
{
 
37
        gboolean dispose_has_run;
 
38
        LibertyConformanceLevel conformance;
 
39
        GHashTable *SPDescriptor;
 
40
        char *default_assertion_consumer;
 
41
        GHashTable *IDPDescriptor;
 
42
        xmlNode *organization;
 
43
        xmlSecKey *public_key;
 
44
        xmlNode *signing_key_descriptor;
 
45
};
 
46
 
 
47
static char *protocol_uris[] = {
 
48
        "http://projectliberty.org/profiles/fedterm",
 
49
        "http://projectliberty.org/profiles/nim",
 
50
        "http://projectliberty.org/profiles/rni",
 
51
        "http://projectliberty.org/profiles/slo",
 
52
        NULL /* none for single sign on */
 
53
};
 
54
static char *protocol_md_nodename[] = {
 
55
        "FederationTerminationNotificationProtocolProfile",
 
56
        "NameIdentifierMappingProtocolProfile",
 
57
        "RegisterNameIdentifierProtocolProfile",
 
58
        "SingleLogoutProtocolProfile",
 
59
        "SingleSignOnProtocolProfile"
 
60
};
 
61
static char *protocol_roles[] = { NULL, "sp", "idp"};
 
62
char *protocol_methods[] = {"", "", "", "", "", "-http", "-soap"};
 
63
 
 
64
/*****************************************************************************/
 
65
/* public methods */
 
66
/*****************************************************************************/
 
67
 
 
68
/**
 
69
 * lasso_provider_get_assertion_consumer_service_url:
 
70
 * @provider: a #LassoProvider
 
71
 * @service_id: the AssertionConsumerServiceID, NULL for default
 
72
 *
 
73
 * Extracts the AssertionConsumerServiceURL from the provider metadata
 
74
 * descriptor.
 
75
 *
 
76
 * Return value: the element value, NULL if the element was not found.  This
 
77
 *      string must be freed by the caller.
 
78
 **/
 
79
gchar*
 
80
lasso_provider_get_assertion_consumer_service_url(LassoProvider *provider, const char *service_id)
 
81
{
 
82
        GHashTable *descriptor;
 
83
        GList *l;
 
84
        char *sid = (char*)service_id;
 
85
        char *name;
 
86
 
 
87
        if (sid == NULL)
 
88
                sid = provider->private_data->default_assertion_consumer;
 
89
 
 
90
        descriptor = provider->private_data->SPDescriptor;
 
91
        if (descriptor == NULL)
 
92
                return NULL;
 
93
 
 
94
        name = g_strdup_printf("AssertionConsumerServiceURL %s", sid);
 
95
        l = g_hash_table_lookup(descriptor, name);
 
96
        g_free(name);
 
97
        if (l == NULL)
 
98
                return NULL;
 
99
 
 
100
        return g_strdup(l->data);
 
101
}
 
102
 
 
103
/**
 
104
 * lasso_provider_get_metadata_one:
 
105
 * @provider: a #LassoProvider
 
106
 * @name: the element name
 
107
 *
 
108
 * Extracts the element @name from the provider metadata descriptor.
 
109
 *
 
110
 * Return value: the element value, NULL if the element was not found.  This
 
111
 *      string must be freed by the caller.
 
112
 **/
 
113
gchar*
 
114
lasso_provider_get_metadata_one(LassoProvider *provider, const char *name)
 
115
{
 
116
        GList *l;
 
117
        GHashTable *descriptor;
 
118
 
 
119
        descriptor = provider->private_data->SPDescriptor; /* default to SP */
 
120
        if (provider->role == LASSO_PROVIDER_ROLE_IDP)
 
121
                descriptor = provider->private_data->IDPDescriptor;
 
122
        if (descriptor == NULL)
 
123
                return NULL;
 
124
 
 
125
        l = g_hash_table_lookup(descriptor, name);
 
126
        if (l)
 
127
                return g_strdup(l->data);
 
128
 
 
129
        return NULL;
 
130
}
 
131
 
 
132
 
 
133
/**
 
134
 * lasso_provider_get_metadata_list:
 
135
 * @provider: a #LassoProvider
 
136
 * @name: the element name
 
137
 *
 
138
 * Extracts zero to many elements from the provider metadata descriptor.
 
139
 *
 
140
 * Return value: a #GList with the elements.  This GList is internally
 
141
 *      allocated and points to internally allocated strings.  It must
 
142
 *      not be freed, modified or stored.
 
143
 **/
 
144
GList*
 
145
lasso_provider_get_metadata_list(LassoProvider *provider, const char *name)
 
146
{
 
147
        GHashTable *descriptor;
 
148
 
 
149
        descriptor = provider->private_data->SPDescriptor; /* default to SP */
 
150
        if (provider->role == LASSO_PROVIDER_ROLE_IDP)
 
151
                descriptor = provider->private_data->IDPDescriptor;
 
152
 
 
153
        return g_hash_table_lookup(descriptor, name);
 
154
}
 
155
 
 
156
 
 
157
/**
 
158
 * lasso_provider_get_first_http_method:
 
159
 * @provider: a #LassoProvider
 
160
 * @remote_provider: a #LassoProvider depicting the remote provider
 
161
 * @protocol_type: a Liberty profile
 
162
 *
 
163
 * Looks up and returns a #LassoHttpMethod appropriate for performing the
 
164
 * @protocol_type between @provider and @remote_provider.
 
165
 *
 
166
 * Return value: the #LassoHttpMethod
 
167
 **/
 
168
LassoHttpMethod lasso_provider_get_first_http_method(LassoProvider *provider,
 
169
                LassoProvider *remote_provider, LassoMdProtocolType protocol_type)
 
170
{
 
171
        char *protocol_profile_prefix;
 
172
        GList *local_supported_profiles;
 
173
        GList *remote_supported_profiles;
 
174
        GList *t1, *t2 = NULL;
 
175
        gboolean found;
 
176
 
 
177
        if (remote_provider->role == LASSO_PROVIDER_ROLE_SP)
 
178
                provider->role = LASSO_PROVIDER_ROLE_IDP;
 
179
        if (remote_provider->role == LASSO_PROVIDER_ROLE_IDP)
 
180
                provider->role = LASSO_PROVIDER_ROLE_SP;
 
181
 
 
182
        protocol_profile_prefix = g_strdup_printf("%s-%s",
 
183
                        protocol_uris[protocol_type], protocol_roles[provider->role]);
 
184
 
 
185
        local_supported_profiles = lasso_provider_get_metadata_list(
 
186
                        provider, protocol_md_nodename[protocol_type]);
 
187
        remote_supported_profiles = lasso_provider_get_metadata_list(
 
188
                        remote_provider, protocol_md_nodename[protocol_type]);
 
189
 
 
190
        found = FALSE;
 
191
        t1 = local_supported_profiles;
 
192
        while (t1 && !found) {
 
193
                if (g_str_has_prefix(t1->data, protocol_profile_prefix)) {
 
194
                        t2 = remote_supported_profiles;
 
195
                        while (t2 && !found) {
 
196
                                if (strcmp(t1->data, t2->data) == 0) {
 
197
                                        found = TRUE;
 
198
                                        break; /* avoid the g_list_next */
 
199
                                }
 
200
                                t2 = g_list_next(t2);
 
201
                        }
 
202
                }
 
203
                t1 = g_list_next(t1);
 
204
        }
 
205
        g_free(protocol_profile_prefix);
 
206
 
 
207
        if (found) {
 
208
                if (g_str_has_suffix(t2->data, "http"))
 
209
                        return LASSO_HTTP_METHOD_REDIRECT;
 
210
                if (t2 && g_str_has_suffix(t2->data, "soap"))
 
211
                        return LASSO_HTTP_METHOD_SOAP;
 
212
                g_assert_not_reached();
 
213
        }
 
214
 
 
215
        return LASSO_HTTP_METHOD_NONE;
 
216
}
 
217
 
 
218
/**
 
219
 * lasso_provider_accept_http_method:
 
220
 * @provider: a #LassoProvider
 
221
 * @remote_provider: a #LassoProvider depicting the remote provider
 
222
 * @protocol_type: a Liberty profile type
 
223
 * @http_method: an HTTP method
 
224
 * @initiate_profile: whether @provider initiates the profile
 
225
 *
 
226
 * Gets if @http_method is an appropriate method for the @protocol_type profile
 
227
 * between @provider and @remote_provider.
 
228
 *
 
229
 * Return value: %TRUE if it is appropriate
 
230
 **/
 
231
gboolean
 
232
lasso_provider_accept_http_method(LassoProvider *provider, LassoProvider *remote_provider,
 
233
                LassoMdProtocolType protocol_type, LassoHttpMethod http_method,
 
234
                gboolean initiate_profile)
 
235
 
236
        LassoProviderRole initiating_role;
 
237
        char *protocol_profile;
 
238
 
 
239
        initiating_role = remote_provider->role;
 
240
        if (remote_provider->role == LASSO_PROVIDER_ROLE_SP) {
 
241
                provider->role = LASSO_PROVIDER_ROLE_IDP;
 
242
        }
 
243
        if (remote_provider->role == LASSO_PROVIDER_ROLE_IDP) {
 
244
                provider->role = LASSO_PROVIDER_ROLE_SP;
 
245
        }
 
246
        if (initiate_profile)
 
247
                initiating_role = provider->role;
 
248
 
 
249
        protocol_profile = g_strdup_printf("%s-%s%s",
 
250
                        protocol_uris[protocol_type],
 
251
                        protocol_roles[initiating_role],
 
252
                        protocol_methods[http_method+1]);
 
253
 
 
254
        if (lasso_provider_has_protocol_profile(provider,
 
255
                                protocol_type, protocol_profile) == FALSE)
 
256
                return FALSE;
 
257
 
 
258
        if (lasso_provider_has_protocol_profile(remote_provider,
 
259
                                protocol_type, protocol_profile) == FALSE)
 
260
                return FALSE;
 
261
 
 
262
        return TRUE;
 
263
}
 
264
 
 
265
/**
 
266
 * lasso_provider_has_protocol_profile:
 
267
 * @provider: a #LassoProvider
 
268
 * @protocol_type: a Liberty profile type
 
269
 * @protocol_profile: a fully-qualified Liberty profile
 
270
 *
 
271
 * Gets if @provider supports @protocol_profile.
 
272
 *
 
273
 * Return value: %TRUE if it is supported
 
274
 **/
 
275
gboolean
 
276
lasso_provider_has_protocol_profile(LassoProvider *provider,
 
277
                LassoMdProtocolType protocol_type, const char *protocol_profile)
 
278
{
 
279
        GList *supported;
 
280
        
 
281
        supported = lasso_provider_get_metadata_list(
 
282
                        provider, protocol_md_nodename[protocol_type]);
 
283
        
 
284
        if (g_list_find_custom(supported, protocol_profile, (GCompareFunc)strcmp) == NULL)
 
285
                return FALSE;
 
286
        return TRUE;
 
287
}
 
288
 
 
289
/**
 
290
 * lasso_provider_get_base64_succinct_id:
 
291
 * @provider: a #LassoProvider
 
292
 *
 
293
 * Computes and returns the base64-encoded provider succinct ID.
 
294
 *
 
295
 * Return value: the provider succinct ID.  This string must be freed by the
 
296
 *      caller.
 
297
 **/
 
298
char*
 
299
lasso_provider_get_base64_succinct_id(LassoProvider *provider)
 
300
{
 
301
        char *succinct_id, *base64_succinct_id;
 
302
 
 
303
        succinct_id = lasso_sha1(provider->ProviderID);
 
304
        base64_succinct_id = xmlSecBase64Encode(succinct_id, 20, 0);
 
305
        xmlFree(succinct_id);
 
306
        return base64_succinct_id;
 
307
}
 
308
 
 
309
 
 
310
/**
 
311
 * lasso_provider_get_organization
 
312
 * @provider: a #LassoProvider
 
313
 *
 
314
 * Returns the provider metadata &lt;Organization&gt; XML node.
 
315
 *
 
316
 * Return value: the &lt;Organization/&gt; node (libxml2 xmlNode*); or NULL if it is
 
317
 *      not found.  This xmlnode must be freed by the caller.
 
318
 **/
 
319
xmlNode*
 
320
lasso_provider_get_organization(LassoProvider *provider)
 
321
{
 
322
        if (provider->private_data->organization) {
 
323
                return xmlCopyNode(provider->private_data->organization, 1);
 
324
        } else {
 
325
                return NULL;
 
326
        }
 
327
}
 
328
 
 
329
 
 
330
/*****************************************************************************/
 
331
/* private methods                                                           */
 
332
/*****************************************************************************/
 
333
 
 
334
static struct XmlSnippet schema_snippets[] = {
 
335
        { "PublicKeyFilePath", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoProvider, public_key) },
 
336
        { "CaCertChainFilePath", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoProvider, ca_cert_chain) },
 
337
        { "MetadataFilePath", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoProvider, metadata_filename) },
 
338
        { "ProviderID", SNIPPET_ATTRIBUTE, G_STRUCT_OFFSET(LassoProvider, ProviderID) },
 
339
        { NULL, 0, 0}
 
340
};
 
341
 
 
342
static LassoNodeClass *parent_class = NULL;
 
343
 
 
344
static void
 
345
load_descriptor(xmlNode *xmlnode, GHashTable *descriptor, LassoProvider *provider)
 
346
{
 
347
        xmlNode *t;
 
348
        GList *elements;
 
349
        char *name;
 
350
        xmlChar *value;
 
351
 
 
352
        t = xmlnode->children;
 
353
        while (t) {
 
354
                if (t->type != XML_ELEMENT_NODE) {
 
355
                        t = t->next;
 
356
                        continue;
 
357
                }
 
358
                if (strcmp(t->name, "KeyDescriptor") == 0) {
 
359
                        char *use = xmlGetProp(t, "use");
 
360
                        if (use && strcmp(use, "signing") == 0) {
 
361
                                provider->private_data->signing_key_descriptor = xmlCopyNode(t, 1);
 
362
                        }
 
363
                        t = t->next;
 
364
                        continue;
 
365
                }
 
366
                if (strcmp(t->name, "AssertionConsumerServiceURL") == 0) {
 
367
                        char *isDefault = xmlGetProp(t, "isDefault");
 
368
                        char *id = xmlGetProp(t, "id");
 
369
                        name = g_strdup_printf("%s %s", t->name, id);
 
370
                        if (isDefault) {
 
371
                                if (strcmp(isDefault, "true") == 0 || strcmp(isDefault, "1") == 0)
 
372
                                        provider->private_data->default_assertion_consumer =
 
373
                                                g_strdup(id);
 
374
                                xmlFree(isDefault);
 
375
                        }
 
376
                        xmlFree(id);
 
377
                } else {
 
378
                        name = g_strdup(t->name);
 
379
                }
 
380
                elements = g_hash_table_lookup(descriptor, name);
 
381
                value = xmlNodeGetContent(t);
 
382
                elements = g_list_append(elements, g_strdup(value));
 
383
                xmlFree(value);
 
384
                g_hash_table_insert(descriptor, name, elements);
 
385
                t = t->next;
 
386
        }
 
387
}
 
388
 
 
389
static xmlNode*
 
390
get_xmlNode(LassoNode *node, gboolean lasso_dump)
 
391
{
 
392
        xmlNode *xmlnode;
 
393
        LassoProvider *provider = LASSO_PROVIDER(node);
 
394
        char *roles[] = { "None", "SP", "IdP"};
 
395
 
 
396
        xmlnode = parent_class->get_xmlNode(node, lasso_dump);
 
397
        xmlSetProp(xmlnode, "ProviderDumpVersion", "2");
 
398
        if (provider->role)
 
399
                xmlSetProp(xmlnode, "ProviderRole", roles[provider->role]);
 
400
 
 
401
        return xmlnode;
 
402
}
 
403
 
 
404
 
 
405
static int
 
406
init_from_xml(LassoNode *node, xmlNode *xmlnode)
 
407
{
 
408
        LassoProvider *provider = LASSO_PROVIDER(node);
 
409
        xmlChar *s;
 
410
 
 
411
        parent_class->init_from_xml(node, xmlnode);
 
412
        
 
413
        if (xmlnode == NULL)
 
414
                return LASSO_ERROR_UNDEFINED;
 
415
 
 
416
        s = xmlGetProp(xmlnode, "ProviderRole");
 
417
        if (s && strcmp(s, "SP") == 0)
 
418
                provider->role = LASSO_PROVIDER_ROLE_SP;
 
419
        if (s && strcmp(s, "IdP") == 0)
 
420
                provider->role = LASSO_PROVIDER_ROLE_IDP;
 
421
        if (s)
 
422
                xmlFree(s);
 
423
 
 
424
        if (provider->metadata_filename)
 
425
                lasso_provider_load_metadata(provider, provider->metadata_filename);
 
426
 
 
427
        return 0;
 
428
}
 
429
 
 
430
/*****************************************************************************/
 
431
/* overridden parent class methods                                           */
 
432
/*****************************************************************************/
 
433
 
 
434
static void
 
435
free_string(char *string)
 
436
{
 
437
        g_free(string);
 
438
}
 
439
 
 
440
static void
 
441
free_list_strings(gchar *key, GList *list, gpointer data)
 
442
{
 
443
        g_list_foreach(list, (GFunc)free_string, NULL);
 
444
        g_list_free(list);
 
445
}
 
446
 
 
447
static void
 
448
dispose(GObject *object)
 
449
{
 
450
        LassoProvider *provider = LASSO_PROVIDER(object);
 
451
 
 
452
        if (provider->private_data->dispose_has_run) {
 
453
                return;
 
454
        }
 
455
        provider->private_data->dispose_has_run = TRUE;
 
456
 
 
457
        if (provider->private_data->IDPDescriptor) {
 
458
                g_hash_table_foreach(provider->private_data->IDPDescriptor,
 
459
                                (GHFunc)free_list_strings, NULL);
 
460
                g_hash_table_destroy(provider->private_data->IDPDescriptor);
 
461
        }
 
462
        provider->private_data->IDPDescriptor = NULL;
 
463
 
 
464
        if (provider->private_data->SPDescriptor) {
 
465
                g_hash_table_foreach(provider->private_data->SPDescriptor,
 
466
                                (GHFunc)free_list_strings, NULL);
 
467
                g_hash_table_destroy(provider->private_data->SPDescriptor);
 
468
        }
 
469
        provider->private_data->SPDescriptor = NULL;
 
470
 
 
471
        if (provider->private_data->organization) {
 
472
                xmlFreeNode(provider->private_data->organization);
 
473
                provider->private_data->organization = NULL;
 
474
        }
 
475
 
 
476
        if (provider->private_data->default_assertion_consumer) {
 
477
                g_free(provider->private_data->default_assertion_consumer);
 
478
                provider->private_data->default_assertion_consumer = NULL;
 
479
        }
 
480
 
 
481
        if (provider->private_data->public_key) {
 
482
                xmlSecKeyDestroy(provider->private_data->public_key);
 
483
                provider->private_data->public_key = NULL;
 
484
        }
 
485
 
 
486
        if (provider->private_data->signing_key_descriptor) {
 
487
                xmlFreeNode(provider->private_data->signing_key_descriptor);
 
488
                provider->private_data->signing_key_descriptor = NULL;
 
489
        }
 
490
 
 
491
        G_OBJECT_CLASS(parent_class)->dispose(G_OBJECT(provider));
 
492
}
 
493
 
 
494
static void
 
495
finalize(GObject *object)
 
496
{
 
497
        LassoProvider *provider = LASSO_PROVIDER(object);
 
498
 
 
499
        g_free(provider->public_key);
 
500
        provider->public_key = NULL;
 
501
        g_free(provider->ca_cert_chain);
 
502
        provider->ca_cert_chain = NULL;
 
503
        g_free(provider->private_data);
 
504
        provider->private_data = NULL;
 
505
 
 
506
        G_OBJECT_CLASS(parent_class)->finalize(G_OBJECT(provider));
 
507
}
 
508
 
 
509
/*****************************************************************************/
 
510
/* instance and class init functions */
 
511
/*****************************************************************************/
 
512
 
 
513
 
 
514
static void
 
515
instance_init(LassoProvider *provider)
 
516
{
 
517
        provider->role = LASSO_PROVIDER_ROLE_NONE;
 
518
        provider->ProviderID = NULL;
 
519
        provider->metadata_filename = NULL;
 
520
        provider->public_key = NULL;
 
521
        provider->ca_cert_chain = NULL;
 
522
        provider->private_data = g_new(LassoProviderPrivate, 1);
 
523
        provider->private_data->dispose_has_run = FALSE;
 
524
        provider->private_data->default_assertion_consumer = NULL;
 
525
        provider->private_data->organization = NULL;
 
526
        provider->private_data->public_key = NULL;
 
527
        provider->private_data->signing_key_descriptor = NULL;
 
528
 
 
529
        /* no value_destroy_func since it shouldn't destroy the GList on insert */
 
530
        provider->private_data->IDPDescriptor = g_hash_table_new_full(
 
531
                        g_str_hash, g_str_equal, g_free, NULL);
 
532
        provider->private_data->SPDescriptor = g_hash_table_new_full(
 
533
                        g_str_hash, g_str_equal, g_free, NULL);
 
534
}
 
535
 
 
536
static void
 
537
class_init(LassoProviderClass *klass)
 
538
{
 
539
        LassoNodeClass *nclass = LASSO_NODE_CLASS(klass);
 
540
 
 
541
        parent_class = g_type_class_peek_parent(klass);
 
542
        nclass->node_data = g_new0(LassoNodeClassData, 1);
 
543
        lasso_node_class_set_nodename(nclass, "Provider");
 
544
        lasso_node_class_set_ns(nclass, LASSO_LASSO_HREF, LASSO_LASSO_PREFIX);
 
545
        lasso_node_class_add_snippets(nclass, schema_snippets);
 
546
        nclass->get_xmlNode = get_xmlNode;
 
547
        nclass->init_from_xml = init_from_xml;
 
548
 
 
549
        G_OBJECT_CLASS(klass)->dispose = dispose;
 
550
        G_OBJECT_CLASS(klass)->finalize = finalize;
 
551
}
 
552
 
 
553
GType
 
554
lasso_provider_get_type()
 
555
{
 
556
        static GType this_type = 0;
 
557
 
 
558
        if (!this_type) {
 
559
                static const GTypeInfo this_info = {
 
560
                        sizeof (LassoProviderClass),
 
561
                        NULL,
 
562
                        NULL,
 
563
                        (GClassInitFunc) class_init,
 
564
                        NULL,
 
565
                        NULL,
 
566
                        sizeof(LassoProvider),
 
567
                        0,
 
568
                        (GInstanceInitFunc) instance_init,
 
569
                };
 
570
 
 
571
                this_type = g_type_register_static(LASSO_TYPE_NODE,
 
572
                                "LassoProvider", &this_info, 0);
 
573
        }
 
574
        return this_type;
 
575
}
 
576
 
 
577
LibertyConformanceLevel
 
578
lasso_provider_compatibility_level(LassoProvider *provider)
 
579
{
 
580
        return provider->private_data->conformance;
 
581
}
 
582
 
 
583
gboolean
 
584
lasso_provider_load_metadata(LassoProvider *provider, const gchar *metadata)
 
585
{
 
586
        xmlDoc *doc;
 
587
        xmlXPathContext *xpathCtx;
 
588
        xmlXPathObject *xpathObj;
 
589
        xmlNode *node;
 
590
        const char *xpath_idp = "/md:EntityDescriptor/md:IDPDescriptor";
 
591
        const char *xpath_sp = "/md:EntityDescriptor/md:SPDescriptor";
 
592
        const char *xpath_organization = "/md:EntityDescriptor/md:Organization";
 
593
 
 
594
        doc = xmlParseFile(metadata);
 
595
        if (doc == NULL)
 
596
                return FALSE;
 
597
 
 
598
        provider->metadata_filename = g_strdup(metadata);
 
599
        provider->private_data->conformance = LIBERTY_1_2;
 
600
 
 
601
        xpathCtx = xmlXPathNewContext(doc);
 
602
        xmlXPathRegisterNs(xpathCtx, "md", LASSO_METADATA_HREF);
 
603
        xpathObj = xmlXPathEvalExpression("/md:EntityDescriptor", xpathCtx);
 
604
        /* if empty: not a ID-FF 1.2 metadata file -> bails out */
 
605
        if (xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr == 0) {
 
606
                xmlXPathFreeObject(xpathObj);
 
607
                xmlXPathRegisterNs(xpathCtx, "md11",
 
608
                                "http://projectliberty.org/schemas/core/2002/12");
 
609
                xpathObj = xmlXPathEvalExpression(
 
610
                                "/md11:SPDescriptor|/md11:IDPDescriptor", xpathCtx);
 
611
                if (xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr == 0) {
 
612
                        xmlXPathFreeObject(xpathObj);
 
613
                        xmlFreeDoc(doc);
 
614
                        xmlXPathFreeContext(xpathCtx);
 
615
                        return FALSE;
 
616
                }
 
617
                provider->private_data->conformance = LIBERTY_1_1;
 
618
                xpath_idp = "/md11:IDPDescriptor";
 
619
                xpath_sp = "/md11:SPDescriptor";
 
620
        }
 
621
        node = xpathObj->nodesetval->nodeTab[0];
 
622
        provider->ProviderID = xmlGetProp(node, "providerID");
 
623
 
 
624
        xpathObj = xmlXPathEvalExpression(xpath_idp, xpathCtx);
 
625
        if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr == 1) {
 
626
                load_descriptor(xpathObj->nodesetval->nodeTab[0],
 
627
                                provider->private_data->IDPDescriptor, provider);
 
628
                if (provider->private_data->conformance < LIBERTY_1_2) {
 
629
                        /* lookup ProviderID */
 
630
                        node = xpathObj->nodesetval->nodeTab[0]->children;
 
631
                        while (node) {
 
632
                                if (strcmp(node->name, "ProviderID") == 0) {
 
633
                                        provider->ProviderID = xmlNodeGetContent(node);
 
634
                                        break;
 
635
                                }
 
636
                                node = node->next;
 
637
                        }
 
638
                }
 
639
        }
 
640
        xmlXPathFreeObject(xpathObj);
 
641
 
 
642
        xpathObj = xmlXPathEvalExpression(xpath_sp, xpathCtx);
 
643
        if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr == 1) {
 
644
                load_descriptor(xpathObj->nodesetval->nodeTab[0],
 
645
                                provider->private_data->SPDescriptor, provider);
 
646
                if (provider->private_data->conformance < LIBERTY_1_2) {
 
647
                        /* lookup ProviderID */
 
648
                        node = xpathObj->nodesetval->nodeTab[0]->children;
 
649
                        while (node) {
 
650
                                if (strcmp(node->name, "ProviderID") == 0) {
 
651
                                        provider->ProviderID = xmlNodeGetContent(node);
 
652
                                        break;
 
653
                                }
 
654
                                node = node->next;
 
655
                        }
 
656
                }
 
657
        }
 
658
        xmlXPathFreeObject(xpathObj);
 
659
 
 
660
        xpathObj = xmlXPathEvalExpression(xpath_organization, xpathCtx);
 
661
        if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr == 1) {
 
662
                provider->private_data->organization = xmlCopyNode(
 
663
                                xpathObj->nodesetval->nodeTab[0], 1);
 
664
        }
 
665
        xmlXPathFreeObject(xpathObj);
 
666
 
 
667
        xmlFreeDoc(doc);
 
668
        xmlXPathFreeContext(xpathCtx);
 
669
 
 
670
        return TRUE;
 
671
}
 
672
 
 
673
/**
 
674
 * lasso_provider_new:
 
675
 * @role: provider role, identity provider or service provider
 
676
 * @metadata: path to the provider metadata file
 
677
 * @public_key: path to the provider public key file (may be a certificate) or NULL
 
678
 * @ca_cert_chain: path to the provider CA certificate chain file or NULL
 
679
 *
 
680
 * Creates a new #LassoProvider.
 
681
 *
 
682
 * Return value: a newly created #LassoProvider; or NULL if an error occured
 
683
 */
 
684
LassoProvider*
 
685
lasso_provider_new(LassoProviderRole role, const char *metadata,
 
686
                const char *public_key, const char *ca_cert_chain)
 
687
{
 
688
        LassoProvider *provider;
 
689
 
 
690
        provider = LASSO_PROVIDER(g_object_new(LASSO_TYPE_PROVIDER, NULL));
 
691
        provider->role = role;
 
692
        if (lasso_provider_load_metadata(provider, metadata) == FALSE) {
 
693
                message(G_LOG_LEVEL_CRITICAL, "Failed to load metadata from %s.", metadata);
 
694
                lasso_node_destroy(LASSO_NODE(provider));
 
695
                return NULL;
 
696
        }
 
697
 
 
698
        provider->public_key = g_strdup(public_key);
 
699
        provider->ca_cert_chain = g_strdup(ca_cert_chain);
 
700
 
 
701
        lasso_provider_load_public_key(provider);
 
702
 
 
703
        return provider;
 
704
}
 
705
 
 
706
void
 
707
lasso_provider_load_public_key(LassoProvider *provider)
 
708
{
 
709
        LassoPemFileType file_type;
 
710
        xmlSecKey *pub_key = NULL;
 
711
 
 
712
        if (provider->public_key == NULL && provider->private_data->signing_key_descriptor == NULL)
 
713
                return;
 
714
 
 
715
        if (provider->public_key == NULL) {
 
716
                xmlNode *t = provider->private_data->signing_key_descriptor->children;
 
717
                xmlChar *b64_value;
 
718
                xmlSecByte *value;
 
719
                int length;
 
720
                int rc;
 
721
 
 
722
                /* could use XPath but going down manually will do */
 
723
                while (t) {
 
724
                        if (t->type == XML_ELEMENT_NODE) {
 
725
                                if (strcmp(t->name, "KeyInfo") == 0 ||
 
726
                                                strcmp(t->name, "X509Data") == 0) {
 
727
                                        t = t->children;
 
728
                                        continue;
 
729
                                }
 
730
                                if (strcmp(t->name, "X509Certificate") == 0)
 
731
                                        break;
 
732
                        }
 
733
                        t = t->next;
 
734
                }
 
735
                if (t == NULL)
 
736
                        return;
 
737
 
 
738
                b64_value = xmlNodeGetContent(t);
 
739
                length = strlen(b64_value);
 
740
                value = g_malloc(length);
 
741
                rc = xmlSecBase64Decode(b64_value, value, length);
 
742
                if (rc < 0) {
 
743
                        /* bad base-64 */
 
744
                        xmlFree(b64_value);
 
745
                        g_free(value);
 
746
                }
 
747
                pub_key = xmlSecCryptoAppKeyLoadMemory(value, rc,
 
748
                                xmlSecKeyDataFormatCertDer, NULL, NULL, NULL);
 
749
                xmlFree(b64_value);
 
750
                g_free(value);
 
751
                if (pub_key == NULL) {
 
752
                        /* XXX: bad key */
 
753
                }
 
754
                provider->private_data->public_key = pub_key;
 
755
                return;
 
756
        }
 
757
 
 
758
        file_type = lasso_get_pem_file_type(provider->public_key);
 
759
        switch (file_type) {
 
760
                case LASSO_PEM_FILE_TYPE_UNKNOWN:
 
761
                        break; /* with a warning ? */
 
762
                case LASSO_PEM_FILE_TYPE_CERT:
 
763
                        pub_key = lasso_get_public_key_from_pem_cert_file(
 
764
                                        provider->public_key);
 
765
                        break;
 
766
                case LASSO_PEM_FILE_TYPE_PUB_KEY:
 
767
                        pub_key = xmlSecCryptoAppKeyLoad(provider->public_key,
 
768
                                        xmlSecKeyDataFormatPem, NULL, NULL, NULL);
 
769
                        break;
 
770
                case LASSO_PEM_FILE_TYPE_PRIVATE_KEY:
 
771
                        break; /* with a warning ? */
 
772
        }
 
773
        provider->private_data->public_key = pub_key;
 
774
}
 
775
 
 
776
 
 
777
/**
 
778
 * lasso_provider_new_from_dump:
 
779
 * @dump: XML provider dump
 
780
 *
 
781
 * Restores the @dump to a new #LassoProvider.
 
782
 *
 
783
 * Return value: a newly created #LassoProvider; or NULL if an error occured.
 
784
 **/
 
785
LassoProvider*
 
786
lasso_provider_new_from_dump(const gchar *dump)
 
787
{
 
788
        LassoProvider *provider;
 
789
        xmlDoc *doc;
 
790
 
 
791
        provider = g_object_new(LASSO_TYPE_PROVIDER, NULL);
 
792
        doc = xmlParseMemory(dump, strlen(dump));
 
793
        init_from_xml(LASSO_NODE(provider), xmlDocGetRootElement(doc)); 
 
794
 
 
795
        lasso_provider_load_public_key(provider);
 
796
 
 
797
        return provider;
 
798
}
 
799
 
 
800
int lasso_provider_verify_signature(LassoProvider *provider,
 
801
                const char *message, const char *id_attr_name, LassoMessageFormat format)
 
802
{
 
803
        /* this duplicates some code from lasso_node_init_from_message;
 
804
         * reflection about code reuse is under way...
 
805
         */
 
806
        char *msg;
 
807
        xmlDoc *doc;
 
808
        xmlNode *xmlnode = NULL, *sign, *x509data;
 
809
        xmlSecKeysMngr *keys_mngr = NULL;
 
810
        xmlSecDSigCtx *dsigCtx;
 
811
        int rc;
 
812
 
 
813
        msg = (char*)message;
 
814
 
 
815
        if (message == NULL)
 
816
                return -2;
 
817
 
 
818
        if (format == LASSO_MESSAGE_FORMAT_ERROR)
 
819
                return -2;
 
820
        if (format == LASSO_MESSAGE_FORMAT_UNKNOWN)
 
821
                return -2;
 
822
 
 
823
        if (format == LASSO_MESSAGE_FORMAT_QUERY) {
 
824
                return lasso_query_verify_signature(message, provider->private_data->public_key);
 
825
        }
 
826
 
 
827
        if (format == LASSO_MESSAGE_FORMAT_BASE64) {
 
828
                msg = g_malloc(strlen(message));
 
829
                rc = xmlSecBase64Decode(message, msg, strlen(message));
 
830
                if (rc < 0) {
 
831
                        g_free(msg);
 
832
                        return -3;
 
833
                }
 
834
        }
 
835
 
 
836
        doc = xmlParseMemory(msg, strlen(msg));
 
837
        if (format == LASSO_MESSAGE_FORMAT_BASE64) {
 
838
                g_free(msg);
 
839
                msg = NULL;
 
840
        }
 
841
 
 
842
        if (format == LASSO_MESSAGE_FORMAT_SOAP) {
 
843
                xmlXPathContext *xpathCtx = NULL;
 
844
                xmlXPathObject *xpathObj;
 
845
 
 
846
                xpathCtx = xmlXPathNewContext(doc);
 
847
                xmlXPathRegisterNs(xpathCtx, "s", LASSO_SOAP_ENV_HREF);
 
848
                xpathObj = xmlXPathEvalExpression("//s:Body/*", xpathCtx);
 
849
                if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr ) {
 
850
                        xmlnode = xpathObj->nodesetval->nodeTab[0];
 
851
                }
 
852
                xmlXPathFreeObject(xpathObj);
 
853
                xmlXPathFreeContext(xpathCtx);
 
854
                if (xmlnode == NULL) {
 
855
                        xmlFreeDoc(doc);
 
856
                        return -4;
 
857
                }
 
858
        } else {
 
859
                xmlnode = xmlDocGetRootElement(doc);
 
860
        }
 
861
 
 
862
        if (id_attr_name) {
 
863
                char *id_value = xmlGetProp(xmlnode, id_attr_name);
 
864
                xmlAttr *id_attr = xmlHasProp(xmlnode, id_attr_name);
 
865
                if (id_value) {
 
866
                        xmlAddID(NULL, doc, id_value, id_attr);
 
867
                        xmlFree(id_value);
 
868
                }
 
869
        }
 
870
 
 
871
        sign = NULL;
 
872
        for (sign = xmlnode->children; sign; sign = sign->next) {
 
873
                if (strcmp(sign->name, "Signature") == 0)
 
874
                        break;
 
875
        }
 
876
 
 
877
        if (sign == NULL) {
 
878
                xmlFreeDoc(doc);
 
879
                return LASSO_DS_ERROR_SIGNATURE_NOT_FOUND;
 
880
        }
 
881
 
 
882
        x509data = xmlSecFindNode(xmlnode, xmlSecNodeX509Data, xmlSecDSigNs);
 
883
        if (x509data != NULL && provider->ca_cert_chain != NULL) {
 
884
                keys_mngr = lasso_load_certs_from_pem_certs_chain_file(
 
885
                                provider->ca_cert_chain);
 
886
                if (keys_mngr == NULL) {
 
887
                        xmlFreeDoc(doc);
 
888
                        return LASSO_DS_ERROR_CA_CERT_CHAIN_LOAD_FAILED;
 
889
                }
 
890
        }
 
891
 
 
892
        dsigCtx = xmlSecDSigCtxCreate(keys_mngr);
 
893
        if (keys_mngr == NULL) {
 
894
                dsigCtx->signKey = provider->private_data->public_key;
 
895
                if (dsigCtx->signKey == NULL) {
 
896
                        /* XXX: should this be detected on lasso_provider_new ? */
 
897
                        xmlSecDSigCtxDestroy(dsigCtx);
 
898
                        xmlFreeDoc(doc);
 
899
                        return LASSO_DS_ERROR_PUBLIC_KEY_LOAD_FAILED;
 
900
                }
 
901
        }
 
902
 
 
903
        if (xmlSecDSigCtxVerify(dsigCtx, sign) < 0) {
 
904
                xmlSecDSigCtxDestroy(dsigCtx);
 
905
                if (keys_mngr)
 
906
                        xmlSecKeysMngrDestroy(keys_mngr);
 
907
                xmlFreeDoc(doc);
 
908
                return LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED;
 
909
        }
 
910
        if (keys_mngr)
 
911
                xmlSecKeysMngrDestroy(keys_mngr);
 
912
        if (dsigCtx->status != xmlSecDSigStatusSucceeded) {
 
913
                xmlSecDSigCtxDestroy(dsigCtx);
 
914
                xmlFreeDoc(doc);
 
915
                return LASSO_DS_ERROR_INVALID_SIGNATURE;
 
916
        }
 
917
 
 
918
        xmlFreeDoc(doc);
 
919
        return 0;
 
920
}