Missing call to setApplicationID(), fixed.
[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  * Copyright 2001-2009 Internet2
34  * 
35  * Licensed under the Apache License, Version 2.0 (the "License");
36  * you may not use this file except in compliance with the License.
37  * You may obtain a copy of the License at
38  *
39  *     http://www.apache.org/licenses/LICENSE-2.0
40  *
41  * Unless required by applicable law or agreed to in writing, software
42  * distributed under the License is distributed on an "AS IS" BASIS,
43  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
44  * See the License for the specific language governing permissions and
45  * limitations under the License.
46  */
47
48 #include "gssapiP_eap.h"
49
50 #include <shibsp/Application.h>
51 #include <shibsp/exceptions.h>
52 #include <shibsp/SPConfig.h>
53 #include <shibsp/ServiceProvider.h>
54 #include <shibsp/attribute/Attribute.h>
55 #include <shibsp/attribute/SimpleAttribute.h>
56 #include <shibsp/attribute/resolver/ResolutionContext.h>
57 #include <shibsp/handler/AssertionConsumerService.h>
58 #include <shibsp/metadata/MetadataProviderCriteria.h>
59 #include <shibsp/util/SPConstants.h>
60
61 #include <saml/saml1/core/Assertions.h>
62 #include <saml/saml2/core/Assertions.h>
63 #include <saml/saml2/metadata/Metadata.h>
64 #include <xercesc/util/XMLUniDefs.hpp>
65 #include <xmltooling/XMLToolingConfig.h>
66 #include <xmltooling/util/XMLHelper.h>
67
68 #include "resolver.h"
69
70 using namespace shibsp;
71 using namespace shibresolver;
72 using namespace opensaml::saml2md;
73 using namespace opensaml;
74 using namespace xmltooling::logging;
75 using namespace xmltooling;
76 using namespace xercesc;
77 using namespace std;
78
79 static vector <Attribute *>
80 duplicateAttributes(const vector <Attribute *>src);
81
82 /*
83  * Class representing the SAML compoments of a EAP GSS name.
84  */
85 struct gss_eap_saml_attr_ctx
86 {
87 public:
88     gss_eap_saml_attr_ctx(void) {}
89
90     gss_eap_saml_attr_ctx(const vector<Attribute*>& attributes,
91                           const saml2::Assertion *assertion = NULL) {
92         if (assertion != NULL)
93             setAssertion(assertion);
94         if (attributes.size())
95             setAttributes(duplicateAttributes(attributes));
96     }
97
98     gss_eap_saml_attr_ctx(const gss_eap_saml_attr_ctx &ctx) {
99         gss_eap_saml_attr_ctx(ctx.m_attributes, ctx.m_assertion);
100     }
101
102     ~gss_eap_saml_attr_ctx() {
103         for_each(m_attributes.begin(),
104                  m_attributes.end(),
105                  xmltooling::cleanup<Attribute>())
106             ;
107         delete m_assertion;
108     }
109
110     const vector <Attribute *> getAttributes(void) const {
111         return m_attributes;
112     }
113
114     void addAttribute(Attribute *attr, bool copy = true);
115     void setAttributes(const vector<Attribute*> attributes);
116
117     void setAttribute(int complete,
118                       const gss_buffer_t attr,
119                       const gss_buffer_t value);
120     void deleteAttribute(const gss_buffer_t attr);
121
122     int getAttributeIndex(const gss_buffer_t attr) const;
123     const Attribute *getAttribute(const gss_buffer_t attr) const;
124
125     bool getAttribute(const gss_buffer_t attr,
126                       int *authenticated,
127                       int *complete,
128                       gss_buffer_t value,
129                       gss_buffer_t display_value,
130                       int *more);
131
132     const saml2::Assertion *getAssertion(void) const {
133         return m_assertion;
134     }
135
136     void setAssertion(const saml2::Assertion *assertion) {
137         delete m_assertion;
138         if (assertion != NULL)
139             m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
140         else
141             m_assertion = NULL;
142     }
143
144     void setAssertion(const gss_buffer_t buffer) {
145         delete m_assertion;
146         m_assertion = parseAssertion(buffer);
147     }
148
149     bool getAssertion(gss_buffer_t buffer);
150
151     DDF marshall() const;
152     static gss_eap_saml_attr_ctx *unmarshall(DDF &in);
153
154     void marshall(gss_buffer_t buffer);
155     static gss_eap_saml_attr_ctx *unmarshall(const gss_buffer_t buffer);
156
157 private:
158     mutable vector<Attribute*> m_attributes;
159     mutable saml2::Assertion *m_assertion;
160
161     static saml2::Assertion *parseAssertion(const gss_buffer_t buffer);
162 };
163
164 /*
165  * Map an exception to a GSS major/mechanism status code.
166  * TODO
167  */
168 static OM_uint32
169 mapException(OM_uint32 *minor, exception &e)
170 {
171     *minor = 0;
172     return GSS_S_FAILURE;
173 }
174
175 /*
176  * Parse a GSS buffer into a SAML v2 assertion.
177  */
178 saml2::Assertion *
179 gss_eap_saml_attr_ctx::parseAssertion(const gss_buffer_t buffer)
180 {
181     DOMDocument *doc;
182     const XMLObjectBuilder *b;
183     DOMElement *elem;
184     XMLObject *xobj;
185     string str((char *)buffer->value, buffer->length);
186     istringstream istream(str);
187
188     doc = XMLToolingConfig::getConfig().getParser().parse(istream);
189     b = XMLObjectBuilder::getDefaultBuilder();
190     elem = doc->getDocumentElement();
191     xobj = b->buildOneFromElement(elem, true);
192
193     return dynamic_cast<saml2::Assertion *>(xobj);
194 }
195
196 static inline void
197 duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
198 {
199     OM_uint32 minor;
200
201     if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
202         throw new bad_alloc();
203 }
204
205 static inline void
206 duplicateBuffer(string &str, gss_buffer_t buffer)
207 {
208     gss_buffer_desc tmp;
209
210     tmp.length = str.length();
211     tmp.value = (char *)str.c_str();
212
213     duplicateBuffer(tmp, buffer);
214 }
215
216 /*
217  * Marshall SAML attribute context into a form suitable for
218  * exported names.
219  */
220 DDF
221 gss_eap_saml_attr_ctx::marshall() const
222 {
223     DDF obj(NULL);
224     DDF attrs;
225     DDF assertion;
226
227     obj.addmember("version").integer(1);
228
229     attrs = obj.addmember("attributes").list();
230     for (vector<Attribute*>::const_iterator a = m_attributes.begin();
231          a != m_attributes.end(); ++a) {
232         DDF attr = (*a)->marshall();
233         attrs.add(attr);
234     }
235
236     ostringstream sink;
237     sink << *m_assertion;
238     assertion = obj.addmember("assertion").string(sink.str().c_str());
239
240     return obj;
241 }
242
243 /*
244  * Unmarshall SAML attribute context from a form suitable for
245  * exported names.
246  */
247 gss_eap_saml_attr_ctx *
248 gss_eap_saml_attr_ctx::unmarshall(DDF &obj)
249 {
250     gss_eap_saml_attr_ctx *ctx = new gss_eap_saml_attr_ctx();
251
252     DDF version = obj["version"];
253     if (version.integer() != 1)
254         return NULL;
255
256     DDF assertion = obj["assertion"];
257     gss_buffer_desc buffer;
258
259     if (!assertion.isnull()) {
260         buffer.length = assertion.strlen();
261         buffer.value = (void *)assertion.string();
262     } else {
263         buffer.length = 0;
264     }
265
266     if (buffer.length != 0)
267         ctx->parseAssertion(&buffer);
268
269     DDF attrs = obj["attributes"];
270     DDF attr = attrs.first();
271     while (!attr.isnull()) {
272         Attribute *attribute = Attribute::unmarshall(attr);
273         ctx->addAttribute(attribute, false);
274         attr = attrs.next();
275     }
276
277     return ctx;
278 }
279
280 void
281 gss_eap_saml_attr_ctx::marshall(gss_buffer_t buffer)
282 {
283     DDF obj = marshall();
284     ostringstream sink;
285     sink << obj;
286     string str = sink.str();
287
288     duplicateBuffer(str, buffer);
289
290     obj.destroy();
291 }
292
293 gss_eap_saml_attr_ctx *
294 gss_eap_saml_attr_ctx::unmarshall(const gss_buffer_t buffer)
295 {
296     gss_eap_saml_attr_ctx *ctx;
297
298     string str((const char *)buffer->value, buffer->length);
299     istringstream source(str);
300     DDF obj(NULL);
301     source >> obj;
302
303     ctx = unmarshall(obj);
304
305     obj.destroy();
306
307     return ctx;
308 }
309
310 /*
311  * Return the serialised assertion.
312  */
313 bool
314 gss_eap_saml_attr_ctx::getAssertion(gss_buffer_t buffer)
315 {
316     string str;
317
318     if (m_assertion == NULL)
319         return false;
320
321     buffer->value = NULL;
322     buffer->length = 0;
323
324     XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
325
326     duplicateBuffer(str, buffer);
327
328     return true;
329 }
330
331 static Attribute *
332 duplicateAttribute(const Attribute *src)
333 {
334     Attribute *attribute;
335
336     DDF obj = src->marshall();
337     attribute = Attribute::unmarshall(obj);
338     obj.destroy();
339
340     return attribute;
341 }
342
343 static vector <Attribute *>
344 duplicateAttributes(const vector <Attribute *>src)
345 {
346     vector <Attribute *> dst;
347
348     for (vector<Attribute *>::const_iterator a = src.begin();
349          a != src.end();
350          ++a)
351         dst.push_back(duplicateAttribute(*a));
352
353     return dst;
354 }
355
356 void
357 gss_eap_saml_attr_ctx::addAttribute(Attribute *attribute, bool copy)
358 {
359     Attribute *a;
360
361     a = copy ? duplicateAttribute(attribute) : attribute;
362
363     m_attributes.push_back(a);
364 }
365
366 void
367 gss_eap_saml_attr_ctx::setAttributes(const vector<Attribute*> attributes)
368 {
369     for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
370     m_attributes = attributes;
371 }
372
373 int
374 gss_eap_saml_attr_ctx::getAttributeIndex(const gss_buffer_t attr) const
375 {
376     int i = 0;
377
378     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
379          a != getAttributes().end();
380          ++a)
381     {
382         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
383              s != (*a)->getAliases().end();
384              ++s) {
385             if (attr->length == (*s).length() &&
386                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
387                 return i;
388             }
389         }
390     }
391
392     return -1;
393 }
394
395 const Attribute *
396 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr) const
397 {
398     const Attribute *ret = NULL;
399
400     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
401          a != getAttributes().end();
402          ++a)
403     {
404         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
405              s != (*a)->getAliases().end();
406              ++s) {
407             if (attr->length == (*s).length() &&
408                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
409                 ret = *a;
410                 break;
411             }
412         }
413         if (ret != NULL)
414             break;
415     }
416
417     return ret;
418 }
419
420 bool
421 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr,
422                                     int *authenticated,
423                                     int *complete,
424                                     gss_buffer_t value,
425                                     gss_buffer_t display_value,
426                                     int *more)
427 {
428     const Attribute *shibAttr = NULL;
429     gss_buffer_desc buf;
430
431     shibAttr = getAttribute(attr);
432     if (shibAttr == NULL)
433         return false;
434
435     if (*more == -1) {
436         *more = 0;
437     } else if (*more >= (int)shibAttr->valueCount()) {
438         *more = 0;
439         return true;
440     }
441
442     buf.value = (void *)shibAttr->getString(*more);
443     buf.length = strlen((char *)buf.value);
444
445     duplicateBuffer(buf, value);
446  
447     *authenticated = TRUE;
448     *complete = FALSE;
449
450     return true;
451 }
452
453 static Attribute *
454 samlAttributeFromGssBuffers(const gss_buffer_t attr,
455                             const gss_buffer_t value)
456 {
457     string attrStr((char *)attr->value, attr->length);
458     vector <string> ids(1);
459     SimpleAttribute *a;
460
461     ids.push_back(attrStr);
462
463     a = new SimpleAttribute(ids);
464
465     if (value->length != 0) {
466         string valStr((char *)value->value, value->length);
467
468         a->getValues().push_back(valStr);        
469     }
470
471     return a;
472 }
473
474 void
475 gss_eap_saml_attr_ctx::setAttribute(int complete,
476                                     const gss_buffer_t attr,
477                                     const gss_buffer_t value)
478 {
479     Attribute *a = samlAttributeFromGssBuffers(attr, value);
480
481     addAttribute(a, false);
482 }
483
484 void
485 gss_eap_saml_attr_ctx::deleteAttribute(const gss_buffer_t attr)
486 {
487     int i;
488
489     i = getAttributeIndex(attr);
490     if (i >= 0)
491         m_attributes.erase(m_attributes.begin() + i);
492 }
493
494 OM_uint32
495 samlReleaseAttrContext(OM_uint32 *minor, gss_name_t name)
496 {
497     try {
498         delete name->samlCtx;
499         name->samlCtx = NULL;
500     } catch (exception &e) {
501         return mapException(minor, e);
502     }
503
504     return GSS_S_COMPLETE;
505 }
506
507 static gss_buffer_desc
508 gssEapRadiusAssertionAttr = { 3, (void *)"128" };   /* TODO */
509
510 class gss_eap_saml_attr_args {
511 public:
512     vector <Attribute *> attrs;
513     ShibbolethResolver *resolver;
514 };
515
516 /*
517  * Callback to add a RADIUS attribute as input to the resolver.
518  */
519 static OM_uint32
520 samlAddRadiusAttribute(OM_uint32 *minor,
521                        gss_name_t name,
522                        gss_buffer_t attr,
523                        void *data)
524 {
525     OM_uint32 major;
526     gss_eap_saml_attr_args *args = (gss_eap_saml_attr_args *)data;
527     Attribute *a;
528     int authenticated, complete, more = -1;
529     gss_buffer_desc value;
530
531     /* Put attributes to skip here (or in a table somewhere) */
532     if (bufferEqual(attr, &gssEapRadiusAssertionAttr)) {
533         return GSS_S_COMPLETE;
534     }
535
536     major = radiusGetAttribute(minor, name, attr,
537                                &authenticated, &complete,
538                                &value, GSS_C_NO_BUFFER, &more);
539     if (major == GSS_S_COMPLETE) {
540         /* XXX TODO prefix */
541         a = samlAttributeFromGssBuffers(attr, &value);
542         args->attrs.push_back(a);
543         args->resolver->addAttribute(a);
544     }
545
546     return GSS_S_COMPLETE;
547 }
548
549 /*
550  * Add attributes retrieved via RADIUS.
551  */
552 static OM_uint32
553 samlAddRadiusAttributes(OM_uint32 *minor,
554                         gss_name_t name,
555                         gss_eap_saml_attr_args *args)
556 {
557     return radiusGetAttributeTypes(minor,
558                                    name,
559                                    samlAddRadiusAttribute,
560                                    (void *)args);
561 }
562
563 /*
564  * Add assertion retrieved via RADIUS.
565  */
566 static OM_uint32
567 samlAddRadiusAssertion(OM_uint32 *minor,
568                        gss_name_t name,
569                        gss_eap_saml_attr_ctx *ctx)
570 {
571     OM_uint32 major;
572     int authenticated, complete, more = -1;
573     gss_buffer_desc value;
574
575     value.value = NULL;
576     value.length = 0;
577
578     major = radiusGetAttribute(minor, name, &gssEapRadiusAssertionAttr,
579                                &authenticated, &complete,
580                                &value, GSS_C_NO_BUFFER, &more);
581     if (GSS_ERROR(major) && major != GSS_S_UNAVAILABLE)
582         return major;
583
584     ctx->setAssertion(&value);
585
586     gss_release_buffer(minor, &value);
587
588     return GSS_S_COMPLETE;
589 }
590
591 /*
592  * Initialise SAML attribute context in initiator name. RADIUS context
593  * must have been previously initialised.
594  */
595 OM_uint32
596 samlCreateAttrContext(OM_uint32 *minor,
597                       gss_cred_id_t acceptorCred,
598                       gss_name_t initiatorName,
599                       time_t *pExpiryTime)
600 {
601     OM_uint32 major, tmpMinor;
602     gss_buffer_desc nameBuf;
603     gss_eap_saml_attr_ctx *ctx = NULL;
604     ShibbolethResolver *resolver = NULL;
605     gss_eap_saml_attr_args args;
606
607     assert(initiatorName != GSS_C_NO_NAME);
608
609     if (initiatorName->radiusCtx == NULL)
610         return GSS_S_UNAVAILABLE;
611
612     nameBuf.length = 0;
613     nameBuf.value = NULL;
614
615     resolver = ShibbolethResolver::create();
616     if (resolver == NULL)
617         return GSS_S_FAILURE;
618
619     args.resolver = resolver;
620
621     if (acceptorCred != GSS_C_NO_CREDENTIAL) {
622         major = gss_display_name(minor, acceptorCred->name, &nameBuf, NULL);
623         if (GSS_ERROR(major))
624             goto cleanup;
625     }
626
627     try {
628         const saml2::Assertion *assertion;
629         vector <Attribute *> attrs;
630
631         ctx = new gss_eap_saml_attr_ctx();
632
633         major = samlAddRadiusAssertion(minor, initiatorName, ctx);
634         if (GSS_ERROR(major))
635             goto cleanup;
636
637         assertion = ctx->getAssertion();
638
639         if (assertion != NULL) {
640             if (assertion->getConditions()) {
641                 *pExpiryTime =
642                     assertion->getConditions()->getNotOnOrAfter()->getEpoch();
643             }
644
645             resolver->addToken(assertion);
646         }
647
648         resolver->setApplicationID((const char *)nameBuf.value);
649         if (initiatorName->radiusCtx != NULL)
650             samlAddRadiusAttributes(minor, initiatorName, &args);
651         resolver->resolveAttributes(attrs);
652         ctx->setAttributes(attrs);
653     } catch (exception &ex) {
654         major = mapException(minor, ex);
655         goto cleanup;
656     }
657
658     *minor = 0;
659     major = GSS_S_COMPLETE;
660
661     initiatorName->samlCtx = ctx;
662
663 cleanup:
664     for_each(args.attrs.begin(), args.attrs.end(), xmltooling::cleanup<Attribute>());
665     gss_release_buffer(&tmpMinor, &nameBuf);
666     if (GSS_ERROR(major))
667         delete ctx;
668     delete resolver;
669
670     return major;
671 }
672
673 OM_uint32
674 samlGetAttributeTypes(OM_uint32 *minor,
675                       gss_name_t name,
676                       enum gss_eap_attribute_type type,
677                       gss_eap_add_attr_cb addAttribute,
678                       void *data)
679 {
680     OM_uint32 major = GSS_S_COMPLETE;
681     gss_eap_saml_attr_ctx *ctx = name->samlCtx;
682
683     if (ctx == NULL)
684         return GSS_S_COMPLETE;
685
686     if (type != ATTR_TYPE_NONE)
687         return GSS_S_UNAVAILABLE;
688
689     for (vector<Attribute*>::const_iterator a = ctx->getAttributes().begin();
690         a != ctx->getAttributes().end();
691         ++a)
692     {
693         gss_buffer_desc attribute;
694
695         attribute.value = (void *)((*a)->getId());
696         attribute.length = strlen((char *)attribute.value);
697
698         major = addAttribute(minor, name, &attribute, data);
699         if (GSS_ERROR(major))
700             break;
701     }
702
703     return major;
704 }
705
706 /*
707  * SAML implementation of gss_get_name_attribute
708  */
709 OM_uint32
710 samlGetAttribute(OM_uint32 *minor,
711                  enum gss_eap_attribute_type type,
712                  gss_name_t name,
713                  gss_buffer_t attr,
714                  int *authenticated,
715                  int *complete,
716                  gss_buffer_t value,
717                  gss_buffer_t display_value,
718                  int *more)
719 {
720     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
721     bool ret;
722
723     if (ctx == NULL)
724         return GSS_S_UNAVAILABLE;
725
726     switch (type) {
727     case ATTR_TYPE_NONE:
728         ret = ctx->getAttribute(attr, authenticated, complete,
729                                 value, display_value, more);
730         break;
731     default:
732         ret = false;
733         break;
734     }
735
736     return ret ? GSS_S_COMPLETE : GSS_S_UNAVAILABLE;
737 }
738
739 OM_uint32
740 samlSetAttribute(OM_uint32 *minor,
741                  gss_name_t name,
742                  int complete,
743                  gss_buffer_t attr,
744                  gss_buffer_t value)
745 {
746     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
747
748     if (ctx == NULL)
749         return GSS_S_UNAVAILABLE;
750
751     try {
752         ctx->setAttribute(complete, attr, value);
753     } catch (exception &e) {
754         return mapException(minor, e);
755     }
756
757     return GSS_S_COMPLETE;
758 }
759
760 OM_uint32
761 samlDeleteAttribute(OM_uint32 *minor,
762                     gss_name_t name,
763                     gss_buffer_t attr)
764 {
765     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
766
767     if (ctx == NULL)
768         return GSS_S_UNAVAILABLE;
769
770     try {
771         ctx->deleteAttribute(attr);
772     } catch (exception &e) {
773         return mapException(minor, e);
774     }
775
776     return GSS_S_COMPLETE;
777 }
778
779 /*
780  * In order to implement gss_export_name and gss_export_sec_context,
781  * we need to serialise a resolved attribute context to a buffer.
782  */
783 OM_uint32
784 samlExportAttrContext(OM_uint32 *minor,
785                       gss_name_t name,
786                       gss_buffer_t buffer)
787 {
788     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
789
790     try {
791         ctx->marshall(buffer);
792     } catch (exception &e) {
793         return mapException(minor, e);
794     }        
795
796     return GSS_S_COMPLETE;
797 }
798
799 /*
800  * In order to implement gss_import_name and gss_import_sec_context,
801  * we need to deserialise a resolved attribute context from a buffer.
802  */
803 OM_uint32
804 samlImportAttrContext(OM_uint32 *minor,
805                       gss_buffer_t buffer,
806                       gss_name_t name)
807 {
808     try {
809         assert(name->samlCtx == NULL);
810         name->samlCtx = gss_eap_saml_attr_ctx::unmarshall(buffer);
811     } catch (exception &e) {
812         return mapException(minor, e);
813     }
814
815     return GSS_S_COMPLETE;
816 }
817
818 OM_uint32
819 samlGetAssertion(OM_uint32 *minor,
820                  gss_name_t name,
821                  gss_buffer_t assertion)
822 {
823     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
824
825     if (ctx == NULL)
826         return GSS_S_UNAVAILABLE;
827
828     try {
829         ctx->getAssertion(assertion);
830     } catch (exception &e) {
831         return mapException(minor, e);
832     }
833
834     return GSS_S_COMPLETE;
835 }
836
837 OM_uint32
838 samlDuplicateAttrContext(OM_uint32 *minor,
839                          gss_name_t in,
840                          gss_name_t out)
841 {
842     try {
843         if (in->samlCtx != NULL)
844             out->samlCtx = new gss_eap_saml_attr_ctx(*(in->samlCtx));
845         else
846             out->samlCtx = NULL;
847     } catch (exception &e) {
848         return mapException(minor, e);
849     }
850
851     return GSS_S_COMPLETE;
852 }
853
854 OM_uint32
855 samlMapNameToAny(OM_uint32 *minor,
856                  gss_name_t name,
857                  int authenticated,
858                  gss_buffer_t type_id,
859                  gss_any_t *output)
860 {
861     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
862
863     if (bufferEqualString(type_id, "shibsp::Attribute")) {
864         vector <Attribute *>v = duplicateAttributes(ctx->getAttributes());
865
866         *output = (gss_any_t)new vector <Attribute *>(v);
867     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
868         *output = (gss_any_t)ctx->getAssertion()->clone();
869     } else {
870         *output = (gss_any_t)NULL;
871         return GSS_S_UNAVAILABLE;
872     }
873
874     return GSS_S_COMPLETE;
875 }
876
877 OM_uint32
878 samlReleaseAnyNameMapping(OM_uint32 *minor,
879                           gss_name_t name,
880                           gss_buffer_t type_id,
881                           gss_any_t *input)
882 {
883     if (bufferEqualString(type_id, "vector<shibsp::Attribute>")) {
884         vector <Attribute *> *v = ((vector <Attribute *> *)*input);
885         delete v;
886     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
887         delete (Assertion *)*input;
888     } else {
889         return GSS_S_UNAVAILABLE;
890     }
891
892     *input = (gss_any_t)NULL;
893     return GSS_S_COMPLETE;
894 }
895
896 OM_uint32
897 samlInit(OM_uint32 *minor)
898 {
899     *minor = 0;
900
901     return ShibbolethResolver::init() ? GSS_S_COMPLETE : GSS_S_FAILURE;
902 }
903
904 OM_uint32
905 samlFinalize(OM_uint32 *minor)
906 {
907     *minor = 0;
908
909     ShibbolethResolver::term();
910     return GSS_S_COMPLETE;
911 }