More work on SAML code
[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 struct gss_eap_saml_attr_ctx
83 {
84 public:
85     gss_eap_saml_attr_ctx(const gss_buffer_t buffer = GSS_C_NO_BUFFER) {
86         if (buffer != GSS_C_NO_BUFFER && buffer->length != 0)
87             parseAssertion(buffer);
88     }
89
90     gss_eap_saml_attr_ctx(const vector<Attribute*>& attributes,
91                           const saml2::Assertion *assertion = NULL) {
92         if (assertion != NULL)
93             m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
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     bool getAssertion(gss_buffer_t buffer);
137
138     DDF marshall() const;
139     static gss_eap_saml_attr_ctx *unmarshall(DDF &in);
140
141     void marshall(gss_buffer_t buffer);
142     static gss_eap_saml_attr_ctx *unmarshall(const gss_buffer_t buffer);
143
144 private:
145     mutable vector<Attribute*> m_attributes;
146     mutable saml2::Assertion *m_assertion;
147
148     bool parseAssertion(const gss_buffer_t buffer);
149 };
150
151 static OM_uint32
152 mapException(OM_uint32 *minor, exception &e)
153 {
154     *minor = 0;
155     return GSS_S_FAILURE;
156 }
157
158 bool
159 gss_eap_saml_attr_ctx::parseAssertion(const gss_buffer_t buffer)
160 {
161     DOMDocument *doc;
162     const XMLObjectBuilder *b;
163     DOMElement *elem;
164     XMLObject *xobj;
165     string str((char *)buffer->value, buffer->length);
166     istringstream istream(str);
167
168     doc = XMLToolingConfig::getConfig().getParser().parse(istream);
169     b = XMLObjectBuilder::getDefaultBuilder();
170     elem = doc->getDocumentElement();
171     xobj = b->buildOneFromElement(elem, true);
172
173     m_assertion = dynamic_cast<saml2::Assertion *>(xobj);
174
175     return (m_assertion != NULL);
176 }
177
178 static inline void
179 duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
180 {
181     OM_uint32 minor;
182
183     if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
184         throw new bad_alloc();
185 }
186
187 static inline void
188 duplicateBuffer(string &str, gss_buffer_t buffer)
189 {
190     gss_buffer_desc tmp;
191
192     tmp.length = str.length();
193     tmp.value = (char *)str.c_str();
194
195     duplicateBuffer(tmp, buffer);
196 }
197
198 DDF
199 gss_eap_saml_attr_ctx::marshall() const
200 {
201     DDF obj(NULL);
202     DDF attrs;
203     DDF assertion;
204
205     obj.addmember("version").integer(1);
206
207     attrs = obj.addmember("attributes").list();
208     for (vector<Attribute*>::const_iterator a = m_attributes.begin();
209          a != m_attributes.end(); ++a) {
210         DDF attr = (*a)->marshall();
211         attrs.add(attr);
212     }
213
214     ostringstream sink;
215     sink << *m_assertion;
216     assertion = obj.addmember("assertion").string(sink.str().c_str());
217
218     return obj;
219 }
220
221 gss_eap_saml_attr_ctx *
222 gss_eap_saml_attr_ctx::unmarshall(DDF &obj)
223 {
224     gss_eap_saml_attr_ctx *ctx = new gss_eap_saml_attr_ctx();
225
226     DDF version = obj["version"];
227     if (version.integer() != 1)
228         return NULL;
229
230     DDF assertion = obj["assertion"];
231     gss_buffer_desc buffer;
232
233     if (!assertion.isnull()) {
234         buffer.length = assertion.strlen();
235         buffer.value = (void *)assertion.string();
236     } else {
237         buffer.length = 0;
238     }
239
240     if (buffer.length != 0)
241         ctx->parseAssertion(&buffer);
242
243     DDF attrs = obj["attributes"];
244     DDF attr = attrs.first();
245     while (!attr.isnull()) {
246         Attribute *attribute = Attribute::unmarshall(attr);
247         ctx->addAttribute(attribute, false);
248         attr = attrs.next();
249     }
250
251     return ctx;
252 }
253
254 void
255 gss_eap_saml_attr_ctx::marshall(gss_buffer_t buffer)
256 {
257     DDF obj = marshall();
258     ostringstream sink;
259     sink << obj;
260     string str = sink.str();
261
262     duplicateBuffer(str, buffer);
263
264     obj.destroy();
265 }
266
267 gss_eap_saml_attr_ctx *
268 gss_eap_saml_attr_ctx::unmarshall(const gss_buffer_t buffer)
269 {
270     gss_eap_saml_attr_ctx *ctx;
271
272     string str((const char *)buffer->value, buffer->length);
273     istringstream source(str);
274     DDF obj(NULL);
275     source >> obj;
276
277     ctx = unmarshall(obj);
278
279     obj.destroy();
280
281     return ctx;
282 }
283
284 bool
285 gss_eap_saml_attr_ctx::getAssertion(gss_buffer_t buffer)
286 {
287     string str;
288
289     if (m_assertion == NULL)
290         return false;
291
292     buffer->value = NULL;
293     buffer->length = 0;
294
295     XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
296
297     duplicateBuffer(str, buffer);
298
299     return true;
300 }
301
302 static Attribute *
303 duplicateAttribute(const Attribute *src)
304 {
305     Attribute *attribute;
306
307     DDF obj = src->marshall();
308     attribute = Attribute::unmarshall(obj);
309     obj.destroy();
310
311     return attribute;
312 }
313
314 static vector <Attribute *>
315 duplicateAttributes(const vector <Attribute *>src)
316 {
317     vector <Attribute *> dst;
318
319     for (vector<Attribute *>::const_iterator a = src.begin();
320          a != src.end();
321          ++a)
322         dst.push_back(duplicateAttribute(*a));
323
324     return dst;
325 }
326
327 void
328 gss_eap_saml_attr_ctx::addAttribute(Attribute *attribute, bool copy)
329 {
330     Attribute *a;
331
332     a = copy ? duplicateAttribute(attribute) : attribute;
333
334     m_attributes.push_back(a);
335 }
336
337 void
338 gss_eap_saml_attr_ctx::setAttributes(const vector<Attribute*> attributes)
339 {
340     for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
341     m_attributes = attributes;
342 }
343
344 int
345 gss_eap_saml_attr_ctx::getAttributeIndex(const gss_buffer_t attr) const
346 {
347     int i = 0;
348
349     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
350          a != getAttributes().end();
351          ++a)
352     {
353         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
354              s != (*a)->getAliases().end();
355              ++s) {
356             if (attr->length == (*s).length() &&
357                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
358                 return i;
359             }
360         }
361     }
362
363     return -1;
364 }
365
366 const Attribute *
367 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr) const
368 {
369     const Attribute *ret = NULL;
370
371     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
372          a != getAttributes().end();
373          ++a)
374     {
375         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
376              s != (*a)->getAliases().end();
377              ++s) {
378             if (attr->length == (*s).length() &&
379                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
380                 ret = *a;
381                 break;
382             }
383         }
384         if (ret != NULL)
385             break;
386     }
387
388     return ret;
389 }
390
391 bool
392 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr,
393                                     int *authenticated,
394                                     int *complete,
395                                     gss_buffer_t value,
396                                     gss_buffer_t display_value,
397                                     int *more)
398 {
399     const Attribute *shibAttr = NULL;
400     gss_buffer_desc buf;
401
402     shibAttr = getAttribute(attr);
403     if (shibAttr == NULL)
404         return false;
405
406     if (*more == -1) {
407         *more = 0;
408     } else if (*more >= (int)shibAttr->valueCount()) {
409         *more = 0;
410         return true;
411     }
412
413     buf.value = (void *)shibAttr->getString(*more);
414     buf.length = strlen((char *)buf.value);
415
416     duplicateBuffer(buf, value);
417  
418     *authenticated = TRUE;
419     *complete = FALSE;
420
421     return true;
422 }
423
424 static Attribute *
425 samlAttributeFromGssBuffers(const gss_buffer_t attr,
426                             const gss_buffer_t value)
427 {
428     string attrStr((char *)attr->value, attr->length);
429     vector <string> ids(1);
430     SimpleAttribute *a;
431
432     ids.push_back(attrStr);
433
434     a = new SimpleAttribute(ids);
435
436     if (value->length != 0) {
437         string valStr((char *)value->value, value->length);
438
439         a->getValues().push_back(valStr);        
440     }
441
442     return a;
443 }
444
445 void
446 gss_eap_saml_attr_ctx::setAttribute(int complete,
447                                     const gss_buffer_t attr,
448                                     const gss_buffer_t value)
449 {
450     Attribute *a = samlAttributeFromGssBuffers(attr, value);
451
452     addAttribute(a, false);
453 }
454
455 void
456 gss_eap_saml_attr_ctx::deleteAttribute(const gss_buffer_t attr)
457 {
458     int i;
459
460     i = getAttributeIndex(attr);
461     if (i >= 0)
462         m_attributes.erase(m_attributes.begin() + i);
463 }
464
465 OM_uint32
466 samlReleaseAttrContext(OM_uint32 *minor, gss_name_t name)
467 {
468     try {
469         delete name->samlCtx;
470         name->samlCtx = NULL;
471     } catch (exception &e) {
472         return mapException(minor, e);
473     }
474
475     return GSS_S_COMPLETE;
476 }
477
478 static gss_buffer_desc
479 gssEapRadiusAssertionAttr = { 3, (void *)"128" };
480
481 static OM_uint32
482 samlAddRadiusAttribute(OM_uint32 *minor,
483                        gss_name_t name,
484                        gss_buffer_t attr,
485                        void *data)
486 {
487     OM_uint32 major;
488     ShibbolethResolver *resolver = (ShibbolethResolver *)resolver;
489     Attribute *a;
490     int authenticated, complete, more = -1;
491     gss_buffer_desc value;
492
493     if (bufferEqual(attr, &gssEapRadiusAssertionAttr)) {
494         return GSS_S_COMPLETE;
495     }
496
497     major = radiusGetAttribute(minor, name, attr,
498                                &authenticated, &complete,
499                                &value, GSS_C_NO_BUFFER, &more);
500     if (major == GSS_S_COMPLETE) {
501         /* Do some prefixing? */
502         a = samlAttributeFromGssBuffers(attr, &value);
503         /* XXX leaky */
504         resolver->addAttribute(a);
505     }
506
507     return GSS_S_COMPLETE;
508 }
509
510 static OM_uint32
511 samlAddRadiusAttributes(OM_uint32 *minor,
512                         gss_name_t name,
513                         ShibbolethResolver *resolver)
514 {
515     return radiusGetAttributeTypes(minor,
516                                    name,
517                                    samlAddRadiusAttribute,
518                                    (void *)resolver);
519 }
520
521 static OM_uint32
522 samlInitAttrContextFromRadius(OM_uint32 *minor,
523                               gss_name_t name,
524                               gss_eap_saml_attr_ctx **pSamlCtx)
525 {
526     OM_uint32 major;
527     int authenticated, complete, more = -1;
528     gss_buffer_desc value;
529
530     value.value = NULL;
531     value.length = 0;
532
533     major = radiusGetAttribute(minor, name, &gssEapRadiusAssertionAttr,
534                                &authenticated, &complete,
535                                &value, GSS_C_NO_BUFFER, &more);
536     if (major == GSS_S_UNAVAILABLE) {
537         /* No assertion provided via RADIUS. */
538         value.length = 0;
539         value.value = NULL;
540     } else if (GSS_ERROR(major)) {
541         /* Some other error */
542         return major;
543     }
544
545     *pSamlCtx = new gss_eap_saml_attr_ctx(&value);
546
547     gss_release_buffer(minor, &value);
548
549     return GSS_S_COMPLETE;
550 }
551
552 OM_uint32
553 samlCreateAttrContext(OM_uint32 *minor,
554                       gss_cred_id_t acceptorCred,
555                       gss_name_t initiatorName,
556                       time_t *pExpiryTime)
557 {
558     OM_uint32 major, tmpMinor;
559     gss_buffer_desc nameBuf;
560     gss_eap_saml_attr_ctx *ctx = NULL;
561     ShibbolethResolver *resolver = NULL;
562
563     assert(initiatorName != GSS_C_NO_NAME);
564
565     nameBuf.length = 0;
566     nameBuf.value = NULL;
567
568     resolver = ShibbolethResolver::create();
569     if (resolver == NULL)
570         return GSS_S_FAILURE;
571
572     if (acceptorCred != GSS_C_NO_CREDENTIAL) {
573         major = gss_display_name(minor, acceptorCred->name, &nameBuf, NULL);
574         if (GSS_ERROR(major))
575             goto cleanup;
576     }
577
578     try {
579         const saml2::Assertion *assertion;
580         vector <Attribute *> attrs;
581
582         major = samlInitAttrContextFromRadius(minor, initiatorName, &ctx);
583         if (GSS_ERROR(major))
584             goto cleanup;
585
586         assertion = ctx->getAssertion();
587
588         if (assertion != NULL) {
589             if (assertion->getConditions()) {
590                 *pExpiryTime =
591                     assertion->getConditions()->getNotOnOrAfter()->getEpoch();
592             }
593
594             resolver->addToken(assertion);
595         }
596
597         if (initiatorName->radiusCtx != NULL) {
598             samlAddRadiusAttributes(minor, initiatorName, resolver);
599         }
600
601         resolver->resolveAttributes(attrs);
602         ctx->setAttributes(attrs);
603     } catch (exception &ex) {
604         major = mapException(minor, ex);
605         goto cleanup;
606     }
607
608     *minor = 0;
609     major = GSS_S_COMPLETE;
610
611     initiatorName->samlCtx = ctx;
612
613 cleanup:
614     gss_release_buffer(&tmpMinor, &nameBuf);
615     if (GSS_ERROR(major))
616         delete ctx;
617     delete resolver;
618
619     return major;
620 }
621
622 OM_uint32
623 samlGetAttributeTypes(OM_uint32 *minor,
624                       gss_name_t name,
625                       enum gss_eap_attribute_type type,
626                       gss_eap_add_attr_cb addAttribute,
627                       void *data)
628 {
629     OM_uint32 major = GSS_S_COMPLETE;
630     gss_eap_saml_attr_ctx *ctx = name->samlCtx;
631
632     if (ctx == NULL)
633         return GSS_S_COMPLETE;
634
635     if (type != ATTR_TYPE_NONE)
636         return GSS_S_UNAVAILABLE;
637
638     for (vector<Attribute*>::const_iterator a = ctx->getAttributes().begin();
639         a != ctx->getAttributes().end();
640         ++a)
641     {
642         gss_buffer_desc attribute;
643
644         attribute.value = (void *)((*a)->getId());
645         attribute.length = strlen((char *)attribute.value);
646
647         major = addAttribute(minor, name, &attribute, data);
648         if (GSS_ERROR(major))
649             break;
650     }
651
652     return major;
653 }
654
655 /*
656  * SAML implementation of gss_get_name_attribute
657  */
658 OM_uint32
659 samlGetAttribute(OM_uint32 *minor,
660                  enum gss_eap_attribute_type type,
661                  gss_name_t name,
662                  gss_buffer_t attr,
663                  int *authenticated,
664                  int *complete,
665                  gss_buffer_t value,
666                  gss_buffer_t display_value,
667                  int *more)
668 {
669     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
670     bool ret;
671
672     if (ctx == NULL)
673         return GSS_S_UNAVAILABLE;
674
675     switch (type) {
676     case ATTR_TYPE_NONE:
677         ret = ctx->getAttribute(attr, authenticated, complete,
678                                 value, display_value, more);
679         break;
680     default:
681         ret = false;
682         break;
683     }
684
685     return ret ? GSS_S_COMPLETE : GSS_S_UNAVAILABLE;
686 }
687
688 OM_uint32
689 samlSetAttribute(OM_uint32 *minor,
690                  gss_name_t name,
691                  int complete,
692                  gss_buffer_t attr,
693                  gss_buffer_t value)
694 {
695     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
696
697     if (ctx == NULL)
698         return GSS_S_UNAVAILABLE;
699
700     try {
701         ctx->setAttribute(complete, attr, value);
702     } catch (exception &e) {
703         return mapException(minor, e);
704     }
705
706     return GSS_S_COMPLETE;
707 }
708
709 OM_uint32
710 samlDeleteAttribute(OM_uint32 *minor,
711                     gss_name_t name,
712                     gss_buffer_t attr)
713 {
714     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
715
716     if (ctx == NULL)
717         return GSS_S_UNAVAILABLE;
718
719     try {
720         ctx->deleteAttribute(attr);
721     } catch (exception &e) {
722         return mapException(minor, e);
723     }
724
725     return GSS_S_COMPLETE;
726 }
727
728 /*
729  * In order to implement gss_export_name and gss_export_sec_context,
730  * we need to serialise a resolved attribute context to a buffer.
731  */
732 OM_uint32
733 samlExportAttrContext(OM_uint32 *minor,
734                       gss_name_t name,
735                       gss_buffer_t buffer)
736 {
737     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
738
739     try {
740         ctx->marshall(buffer);
741     } catch (exception &e) {
742         return mapException(minor, e);
743     }        
744
745     return GSS_S_COMPLETE;
746 }
747
748 /*
749  * In order to implement gss_import_name and gss_import_sec_context,
750  * we need to deserialise a resolved attribute context from a buffer.
751  */
752 OM_uint32
753 samlImportAttrContext(OM_uint32 *minor,
754                       gss_buffer_t buffer,
755                       gss_name_t name)
756 {
757     try {
758         assert(name->samlCtx == NULL);
759         name->samlCtx = gss_eap_saml_attr_ctx::unmarshall(buffer);
760     } catch (exception &e) {
761         return mapException(minor, e);
762     }
763
764     return GSS_S_COMPLETE;
765 }
766
767 OM_uint32
768 samlGetAssertion(OM_uint32 *minor,
769                  gss_name_t name,
770                  gss_buffer_t assertion)
771 {
772     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
773
774     if (ctx == NULL)
775         return GSS_S_UNAVAILABLE;
776
777     try {
778         ctx->getAssertion(assertion);
779     } catch (exception &e) {
780         return mapException(minor, e);
781     }
782
783     return GSS_S_COMPLETE;
784 }
785
786 OM_uint32
787 samlDuplicateAttrContext(OM_uint32 *minor,
788                          gss_name_t in,
789                          gss_name_t out)
790 {
791     try {
792         if (in->samlCtx != NULL)
793             out->samlCtx = new gss_eap_saml_attr_ctx(*(in->samlCtx));
794         else
795             out->samlCtx = NULL;
796     } catch (exception &e) {
797         return mapException(minor, e);
798     }
799
800     return GSS_S_COMPLETE;
801 }
802
803 OM_uint32
804 samlMapNameToAny(OM_uint32 *minor,
805                  gss_name_t name,
806                  int authenticated,
807                  gss_buffer_t type_id,
808                  gss_any_t *output)
809 {
810     struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
811
812     if (bufferEqualString(type_id, "shibsp::Attribute")) {
813         vector <Attribute *>v = duplicateAttributes(ctx->getAttributes());
814
815         *output = (gss_any_t)new vector <Attribute *>(v);
816     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
817         *output = (gss_any_t)ctx->getAssertion()->clone();
818     } else {
819         *output = (gss_any_t)NULL;
820         return GSS_S_UNAVAILABLE;
821     }
822
823     return GSS_S_COMPLETE;
824 }
825
826 OM_uint32
827 samlReleaseAnyNameMapping(OM_uint32 *minor,
828                           gss_name_t name,
829                           gss_buffer_t type_id,
830                           gss_any_t *input)
831 {
832     if (bufferEqualString(type_id, "vector<shibsp::Attribute>")) {
833         vector <Attribute *> *v = ((vector <Attribute *> *)*input);
834         delete v;
835     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
836         delete (Assertion *)*input;
837     } else {
838         return GSS_S_UNAVAILABLE;
839     }
840
841     *input = (gss_any_t)NULL;
842     return GSS_S_COMPLETE;
843 }
844
845 OM_uint32
846 samlInit(OM_uint32 *minor)
847 {
848     *minor = 0;
849
850     return ShibbolethResolver::init() ? GSS_S_COMPLETE : GSS_S_FAILURE;
851 }
852
853 OM_uint32
854 samlFinalize(OM_uint32 *minor)
855 {
856     *minor = 0;
857
858     ShibbolethResolver::term();
859     return GSS_S_COMPLETE;
860 }