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(const gss_buffer_t buffer = GSS_C_NO_BUFFER) {
86 if (buffer != GSS_C_NO_BUFFER && buffer->length != 0)
87 parseAssertion(buffer);
90 gss_eap_saml_attr_ctx(const vector<Attribute*>& attributes,
91 const saml2::Assertion *assertion = NULL) {
92 if (assertion != NULL)
93 m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
94 if (attributes.size())
95 setAttributes(duplicateAttributes(attributes));
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);
102 ~gss_eap_saml_attr_ctx() {
103 for_each(m_attributes.begin(),
105 xmltooling::cleanup<Attribute>())
110 const vector <Attribute *> getAttributes(void) const {
114 void addAttribute(Attribute *attr, bool copy = true);
115 void setAttributes(const vector<Attribute*> attributes);
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);
122 int getAttributeIndex(const gss_buffer_t attr) const;
123 const Attribute *getAttribute(const gss_buffer_t attr) const;
125 bool getAttribute(const gss_buffer_t attr,
129 gss_buffer_t display_value,
132 const saml2::Assertion *getAssertion(void) const {
136 bool getAssertion(gss_buffer_t buffer);
138 DDF marshall() const;
139 static gss_eap_saml_attr_ctx *unmarshall(DDF &in);
141 void marshall(gss_buffer_t buffer);
142 static gss_eap_saml_attr_ctx *unmarshall(const gss_buffer_t buffer);
145 mutable vector<Attribute*> m_attributes;
146 mutable saml2::Assertion *m_assertion;
148 bool parseAssertion(const gss_buffer_t buffer);
152 mapException(OM_uint32 *minor, exception &e)
155 return GSS_S_FAILURE;
159 gss_eap_saml_attr_ctx::parseAssertion(const gss_buffer_t buffer)
162 const XMLObjectBuilder *b;
165 string str((char *)buffer->value, buffer->length);
166 istringstream istream(str);
168 doc = XMLToolingConfig::getConfig().getParser().parse(istream);
169 b = XMLObjectBuilder::getDefaultBuilder();
170 elem = doc->getDocumentElement();
171 xobj = b->buildOneFromElement(elem, true);
173 m_assertion = dynamic_cast<saml2::Assertion *>(xobj);
175 return (m_assertion != NULL);
179 duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
183 if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
184 throw new bad_alloc();
188 duplicateBuffer(string &str, gss_buffer_t buffer)
192 tmp.length = str.length();
193 tmp.value = (char *)str.c_str();
195 duplicateBuffer(tmp, buffer);
199 gss_eap_saml_attr_ctx::marshall() const
205 obj.addmember("version").integer(1);
207 attrs = obj.addmember("attributes").list();
208 for (vector<Attribute*>::const_iterator a = m_attributes.begin();
209 a != m_attributes.end(); ++a) {
210 DDF attr = (*a)->marshall();
215 sink << *m_assertion;
216 assertion = obj.addmember("assertion").string(sink.str().c_str());
221 gss_eap_saml_attr_ctx *
222 gss_eap_saml_attr_ctx::unmarshall(DDF &obj)
224 gss_eap_saml_attr_ctx *ctx = new gss_eap_saml_attr_ctx();
226 DDF version = obj["version"];
227 if (version.integer() != 1)
230 DDF assertion = obj["assertion"];
231 gss_buffer_desc buffer;
233 if (!assertion.isnull()) {
234 buffer.length = assertion.strlen();
235 buffer.value = (void *)assertion.string();
240 if (buffer.length != 0)
241 ctx->parseAssertion(&buffer);
243 DDF attrs = obj["attributes"];
244 DDF attr = attrs.first();
245 while (!attr.isnull()) {
246 Attribute *attribute = Attribute::unmarshall(attr);
247 ctx->addAttribute(attribute, false);
255 gss_eap_saml_attr_ctx::marshall(gss_buffer_t buffer)
257 DDF obj = marshall();
260 string str = sink.str();
262 duplicateBuffer(str, buffer);
267 gss_eap_saml_attr_ctx *
268 gss_eap_saml_attr_ctx::unmarshall(const gss_buffer_t buffer)
270 gss_eap_saml_attr_ctx *ctx;
272 string str((const char *)buffer->value, buffer->length);
273 istringstream source(str);
277 ctx = unmarshall(obj);
285 gss_eap_saml_attr_ctx::getAssertion(gss_buffer_t buffer)
289 if (m_assertion == NULL)
292 buffer->value = NULL;
295 XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
297 duplicateBuffer(str, buffer);
303 duplicateAttribute(const Attribute *src)
305 Attribute *attribute;
307 DDF obj = src->marshall();
308 attribute = Attribute::unmarshall(obj);
314 static vector <Attribute *>
315 duplicateAttributes(const vector <Attribute *>src)
317 vector <Attribute *> dst;
319 for (vector<Attribute *>::const_iterator a = src.begin();
322 dst.push_back(duplicateAttribute(*a));
328 gss_eap_saml_attr_ctx::addAttribute(Attribute *attribute, bool copy)
332 a = copy ? duplicateAttribute(attribute) : attribute;
334 m_attributes.push_back(a);
338 gss_eap_saml_attr_ctx::setAttributes(const vector<Attribute*> attributes)
340 for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<Attribute>());
341 m_attributes = attributes;
345 gss_eap_saml_attr_ctx::getAttributeIndex(const gss_buffer_t attr) const
349 for (vector<Attribute *>::const_iterator a = getAttributes().begin();
350 a != getAttributes().end();
353 for (vector<string>::const_iterator s = (*a)->getAliases().begin();
354 s != (*a)->getAliases().end();
356 if (attr->length == (*s).length() &&
357 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
367 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr) const
369 const Attribute *ret = NULL;
371 for (vector<Attribute *>::const_iterator a = getAttributes().begin();
372 a != getAttributes().end();
375 for (vector<string>::const_iterator s = (*a)->getAliases().begin();
376 s != (*a)->getAliases().end();
378 if (attr->length == (*s).length() &&
379 memcmp((*s).c_str(), attr->value, attr->length) == 0) {
392 gss_eap_saml_attr_ctx::getAttribute(const gss_buffer_t attr,
396 gss_buffer_t display_value,
399 const Attribute *shibAttr = NULL;
402 shibAttr = getAttribute(attr);
403 if (shibAttr == NULL)
408 } else if (*more >= (int)shibAttr->valueCount()) {
413 buf.value = (void *)shibAttr->getString(*more);
414 buf.length = strlen((char *)buf.value);
416 duplicateBuffer(buf, value);
418 *authenticated = TRUE;
425 samlAttributeFromGssBuffers(const gss_buffer_t attr,
426 const gss_buffer_t value)
428 string attrStr((char *)attr->value, attr->length);
429 vector <string> ids(1);
432 ids.push_back(attrStr);
434 a = new SimpleAttribute(ids);
436 if (value->length != 0) {
437 string valStr((char *)value->value, value->length);
439 a->getValues().push_back(valStr);
446 gss_eap_saml_attr_ctx::setAttribute(int complete,
447 const gss_buffer_t attr,
448 const gss_buffer_t value)
450 Attribute *a = samlAttributeFromGssBuffers(attr, value);
452 addAttribute(a, false);
456 gss_eap_saml_attr_ctx::deleteAttribute(const gss_buffer_t attr)
460 i = getAttributeIndex(attr);
462 m_attributes.erase(m_attributes.begin() + i);
466 samlReleaseAttrContext(OM_uint32 *minor, gss_name_t name)
469 delete name->samlCtx;
470 name->samlCtx = NULL;
471 } catch (exception &e) {
472 return mapException(minor, e);
475 return GSS_S_COMPLETE;
478 static gss_buffer_desc
479 gssEapRadiusAssertionAttr = { 3, (void *)"128" };
482 samlAddRadiusAttribute(OM_uint32 *minor,
488 ShibbolethResolver *resolver = (ShibbolethResolver *)resolver;
490 int authenticated, complete, more = -1;
491 gss_buffer_desc value;
493 if (bufferEqual(attr, &gssEapRadiusAssertionAttr)) {
494 return GSS_S_COMPLETE;
497 major = radiusGetAttribute(minor, name, attr,
498 &authenticated, &complete,
499 &value, GSS_C_NO_BUFFER, &more);
500 if (major == GSS_S_COMPLETE) {
501 /* Do some prefixing? */
502 a = samlAttributeFromGssBuffers(attr, &value);
504 resolver->addAttribute(a);
507 return GSS_S_COMPLETE;
511 samlAddRadiusAttributes(OM_uint32 *minor,
513 ShibbolethResolver *resolver)
515 return radiusGetAttributeTypes(minor,
517 samlAddRadiusAttribute,
522 samlInitAttrContextFromRadius(OM_uint32 *minor,
524 gss_eap_saml_attr_ctx **pSamlCtx)
527 int authenticated, complete, more = -1;
528 gss_buffer_desc value;
533 major = radiusGetAttribute(minor, name, &gssEapRadiusAssertionAttr,
534 &authenticated, &complete,
535 &value, GSS_C_NO_BUFFER, &more);
536 if (major == GSS_S_UNAVAILABLE) {
537 /* No assertion provided via RADIUS. */
540 } else if (GSS_ERROR(major)) {
541 /* Some other error */
545 *pSamlCtx = new gss_eap_saml_attr_ctx(&value);
547 gss_release_buffer(minor, &value);
549 return GSS_S_COMPLETE;
553 samlCreateAttrContext(OM_uint32 *minor,
554 gss_cred_id_t acceptorCred,
555 gss_name_t initiatorName,
558 OM_uint32 major, tmpMinor;
559 gss_buffer_desc nameBuf;
560 gss_eap_saml_attr_ctx *ctx = NULL;
561 ShibbolethResolver *resolver = NULL;
563 assert(initiatorName != GSS_C_NO_NAME);
566 nameBuf.value = NULL;
568 resolver = ShibbolethResolver::create();
569 if (resolver == NULL)
570 return GSS_S_FAILURE;
572 if (acceptorCred != GSS_C_NO_CREDENTIAL) {
573 major = gss_display_name(minor, acceptorCred->name, &nameBuf, NULL);
574 if (GSS_ERROR(major))
579 const saml2::Assertion *assertion;
580 vector <Attribute *> attrs;
582 major = samlInitAttrContextFromRadius(minor, initiatorName, &ctx);
583 if (GSS_ERROR(major))
586 assertion = ctx->getAssertion();
588 if (assertion != NULL) {
589 if (assertion->getConditions()) {
591 assertion->getConditions()->getNotOnOrAfter()->getEpoch();
594 resolver->addToken(assertion);
597 if (initiatorName->radiusCtx != NULL) {
598 samlAddRadiusAttributes(minor, initiatorName, resolver);
601 resolver->resolveAttributes(attrs);
602 ctx->setAttributes(attrs);
603 } catch (exception &ex) {
604 major = mapException(minor, ex);
609 major = GSS_S_COMPLETE;
611 initiatorName->samlCtx = ctx;
614 gss_release_buffer(&tmpMinor, &nameBuf);
615 if (GSS_ERROR(major))
623 samlGetAttributeTypes(OM_uint32 *minor,
625 enum gss_eap_attribute_type type,
626 gss_eap_add_attr_cb addAttribute,
629 OM_uint32 major = GSS_S_COMPLETE;
630 gss_eap_saml_attr_ctx *ctx = name->samlCtx;
633 return GSS_S_COMPLETE;
635 if (type != ATTR_TYPE_NONE)
636 return GSS_S_UNAVAILABLE;
638 for (vector<Attribute*>::const_iterator a = ctx->getAttributes().begin();
639 a != ctx->getAttributes().end();
642 gss_buffer_desc attribute;
644 attribute.value = (void *)((*a)->getId());
645 attribute.length = strlen((char *)attribute.value);
647 major = addAttribute(minor, name, &attribute, data);
648 if (GSS_ERROR(major))
656 * SAML implementation of gss_get_name_attribute
659 samlGetAttribute(OM_uint32 *minor,
660 enum gss_eap_attribute_type type,
666 gss_buffer_t display_value,
669 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
673 return GSS_S_UNAVAILABLE;
677 ret = ctx->getAttribute(attr, authenticated, complete,
678 value, display_value, more);
685 return ret ? GSS_S_COMPLETE : GSS_S_UNAVAILABLE;
689 samlSetAttribute(OM_uint32 *minor,
695 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
698 return GSS_S_UNAVAILABLE;
701 ctx->setAttribute(complete, attr, value);
702 } catch (exception &e) {
703 return mapException(minor, e);
706 return GSS_S_COMPLETE;
710 samlDeleteAttribute(OM_uint32 *minor,
714 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
717 return GSS_S_UNAVAILABLE;
720 ctx->deleteAttribute(attr);
721 } catch (exception &e) {
722 return mapException(minor, e);
725 return GSS_S_COMPLETE;
729 * In order to implement gss_export_name and gss_export_sec_context,
730 * we need to serialise a resolved attribute context to a buffer.
733 samlExportAttrContext(OM_uint32 *minor,
737 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
740 ctx->marshall(buffer);
741 } catch (exception &e) {
742 return mapException(minor, e);
745 return GSS_S_COMPLETE;
749 * In order to implement gss_import_name and gss_import_sec_context,
750 * we need to deserialise a resolved attribute context from a buffer.
753 samlImportAttrContext(OM_uint32 *minor,
758 assert(name->samlCtx == NULL);
759 name->samlCtx = gss_eap_saml_attr_ctx::unmarshall(buffer);
760 } catch (exception &e) {
761 return mapException(minor, e);
764 return GSS_S_COMPLETE;
768 samlGetAssertion(OM_uint32 *minor,
770 gss_buffer_t assertion)
772 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
775 return GSS_S_UNAVAILABLE;
778 ctx->getAssertion(assertion);
779 } catch (exception &e) {
780 return mapException(minor, e);
783 return GSS_S_COMPLETE;
787 samlDuplicateAttrContext(OM_uint32 *minor,
792 if (in->samlCtx != NULL)
793 out->samlCtx = new gss_eap_saml_attr_ctx(*(in->samlCtx));
796 } catch (exception &e) {
797 return mapException(minor, e);
800 return GSS_S_COMPLETE;
804 samlMapNameToAny(OM_uint32 *minor,
807 gss_buffer_t type_id,
810 struct gss_eap_saml_attr_ctx *ctx = name->samlCtx;
812 if (bufferEqualString(type_id, "shibsp::Attribute")) {
813 vector <Attribute *>v = duplicateAttributes(ctx->getAttributes());
815 *output = (gss_any_t)new vector <Attribute *>(v);
816 } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
817 *output = (gss_any_t)ctx->getAssertion()->clone();
819 *output = (gss_any_t)NULL;
820 return GSS_S_UNAVAILABLE;
823 return GSS_S_COMPLETE;
827 samlReleaseAnyNameMapping(OM_uint32 *minor,
829 gss_buffer_t type_id,
832 if (bufferEqualString(type_id, "vector<shibsp::Attribute>")) {
833 vector <Attribute *> *v = ((vector <Attribute *> *)*input);
835 } else if (bufferEqualString(type_id, "opensaml::Assertion")) {
836 delete (Assertion *)*input;
838 return GSS_S_UNAVAILABLE;
841 *input = (gss_any_t)NULL;
842 return GSS_S_COMPLETE;
846 samlInit(OM_uint32 *minor)
850 return ShibbolethResolver::init() ? GSS_S_COMPLETE : GSS_S_FAILURE;
854 samlFinalize(OM_uint32 *minor)
858 ShibbolethResolver::term();
859 return GSS_S_COMPLETE;