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