X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=saml%2Fsaml2%2Fbinding%2Fimpl%2FSAML2ECPDecoder.cpp;h=d571b1bee75c2ffb368fea4a2bcc0eb26390e2f9;hb=1462057b3b9ae7e165d34d988e30b14c213672ca;hp=9d4e2fd5bd0621339a78dafe2ad53f7597629694;hpb=33173e3228184a0fcc4115516f7d3daccfadcbff;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/binding/impl/SAML2ECPDecoder.cpp b/saml/saml2/binding/impl/SAML2ECPDecoder.cpp index 9d4e2fd..d571b1b 100644 --- a/saml/saml2/binding/impl/SAML2ECPDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2ECPDecoder.cpp @@ -1,33 +1,42 @@ -/* - * Copyright 2001-2007 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the + * License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. */ /** * SAML2ECPDecoder.cpp * - * SAML 2.0 ECP profile message decoder + * SAML 2.0 ECP profile message decoder. */ #include "internal.h" #include "exceptions.h" +#include "binding/SecurityPolicy.h" #include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/core/Protocols.h" #include +#include +#include #include #include +#include +#include #include using namespace opensaml::saml2p; @@ -68,18 +77,22 @@ XMLObject* SAML2ECPDecoder::decode( #ifdef _DEBUG xmltooling::NDC ndc("decode"); #endif - Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2ECP"); + Category& log = Category::getInstance(SAML_LOGCAT ".MessageDecoder.SAML2ECP"); log.debug("validating input"); - string s = genericRequest.getContentType(); - if (s.find("application/vnd.paos+xml") == string::npos) { - log.warn("ignoring incorrect content type (%s)", s.c_str() ? s.c_str() : "none"); - throw BindingException("Invalid content type for PAOS message."); + const HTTPRequest* httpRequest = dynamic_cast(&genericRequest); + if (httpRequest) { + string s = httpRequest->getContentType(); + if (s.find("application/vnd.paos+xml") == string::npos) { + log.warn("ignoring incorrect content type (%s)", s.c_str() ? s.c_str() : "none"); + throw BindingException("Invalid content type for PAOS message."); + } } const char* data = genericRequest.getRequestBody(); if (!data) throw BindingException("PAOS message had an empty request body."); + log.debug("received message:\n%s", data); istringstream is(data); // Parse and bind the document into an XMLObject. @@ -93,8 +106,7 @@ XMLObject* SAML2ECPDecoder::decode( if (!env) throw BindingException("Decoded message was not a SOAP 1.1 Envelope."); - if (!policy.getValidating()) - SchemaValidators.validate(env); + SchemaValidators.validate(env); Body* body = env->getBody(); if (body && body->hasChildren()) { @@ -106,23 +118,33 @@ XMLObject* SAML2ECPDecoder::decode( policy.reset(true); extractMessageDetails(*response, genericRequest, samlconstants::SAML20P_NS, policy); policy.evaluate(*response, &genericRequest); - + + // Check destination URL if this is HTTP. + if (httpRequest) { + auto_ptr_char dest(response->getDestination()); + const char* dest2 = httpRequest->getRequestURL(); + const char* delim = strchr(dest2, '?'); + if (response->getSignature() && (!dest.get() || !*(dest.get()))) { + log.error("signed SAML message missing Destination attribute"); + throw BindingException("Signed SAML message missing Destination attribute identifying intended destination."); + } + else if (dest.get() && *dest.get() && ((delim && strncmp(dest.get(), dest2, delim - dest2)) || (!delim && strcmp(dest.get(), dest2)))) { + log.error("PAOS response targeted at (%s), but delivered to (%s)", dest.get(), dest2); + throw BindingException("SAML message delivered with PAOS to incorrect server URL."); + } + } + // Check for RelayState header. if (env->getHeader()) { + static const XMLCh RelayState[] = UNICODE_LITERAL_10(R,e,l,a,y,S,t,a,t,e); const vector& blocks = const_cast(env->getHeader())->getUnknownXMLObjects(); - for (vector::const_iterator h = blocks.begin(); h != blocks.end(); ++h) { - static const XMLCh RelayState[] = UNICODE_LITERAL_10(R,e,l,a,y,S,t,a,t,e); - if (XMLString::equals((*h)->getElementQName().getLocalPart(), RelayState) && - XMLString::equals((*h)->getElementQName().getNamespaceURI(), samlconstants::SAML20ECP_NS)) { - const ElementProxy* ep = dynamic_cast(*h); - if (ep) { - auto_ptr_char rs(ep->getTextContent()); - if (rs.get()) { - relayState = rs.get(); - break; - } - } - } + vector::const_iterator h = + find_if(blocks.begin(), blocks.end(), hasQName(xmltooling::QName(samlconstants::SAML20ECP_NS, RelayState))); + const ElementProxy* ep = dynamic_cast(h != blocks.end() ? *h : nullptr); + if (ep) { + auto_ptr_char rs(ep->getTextContent()); + if (rs.get()) + relayState = rs.get(); } }