X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fmetadata%2FDynamicMetadataProvider.cpp;h=607cad693c968fbd08c1095988c22e8e0e6e1710;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=2698baadec279261759c0af463f71468cc47cc14;hpb=9ccdbac09f806eb2fcd298c07110932d9b8c9004;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/metadata/DynamicMetadataProvider.cpp b/shibsp/metadata/DynamicMetadataProvider.cpp index 2698baa..607cad6 100644 --- a/shibsp/metadata/DynamicMetadataProvider.cpp +++ b/shibsp/metadata/DynamicMetadataProvider.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2009 Internet2 +/** + * 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. * - * 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 + * 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. */ /** @@ -26,6 +30,12 @@ #include "ServiceProvider.h" #include "metadata/MetadataProviderCriteria.h" +#include +#include +#include +#include +#include + #include #include #include @@ -39,11 +49,10 @@ #include #include #include +#include +#include #include -#include -#include - using namespace shibsp; using namespace opensaml; using namespace xmltooling::logging; @@ -51,74 +60,79 @@ using namespace xmltooling; using namespace std; namespace shibsp { - class SAML_DLLLOCAL DummyCredentialResolver : public CredentialResolver - { - public: - DummyCredentialResolver() {} - ~DummyCredentialResolver() {} - - Lockable* lock() {return this;} - void unlock() {} - - const Credential* resolve(const CredentialCriteria* criteria=NULL) const {return NULL;} - vector::size_type resolve( - vector& results, const CredentialCriteria* criteria=NULL - ) const {return 0;} - }; - class SHIBSP_DLLLOCAL DynamicMetadataProvider : public saml2md::DynamicMetadataProvider { public: - DynamicMetadataProvider(const xercesc::DOMElement* e=NULL); + DynamicMetadataProvider(const xercesc::DOMElement* e=nullptr); - virtual ~DynamicMetadataProvider() { - delete m_trust; - } + virtual ~DynamicMetadataProvider() {} protected: saml2md::EntityDescriptor* resolve(const saml2md::MetadataProvider::Criteria& criteria) const; private: - bool m_verifyHost,m_ignoreTransport; - X509TrustEngine* m_trust; + bool m_verifyHost,m_ignoreTransport,m_encoded; + string m_subst, m_match, m_regex; + boost::scoped_ptr m_trust; + boost::scoped_ptr m_dummyCR; }; - saml2md::MetadataProvider* SHIBSP_DLLLOCAL DynamicMetadataProviderFactory(const DOMElement* const & e) { return new DynamicMetadataProvider(e); } + static const XMLCh encoded[] = UNICODE_LITERAL_7(e,n,c,o,d,e,d); static const XMLCh ignoreTransport[] = UNICODE_LITERAL_15(i,g,n,o,r,e,T,r,a,n,s,p,o,r,t); + static const XMLCh match[] = UNICODE_LITERAL_5(m,a,t,c,h); + static const XMLCh Regex[] = UNICODE_LITERAL_5(R,e,g,e,x); + static const XMLCh Subst[] = UNICODE_LITERAL_5(S,u,b,s,t); static const XMLCh _TrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e); - static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); + static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e); static const XMLCh verifyHost[] = UNICODE_LITERAL_10(v,e,r,i,f,y,H,o,s,t); }; DynamicMetadataProvider::DynamicMetadataProvider(const DOMElement* e) - : saml2md::DynamicMetadataProvider(e), m_verifyHost(true), m_ignoreTransport(false), m_trust(NULL) + : saml2md::DynamicMetadataProvider(e), + m_verifyHost(XMLHelper::getAttrBool(e, true, verifyHost)), + m_ignoreTransport(XMLHelper::getAttrBool(e, false, ignoreTransport)), + m_encoded(true), m_trust(nullptr) { - const XMLCh* flag = e ? e->getAttributeNS(NULL, verifyHost) : NULL; - if (flag && (*flag == chLatin_f || *flag == chDigit_0)) - m_verifyHost = false; - flag = e ? e->getAttributeNS(NULL, ignoreTransport) : NULL; - if (flag && (*flag == chLatin_t || *flag == chDigit_1)) { - m_ignoreTransport = true; - return; + const DOMElement* child = XMLHelper::getFirstChildElement(e, Subst); + if (child && child->hasChildNodes()) { + auto_ptr_char s(child->getFirstChild()->getNodeValue()); + if (s.get() && *s.get()) { + m_subst = s.get(); + m_encoded = XMLHelper::getAttrBool(child, true, encoded); + } } - e = e ? XMLHelper::getFirstChildElement(e, _TrustEngine) : NULL; - auto_ptr_char t2(e ? e->getAttributeNS(NULL,type) : NULL); - if (t2.get()) { - TrustEngine* trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(t2.get(),e); - if (!(m_trust = dynamic_cast(trust))) { - delete trust; - throw ConfigurationException("DynamicMetadataProvider requires an X509TrustEngine plugin."); + if (m_subst.empty()) { + child = XMLHelper::getFirstChildElement(e, Regex); + if (child && child->hasChildNodes() && child->hasAttributeNS(nullptr, match)) { + m_match = XMLHelper::getAttrString(child, nullptr, match); + auto_ptr_char repl(child->getFirstChild()->getNodeValue()); + if (repl.get() && *repl.get()) + m_regex = repl.get(); } - return; } - throw ConfigurationException("DynamicMetadataProvider requires an X509TrustEngine plugin unless ignoreTransport is true."); + if (!m_ignoreTransport) { + child = XMLHelper::getFirstChildElement(e, _TrustEngine); + string t = XMLHelper::getAttrString(child, nullptr, _type); + if (!t.empty()) { + TrustEngine* trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(t.c_str(), child); + if (!dynamic_cast(trust)) { + delete trust; + throw ConfigurationException("DynamicMetadataProvider requires an X509TrustEngine plugin."); + } + m_trust.reset(dynamic_cast(trust)); + m_dummyCR.reset(XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(DUMMY_CREDENTIAL_RESOLVER, nullptr)); + } + + if (!m_trust.get() || !m_dummyCR.get()) + throw ConfigurationException("DynamicMetadataProvider requires an X509TrustEngine plugin unless ignoreTransport is true."); + } } saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::MetadataProvider::Criteria& criteria) const @@ -126,7 +140,7 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad #ifdef _DEBUG xmltooling::NDC("resolve"); #endif - Category& log=Category::getInstance(SHIBSP_LOGCAT".MetadataProvider.Dynamic"); + Category& log=Category::getInstance(SHIBSP_LOGCAT ".MetadataProvider.Dynamic"); string name; if (criteria.entityID_ascii) { @@ -137,7 +151,37 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad name = temp.get(); } else if (criteria.artifact) { - throw saml2md::MetadataException("Unable to resolve metadata dynamically from an artifact."); + if (m_subst.empty() && (m_regex.empty() || m_match.empty())) + throw saml2md::MetadataException("Unable to resolve metadata dynamically from an artifact."); + name = "{sha1}" + criteria.artifact->getSource(); + } + + // Possibly transform the input into a different URL to use. + if (!m_subst.empty()) { + string name2 = boost::replace_first_copy(m_subst, "$entityID", + m_encoded ? XMLToolingConfig::getConfig().getURLEncoder()->encode(name.c_str()) : name); + log.info("transformed location from (%s) to (%s)", name.c_str(), name2.c_str()); + name = name2; + } + else if (!m_match.empty() && !m_regex.empty()) { + try { + RegularExpression exp(m_match.c_str()); + XMLCh* temp = exp.replace(name.c_str(), m_regex.c_str()); + if (temp) { + auto_ptr_char narrow(temp); + XMLString::release(&temp); + + // For some reason it returns the match string if it doesn't match the expression. + if (name != narrow.get()) { + log.info("transformed location from (%s) to (%s)", name.c_str(), narrow.get()); + name = narrow.get(); + } + } + } + catch (XMLException& ex) { + auto_ptr_char msg(ex.getMessage()); + log.error("caught error applying regular expression: %s", msg.get()); + } } // Establish networking properties based on calling application. @@ -145,7 +189,9 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad if (!mpc) throw saml2md::MetadataException("Dynamic MetadataProvider requires Shibboleth-aware lookup criteria, check calling code."); const PropertySet* relyingParty; - if (criteria.entityID_unicode) + if (criteria.artifact) + relyingParty = mpc->application.getRelyingParty((XMLCh*)nullptr); + else if (criteria.entityID_unicode) relyingParty = mpc->application.getRelyingParty(criteria.entityID_unicode); else { auto_ptr_XMLCh temp2(name.c_str()); @@ -156,26 +202,24 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad SOAPTransport::Address addr(relyingParty->getString("entityID").second, name.c_str(), name.c_str()); const char* pch = strchr(addr.m_endpoint,':'); if (!pch) - throw IOException("entityID was not a URL."); + throw IOException("location was not a URL."); string scheme(addr.m_endpoint, pch-addr.m_endpoint); - SOAPTransport* transport=NULL; + boost::scoped_ptr transport; try { - transport = XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr); + transport.reset(XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr)); } catch (exception& ex) { log.error("exception while building transport object to resolve URL: %s", ex.what()); throw IOException("Unable to resolve entityID with a known transport protocol."); } - auto_ptr transportwrapper(transport); // Apply properties as directed. transport->setVerifyHost(m_verifyHost); - DummyCredentialResolver dcr; - if (m_trust && !transport->setTrustEngine(m_trust, &dcr)) - throw IOException("Unable to install X509TrustEngine into metadata resolver."); + if (m_trust.get() && m_dummyCR.get() && !transport->setTrustEngine(m_trust.get(), m_dummyCR.get())) + throw IOException("Unable to install X509TrustEngine into transport object."); - Locker credlocker(NULL, false); - CredentialResolver* credResolver = NULL; + Locker credlocker(nullptr, false); + CredentialResolver* credResolver = nullptr; pair authType=relyingParty->getString("authType"); if (!authType.first || !strcmp(authType.second,"TLS")) { credResolver = mpc->application.getCredentialResolver(); @@ -231,23 +275,22 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad transport->setTimeout(timeout.first ? timeout.second : 20); mpc->application.getServiceProvider().setTransportOptions(*transport); - HTTPSOAPTransport* http = dynamic_cast(transport); + HTTPSOAPTransport* http = dynamic_cast(transport.get()); if (http) { pair flag = relyingParty->getBool("chunkedEncoding"); http->useChunkedEncoding(flag.first && flag.second); http->setRequestHeader("Xerces-C", XERCES_FULLVERSIONDOT); http->setRequestHeader("XML-Security-C", XSEC_FULLVERSIONDOT); - http->setRequestHeader("OpenSAML-C", OPENSAML_FULLVERSIONDOT); - http->setRequestHeader("User-Agent", PACKAGE_NAME); + http->setRequestHeader("OpenSAML-C", gOpenSAMLDotVersionStr); http->setRequestHeader(PACKAGE_NAME, PACKAGE_VERSION); } try { - // Use a NULL stream to trigger a body-less "GET" operation. + // Use a nullptr stream to trigger a body-less "GET" operation. transport->send(); istream& msg = transport->receive(); - DOMDocument* doc=NULL; + DOMDocument* doc=nullptr; StreamInputSource src(msg, "DynamicMetadataProvider"); Wrapper4InputSource dsrc(&src,false); if (m_validate) @@ -258,6 +301,12 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad // Wrap the document for now. XercesJanitor docjanitor(doc); + // Check root element. + if (!doc->getDocumentElement() || !XMLHelper::isNodeNamed(doc->getDocumentElement(), + samlconstants::SAML20MD_NS, saml2md::EntityDescriptor::LOCAL_NAME)) { + throw saml2md::MetadataException("Root of metadata instance was not an EntityDescriptor"); + } + // Unmarshall objects, binding the document. auto_ptr xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true)); docjanitor.release(); @@ -274,7 +323,7 @@ saml2md::EntityDescriptor* DynamicMetadataProvider::resolve(const saml2md::Metad } catch (XMLException& e) { auto_ptr_char msg(e.getMessage()); - log.error("Xerces error while resolving entityID (%s): %s", name.c_str(), msg.get()); + log.error("Xerces error while resolving location (%s): %s", name.c_str(), msg.get()); throw saml2md::MetadataException(msg.get()); } }