377cd60c2fad89e6de8b380ef3341fd517dba5ea
[mech_eap.orig] / 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 <gssapi/gssapi.h>
49 #include <gssapi/gssapi_ext.h>
50 #include "util.h"
51
52 #include <shibsp/Application.h>
53 #include <shibsp/exceptions.h>
54 #include <shibsp/SPConfig.h>
55 #include <shibsp/ServiceProvider.h>
56 #include <shibsp/attribute/Attribute.h>
57 #include <shibsp/attribute/SimpleAttribute.h>
58 #include <shibsp/attribute/resolver/ResolutionContext.h>
59 #include <shibsp/handler/AssertionConsumerService.h>
60 #include <shibsp/metadata/MetadataProviderCriteria.h>
61 #include <shibsp/util/SPConstants.h>
62
63 #include <saml/saml1/core/Assertions.h>
64 #include <saml/saml2/core/Assertions.h>
65 #include <saml/saml2/metadata/Metadata.h>
66 #include <xercesc/util/XMLUniDefs.hpp>
67 #include <xmltooling/XMLToolingConfig.h>
68 #include <xmltooling/util/XMLHelper.h>
69
70 using namespace shibsp;
71 using namespace opensaml::saml2md;
72 using namespace opensaml;
73 using namespace xmltooling::logging;
74 using namespace xmltooling;
75 using namespace xercesc;
76 using namespace std;
77
78 class GSSEAPResolver : public shibsp::AssertionConsumerService
79 {
80 public:
81     GSSEAPResolver(const DOMElement *e, const char *appId)
82         : shibsp::AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".GSSEAPResolver")) {
83     }
84     virtual ~GSSEAPResolver() {}
85
86     ResolutionContext* resolveAttributes (
87         const Application& application,
88         const RoleDescriptor* issuer,
89         const XMLCh* protocol,
90         const saml1::NameIdentifier* v1nameid,
91         const saml2::NameID* nameid,
92         const XMLCh* authncontext_class,
93         const XMLCh* authncontext_decl,
94         const vector<const Assertion*>* tokens
95         ) const {
96             return shibsp::AssertionConsumerService::resolveAttributes(
97                     application, issuer, protocol, v1nameid,
98                     nameid, authncontext_class, authncontext_decl, tokens
99             );
100     }
101
102 private:
103     void implementProtocol(
104         const Application& application,
105         const HTTPRequest& httpRequest,
106         HTTPResponse& httpResponse,
107         SecurityPolicy& policy,
108         const PropertySet* settings,
109         const XMLObject& xmlObject
110         ) const {
111             throw FatalProfileException("Should never be called.");
112     }
113 };
114
115 struct eap_gss_saml_attr_ctx {
116 public:
117     eap_gss_saml_attr_ctx();
118     eap_gss_saml_attr_ctx(const gss_buffer_t buffer);
119     eap_gss_saml_attr_ctx(const Assertion *assertion);
120
121     eap_gss_saml_attr_ctx(const vector<Attribute*>& attributes,
122                           const Assertion *assertion);
123
124     eap_gss_saml_attr_ctx(const eap_gss_saml_attr_ctx &ctx) {
125         eap_gss_saml_attr_ctx(ctx.m_attributes, ctx.m_assertion);
126     }
127
128     ~eap_gss_saml_attr_ctx();
129
130     const vector <Attribute *> getAttributes(void) const {
131         return m_attributes;
132     }
133
134     void addAttribute(Attribute *attr, bool copy = true);
135     void setAttributes(const vector<Attribute*> attributes);
136
137     void setAttribute(int complete,
138                       const gss_buffer_t attr,
139                       const gss_buffer_t value);
140     void deleteAttribute(const gss_buffer_t attr);
141
142     int getAttributeIndex(const gss_buffer_t attr) const;
143     const Attribute *getAttribute(const gss_buffer_t attr) const;
144
145     bool getAttribute(const gss_buffer_t attr,
146                       int *authenticated,
147                       int *complete,
148                       gss_buffer_t value,
149                       gss_buffer_t display_value,
150                       int *more);
151
152     const Assertion *getAssertion(void) const {
153         return m_assertion;
154     }
155
156     bool getAssertion(gss_buffer_t buffer);
157
158     DDF marshall() const;
159     static eap_gss_saml_attr_ctx *unmarshall(DDF &in);
160
161     void marshall(gss_buffer_t buffer);
162     static eap_gss_saml_attr_ctx *unmarshall(const gss_buffer_t buffer);
163
164 private:
165     mutable vector<Attribute*> m_attributes;
166     mutable Assertion *m_assertion;
167
168     bool parseAssertion(const gss_buffer_t buffer);
169 };
170
171 eap_gss_saml_attr_ctx::eap_gss_saml_attr_ctx(const vector<Attribute*>& attributes,
172                                              const Assertion *assertion)
173 {
174     m_assertion = dynamic_cast<Assertion *>(assertion->clone());
175     setAttributes(attributes);
176 }
177
178 eap_gss_saml_attr_ctx::~eap_gss_saml_attr_ctx()
179 {
180     for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
181     delete m_assertion;
182 }
183
184 eap_gss_saml_attr_ctx::eap_gss_saml_attr_ctx(const gss_buffer_t buffer)
185 {
186     parseAssertion(buffer);
187 }
188
189 static OM_uint32
190 mapException(OM_uint32 *minor, exception &e)
191 {
192     *minor = 0;
193     return GSS_S_FAILURE;
194 }
195
196 bool
197 eap_gss_saml_attr_ctx::parseAssertion(const gss_buffer_t buffer)
198 {
199     DOMDocument *doc;
200     const XMLObjectBuilder *b;
201     DOMElement *elem;
202     XMLObject *xobj;
203     string str((char *)buffer->value, buffer->length);
204     istringstream istream(str);
205
206     doc = XMLToolingConfig::getConfig().getParser().parse(istream);
207     b = XMLObjectBuilder::getDefaultBuilder();
208     elem = doc->getDocumentElement();
209     xobj = b->buildOneFromElement(elem, true);
210
211     m_assertion = dynamic_cast<Assertion *>(xobj);
212
213     return (m_assertion != NULL);
214 }
215
216 static inline void
217 duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
218 {
219     OM_uint32 minor;
220
221     if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
222         throw new bad_alloc();
223 }
224
225 static inline void
226 duplicateBuffer(string &str, gss_buffer_t buffer)
227 {
228     gss_buffer_desc tmp;
229
230     tmp.length = str.length();
231     tmp.value = (char *)str.c_str();
232
233     duplicateBuffer(tmp, buffer);
234 }
235
236 DDF
237 eap_gss_saml_attr_ctx::marshall() const
238 {
239     DDF obj(NULL);
240     DDF attrs;
241     DDF assertion;
242
243     obj.addmember("version").integer(1);
244
245     attrs = obj.addmember("attributes").list();
246     for (vector<Attribute*>::const_iterator a = m_attributes.begin();
247          a != m_attributes.end(); ++a) {
248         DDF attr = (*a)->marshall();
249         attrs.add(attr);
250     }
251
252     ostringstream sink;
253     sink << *m_assertion;
254     assertion = obj.addmember("assertion").string(sink.str().c_str());
255
256     return obj;
257 }
258
259 eap_gss_saml_attr_ctx *
260 eap_gss_saml_attr_ctx::unmarshall(DDF &obj)
261 {
262     eap_gss_saml_attr_ctx *ctx = new eap_gss_saml_attr_ctx();
263
264     DDF version = obj["version"];
265     if (version.integer() != 1)
266         return NULL;
267
268     DDF assertion = obj["assertion"];
269     gss_buffer_desc buffer;
270
271     if (!assertion.isnull()) {
272         buffer.length = assertion.strlen();
273         buffer.value = (void *)assertion.string();
274     } else {
275         buffer.length = 0;
276     }
277
278     if (buffer.length != 0)
279         ctx->parseAssertion(&buffer);
280
281     DDF attrs = obj["attributes"];
282     DDF attr = attrs.first();
283     while (!attr.isnull()) {
284         Attribute *attribute = Attribute::unmarshall(attr);
285         ctx->addAttribute(attribute, false);
286         attr = attrs.next();
287     }
288
289     return ctx;
290 }
291
292 void
293 eap_gss_saml_attr_ctx::marshall(gss_buffer_t buffer)
294 {
295     DDF obj = marshall();
296     ostringstream sink;
297     sink << obj;
298     string str = sink.str();
299
300     duplicateBuffer(str, buffer);
301
302     obj.destroy();
303 }
304
305 eap_gss_saml_attr_ctx *
306 eap_gss_saml_attr_ctx::unmarshall(const gss_buffer_t buffer)
307 {
308     eap_gss_saml_attr_ctx *ctx;
309
310     string str((const char *)buffer->value, buffer->length);
311     istringstream source(str);
312     DDF obj(NULL);
313     source >> obj;
314
315     ctx = unmarshall(obj);
316
317     obj.destroy();
318
319     return ctx;
320 }
321
322 bool
323 eap_gss_saml_attr_ctx::getAssertion(gss_buffer_t buffer)
324 {
325     string str;
326
327     if (m_assertion == NULL)
328         return false;
329
330     buffer->value = NULL;
331     buffer->length = 0;
332
333     XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
334
335     duplicateBuffer(str, buffer);
336
337     return true;
338 }
339
340 static Attribute *
341 duplicateAttribute(const Attribute *src)
342 {
343     Attribute *attribute;
344
345     DDF obj = src->marshall();
346     attribute = Attribute::unmarshall(obj);
347     obj.destroy();
348
349     return attribute;
350 }
351
352 static vector <Attribute *>
353 duplicateAttributes(const vector <Attribute *>src)
354 {
355     vector <Attribute *> dst;
356
357     for (vector<Attribute *>::const_iterator a = src.begin();
358          a != src.end();
359          ++a)
360         dst.push_back(duplicateAttribute(*a));
361
362     return dst;
363 }
364
365 void
366 eap_gss_saml_attr_ctx::addAttribute(Attribute *attribute, bool copy)
367 {
368     Attribute *a;
369
370     a = copy ? duplicateAttribute(attribute) : attribute;
371
372     m_attributes.push_back(a);
373 }
374
375 void
376 eap_gss_saml_attr_ctx::setAttributes(const vector<Attribute*> attributes)
377 {
378     for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
379     m_attributes = duplicateAttributes(attributes);
380 }
381
382 int
383 eap_gss_saml_attr_ctx::getAttributeIndex(const gss_buffer_t attr) const
384 {
385     int i = 0;
386
387     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
388          a != getAttributes().end();
389          ++a)
390     {
391         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
392              s != (*a)->getAliases().end();
393              ++s) {
394             if (attr->length == (*s).length() &&
395                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
396                 return i;
397             }
398         }
399     }
400
401     return -1;
402 }
403
404 const Attribute *
405 eap_gss_saml_attr_ctx::getAttribute(const gss_buffer_t attr) const
406 {
407     const Attribute *ret = NULL;
408
409     for (vector<Attribute *>::const_iterator a = getAttributes().begin();
410          a != getAttributes().end();
411          ++a)
412     {
413         for (vector<string>::const_iterator s = (*a)->getAliases().begin();
414              s != (*a)->getAliases().end();
415              ++s) {
416             if (attr->length == (*s).length() &&
417                 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
418                 ret = *a;
419                 break;
420             }
421         }
422         if (ret != NULL)
423             break;
424     }
425
426     return ret;
427 }
428
429 bool
430 eap_gss_saml_attr_ctx::getAttribute(const gss_buffer_t attr,
431                                     int *authenticated,
432                                     int *complete,
433                                     gss_buffer_t value,
434                                     gss_buffer_t display_value,
435                                     int *more)
436 {
437     const Attribute *shibAttr = NULL;
438     gss_buffer_desc buf;
439
440     shibAttr = getAttribute(attr);
441     if (shibAttr == NULL)
442         return false;
443
444     if (*more == -1) {
445         *more = 0;
446     } else if (*more >= (int)shibAttr->valueCount()) {
447         *more = 0;
448         return true;
449     }
450
451     buf.value = (void *)shibAttr->getString(*more);
452     buf.length = strlen((char *)buf.value);
453
454     duplicateBuffer(buf, value);
455  
456     *authenticated = TRUE;
457     *complete = FALSE;
458
459     return true;
460 }
461
462 void
463 eap_gss_saml_attr_ctx::setAttribute(int complete,
464                                     const gss_buffer_t attr,
465                                     const gss_buffer_t value)
466 {
467     string attrStr((char *)attr->value, attr->length);
468     vector <string> ids(1);
469     SimpleAttribute *a;
470
471     ids.push_back(attrStr);
472
473     a = new SimpleAttribute(ids);
474
475     if (value->length != 0) {
476         string valStr((char *)value->value, value->length);
477
478         a->getValues().push_back(valStr);        
479     }
480
481     m_attributes.push_back(a);
482 }
483
484 void
485 eap_gss_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,
496                        struct eap_gss_saml_attr_ctx **pCtx)
497 {
498     eap_gss_saml_attr_ctx *ctx = *pCtx;
499
500     if (ctx != NULL) {
501         delete ctx;
502         *pCtx = NULL;
503     }
504
505     *minor = 0;
506     return GSS_S_COMPLETE;
507 }
508
509 OM_uint32
510 samlCreateAttrContext(OM_uint32 *minor,
511                       gss_buffer_t buffer,
512                       gss_name_t acceptorName,
513                       struct eap_gss_saml_attr_ctx **pCtx,
514                       time_t *pExpiryTime)
515 {
516     OM_uint32 major, tmpMinor;
517     eap_gss_saml_attr_ctx *ctx = NULL;
518     SPConfig &conf = SPConfig::getConfig();
519     ServiceProvider *sp;
520     const Application *app;
521     MetadataProvider *m;
522     gss_buffer_desc nameBuf;
523     const XMLCh *issuer = NULL;
524     saml2::NameID *subjectName = NULL;
525     saml2::Assertion *assertion;
526     ResolutionContext *resolverContext;
527
528     nameBuf.length = 0;
529     nameBuf.value = NULL;
530
531     conf.setFeatures(SPConfig::Metadata             |
532                      SPConfig::Trust                |
533                      SPConfig::AttributeResolution  |
534                      SPConfig::Credentials          |
535                      SPConfig::OutOfProcess);
536     if (!conf.init())
537         return GSS_S_FAILURE;
538     if (!conf.instantiate())
539         return GSS_S_FAILURE;
540
541     sp = conf.getServiceProvider();
542     sp->lock();
543
544     major = gss_display_name(minor, acceptorName, &nameBuf, NULL);
545     if (GSS_ERROR(major))
546         goto cleanup;
547
548     app = sp->getApplication((const char *)nameBuf.value);
549     if (app == NULL) {
550         major = GSS_S_FAILURE;
551         goto cleanup;
552     }
553
554     try {
555         ctx = new eap_gss_saml_attr_ctx(buffer);
556
557         if (assertion->getIssuer() != NULL)
558             issuer = assertion->getIssuer()->getName();
559         if (assertion->getSubject() != NULL)
560             subjectName = assertion->getSubject()->getNameID();
561         if (assertion->getConditions())
562             *pExpiryTime = assertion->getConditions()->getNotOnOrAfter()->getEpoch();
563
564         m = app->getMetadataProvider();
565         xmltooling::Locker mlocker(m);
566         MetadataProviderCriteria mc(*app, issuer,
567                                     &IDPSSODescriptor::ELEMENT_QNAME,
568                                     samlconstants::SAML20P_NS);
569         pair<const EntityDescriptor *, const RoleDescriptor *> site =
570             m->getEntityDescriptor(mc);
571         if (!site.first) {
572             auto_ptr_char temp(issuer);
573             throw MetadataException("Unable to locate metadata for IdP ($1).",
574                                     params(1,temp.get()));
575         }
576         vector<const Assertion*> tokens(1, assertion);
577         GSSEAPResolver gssResolver(NULL, (const char *)nameBuf.value);
578         resolverContext = gssResolver.resolveAttributes(*app, site.second,
579                                                         samlconstants::SAML20P_NS,
580                                                         NULL, subjectName, NULL,
581                                                         NULL, &tokens);
582         ctx->setAttributes(resolverContext->getResolvedAttributes());
583     } catch (exception &ex) {
584         major = mapException(minor, ex);
585         goto cleanup;
586     }
587
588     major = GSS_S_COMPLETE;
589     *pCtx = ctx;
590
591 cleanup:
592     sp->unlock();
593     conf.term();
594
595     if (GSS_ERROR(major))
596         delete ctx;
597     gss_release_buffer(&tmpMinor, &nameBuf);
598
599     return major;
600 }
601
602 OM_uint32
603 samlGetAttributeTypes(OM_uint32 *minor,
604                       const struct eap_gss_saml_attr_ctx *ctx,
605                       void *data,
606                       OM_uint32 (*addAttribute)(OM_uint32 *, void *, gss_buffer_t))
607 {
608     OM_uint32 major = GSS_S_COMPLETE;
609
610     if (ctx == NULL)
611         return GSS_S_COMPLETE;
612
613     for (vector<Attribute*>::const_iterator a = ctx->getAttributes().begin();
614         a != ctx->getAttributes().end();
615         ++a)
616     {
617         gss_buffer_desc attribute;
618
619         attribute.value = (void *)((*a)->getId());
620         attribute.length = strlen((char *)attribute.value);
621
622         major = addAttribute(minor, data, &attribute);
623         if (GSS_ERROR(major))
624             break;
625     }
626
627     return major;
628 }
629
630 /*
631  * SAML implementation of gss_get_name_attribute
632  */
633 OM_uint32
634 samlGetAttribute(OM_uint32 *minor,
635                  struct eap_gss_saml_attr_ctx *ctx,
636                  gss_buffer_t attr,
637                  int *authenticated,
638                  int *complete,
639                  gss_buffer_t value,
640                  gss_buffer_t display_value,
641                  int *more)
642 {
643     if (ctx == NULL)
644         return GSS_S_UNAVAILABLE;
645
646     if (!ctx->getAttribute(attr, authenticated, complete,
647                            value, display_value, more))
648         return GSS_S_UNAVAILABLE;
649
650     return GSS_S_COMPLETE;
651 }
652
653 OM_uint32
654 samlSetAttribute(OM_uint32 *minor,
655                  struct eap_gss_saml_attr_ctx *ctx,
656                  int complete,
657                  gss_buffer_t attr,
658                  gss_buffer_t value)
659 {
660     try {
661         ctx->setAttribute(complete, attr, value);
662     } catch (exception &e) {
663         return mapException(minor, e);
664     }
665
666     return GSS_S_COMPLETE;
667 }
668
669 OM_uint32
670 samlDeleteAttribute(OM_uint32 *minor,
671                     struct eap_gss_saml_attr_ctx *ctx,
672                     gss_buffer_t attr)
673 {
674     try {
675         ctx->deleteAttribute(attr);
676     } catch (exception &e) {
677         return mapException(minor, e);
678     }
679
680     return GSS_S_COMPLETE;
681 }
682
683 /*
684  * In order to implement gss_export_name and gss_export_sec_context,
685  * we need to serialise a resolved attribute context to a buffer.
686  */
687 OM_uint32
688 samlExportAttrContext(OM_uint32 *minor,
689                       struct eap_gss_saml_attr_ctx *ctx,
690                       gss_buffer_t buffer)
691 {
692     try {
693         ctx->marshall(buffer);
694     } catch (exception &e) {
695         return mapException(minor, e);
696     }        
697
698     return GSS_S_COMPLETE;
699 }
700
701 /*
702  * In order to implement gss_import_name and gss_import_sec_context,
703  * we need to deserialise a resolved attribute context from a buffer.
704  */
705 OM_uint32
706 samlImportAttrContext(OM_uint32 *minor,
707                       gss_buffer_t buffer,
708                       struct eap_gss_saml_attr_ctx **pCtx)
709 {
710     try {
711         *pCtx = eap_gss_saml_attr_ctx::unmarshall(buffer);
712     } catch (exception &e) {
713         return mapException(minor, e);
714     }
715
716     return GSS_S_COMPLETE;
717 }
718
719 OM_uint32
720 samlGetAssertion(OM_uint32 *minor,
721                  struct eap_gss_saml_attr_ctx *ctx,
722                  gss_buffer_t assertion)
723 {
724     try {
725         ctx->getAssertion(assertion);
726     } catch (exception &e) {
727         return mapException(minor, e);
728     }
729
730     return GSS_S_COMPLETE;
731 }
732
733 OM_uint32
734 samlDuplicateAttrContext(OM_uint32 *minor,
735                          const struct eap_gss_saml_attr_ctx *in,
736                          struct eap_gss_saml_attr_ctx **out)
737 {
738     try {
739         *out = new eap_gss_saml_attr_ctx(*in);
740     } catch (exception &e) {
741         return mapException(minor, e);
742     }
743
744     return GSS_S_COMPLETE;
745 }
746
747 OM_uint32
748 samlMapNametoAny(OM_uint32 *minor,
749                  const struct eap_gss_saml_attr_ctx *ctx,
750                  int authenticated,
751                  gss_buffer_t type_id,
752                  gss_any_t *output)
753 {
754     if (bufferEqualString(type_id, "shibsp::Attribute")) {
755         vector <Attribute *>v = duplicateAttributes(ctx->getAttributes());
756
757         *output = (gss_any_t)new vector <Attribute *>(v);
758     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
759         *output = (gss_any_t)ctx->getAssertion()->clone();
760     } else {
761         *output = (gss_any_t)NULL;
762         return GSS_S_UNAVAILABLE;
763     }
764
765     return GSS_S_COMPLETE;
766 }
767
768 OM_uint32
769 samlReleaseAnyNameMapping(OM_uint32 *minor,
770                           const struct eap_gss_saml_attr_ctx *ctx,
771                           gss_buffer_t type_id,
772                           gss_any_t *input)
773 {
774     if (bufferEqualString(type_id, "vector<shibsp::Attribute>")) {
775         vector <Attribute *> *v = ((vector <Attribute *> *)*input);
776         delete v;
777     } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
778         delete (Assertion *)*input;
779     } else {
780         return GSS_S_UNAVAILABLE;
781     }
782
783     *input = (gss_any_t)NULL;
784     return GSS_S_COMPLETE;
785 }