X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fimpl%2FXMLServiceProvider.cpp;h=ae94a16eefebbc3630e72ef4264011bcd30a59dc;hb=ce7abd70f1a7b6d8bf02ff4a23f2e57f2b18fff7;hp=7664a4011b847f5f60255102a7bd34b41f454a41;hpb=f364df34d639782670b3db8d82e884af5607c675;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index 7664a40..ae94a16 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Internet2 + * Copyright 2001-2009 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,17 +17,19 @@ /** * XMLServiceProvider.cpp * - * XML-based SP configuration and mgmt + * XML-based SP configuration and mgmt. */ #include "internal.h" #include "exceptions.h" +#include "version.h" #include "AccessControl.h" #include "Application.h" #include "RequestMapper.h" #include "ServiceProvider.h" #include "SessionCache.h" #include "SPConfig.h" +#include "SPRequest.h" #include "handler/SessionInitiator.h" #include "remoting/ListenerService.h" #include "util/DOMPropertySet.h" @@ -40,10 +42,13 @@ #else # error "Supported logging library not available." #endif +#include #include #include +#include #include #include +#include #include #ifndef SHIBSP_LITE @@ -53,17 +58,27 @@ # include "attribute/resolver/AttributeResolver.h" # include "security/PKIXTrustEngine.h" # include +# include # include # include +# include # include +# include # include -# include -# include +# include +# include +# include +# include +# include +# include # include +# include using namespace opensaml::saml2; using namespace opensaml::saml2p; using namespace opensaml::saml2md; using namespace opensaml; +#else +# include "lite/SAMLConstants.h" #endif using namespace shibsp; @@ -102,7 +117,11 @@ namespace { index = props->getInt("artifactEndpointIndex"); if (!index.first) index = getArtifactEndpointIndex(); - return new SAML2ArtifactType0004(SAMLConfig::getConfig().hashSHA1(props->getString("entityID").second),index.first ? index.second : 1); + pair entityID = props->getString("entityID"); + return new SAML2ArtifactType0004( + SecurityHelper::doHash("SHA1", entityID.second, strlen(entityID.second), false), + index.first ? index.second : 1 + ); } MetadataProvider* getMetadataProvider(bool required=true) const { @@ -139,6 +158,10 @@ namespace { return (m_remoteUsers.empty() && m_base) ? m_base->getRemoteUserAttributeIds() : m_remoteUsers; } + void clearHeader(SPRequest& request, const char* rawname, const char* cginame) const; + void setHeader(SPRequest& request, const char* name, const char* value) const; + string getSecureHeader(const SPRequest& request, const char* name) const; + const SessionInitiator* getDefaultSessionInitiator() const; const SessionInitiator* getSessionInitiatorById(const char* id) const; const Handler* getDefaultAssertionConsumerService() const; @@ -160,12 +183,18 @@ namespace { } // Provides filter to exclude special config elements. - short acceptNode(const DOMNode* node) const; +#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE + short +#else + FilterAction +#endif + acceptNode(const DOMNode* node) const; private: void cleanup(); const XMLApplication* m_base; string m_hash; + std::pair m_attributePrefix; #ifndef SHIBSP_LITE MetadataProvider* m_metadata; TrustEngine* m_trust; @@ -176,11 +205,7 @@ namespace { vector m_audiences; // RelyingParty properties -#ifdef HAVE_GOOD_STL map m_partyMap; -#else - map m_partyMap; -#endif #endif vector m_remoteUsers,m_frontLogout,m_backLogout; @@ -197,11 +222,7 @@ namespace { const Handler* m_acsDefault; // maps binding strings to supporting consumer service(s) -#ifdef HAVE_GOOD_STL typedef map > ACSBindingMap; -#else - typedef map > ACSBindingMap; -#endif ACSBindingMap m_acsBindingMap; // pointer to default session initiator @@ -235,7 +256,12 @@ namespace { #endif // Provides filter to exclude special config elements. - short acceptNode(const DOMNode* node) const; +#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE + short +#else + FilterAction +#endif + acceptNode(const DOMNode* node) const; void setDocument(DOMDocument* doc) { m_document = doc; @@ -410,6 +436,7 @@ namespace { static const XMLCh OutOfProcess[] = UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s); static const XMLCh _path[] = UNICODE_LITERAL_4(p,a,t,h); static const XMLCh Policy[] = UNICODE_LITERAL_6(P,o,l,i,c,y); + static const XMLCh PolicyRule[] = UNICODE_LITERAL_10(P,o,l,i,c,y,R,u,l,e); static const XMLCh _provider[] = UNICODE_LITERAL_8(p,r,o,v,i,d,e,r); static const XMLCh RelyingParty[] = UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y); static const XMLCh _ReplayCache[] = UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e); @@ -431,7 +458,12 @@ namespace { class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter { public: - short acceptNode(const DOMNode* node) const { +#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE + short +#else + FilterAction +#endif + acceptNode(const DOMNode* node) const { return FILTER_REJECT; } }; @@ -483,6 +515,18 @@ XMLApplication::XMLApplication( m_hash += (DIGITS[0x0F & *ch]); } + // Populate prefix pair. + m_attributePrefix.second = "HTTP_"; + pair prefix = getString("attributePrefix"); + if (prefix.first) { + m_attributePrefix.first = prefix.second; + const char* pch = prefix.second; + while (*pch) { + m_attributePrefix.second += (isalnum(*pch) ? toupper(*pch) : '_'); + pch++; + } + } + // Load attribute ID lists for REMOTE_USER and header clearing. if (conf.isEnabled(SPConfig::InProcess)) { pair attributes = getString("REMOTE_USER"); @@ -506,9 +550,9 @@ XMLApplication::XMLApplication( attributes = getString("unsetHeaders"); if (attributes.first) { - string transformedprefix("HTTP_"); + string transformedprefix(m_attributePrefix.second); const char* pch; - pair prefix = getString("metadataAttributePrefix"); + prefix = getString("metadataAttributePrefix"); if (prefix.first) { pch = prefix.second; while (*pch) { @@ -534,13 +578,14 @@ XMLApplication::XMLApplication( transformed += (isalnum(*pch) ? toupper(*pch) : '_'); pch++; } - m_unsetHeaders.push_back(pair(start,string("HTTP_") + transformed)); + + m_unsetHeaders.push_back(pair(m_attributePrefix.first + start, m_attributePrefix.second + transformed)); if (prefix.first) - m_unsetHeaders.push_back(pair(string(prefix.second) + start, transformedprefix + transformed)); + m_unsetHeaders.push_back(pair(m_attributePrefix.first + prefix.second + start, transformedprefix + transformed)); start = pos ? pos+1 : NULL; } free(dup); - m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); + m_unsetHeaders.push_back(pair(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID")); } } @@ -593,11 +638,7 @@ XMLApplication::XMLApplication( } handler=conf.AssertionConsumerServiceManager.newPlugin(bindprop.get(),make_pair(child, getId())); // Map by binding (may be > 1 per binding, e.g. SAML 1.0 vs 1.1) -#ifdef HAVE_GOOD_STL m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler); -#else - m_acsBindingMap[handler->getString("Binding").second].push_back(handler); -#endif m_acsIndexMap[handler->getUnsignedInt("index").second]=handler; if (!hardACS) { @@ -728,9 +769,12 @@ XMLApplication::XMLApplication( #ifndef SHIBSP_LITE nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME); - for (XMLSize_t i=0; nlist && igetLength(); i++) - if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes()) - m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue()); + if (nlist && nlist->getLength()) { + log.warn("use of elements outside of a Security Policy Rule is deprecated"); + for (XMLSize_t i=0; igetLength(); i++) + if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes()) + m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue()); + } if (conf.isEnabled(SPConfig::Metadata)) { child = XMLHelper::getFirstChildElement(e,_MetadataProvider); @@ -805,18 +849,20 @@ XMLApplication::XMLApplication( Locker extlock(m_attrExtractor); m_attrExtractor->getAttributeIds(unsetHeaders); } + else if (m_base && m_base->m_attrExtractor) { + Locker extlock(m_base->m_attrExtractor); + m_base->m_attrExtractor->getAttributeIds(unsetHeaders); + } if (m_attrResolver) { Locker reslock(m_attrResolver); m_attrResolver->getAttributeIds(unsetHeaders); } - if (unsetHeaders.empty()) { - if (m_base) - m_unsetHeaders.insert(m_unsetHeaders.end(), m_base->m_unsetHeaders.begin(), m_base->m_unsetHeaders.end()); - else - m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); + else if (m_base && m_base->m_attrResolver) { + Locker extlock(m_base->m_attrResolver); + m_base->m_attrResolver->getAttributeIds(unsetHeaders); } - else { - string transformedprefix("HTTP_"); + if (!unsetHeaders.empty()) { + string transformedprefix(m_attributePrefix.second); const char* pch; pair prefix = getString("metadataAttributePrefix"); if (prefix.first) { @@ -833,12 +879,12 @@ XMLApplication::XMLApplication( transformed += (isalnum(*pch) ? toupper(*pch) : '_'); pch++; } - m_unsetHeaders.push_back(pair(*hdr, string("HTTP_") + transformed)); + m_unsetHeaders.push_back(pair(m_attributePrefix.first + *hdr, m_attributePrefix.second + transformed)); if (prefix.first) - m_unsetHeaders.push_back(pair(string(prefix.second) + *hdr, transformedprefix + transformed)); + m_unsetHeaders.push_back(pair(m_attributePrefix.first + prefix.second + *hdr, transformedprefix + transformed)); } - m_unsetHeaders.push_back(pair("Shib-Application-ID","HTTP_SHIB_APPLICATION_ID")); } + m_unsetHeaders.push_back(pair(m_attributePrefix.first + "Shib-Application-ID", m_attributePrefix.second + "SHIB_APPLICATION_ID")); } } @@ -900,11 +946,7 @@ void XMLApplication::cleanup() for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup()); m_handlers.clear(); #ifndef SHIBSP_LITE -#ifdef HAVE_GOOD_STL for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair()); -#else - for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair()); -#endif m_partyMap.clear(); delete m_credResolver; m_credResolver = NULL; @@ -921,7 +963,12 @@ void XMLApplication::cleanup() #endif } -short XMLApplication::acceptNode(const DOMNode* node) const +#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE +short +#else +DOMNodeFilter::FilterAction +#endif +XMLApplication::acceptNode(const DOMNode* node) const { const XMLCh* name=node->getLocalName(); if (XMLString::equals(name,ApplicationOverride) || @@ -953,7 +1000,6 @@ const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provi if (!provider) return this; -#ifdef HAVE_GOOD_STL map::const_iterator i=m_partyMap.find(provider->getEntityID()); if (i!=m_partyMap.end()) return i->second; @@ -966,19 +1012,6 @@ const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provi } group=dynamic_cast(group->getParent()); } -#else - map::const_iterator i=m_partyMap.begin(); - for (; i!=m_partyMap.end(); i++) { - if (XMLString::equals(i->first,provider->getEntityID())) - return i->second; - const EntitiesDescriptor* group=dynamic_cast(provider->getParent()); - while (group) { - if (XMLString::equals(i->first,group->getName())) - return i->second; - group=dynamic_cast(group->getParent()); - } - } -#endif return this; } @@ -987,17 +1020,9 @@ const PropertySet* XMLApplication::getRelyingParty(const XMLCh* entityID) const if (!entityID) return this; -#ifdef HAVE_GOOD_STL map::const_iterator i=m_partyMap.find(entityID); if (i!=m_partyMap.end()) return i->second; -#else - map::const_iterator i=m_partyMap.begin(); - for (; i!=m_partyMap.end(); i++) { - if (XMLString::equals(i->first,entityID)) - return i->second; - } -#endif return this; } @@ -1075,6 +1100,49 @@ string XMLApplication::getNotificationURL(const char* resource, bool front, unsi return notifyURL; } +void XMLApplication::clearHeader(SPRequest& request, const char* rawname, const char* cginame) const +{ + if (!m_attributePrefix.first.empty()) { + string temp = m_attributePrefix.first + rawname; + string temp2 = m_attributePrefix.second + (cginame + 5); + request.clearHeader(temp.c_str(), temp2.c_str()); + } + else if (m_base) { + m_base->clearHeader(request, rawname, cginame); + } + else { + request.clearHeader(rawname, cginame); + } +} + +void XMLApplication::setHeader(SPRequest& request, const char* name, const char* value) const +{ + if (!m_attributePrefix.first.empty()) { + string temp = m_attributePrefix.first + name; + request.setHeader(temp.c_str(), value); + } + else if (m_base) { + m_base->setHeader(request, name, value); + } + else { + request.setHeader(name, value); + } +} + +string XMLApplication::getSecureHeader(const SPRequest& request, const char* name) const +{ + if (!m_attributePrefix.first.empty()) { + string temp = m_attributePrefix.first + name; + return request.getSecureHeader(temp.c_str()); + } + else if (m_base) { + return m_base->getSecureHeader(request,name); + } + else { + return request.getSecureHeader(name); + } +} + const SessionInitiator* XMLApplication::getDefaultSessionInitiator() const { if (m_sessionInitDefault) return m_sessionInitDefault; @@ -1103,12 +1171,7 @@ const Handler* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short const vector& XMLApplication::getAssertionConsumerServicesByBinding(const XMLCh* binding) const { -#ifdef HAVE_GOOD_STL ACSBindingMap::const_iterator i=m_acsBindingMap.find(binding); -#else - auto_ptr_char temp(binding); - ACSBindingMap::const_iterator i=m_acsBindingMap.find(temp.get()); -#endif if (i!=m_acsBindingMap.end()) return i->second; return m_base ? m_base->getAssertionConsumerServicesByBinding(binding) : g_noHandlers; @@ -1117,6 +1180,7 @@ const vector& XMLApplication::getAssertionConsumerServicesByBind const Handler* XMLApplication::getHandler(const char* path) const { string wrap(path); + wrap = wrap.substr(0,wrap.find(';')); map::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?'))); if (i!=m_handlerMap.end()) return i->second; @@ -1134,7 +1198,12 @@ void XMLApplication::getHandlers(vector& handlers) const } } -short XMLConfigImpl::acceptNode(const DOMNode* node) const +#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE +short +#else +DOMNodeFilter::FilterAction +#endif +XMLConfigImpl::acceptNode(const DOMNode* node) const { if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS)) return FILTER_ACCEPT; @@ -1166,7 +1235,8 @@ void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Categor auto_ptr_char path(exts->getAttributeNS(NULL,_path)); try { if (path.get()) { - XMLToolingConfig::getConfig().load_library(path.get(),(void*)exts); + if (!XMLToolingConfig::getConfig().load_library(path.get(),(void*)exts)) + throw ConfigurationException("XMLToolingConfig::load_library failed."); log.debug("loaded %s extension library (%s)", label, path.get()); } } @@ -1213,7 +1283,8 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o if (logconf && *logconf) { auto_ptr_char logpath(logconf); log.debug("loading new logging configuration from (%s), check log destination for status of configuration",logpath.get()); - XMLToolingConfig::getConfig().log_config(logpath.get()); + if (!XMLToolingConfig::getConfig().log_config(logpath.get())) + log.crit("failed to load new logging configuration from (%s)", logpath.get()); } #ifndef SHIBSP_LITE @@ -1222,6 +1293,19 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o #endif } + // Re-log library versions now that logging is set up. +#ifndef SHIBSP_LITE + log.info( + "Library versions: Xerces-C %s, XML-Security-C %s, XMLTooling-C %s, OpenSAML-C %s, Shibboleth %s", + XERCES_FULLVERSIONDOT, XSEC_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, OPENSAML_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT + ); +#else + log.info( + "Library versions: Xerces-C %s, XMLTooling-C %s, Shibboleth %s", + XERCES_FULLVERSIONDOT, XMLTOOLING_FULLVERSIONDOT, SHIBSP_FULLVERSIONDOT + ); +#endif + // First load any property sets. load(e,NULL,this); @@ -1235,6 +1319,24 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o if (skew.first) xmlConf.clock_skew_secs=min(skew.second,(60*60*24*7*28)); + pair unsafe = getString("unsafeChars"); + if (unsafe.first) + TemplateEngine::unsafe_chars = unsafe.second; + + unsafe = getString("allowedSchemes"); + if (unsafe.first) { + HTTPResponse::getAllowedSchemes().clear(); + string schemes=unsafe.second; + unsigned int j_sch=0; + for (unsigned int i_sch=0; i_sch < schemes.length(); i_sch++) { + if (schemes.at(i_sch)==' ') { + HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, i_sch-j_sch)); + j_sch = i_sch + 1; + } + } + HTTPResponse::getAllowedSchemes().push_back(schemes.substr(j_sch, schemes.length()-j_sch)); + } + // Extensions doExtensions(e, "global", log); if (conf.isEnabled(SPConfig::OutOfProcess)) @@ -1273,8 +1375,10 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o #ifndef SHIBSP_LITE if (m_outer->m_listener && conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess)) { - m_outer->m_listener->regListener("set::RelayState", m_outer->m_listener); - m_outer->m_listener->regListener("get::RelayState", m_outer->m_listener); + m_outer->m_listener->regListener("set::RelayState", const_cast(m_outer)); + m_outer->m_listener->regListener("get::RelayState", const_cast(m_outer)); + m_outer->m_listener->regListener("set::PostData", const_cast(m_outer)); + m_outer->m_listener->regListener("get::PostData", const_cast(m_outer)); } #endif @@ -1371,8 +1475,8 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o settings->load(child, NULL, &filter); rules.first = settings.release(); - // Process Rule elements. - const DOMElement* rule = XMLHelper::getFirstChildElement(child,Rule); + // Process PolicyRule elements. + const DOMElement* rule = XMLHelper::getFirstChildElement(child,PolicyRule); while (rule) { auto_ptr_char type(rule->getAttributeNS(NULL,_type)); try { @@ -1381,7 +1485,27 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* o catch (exception& ex) { log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what()); } - rule = XMLHelper::getNextSiblingElement(rule,Rule); + rule = XMLHelper::getNextSiblingElement(rule,PolicyRule); + } + + if (rules.second.size() == 0) { + // Process Rule elements. + log.warn("detected legacy Policy configuration, please convert to new PolicyRule syntax"); + rule = XMLHelper::getFirstChildElement(child,Rule); + while (rule) { + auto_ptr_char type(rule->getAttributeNS(NULL,_type)); + try { + rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule)); + } + catch (exception& ex) { + log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what()); + } + rule = XMLHelper::getNextSiblingElement(rule,Rule); + } + + // Manually add a basic Conditions rule. + log.info("installing a default Conditions rule in policy (%s) for compatibility with legacy configuration", id.get()); + rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL)); } child = XMLHelper::getNextSiblingElement(child,Policy); @@ -1479,7 +1603,7 @@ void XMLConfig::receive(DDF& in, ostream& out) } // Repack for return to caller. - DDF ret=DDF(NULL).string(relayState.c_str()); + DDF ret=DDF(NULL).unsafe_string(relayState.c_str()); DDFJanitor jret(ret); out << ret; } @@ -1507,6 +1631,60 @@ void XMLConfig::receive(DDF& in, ostream& out) DDFJanitor jret(ret); out << ret; } + else if (!strcmp(in.name(), "get::PostData")) { + const char* id = in["id"].string(); + const char* key = in["key"].string(); + if (!id || !key) + throw ListenerException("Required parameters missing for PostData recovery."); + + string postData; + StorageService* storage = getStorageService(id); + if (storage) { + if (storage->readString("PostData",key,&postData) > 0) { + storage->deleteString("PostData",key); + } + } + else { + Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + "Storage-backed PostData with invalid StorageService ID (%s)", id + ); + } + // If the data's empty, we'll send nothing back. + // If not, we don't need to round trip it, just send back the serialized DDF list. + if (postData.empty()) { + DDF ret(NULL); + DDFJanitor jret(ret); + out << ret; + } + else { + out << postData; + } + } + else if (!strcmp(in.name(), "set::PostData")) { + const char* id = in["id"].string(); + if (!id || !in["parameters"].islist()) + throw ListenerException("Required parameters missing for PostData creation."); + + string rsKey; + StorageService* storage = getStorageService(id); + if (storage) { + SAMLConfig::getConfig().generateRandomBytes(rsKey,20); + rsKey = SAMLArtifact::toHex(rsKey); + ostringstream params; + params << in["parameters"]; + storage->createString("PostData", rsKey.c_str(), params.str().c_str(), time(NULL) + 600); + } + else { + Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + "Storage-backed PostData with invalid StorageService ID (%s)", id + ); + } + + // Repack for return to caller. + DDF ret=DDF(NULL).string(rsKey.c_str()); + DDFJanitor jret(ret); + out << ret; + } } #endif