X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=saml%2Fsaml1%2Fbinding%2Fimpl%2FSAML1POSTDecoder.cpp;h=fd3258a76da1f3ec74898565173120a5420e65ee;hb=750aa26530f9e8993eae37cd9e68e25497be66b5;hp=181d6f969b31fbcd8b958d247e0461e16672c71e;hpb=bce5046d6d2fd42e4b2b270bb2db557acfd4581c;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp index 181d6f9..fd3258a 100644 --- a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -17,26 +17,26 @@ /** * SAML1POSTDecoder.cpp * - * SAML 1.x POST binding/profile message encoder + * SAML 1.x POST binding/profile message decoder */ #include "internal.h" #include "exceptions.h" -#include "saml/binding/ReplayCache.h" +#include "binding/HTTPRequest.h" +#include "saml1/core/Assertions.h" #include "saml1/binding/SAML1POSTDecoder.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" -#include "security/X509TrustEngine.h" #include #include #include +#include using namespace opensaml::saml2md; using namespace opensaml::saml1p; using namespace opensaml::saml1; using namespace opensaml; -using namespace xmlsignature; using namespace xmltooling; using namespace log4cpp; using namespace std; @@ -52,16 +52,10 @@ namespace opensaml { SAML1POSTDecoder::SAML1POSTDecoder(const DOMElement* e) {} -SAML1POSTDecoder::~SAML1POSTDecoder() {} - -Response* SAML1POSTDecoder::decode( +XMLObject* SAML1POSTDecoder::decode( string& relayState, - const RoleDescriptor*& issuer, - bool& issuerTrusted, - const HTTPRequest& httpRequest, - const MetadataProvider* metadataProvider, - const QName* role, - const X509TrustEngine* trustEngine + const GenericRequest& genericRequest, + SecurityPolicy& policy ) const { #ifdef _DEBUG @@ -70,10 +64,15 @@ Response* SAML1POSTDecoder::decode( Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1POST"); log.debug("validating input"); - if (strcmp(httpRequest.getMethod(),"POST")) + const HTTPRequest* httpRequest=dynamic_cast(&genericRequest); + if (!httpRequest) { + log.error("unable to cast request to HTTPRequest type"); + return NULL; + } + if (strcmp(httpRequest->getMethod(),"POST")) return NULL; - const char* samlResponse = httpRequest.getParameter("SAMLResponse"); - const char* TARGET = httpRequest.getParameter("TARGET"); + const char* samlResponse = httpRequest->getParameter("SAMLResponse"); + const char* TARGET = httpRequest->getParameter("TARGET"); if (!samlResponse || !TARGET) return NULL; relayState = TARGET; @@ -104,7 +103,7 @@ Response* SAML1POSTDecoder::decode( // Check recipient URL. auto_ptr_char recipient(response->getRecipient()); - const char* recipient2 = httpRequest.getRequestURL(); + const char* recipient2 = httpRequest->getRequestURL(); if (!recipient.get() || !*(recipient.get())) { log.error("response missing Recipient attribute"); throw BindingException("SAML response did not contain Recipient attribute identifying intended destination."); @@ -114,99 +113,34 @@ Response* SAML1POSTDecoder::decode( throw BindingException("SAML message delivered with POST to incorrect server URL."); } - // Check freshness. - time_t now = time(NULL); - if (response->getIssueInstant()->getEpoch() < now-(2*XMLToolingConfig::getConfig().clock_skew_secs)) - throw BindingException("Detected expired POST profile response."); - - // Check replay. - ReplayCache* replayCache = SAMLConfig::getConfig().getReplayCache(); - if (replayCache) { - auto_ptr_char id(response->getResponseID()); - if (!replayCache->check("SAML1POST", id.get(), response->getIssueInstant()->getEpoch() + (2*XMLToolingConfig::getConfig().clock_skew_secs))) { - log.error("replay detected of response ID (%s)", id.get()); - throw BindingException("Rejecting replayed response ID ($1).", params(1,id.get())); - } - } - else - log.warn("replay cache was not provided, this is a serious security risk!"); - - /* For SAML 1, the issuer can only be established from any assertions in the message. - * Generally, errors aren't delivered like this, so there should be one. - * The Issuer attribute is matched against metadata, and then trust checking can be - * applied. - */ - issuer = NULL; - issuerTrusted = false; - log.debug("attempting to establish issuer and integrity of message..."); - const vector& assertions=const_cast(response)->getAssertions(); - if (!assertions.empty()) { - log.debug("searching metadata for assertion issuer..."); - const EntityDescriptor* provider= - metadataProvider ? metadataProvider->getEntityDescriptor(assertions.front()->getIssuer()) : NULL; - if (provider) { - log.debug("matched assertion issuer against metadata, searching for applicable role..."); - pair minor = response->getMinorVersion(); - issuer=provider->getRoleDescriptor( - *role, - (minor.first && minor.second==0) ? SAMLConstants::SAML10_PROTOCOL_ENUM : SAMLConstants::SAML11_PROTOCOL_ENUM - ); - if (issuer) { - if (trustEngine && response->getSignature()) { - issuerTrusted = static_cast(trustEngine)->validate( - *(response->getSignature()), *issuer, metadataProvider->getKeyResolver() - ); - if (!issuerTrusted) - log.error("unable to verify signature on message with supplied trust engine"); - } - else { - log.warn("unable to verify integrity of the message, leaving untrusted"); - } - } - else { - log.warn( - "unable to find compatible SAML 1.%d role (%s) in metadata", - (minor.first && minor.second==0) ? 0 : 1, - role->toString().c_str() - ); - } - if (log.isDebugEnabled()) { - auto_ptr_char iname(assertions.front()->getIssuer()); - log.debug("message from (%s), integrity %sverified", iname.get(), issuerTrusted ? "" : "NOT "); - } - } - else { - auto_ptr_char temp(assertions.front()->getIssuer()); - log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); - } - } - else { - log.warn("no assertions found, can't establish identity of issuer"); - } + // Run through the policy. + policy.evaluate(*response, &genericRequest); } catch (XMLToolingException& ex) { + // This is just to maximize the likelihood of attaching a source to the message for support purposes. + if (policy.getIssuerMetadata()) + annotateException(&ex,policy.getIssuerMetadata()); // throws it + // Check for an Issuer. + const EntityDescriptor* provider=NULL; const vector& assertions=const_cast(response)->getAssertions(); - if (!assertions.empty()) { - if (!metadataProvider) { - // Just record it. - auto_ptr_char issuer(assertions.front()->getIssuer()); - if (issuer.get()) - ex.addProperty("entityID", issuer.get()); - throw; - } - // Try and locate metadata for error handling. - const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(assertions.front()->getIssuer(),false); - if (provider) { - pair minor = response->getMinorVersion(); - issuer=provider->getRoleDescriptor( - *role, - (minor.first && minor.second==0) ? SAMLConstants::SAML10_PROTOCOL_ENUM : SAMLConstants::SAML11_PROTOCOL_ENUM - ); - if (issuer) annotateException(&ex,issuer); // throws it - annotateException(&ex,provider); // throws it - } + if (!assertions.empty() || !policy.getMetadataProvider() || + !(provider=policy.getMetadataProvider()->getEntityDescriptor(assertions.front()->getIssuer(), false))) { + // Just record it. + auto_ptr_char iname(assertions.front()->getIssuer()); + if (iname.get()) + ex.addProperty("entityID", iname.get()); + throw; + } + if (policy.getRole()) { + pair minor = response->getMinorVersion(); + const RoleDescriptor* roledesc=provider->getRoleDescriptor( + *(policy.getRole()), + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + ); + if (roledesc) annotateException(&ex,roledesc); // throws it } + annotateException(&ex,provider); // throws it } xmlObject.release();