X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fimpl%2FXMLServiceProvider.cpp;h=f729ed2bab183ea8a5c052da19f61bbe64cafbe3;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=dc8b2daf83bdba4c1924848015b5433194f53ece;hpb=4bae99f2bd19f89ebdfc8e7e0759865fb3c84f3b;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index dc8b2da..f729ed2 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -335,7 +335,7 @@ namespace { #endif { public: - XMLConfig(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".Config")) {} + XMLConfig(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT ".Config")) {} void init() { background_load(); @@ -503,6 +503,7 @@ namespace { static const XMLCh _option[] = UNICODE_LITERAL_6(o,p,t,i,o,n); 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 _policyId[] = UNICODE_LITERAL_8(p,o,l,i,c,y,I,d); static const XMLCh _ProtocolProvider[] = UNICODE_LITERAL_16(P,r,o,t,o,c,o,l,P,r,o,v,i,d,e,r); 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); @@ -543,7 +544,7 @@ XMLApplication::XMLApplication( #ifdef _DEBUG xmltooling::NDC ndc("XMLApplication"); #endif - Category& log = Category::getInstance(SHIBSP_LOGCAT".Application"); + Category& log = Category::getInstance(SHIBSP_LOGCAT ".Application"); // First load any property sets. map remapper; @@ -555,26 +556,27 @@ XMLApplication::XMLApplication( // to ensure we get only our Sessions element. const PropertySet* sessionProps = getPropertySet("Sessions"); if (sessionProps) { - pair redirectLimit = sessionProps->getString("redirectLimit"); - if (redirectLimit.first) { - if (!strcmp(redirectLimit.second, "none")) + pair prop = sessionProps->getString("redirectLimit"); + if (prop.first) { + if (!strcmp(prop.second, "none")) m_redirectLimit = REDIRECT_LIMIT_NONE; - else if (!strcmp(redirectLimit.second, "exact")) + else if (!strcmp(prop.second, "exact")) m_redirectLimit = REDIRECT_LIMIT_EXACT; - else if (!strcmp(redirectLimit.second, "host")) + else if (!strcmp(prop.second, "host")) m_redirectLimit = REDIRECT_LIMIT_HOST; else { - if (!strcmp(redirectLimit.second, "exact+whitelist")) + if (!strcmp(prop.second, "exact+whitelist")) m_redirectLimit = REDIRECT_LIMIT_EXACT_WHITELIST; - else if (!strcmp(redirectLimit.second, "host+whitelist")) + else if (!strcmp(prop.second, "host+whitelist")) m_redirectLimit = REDIRECT_LIMIT_HOST_WHITELIST; - else if (!strcmp(redirectLimit.second, "whitelist")) + else if (!strcmp(prop.second, "whitelist")) m_redirectLimit = REDIRECT_LIMIT_WHITELIST; else - throw ConfigurationException("Unrecognized redirectLimit setting ($1)", params(1, redirectLimit.second)); - redirectLimit = sessionProps->getString("redirectWhitelist"); - if (redirectLimit.first) { - string dup(redirectLimit.second); + throw ConfigurationException("Unrecognized redirectLimit setting ($1)", params(1, prop.second)); + prop = sessionProps->getString("redirectWhitelist"); + if (prop.first) { + string dup(prop.second); + trim(dup); split(m_redirectWhitelist, dup, is_space(), algorithm::token_compress_on); } } @@ -582,6 +584,25 @@ XMLApplication::XMLApplication( else { m_redirectLimit = base ? REDIRECT_LIMIT_INHERIT : REDIRECT_LIMIT_NONE; } + + // Audit some additional settings for logging purposes. + prop = sessionProps->getString("cookieProps"); + if (!prop.first) { + log.warn("empty/missing cookieProps setting, set to \"https\" for SSL/TLS-only usage"); + } + else if (!strcmp(prop.second, "http")) { + log.warn("insecure cookieProps setting, set to \"https\" for SSL/TLS-only usage"); + } + else if (strcmp(prop.second, "https")) { + if (!strstr(prop.second, ";secure") && !strstr(prop.second, "; secure")) + log.warn("custom cookieProps setting should include \"; secure\" for SSL/TLS-only usage"); + else if (!strstr(prop.second, ";HttpOnly") && !strstr(prop.second, "; HttpOnly")) + log.warn("custom cookieProps setting should include \"; HttpOnly\", site is vulnerable to client-side cookie theft"); + } + + pair handlerSSL = sessionProps->getBool("handlerSSL"); + if (handlerSSL.first && !handlerSSL.second) + log.warn("handlerSSL should be enabled for SSL/TLS-enabled web sites"); } else { m_redirectLimit = base ? REDIRECT_LIMIT_INHERIT : REDIRECT_LIMIT_NONE; @@ -812,6 +833,7 @@ void XMLApplication::doAttributeInfo() pair attributes = getString("REMOTE_USER"); if (attributes.first) { string dup(attributes.second); + trim(dup); split(m_remoteUsers, dup, is_space(), algorithm::token_compress_on); } @@ -831,6 +853,7 @@ void XMLApplication::doAttributeInfo() } string dup(attributes.second); + trim(dup); vector headerNames; split(headerNames, dup, is_space(), algorithm::token_compress_on); for (vector::const_iterator h = headerNames.begin(); h != headerNames.end(); ++h) { @@ -1060,6 +1083,8 @@ void XMLApplication::doSSO(const ProtocolProvider& pp, set& protocols, D { if (!e->hasChildNodes()) return; + DOMNamedNodeMap* ssoprops = e->getAttributes(); + XMLSize_t ssopropslen = ssoprops ? ssoprops->getLength() : 0; SPConfig& conf = SPConfig::getConfig(); @@ -1100,6 +1125,20 @@ void XMLApplication::doSSO(const ProtocolProvider& pp, set& protocols, D pathprop = (*b)->getXMLString("path"); if (idprop.first && pathprop.first) { DOMElement* acsdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _AssertionConsumerService); + + // Copy in any attributes from the element so they can be accessed as properties in the ACS handler. + for (XMLSize_t p = 0; p < ssopropslen; ++p) { + DOMNode* ssoprop = ssoprops->item(p); + if (ssoprop->getNodeType() == DOMNode::ATTRIBUTE_NODE) { + acsdom->setAttributeNS( + ((DOMAttr*)ssoprop)->getNamespaceURI(), + ((DOMAttr*)ssoprop)->getLocalName(), + ((DOMAttr*)ssoprop)->getValue() + ); + } + } + + // Set necessary properties based on context. acsdom->setAttributeNS(nullptr, Binding, idprop.second); acsdom->setAttributeNS(nullptr, Location, pathprop.second); xstring indexbuf(1, chDigit_1 + (index % 10)); @@ -1182,6 +1221,8 @@ void XMLApplication::doLogout(const ProtocolProvider& pp, set& protocols { if (!e->hasChildNodes()) return; + DOMNamedNodeMap* sloprops = e->getAttributes(); + XMLSize_t slopropslen = sloprops ? sloprops->getLength() : 0; SPConfig& conf = SPConfig::getConfig(); @@ -1222,8 +1263,24 @@ void XMLApplication::doLogout(const ProtocolProvider& pp, set& protocols pathprop = (*b)->getXMLString("path"); if (idprop.first && pathprop.first) { DOMElement* slodom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _SingleLogoutService); + + // Copy in any attributes from the element so they can be accessed as properties in the SLO handler. + for (XMLSize_t p = 0; p < slopropslen; ++p) { + DOMNode* sloprop = sloprops->item(p); + if (sloprop->getNodeType() == DOMNode::ATTRIBUTE_NODE) { + slodom->setAttributeNS( + ((DOMAttr*)sloprop)->getNamespaceURI(), + ((DOMAttr*)sloprop)->getLocalName(), + ((DOMAttr*)sloprop)->getValue() + ); + } + } + + // Set necessary properties based on context. slodom->setAttributeNS(nullptr, Binding, idprop.second); slodom->setAttributeNS(nullptr, Location, pathprop.second); + if (e->hasAttributeNS(nullptr, _policyId)) + slodom->setAttributeNS(shibspconstants::SHIB2SPCONFIG_NS, _policyId, e->getAttributeNS(nullptr, _policyId)); log.info("adding SingleLogoutService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second); boost::shared_ptr handler( @@ -1270,6 +1327,8 @@ void XMLApplication::doNameIDMgmt(const ProtocolProvider& pp, set& proto { if (!e->hasChildNodes()) return; + DOMNamedNodeMap* nimprops = e->getAttributes(); + XMLSize_t nimpropslen = nimprops ? nimprops->getLength() : 0; SPConfig& conf = SPConfig::getConfig(); @@ -1288,8 +1347,24 @@ void XMLApplication::doNameIDMgmt(const ProtocolProvider& pp, set& proto pathprop = (*b)->getXMLString("path"); if (idprop.first && pathprop.first) { DOMElement* nimdom = e->getOwnerDocument()->createElementNS(samlconstants::SAML20MD_NS, _ManageNameIDService); + + // Copy in any attributes from the element so they can be accessed as properties in the NIM handler. + for (XMLSize_t p = 0; p < nimpropslen; ++p) { + DOMNode* nimprop = nimprops->item(p); + if (nimprop->getNodeType() == DOMNode::ATTRIBUTE_NODE) { + nimdom->setAttributeNS( + ((DOMAttr*)nimprop)->getNamespaceURI(), + ((DOMAttr*)nimprop)->getLocalName(), + ((DOMAttr*)nimprop)->getValue() + ); + } + } + + // Set necessary properties based on context. nimdom->setAttributeNS(nullptr, Binding, idprop.second); nimdom->setAttributeNS(nullptr, Location, pathprop.second); + if (e->hasAttributeNS(nullptr, _policyId)) + nimdom->setAttributeNS(shibspconstants::SHIB2SPCONFIG_NS, _policyId, e->getAttributeNS(nullptr, _policyId)); log.info("adding ManageNameIDService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second); boost::shared_ptr handler( @@ -1721,7 +1796,7 @@ void XMLApplication::limitRedirect(const GenericRequest& request, const char* ur boost::bind(startsWithI, url, boost::bind(&string::c_str, _1))) != m_redirectWhitelist.end()) { return; } - Category::getInstance(SHIBSP_LOGCAT".Application").warn("redirectLimit policy enforced, blocked redirect to (%s)", url); + Category::getInstance(SHIBSP_LOGCAT ".Application").warn("redirectLimit policy enforced, blocked redirect to (%s)", url); throw opensaml::SecurityPolicyException("Blocked unacceptable redirect location."); } } @@ -1996,6 +2071,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, if (unsafe.first) { HTTPResponse::getAllowedSchemes().clear(); string schemes(unsafe.second); + trim(schemes); split(HTTPResponse::getAllowedSchemes(), schemes, is_space(), algorithm::token_compress_on); } @@ -2069,7 +2145,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, // For backward compatibility, wrap in a plugin element. DOMElement* polwrapper = e->getOwnerDocument()->createElementNS(nullptr, _SecurityPolicyProvider); polwrapper->appendChild(child); - log.info("building SecurityPolicyProvider of type %s...", XML_SECURITYPOLICY_PROVIDER); + log.warn("deprecated/legacy SecurityPolicy configuration, consider externalizing with "); m_policy.reset(conf.SecurityPolicyProviderManager.newPlugin(XML_SECURITYPOLICY_PROVIDER, polwrapper)); } else { @@ -2078,22 +2154,32 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, } if (first) { - if (!m_policy->getAlgorithmBlacklist().empty()) { + if (!m_policy->getAlgorithmWhitelist().empty()) { #ifdef SHIBSP_XMLSEC_WHITELISTING - for_each( - m_policy->getAlgorithmBlacklist().begin(), m_policy->getAlgorithmBlacklist().end(), - boost::bind(&XSECPlatformUtils::blacklistAlgorithm, boost::bind(&xstring::c_str, _1)) - ); + for (vector::const_iterator white = m_policy->getAlgorithmWhitelist().begin(); + white != m_policy->getAlgorithmWhitelist().end(); ++white) { + XSECPlatformUtils::whitelistAlgorithm(white->c_str()); + auto_ptr_char whitelog(white->c_str()); + log.info("explicitly whitelisting security algorithm (%s)", whitelog.get()); + } #else log.crit("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists"); #endif } - else if (!m_policy->getAlgorithmWhitelist().empty()) { + else if (!m_policy->getDefaultAlgorithmBlacklist().empty() || !m_policy->getAlgorithmBlacklist().empty()) { #ifdef SHIBSP_XMLSEC_WHITELISTING - for_each( - m_policy->getAlgorithmWhitelist().begin(), m_policy->getAlgorithmWhitelist().end(), - boost::bind(&XSECPlatformUtils::whitelistAlgorithm, boost::bind(&xstring::c_str, _1)) - ); + for (vector::const_iterator black = m_policy->getDefaultAlgorithmBlacklist().begin(); + black != m_policy->getDefaultAlgorithmBlacklist().end(); ++black) { + XSECPlatformUtils::blacklistAlgorithm(black->c_str()); + auto_ptr_char blacklog(black->c_str()); + log.info("automatically blacklisting security algorithm (%s)", blacklog.get()); + } + for (vector::const_iterator black = m_policy->getAlgorithmBlacklist().begin(); + black != m_policy->getAlgorithmBlacklist().end(); ++black) { + XSECPlatformUtils::blacklistAlgorithm(black->c_str()); + auto_ptr_char blacklog(black->c_str()); + log.info("explicitly blacklisting security algorithm (%s)", blacklog.get()); + } #else log.crit("XML-Security-C library prior to 1.6.0 does not support algorithm white/blacklists"); #endif @@ -2155,6 +2241,7 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, pair extraAuthTypes = inprocs->getString("extraAuthTypes"); if (extraAuthTypes.first) { string types(extraAuthTypes.second); + trim(types); split(outer->m_authTypes, types, is_space(), algorithm::token_compress_on); outer->m_authTypes.insert("shibboleth"); } @@ -2184,7 +2271,7 @@ void XMLConfig::receive(DDF& in, ostream& out) } } else { - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").error( "Storage-backed RelayState with invalid StorageService ID (%s)", id ); } @@ -2211,7 +2298,7 @@ void XMLConfig::receive(DDF& in, ostream& out) storage->createText("RelayState", rsKey.c_str(), value, time(nullptr) + 600); } else { - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").error( "Storage-backed RelayState with invalid StorageService ID (%s)", id ); } @@ -2235,7 +2322,7 @@ void XMLConfig::receive(DDF& in, ostream& out) } } else { - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").error( "Storage-backed PostData with invalid StorageService ID (%s)", id ); } @@ -2265,7 +2352,7 @@ void XMLConfig::receive(DDF& in, ostream& out) storage->createText("PostData", rsKey.c_str(), params.str().c_str(), time(nullptr) + 600); } else { - Category::getInstance(SHIBSP_LOGCAT".ServiceProvider").error( + Category::getInstance(SHIBSP_LOGCAT ".ServiceProvider").error( "Storage-backed PostData with invalid StorageService ID (%s)", id ); }