From: Scott Cantor Date: Tue, 10 Nov 2009 18:41:25 +0000 (+0000) Subject: https://issues.shibboleth.net/jira/browse/SSPCPP-262 X-Git-Tag: 2.3.1~13 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-sp.git;a=commitdiff_plain;h=9a48bfdd0b4f71bd37db2e7fa115393c4ad698b4 https://issues.shibboleth.net/jira/browse/SSPCPP-262 --- diff --git a/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp b/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp index 2c9c8fc..5948b5c 100644 --- a/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp +++ b/shibsp/attribute/resolver/impl/QueryAttributeResolver.cpp @@ -366,7 +366,7 @@ bool QueryResolver::SAML1Query(QueryContext& ctx) const } newtoken->detach(); - wrapper.release(); + wrapper.release(); // detach blows away the Response ctx.getResolvedAssertions().push_back(newtoken); // Finally, extract and filter the result. @@ -473,33 +473,77 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const m_log.error("unable to obtain a SAML response from attribute authority"); return false; } + + auto_ptr wrapper(srt); + saml2p::Response* response = dynamic_cast(srt); if (!response) { - delete srt; m_log.error("message was not a samlp:Response"); return true; } else if (!response->getStatus() || !response->getStatus()->getStatusCode() || !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) { - delete srt; m_log.error("attribute authority returned a SAML error"); return true; } + saml2::Assertion* newtoken = NULL; const vector& assertions = const_cast(response)->getAssertions(); if (assertions.empty()) { - delete srt; - m_log.warn("response from attribute authority was empty"); - return true; - } - else if (assertions.size()>1) - m_log.warn("simple resolver only supports one assertion in the query response"); + // Check for encryption. + const vector& encassertions = const_cast(response)->getEncryptedAssertions(); + if (encassertions.empty()) { + m_log.warn("response from attribute authority was empty"); + return true; + } + else if (encassertions.size() > 1) { + m_log.warn("simple resolver only supports one assertion in the query response"); + } - auto_ptr wrapper(srt); - saml2::Assertion* newtoken = assertions.front(); + CredentialResolver* cr=application.getCredentialResolver(); + if (!cr) { + m_log.warn("found encrypted assertion, but no CredentialResolver was available"); + return true; + } + + // Attempt to decrypt it. + try { + Locker credlocker(cr); + auto_ptr mcc( + policy.getIssuerMetadata() ? new MetadataCredentialCriteria(*policy.getIssuerMetadata()) : NULL + ); + auto_ptr tokenwrapper( + encassertions.front()->decrypt(*cr, application.getRelyingParty(ctx.getEntityDescriptor())->getXMLString("entityID").second, mcc.get()) + ); + newtoken = dynamic_cast(tokenwrapper.get()); + if (newtoken) { + tokenwrapper.release(); + if (m_log.isDebugEnabled()) + m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol; + } + } + catch (exception& ex) { + m_log.error(ex.what()); + } + if (newtoken) { + // Free the Response now, so we know this is a stand-alone token later. + delete wrapper.release(); + } + else { + // Nothing decrypted, should already be logged. + return true; + } + } + else { + if (assertions.size() > 1) + m_log.warn("simple resolver only supports one assertion in the query response"); + newtoken = assertions.front(); + } if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) { m_log.error("assertion unsigned, rejecting it based on signedAssertions policy"); + if (!wrapper.get()) + delete newtoken; return true; } @@ -518,11 +562,15 @@ bool QueryResolver::SAML2Query(QueryContext& ctx) const } catch (exception& ex) { m_log.error("assertion failed policy validation: %s", ex.what()); + if (!wrapper.get()) + delete newtoken; return true; } - newtoken->detach(); - wrapper.release(); + if (wrapper.get()) { + newtoken->detach(); + wrapper.release(); // detach blows away the Response + } ctx.getResolvedAssertions().push_back(newtoken); // Finally, extract and filter the result. diff --git a/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp b/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp index c4d3336..1773d9b 100644 --- a/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp +++ b/shibsp/attribute/resolver/impl/SimpleAggregationAttributeResolver.cpp @@ -389,33 +389,77 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha m_log.error("unable to obtain a SAML response from attribute authority (%s)", entityID); return false; } + + auto_ptr wrapper(srt); + saml2p::Response* response = dynamic_cast(srt); if (!response) { - delete srt; m_log.error("message was not a samlp:Response"); return true; } else if (!response->getStatus() || !response->getStatus()->getStatusCode() || !XMLString::equals(response->getStatus()->getStatusCode()->getValue(), saml2p::StatusCode::SUCCESS)) { - delete srt; m_log.error("attribute authority (%s) returned a SAML error", entityID); return true; } + saml2::Assertion* newtoken = NULL; const vector& assertions = const_cast(response)->getAssertions(); if (assertions.empty()) { - delete srt; - m_log.warn("response from attribute authority (%s) was empty", entityID); - return true; - } - else if (assertions.size()>1) - m_log.warn("resolver only supports one assertion in the query response"); + // Check for encryption. + const vector& encassertions = const_cast(response)->getEncryptedAssertions(); + if (encassertions.empty()) { + m_log.warn("response from attribute authority was empty"); + return true; + } + else if (encassertions.size() > 1) { + m_log.warn("simple resolver only supports one assertion in the query response"); + } - auto_ptr wrapper(srt); - saml2::Assertion* newtoken = assertions.front(); + CredentialResolver* cr=application.getCredentialResolver(); + if (!cr) { + m_log.warn("found encrypted assertion, but no CredentialResolver was available"); + return true; + } + + // Attempt to decrypt it. + try { + Locker credlocker(cr); + auto_ptr mcc( + policy.getIssuerMetadata() ? new MetadataCredentialCriteria(*policy.getIssuerMetadata()) : NULL + ); + auto_ptr tokenwrapper( + encassertions.front()->decrypt(*cr, relyingParty->getXMLString("entityID").second, mcc.get()) + ); + newtoken = dynamic_cast(tokenwrapper.get()); + if (newtoken) { + tokenwrapper.release(); + if (m_log.isDebugEnabled()) + m_log.debugStream() << "decrypted Assertion: " << *newtoken << logging::eol; + } + } + catch (exception& ex) { + m_log.error(ex.what()); + } + if (newtoken) { + // Free the Response now, so we know this is a stand-alone token later. + delete wrapper.release(); + } + else { + // Nothing decrypted, should already be logged. + return true; + } + } + else { + if (assertions.size() > 1) + m_log.warn("simple resolver only supports one assertion in the query response"); + newtoken = assertions.front(); + } if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) { m_log.error("assertion unsigned, rejecting it based on signedAssertions policy"); + if (!wrapper.get()) + delete newtoken; return true; } @@ -434,11 +478,15 @@ bool SimpleAggregationResolver::doQuery(SimpleAggregationContext& ctx, const cha } catch (exception& ex) { m_log.error("assertion failed policy validation: %s", ex.what()); + if (!wrapper.get()) + delete newtoken; return true; } - newtoken->detach(); - wrapper.release(); + if (wrapper.get()) { + newtoken->detach(); + wrapper.release(); // detach blows away the Response + } ctx.getResolvedAssertions().push_back(newtoken); // Finally, extract and filter the result.