X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fimpl%2FXMLServiceProvider.cpp;h=f729ed2bab183ea8a5c052da19f61bbe64cafbe3;hb=c51bfd77603cf0ddb0b5e374c35586a8435895d6;hp=d485abdb0ba941168141335327a963c051ebef7a;hpb=779a8e090fcf4610aacdbb0b628904b14d135db0;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index d485abd..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, "exact+host")) + else if (!strcmp(prop.second, "host+whitelist")) m_redirectLimit = REDIRECT_LIMIT_HOST_WHITELIST; - else if (!strcmp(redirectLimit.second, "exact+host")) + 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; @@ -644,7 +665,7 @@ XMLApplication::XMLApplication( if (m_metadata) m_metadata->init(); else if (!m_base) - log.crit("no MetadataProvider available, configuration is probably unusable"); + log.warn("no MetadataProvider available, configure at least one for standard SSO usage"); } catch (std::exception& ex) { log.crit("error initializing MetadataProvider: %s", ex.what()); @@ -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."); } } @@ -1922,6 +1997,8 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e, InProcess); // Initialize logging manually in order to redirect log messages as soon as possible. + // If no explicit config is supplied, we now assume the caller has done this, so that + // setuid processes can potentially do this as root. if (conf.isEnabled(SPConfig::Logging)) { string logconf; if (conf.isEnabled(SPConfig::OutOfProcess)) @@ -1930,15 +2007,6 @@ XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, XMLConfig* outer, logconf = XMLHelper::getAttrString(SHIRE, nullptr, logger); if (logconf.empty()) logconf = XMLHelper::getAttrString(e, nullptr, logger); - if (logconf.empty() && !getenv("SHIBSP_LOGGING")) { - // No properties found, so default them. - if (conf.isEnabled(SPConfig::OutOfProcess) && !conf.isEnabled(SPConfig::InProcess)) - logconf = "shibd.logger"; - else if (!conf.isEnabled(SPConfig::OutOfProcess) && conf.isEnabled(SPConfig::InProcess)) - logconf = "native.logger"; - else - logconf = "shibboleth.logger"; - } if (!logconf.empty()) { log.debug("loading new logging configuration from (%s), check log destination for status of configuration", logconf.c_str()); if (!XMLToolingConfig::getConfig().log_config(logconf.c_str())) @@ -2003,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); } @@ -2076,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 { @@ -2085,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 @@ -2162,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"); } @@ -2191,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 ); } @@ -2218,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 ); } @@ -2242,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 ); } @@ -2272,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 ); }