Fix some build errors, and build with flat_namespace
[mech_eap.git] / util_saml.cpp
1 /*
2  * Copyright (c) 2010, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include "gssapiP_eap.h"
34
35 #include <sstream>
36
37 #include <xercesc/util/XMLUniDefs.hpp>
38 #include <xmltooling/unicode.h>
39 #include <xmltooling/XMLToolingConfig.h>
40 #include <xmltooling/util/XMLHelper.h>
41 #include <xmltooling/util/ParserPool.h>
42 #include <xmltooling/util/DateTime.h>
43
44 #include <saml/saml1/core/Assertions.h>
45 #include <saml/saml2/core/Assertions.h>
46 #include <saml/saml2/metadata/Metadata.h>
47
48 using namespace xmltooling;
49 using namespace opensaml::saml2md;
50 using namespace opensaml;
51 using namespace xercesc;
52 using namespace std;
53
54 /*
55  * gss_eap_saml_assertion_provider is for retrieving the underlying
56  * assertion.
57  */
58 gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
59 {
60     m_assertion = NULL;
61     m_authenticated = false;
62 }
63
64 gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
65 {
66     delete m_assertion;
67 }
68
69 bool
70 gss_eap_saml_assertion_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
71                                                          const gss_eap_attr_provider *ctx)
72 {
73     /* Then we may be creating from an existing attribute context */
74     const gss_eap_saml_assertion_provider *saml;
75
76     assert(m_assertion == NULL);
77
78     if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
79         return false;
80
81     saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
82     setAssertion(saml->getAssertion(), saml->authenticated());
83
84     return true;
85 }
86
87 bool
88 gss_eap_saml_assertion_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
89                                                     const gss_cred_id_t gssCred,
90                                                     const gss_ctx_id_t gssCtx)
91 {
92     const gss_eap_radius_attr_provider *radius;
93     gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
94     int authenticated, complete;
95     OM_uint32 minor;
96
97     assert(m_assertion == NULL);
98
99     if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
100         return false;
101
102     /*
103      * XXX TODO we need to support draft-howlett-radius-saml-attr-00
104      */
105     radius = static_cast<const gss_eap_radius_attr_provider *>
106         (m_manager->getProvider(ATTR_TYPE_RADIUS));
107     if (radius != NULL &&
108         radius->getFragmentedAttribute(VENDOR_ATTR_SAML_AAA_ASSERTION,
109                                        VENDOR_ID_UKERNA,
110                                        &authenticated, &complete, &value)) {
111         setAssertion(&value, authenticated);
112         gss_release_buffer(&minor, &value);
113     } else {
114         m_assertion = NULL;
115     }
116
117     return true;
118 }
119
120 void
121 gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
122                                               bool authenticated)
123 {
124
125     delete m_assertion;
126
127     if (assertion != NULL) {
128 #if 0
129         XMLObject *tmp = assertion->clone();
130         m_assertion = dynamic_cast<saml2::Assertion *>(tmp);
131 //        m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
132 #else
133         m_assertion = (saml2::Assertion *)((void *)assertion->clone());
134 #endif
135         m_authenticated = authenticated;
136     } else {
137         m_assertion = NULL;
138         m_authenticated = false;
139     }
140 }
141
142 void
143 gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
144                                               bool authenticated)
145 {
146     delete m_assertion;
147
148     m_assertion = parseAssertion(buffer);
149     m_authenticated = (m_assertion != NULL && authenticated);
150 }
151
152 saml2::Assertion *
153 gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
154 {
155     string str((char *)buffer->value, buffer->length);
156     istringstream istream(str);
157     DOMDocument *doc;
158     const XMLObjectBuilder *b;
159
160     doc = XMLToolingConfig::getConfig().getParser().parse(istream);
161     if (doc == NULL)
162         return NULL;
163
164     b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
165
166 #if 0
167     return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
168 #else
169     return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
170 #endif
171 }
172
173 bool
174 gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
175                                                    void *data) const
176 {
177     bool ret;
178
179     /* just add the prefix */
180     if (m_assertion != NULL)
181         ret = addAttribute(this, GSS_C_NO_BUFFER, data);
182     else
183         ret = true;
184
185     return ret;
186 }
187
188 void
189 gss_eap_saml_assertion_provider::setAttribute(int complete,
190                                               const gss_buffer_t attr,
191                                               const gss_buffer_t value)
192 {
193     if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
194         setAssertion(value);
195     }
196 }
197
198 void
199 gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value)
200 {
201     delete m_assertion;
202     m_assertion = NULL;
203     m_authenticated = false;
204 }
205
206 time_t
207 gss_eap_saml_assertion_provider::getExpiryTime(void) const
208 {
209     saml2::Conditions *conditions;
210     time_t expiryTime = 0;
211
212     if (m_assertion == NULL)
213         return 0;
214
215     conditions = m_assertion->getConditions();
216
217     if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
218         expiryTime = conditions->getNotOnOrAfter()->getEpoch();
219
220     return expiryTime;
221 }
222
223 bool
224 gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
225                                               int *authenticated,
226                                               int *complete,
227                                               gss_buffer_t value,
228                                               gss_buffer_t display_value,
229                                               int *more) const
230 {
231     string str;
232
233     if (attr != GSS_C_NO_BUFFER && attr->length != 0)
234         return false;
235
236     if (m_assertion == NULL)
237         return false;
238
239     if (*more != -1)
240         return false;
241
242     if (authenticated != NULL)
243         *authenticated = m_authenticated;
244     if (complete != NULL)
245         *complete = true;
246
247     XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
248
249     duplicateBuffer(str, value);
250     *more = 0;
251
252     return true;
253 }
254
255 gss_any_t
256 gss_eap_saml_assertion_provider::mapToAny(int authenticated,
257                                           gss_buffer_t type_id) const
258 {
259     if (authenticated && !m_authenticated)
260         return (gss_any_t)NULL;
261
262     return (gss_any_t)m_assertion;
263 }
264
265 void
266 gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id,
267                                                        gss_any_t input) const
268 {
269     delete ((saml2::Assertion *)input);
270 }
271
272 void
273 gss_eap_saml_assertion_provider::exportToBuffer(gss_buffer_t buffer) const
274 {
275     ostringstream sink;
276     string str;
277
278     buffer->length = 0;
279     buffer->value = NULL;
280
281     if (m_assertion == NULL)
282         return;
283
284     sink << *m_assertion;
285     str = sink.str();
286
287     duplicateBuffer(str, buffer);
288 }
289
290 bool
291 gss_eap_saml_assertion_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
292                                                 const gss_buffer_t buffer)
293 {
294     if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
295         return false;
296
297     if (buffer->length == 0)
298         return true;
299
300     assert(m_assertion == NULL);
301
302     setAssertion(buffer);
303     /* TODO XXX how to propagate authenticated flag? */
304
305     return true;
306 }
307
308 bool
309 gss_eap_saml_assertion_provider::init(void)
310 {
311     gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION,
312                                        "urn:ietf:params:gss-eap:saml-aaa-assertion",
313                                        gss_eap_saml_assertion_provider::createAttrContext);
314     return true;
315 }
316
317 void
318 gss_eap_saml_assertion_provider::finalize(void)
319 {
320     gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION);
321 }
322
323 gss_eap_attr_provider *
324 gss_eap_saml_assertion_provider::createAttrContext(void)
325 {
326     return new gss_eap_saml_assertion_provider;
327 }
328
329 /*
330  * gss_eap_saml_attr_provider is for retrieving the underlying attributes.
331  */
332 bool
333 gss_eap_saml_attr_provider::getAssertion(int *authenticated,
334                                          const saml2::Assertion **pAssertion) const
335 {
336     const gss_eap_saml_assertion_provider *saml;
337
338     if (authenticated != NULL)
339         *authenticated = false;
340     if (pAssertion != NULL)
341         *pAssertion = NULL;
342
343     saml = static_cast<const gss_eap_saml_assertion_provider *>
344         (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
345     if (saml == NULL)
346         return false;
347
348     if (authenticated != NULL)
349         *authenticated = saml->authenticated();
350     if (pAssertion != NULL)
351         *pAssertion = saml->getAssertion();
352
353     return (saml->getAssertion() != NULL);
354 }
355
356 bool
357 gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
358                                               void *data) const
359 {
360     const saml2::Assertion *assertion;
361     bool ret = true;
362     int authenticated;
363
364     if (!getAssertion(&authenticated, &assertion))
365         return true;
366
367     /*
368      * Note: the first prefix is added by the attribute provider manager
369      *
370      * From draft-hartman-gss-eap-naming-00:
371      *
372      *   Each attribute carried in the assertion SHOULD also be a GSS name
373      *   attribute.  The name of this attribute has three parts, all separated
374      *   by an ASCII space character.  The first part is
375      *   urn:ietf:params:gss-eap:saml-attr.  The second part is the URI for
376      *   the SAML attribute name format.  The final part is the name of the
377      *   SAML attribute.  If the mechanism performs an additional attribute
378      *   query, the retrieved attributes SHOULD be GSS-API name attributes
379      *   using the same name syntax.
380      */
381     const vector<saml2::Attribute*>& attrs2 =
382         const_cast<const saml2::AttributeStatement*>(assertion->getAttributeStatements().front())->getAttributes();
383     for (vector<saml2::Attribute*>::const_iterator a = attrs2.begin();
384         a != attrs2.end();
385         ++a)
386     {
387         const XMLCh *attributeName = (*a)->getName();
388         const XMLCh *attributeNameFormat = (*a)->getNameFormat();
389         XMLCh *qualifiedName;
390         XMLCh space[2] = { ' ', 0 };
391         gss_buffer_desc utf8;
392
393         qualifiedName = new XMLCh[XMLString::stringLen(attributeNameFormat) + 1 +
394                                   XMLString::stringLen(attributeName) + 1];
395         XMLString::copyString(qualifiedName, attributeNameFormat);
396         XMLString::catString(qualifiedName, space);
397         XMLString::catString(qualifiedName, attributeName);
398
399         utf8.value = (void *)toUTF8(qualifiedName);
400         utf8.length = strlen((char *)utf8.value);
401
402         ret = addAttribute(this, &utf8, data);
403
404         delete qualifiedName;
405
406         if (!ret)
407             break;
408     }
409
410     return ret;
411 }
412
413 void
414 gss_eap_saml_attr_provider::setAttribute(int complete,
415                                          const gss_buffer_t attr,
416                                          const gss_buffer_t value)
417 {
418 }
419
420 void
421 gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t value)
422 {
423 }
424
425 static BaseRefVectorOf<XMLCh> *
426 decomposeAttributeName(const gss_buffer_t attr)
427 {
428     XMLCh *qualifiedAttr = new XMLCh[attr->length + 1];
429     XMLString::transcode((const char *)attr->value, qualifiedAttr, attr->length);
430
431     BaseRefVectorOf<XMLCh> *components = XMLString::tokenizeString(qualifiedAttr);
432
433     delete qualifiedAttr;
434
435     return components;
436 }
437
438 bool
439 gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
440                                          int *authenticated,
441                                          int *complete,
442                                          const saml2::Attribute **pAttribute) const
443 {
444     const saml2::Assertion *assertion;
445
446     if (authenticated != NULL)
447         *authenticated = false;
448     if (complete != NULL)
449         *complete = true;
450     *pAttribute = NULL;
451
452     if (!getAssertion(authenticated, &assertion) ||
453         assertion->getAttributeStatements().size() == 0)
454         return false;
455
456     /* Check the attribute name consists of name format | whsp | name */
457     BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
458     if (components == NULL || components->size() != 2) {
459         delete components;
460         return false;
461     }
462
463     /* For each attribute statement, look for an attribute match */
464     const vector <saml2::AttributeStatement *>&statements =
465         assertion->getAttributeStatements();
466     const saml2::Attribute *ret = NULL;
467
468     for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
469         s != statements.end();
470         ++s) {
471         const vector<saml2::Attribute*>& attrs =
472             const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
473
474         for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
475             if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
476                 XMLString::equals((*a)->getName(), components->elementAt(1))) {
477                 ret = *a;
478                 break;
479             }
480         }
481
482         if (ret != NULL)
483             break;
484     }
485
486     delete components;
487
488     *pAttribute = ret;
489
490     return (ret != NULL);
491 }
492
493 bool
494 gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
495                                          int *authenticated,
496                                          int *complete,
497                                          gss_buffer_t value,
498                                          gss_buffer_t display_value,
499                                          int *more) const
500 {
501     const saml2::Attribute *a;
502     const saml2::AttributeValue *av;
503     int nvalues, i = *more;
504
505     *more = 0;
506
507     if (!getAttribute(attr, authenticated, complete, &a))
508         return false;
509
510     nvalues = a->getAttributeValues().size();
511
512     if (i == -1)
513         i = 0;
514     else if (i >= nvalues)
515         return false;
516 #if 0
517     av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
518 #else
519     av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
520 #endif
521     if (av != NULL) {
522         if (value != NULL) {
523             value->value = toUTF8(av->getTextContent(), true);
524             value->length = strlen((char *)value->value);
525         }
526         if (display_value != NULL) {
527             display_value->value = toUTF8(av->getTextContent(), true);
528             display_value->length = strlen((char *)value->value);
529         }
530     }
531
532     if (nvalues > ++i)
533         *more = i;
534
535     return true;
536 }
537
538 gss_any_t
539 gss_eap_saml_attr_provider::mapToAny(int authenticated,
540                                      gss_buffer_t type_id) const
541 {
542     return (gss_any_t)NULL;
543 }
544
545 void
546 gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
547                                                   gss_any_t input) const
548 {
549 }
550
551 void
552 gss_eap_saml_attr_provider::exportToBuffer(gss_buffer_t buffer) const
553 {
554     buffer->length = 0;
555     buffer->value = NULL;
556 }
557
558 bool
559 gss_eap_saml_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
560                                            const gss_buffer_t buffer)
561 {
562     return gss_eap_attr_provider::initFromBuffer(ctx, buffer);
563 }
564
565 bool
566 gss_eap_saml_attr_provider::init(void)
567 {
568     gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML,
569                                        "urn:ietf:params:gss-eap:saml-attr",
570                                        gss_eap_saml_attr_provider::createAttrContext);
571     return true;
572 }
573
574 void
575 gss_eap_saml_attr_provider::finalize(void)
576 {
577     gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
578 }
579
580 gss_eap_attr_provider *
581 gss_eap_saml_attr_provider::createAttrContext(void)
582 {
583     return new gss_eap_saml_attr_provider;
584 }
585
586 OM_uint32
587 gssEapSamlAttrProvidersInit(OM_uint32 *minor)
588 {
589     if (gss_eap_saml_assertion_provider::init() &&
590         gss_eap_saml_attr_provider::init())
591         return GSS_S_COMPLETE;
592
593     return GSS_S_FAILURE;
594 }
595
596 OM_uint32
597 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
598 {
599     gss_eap_saml_attr_provider::finalize();
600     gss_eap_saml_assertion_provider::finalize();
601     return GSS_S_COMPLETE;
602 }