2 * Copyright (c) 2010, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
33 * Copyright 2001-2009 Internet2
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
39 * http://www.apache.org/licenses/LICENSE-2.0
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.
48 #include "gssapiP_eap.h"
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>
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>
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;
79 static vector <Attribute *>
80 duplicateAttributes(const vector <Attribute *>src);
82 struct gss_eap_saml_attr_ctx
85 gss_eap_saml_attr_ctx(void) {}
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));
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);
99 ~gss_eap_saml_attr_ctx() {
100 for_each(m_attributes.begin(),
102 xmltooling::cleanup<Attribute>())
107 const vector <Attribute *> getAttributes(void) const {
111 void addAttribute(Attribute *attr, bool copy = true);
112 void setAttributes(const vector<Attribute*> attributes);
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);
119 int getAttributeIndex(const gss_buffer_t attr) const;
120 const Attribute *getAttribute(const gss_buffer_t attr) const;
122 bool getAttribute(const gss_buffer_t attr,
126 gss_buffer_t display_value,
129 const saml2::Assertion *getAssertion(void) const {
133 void setAssertion(const saml2::Assertion *assertion) {
135 if (assertion != NULL)
136 m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
141 void setAssertion(const gss_buffer_t buffer) {
143 m_assertion = parseAssertion(buffer);
146 bool getAssertion(gss_buffer_t buffer);
148 DDF marshall() const;
149 static gss_eap_saml_attr_ctx *unmarshall(DDF &in);
151 void marshall(gss_buffer_t buffer);
152 static gss_eap_saml_attr_ctx *unmarshall(const gss_buffer_t buffer);
155 mutable vector<Attribute*> m_attributes;
156 mutable saml2::Assertion *m_assertion;
158 static saml2::Assertion *parseAssertion(const gss_buffer_t buffer);
162 mapException(OM_uint32 *minor, exception &e)
165 return GSS_S_FAILURE;
169 gss_eap_saml_attr_ctx::parseAssertion(const gss_buffer_t buffer)
172 const XMLObjectBuilder *b;
175 string str((char *)buffer->value, buffer->length);
176 istringstream istream(str);
178 doc = XMLToolingConfig::getConfig().getParser().parse(istream);
179 b = XMLObjectBuilder::getDefaultBuilder();
180 elem = doc->getDocumentElement();
181 xobj = b->buildOneFromElement(elem, true);
183 return dynamic_cast<saml2::Assertion *>(xobj);
187 duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
191 if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
192 throw new bad_alloc();
196 duplicateBuffer(string &str, gss_buffer_t buffer)
200 tmp.length = str.length();
201 tmp.value = (char *)str.c_str();
203 duplicateBuffer(tmp, buffer);
207 gss_eap_saml_attr_ctx::marshall() const
213 obj.addmember("version").integer(1);
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();
223 sink << *m_assertion;
224 assertion = obj.addmember("assertion").string(sink.str().c_str());
229 gss_eap_saml_attr_ctx *
230 gss_eap_saml_attr_ctx::unmarshall(DDF &obj)
232 gss_eap_saml_attr_ctx *ctx = new gss_eap_saml_attr_ctx();
234 DDF version = obj["version"];
235 if (version.integer() != 1)
238 DDF assertion = obj["assertion"];
239 gss_buffer_desc buffer;
241 if (!assertion.isnull()) {
242 buffer.length = assertion.strlen();
243 buffer.value = (void *)assertion.string();
248 if (buffer.length != 0)
249 ctx->parseAssertion(&buffer);
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);
263 gss_eap_saml_attr_ctx::marshall(gss_buffer_t buffer)
265 DDF obj = marshall();
268 string str = sink.str();
270 duplicateBuffer(str, buffer);
275 gss_eap_saml_attr_ctx *
276 gss_eap_saml_attr_ctx::unmarshall(const gss_buffer_t buffer)
278 gss_eap_saml_attr_ctx *ctx;
280 string str((const char *)buffer->value, buffer->length);
281 istringstream source(str);
285 ctx = unmarshall(obj);
293 gss_eap_saml_attr_ctx::getAssertion(gss_buffer_t buffer)
297 if (m_assertion == NULL)
300 buffer->value = NULL;
303 XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
305 duplicateBuffer(str, buffer);
311 duplicateAttribute(const Attribute *src)
313 Attribute *attribute;
315 DDF obj = src->marshall();
316 attribute = Attribute::unmarshall(obj);
322 static vector <Attribute *>
323 duplicateAttributes(const vector <Attribute *>src)
325 vector <Attribute *> dst;
327 for (vector<Attribute *>::const_iterator a = src.begin();
330 dst.push_back(duplicateAttribute(*a));
336 gss_eap_saml_attr_ctx::addAttribute(Attribute *attribute, bool copy)
340 a = copy ? duplicateAttribute(attribute) : attribute;
342 m_attributes.push_back(a);
346 gss_eap_saml_attr_ctx::setAttributes(const vector<Attribute*> attributes)
348 for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
349 m_attributes = attributes;
353 gss_eap_saml_attr_ctx::getAttributeIndex(const gss_buffer_t attr) const
357 for (vector<Attribute *>::const_iterator a = getAttributes().begin();
358 a != getAttributes().end();
361 for (vector<string>::const_iterator s = (*a)->getAliases().begin();
362 s != (*a)->getAliases().end();
364 if (attr->length == (*s).length() &&
365 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
375 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr) const
377 const Attribute *ret = NULL;
379 for (vector<Attribute *>::const_iterator a = getAttributes().begin();
380 a != getAttributes().end();
383 for (vector<string>::const_iterator s = (*a)->getAliases().begin();
384 s != (*a)->getAliases().end();
386 if (attr->length == (*s).length() &&
387 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
400 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr,
404 gss_buffer_t display_value,
407 const Attribute *shibAttr = NULL;
410 shibAttr = getAttribute(attr);
411 if (shibAttr == NULL)
416 } else if (*more >= (int)shibAttr->valueCount()) {
421 buf.value = (void *)shibAttr->getString(*more);
422 buf.length = strlen((char *)buf.value);
424 duplicateBuffer(buf, value);
426 *authenticated = TRUE;
433 samlAttributeFromGssBuffers(const gss_buffer_t attr,
434 const gss_buffer_t value)
436 string attrStr((char *)attr->value, attr->length);
437 vector <string> ids(1);
440 ids.push_back(attrStr);
442 a = new SimpleAttribute(ids);
444 if (value->length != 0) {
445 string valStr((char *)value->value, value->length);
447 a->getValues().push_back(valStr);
454 gss_eap_saml_attr_ctx::setAttribute(int complete,
455 const gss_buffer_t attr,
456 const gss_buffer_t value)
458 Attribute *a = samlAttributeFromGssBuffers(attr, value);
460 addAttribute(a, false);
464 gss_eap_saml_attr_ctx::deleteAttribute(const gss_buffer_t attr)
468 i = getAttributeIndex(attr);
470 m_attributes.erase(m_attributes.begin() + i);
474 samlReleaseAttrContext(OM_uint32 *minor, gss_name_t name)
477 delete name->samlCtx;
478 name->samlCtx = NULL;
479 } catch (exception &e) {
480 return mapException(minor, e);
483 return GSS_S_COMPLETE;
486 static gss_buffer_desc
487 gssEapRadiusAssertionAttr = { 3, (void *)"128" };
490 samlAddRadiusAttribute(OM_uint32 *minor,
496 ShibbolethResolver *resolver = (ShibbolethResolver *)resolver;
498 int authenticated, complete, more = -1;
499 gss_buffer_desc value;
501 if (bufferEqual(attr, &gssEapRadiusAssertionAttr)) {
502 return GSS_S_COMPLETE;
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);
512 resolver->addAttribute(a);
515 return GSS_S_COMPLETE;
519 samlAddRadiusAttributes(OM_uint32 *minor,
521 ShibbolethResolver *resolver)
523 return radiusGetAttributeTypes(minor,
525 samlAddRadiusAttribute,
530 samlInitAttrContextFromRadius(OM_uint32 *minor,
532 gss_eap_saml_attr_ctx *ctx)
535 int authenticated, complete, more = -1;
536 gss_buffer_desc value;
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)
547 ctx->setAssertion(&value);
549 gss_release_buffer(minor, &value);
551 return GSS_S_COMPLETE;
555 samlCreateAttrContext(OM_uint32 *minor,
556 gss_cred_id_t acceptorCred,
557 gss_name_t initiatorName,
560 OM_uint32 major, tmpMinor;
561 gss_buffer_desc nameBuf;
562 gss_eap_saml_attr_ctx *ctx = NULL;
563 ShibbolethResolver *resolver = NULL;
565 assert(initiatorName != GSS_C_NO_NAME);
568 nameBuf.value = NULL;
570 resolver = ShibbolethResolver::create();
571 if (resolver == NULL)
572 return GSS_S_FAILURE;
574 if (acceptorCred != GSS_C_NO_CREDENTIAL) {
575 major = gss_display_name(minor, acceptorCred->name, &nameBuf, NULL);
576 if (GSS_ERROR(major))
581 const saml2::Assertion *assertion;
582 vector <Attribute *> attrs;
584 ctx = new gss_eap_saml_attr_ctx();
586 major = samlInitAttrContextFromRadius(minor, initiatorName, ctx);
587 if (GSS_ERROR(major))
590 assertion = ctx->getAssertion();
592 if (assertion != NULL) {
593 if (assertion->getConditions()) {
595 assertion->getConditions()->getNotOnOrAfter()->getEpoch();
598 resolver->addToken(assertion);
601 if (initiatorName->radiusCtx != NULL) {
602 samlAddRadiusAttributes(minor, initiatorName, resolver);
605 resolver->resolveAttributes(attrs);
606 ctx->setAttributes(attrs);
607 } catch (exception &ex) {
608 major = mapException(minor, ex);
613 major = GSS_S_COMPLETE;
615 initiatorName->samlCtx = ctx;
618 gss_release_buffer(&tmpMinor, &nameBuf);
619 if (GSS_ERROR(major))
627 samlGetAttributeTypes(OM_uint32 *minor,
629 enum gss_eap_attribute_type type,
630 gss_eap_add_attr_cb addAttribute,
633 OM_uint32 major = GSS_S_COMPLETE;
634 gss_eap_saml_attr_ctx *ctx = name->samlCtx;
637 return GSS_S_COMPLETE;
639 if (type != ATTR_TYPE_NONE)
640 return GSS_S_UNAVAILABLE;
642 for (vector<Attribute*>::const_iterator a = ctx->getAttributes().begin();
643 a != ctx->getAttributes().end();
646 gss_buffer_desc attribute;
648 attribute.value = (void *)((*a)->getId());
649 attribute.length = strlen((char *)attribute.value);
651 major = addAttribute(minor, name, &attribute, data);
652 if (GSS_ERROR(major))
660 * SAML implementation of gss_get_name_attribute
663 samlGetAttribute(OM_uint32 *minor,
664 enum gss_eap_attribute_type type,
670 gss_buffer_t display_value,
673 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
677 return GSS_S_UNAVAILABLE;
681 ret = ctx->getAttribute(attr, authenticated, complete,
682 value, display_value, more);
689 return ret ? GSS_S_COMPLETE : GSS_S_UNAVAILABLE;
693 samlSetAttribute(OM_uint32 *minor,
699 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
702 return GSS_S_UNAVAILABLE;
705 ctx->setAttribute(complete, attr, value);
706 } catch (exception &e) {
707 return mapException(minor, e);
710 return GSS_S_COMPLETE;
714 samlDeleteAttribute(OM_uint32 *minor,
718 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
721 return GSS_S_UNAVAILABLE;
724 ctx->deleteAttribute(attr);
725 } catch (exception &e) {
726 return mapException(minor, e);
729 return GSS_S_COMPLETE;
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.
737 samlExportAttrContext(OM_uint32 *minor,
741 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
744 ctx->marshall(buffer);
745 } catch (exception &e) {
746 return mapException(minor, e);
749 return GSS_S_COMPLETE;
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.
757 samlImportAttrContext(OM_uint32 *minor,
762 assert(name->samlCtx == NULL);
763 name->samlCtx = gss_eap_saml_attr_ctx::unmarshall(buffer);
764 } catch (exception &e) {
765 return mapException(minor, e);
768 return GSS_S_COMPLETE;
772 samlGetAssertion(OM_uint32 *minor,
774 gss_buffer_t assertion)
776 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
779 return GSS_S_UNAVAILABLE;
782 ctx->getAssertion(assertion);
783 } catch (exception &e) {
784 return mapException(minor, e);
787 return GSS_S_COMPLETE;
791 samlDuplicateAttrContext(OM_uint32 *minor,
796 if (in->samlCtx != NULL)
797 out->samlCtx = new gss_eap_saml_attr_ctx(*(in->samlCtx));
800 } catch (exception &e) {
801 return mapException(minor, e);
804 return GSS_S_COMPLETE;
808 samlMapNameToAny(OM_uint32 *minor,
811 gss_buffer_t type_id,
814 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
816 if (bufferEqualString(type_id, "shibsp::Attribute")) {
817 vector <Attribute *>v = duplicateAttributes(ctx->getAttributes());
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();
823 *output = (gss_any_t)NULL;
824 return GSS_S_UNAVAILABLE;
827 return GSS_S_COMPLETE;
831 samlReleaseAnyNameMapping(OM_uint32 *minor,
833 gss_buffer_t type_id,
836 if (bufferEqualString(type_id, "vector<shibsp::Attribute>")) {
837 vector <Attribute *> *v = ((vector <Attribute *> *)*input);
839 } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
840 delete (Assertion *)*input;
842 return GSS_S_UNAVAILABLE;
845 *input = (gss_any_t)NULL;
846 return GSS_S_COMPLETE;
850 samlInit(OM_uint32 *minor)
854 return ShibbolethResolver::init() ? GSS_S_COMPLETE : GSS_S_FAILURE;
858 samlFinalize(OM_uint32 *minor)
862 ShibbolethResolver::term();
863 return GSS_S_COMPLETE;