From 6d6cc50f36467e3b61379c19a1cae5796496a464 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Wed, 28 Nov 2012 04:53:47 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/SSPCPP-527 --- schemas/shibboleth-2.0-native-sp-config.xsd | 26 +++++++++--- shibsp/handler/impl/AssertionConsumerService.cpp | 31 +++++++++------ shibsp/handler/impl/SAML2Logout.cpp | 4 +- shibsp/handler/impl/SAML2NameIDMgmt.cpp | 4 +- shibsp/impl/XMLServiceProvider.cpp | 50 +++++++++++++++++++++++- 5 files changed, 95 insertions(+), 20 deletions(-) diff --git a/schemas/shibboleth-2.0-native-sp-config.xsd b/schemas/shibboleth-2.0-native-sp-config.xsd index bfdbc7b..846c10b 100644 --- a/schemas/shibboleth-2.0-native-sp-config.xsd +++ b/schemas/shibboleth-2.0-native-sp-config.xsd @@ -9,7 +9,7 @@ elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="substitution" - version="2.5"> + version="2.5.1"> @@ -480,6 +480,8 @@ + + @@ -494,15 +496,23 @@ + - - - Implicitly configures ManageNameIDService handlers - + + + + Implicitly configures ManageNameIDService handlers + + + + + + + @@ -546,6 +556,12 @@ + + + Used to ignore NoPassive errors in AssertionConsumerService endpoints + + + Options common to explicit and implicit SessionInitiators diff --git a/shibsp/handler/impl/AssertionConsumerService.cpp b/shibsp/handler/impl/AssertionConsumerService.cpp index 7176f81..901d826 100644 --- a/shibsp/handler/impl/AssertionConsumerService.cpp +++ b/shibsp/handler/impl/AssertionConsumerService.cpp @@ -161,7 +161,9 @@ pair AssertionConsumerService::processMessage( { #ifndef SHIBSP_LITE // Locate policy key. - pair prop = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element + pair prop = getString("policyId", m_configNS.get()); // may be namespace-qualified if inside handler element + if (!prop.first) + prop = getString("policyId"); // try unqualified if (!prop.first) prop = application.getString("policyId"); // unqualified in Application(s) element @@ -226,25 +228,32 @@ pair AssertionConsumerService::processMessage( return finalizeResponse(application, httpRequest, httpResponse, relayState); } catch (XMLToolingException& ex) { - // Check for isPassive error condition. - const char* sc2 = ex.getProperty("statusCode2"); - if (sc2 && !strcmp(sc2, "urn:oasis:names:tc:SAML:2.0:status:NoPassive")) { - pair ignore = getBool("ignoreNoPassive", m_configNS.get()); // namespace-qualified if inside handler element - if (ignore.first && ignore.second && !relayState.empty()) { - m_log.debug("ignoring SAML status of NoPassive and redirecting to resource..."); - return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); - } - } + // Recover relay state. if (!relayState.empty()) { try { recoverRelayState(application, httpRequest, httpResponse, relayState, false); } catch (std::exception& rsex) { m_log.warn("error recovering relay state: %s", rsex.what()); + relayState.erase(); + recoverRelayState(application, httpRequest, httpResponse, relayState, false); } - ex.addProperty("RelayState", relayState.c_str()); } + // Check for isPassive error condition. + const char* sc2 = ex.getProperty("statusCode2"); + if (sc2 && !strcmp(sc2, "urn:oasis:names:tc:SAML:2.0:status:NoPassive")) { + pair ignore = getBool("ignoreNoPassive", m_configNS.get()); // may be namespace-qualified inside handler element + if (!ignore.first) + ignore = getBool("ignoreNoPassive"); // try unqualified + if (ignore.first && ignore.second && !relayState.empty()) { + m_log.debug("ignoring SAML status of NoPassive and redirecting to resource..."); + return make_pair(true, httpResponse.sendRedirect(relayState.c_str())); + } + } + + ex.addProperty("RelayState", relayState.c_str()); + // Log the error. try { scoped_ptr event(SPConfig::getConfig().EventManager.newPlugin(LOGIN_EVENT, nullptr)); diff --git a/shibsp/handler/impl/SAML2Logout.cpp b/shibsp/handler/impl/SAML2Logout.cpp index 19f3d7e..56645a2 100644 --- a/shibsp/handler/impl/SAML2Logout.cpp +++ b/shibsp/handler/impl/SAML2Logout.cpp @@ -354,7 +354,9 @@ pair SAML2Logout::doRequest(const Application& application, const HTT // If we get here, it's an external protocol message to decode. // Locate policy key. - pair policyId = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element + pair policyId = getString("policyId", m_configNS.get()); // may be namespace-qualified inside handler element + if (!policyId.first) + policyId = getString("policyId"); // try unqualified if (!policyId.first) policyId = application.getString("policyId"); // unqualified in Application(s) element diff --git a/shibsp/handler/impl/SAML2NameIDMgmt.cpp b/shibsp/handler/impl/SAML2NameIDMgmt.cpp index 4d1bf2c..6bdfecf 100644 --- a/shibsp/handler/impl/SAML2NameIDMgmt.cpp +++ b/shibsp/handler/impl/SAML2NameIDMgmt.cpp @@ -247,7 +247,9 @@ pair SAML2NameIDMgmt::doRequest(const Application& application, const SessionCache* cache = application.getServiceProvider().getSessionCache(); // Locate policy key. - pair policyId = getString("policyId", m_configNS.get()); // namespace-qualified if inside handler element + pair policyId = getString("policyId", m_configNS.get()); // may be namespace-qualified inside handler element + if (!policyId.first) + policyId = getString("policyId"); // try unqualified if (!policyId.first) policyId = application.getString("policyId"); // unqualified in Application(s) element diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index 4ee2205..d719d42 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -1080,6 +1080,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(); @@ -1120,14 +1122,26 @@ 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)); if (index / 10) indexbuf = (XMLCh)(chDigit_1 + (index / 10)) + indexbuf; acsdom->setAttributeNS(nullptr, _index, indexbuf.c_str()); - if (e->hasAttributeNS(nullptr, _policyId)) - acsdom->setAttributeNS(shibspconstants::SHIB2SPCONFIG_NS, _policyId, e->getAttributeNS(nullptr, _policyId)); log.info("adding AssertionConsumerService for Binding (%s) at (%s)", (*b)->getString("id").second, (*b)->getString("path").second); boost::shared_ptr handler( @@ -1204,6 +1218,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(); @@ -1244,6 +1260,20 @@ 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)) @@ -1294,6 +1324,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(); @@ -1312,6 +1344,20 @@ 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)) -- 2.1.4