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