X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fimpl%2FXMLServiceProvider.cpp;h=e6d9da8313aceacb04254b736d102f2a870029c7;hb=1290825a4e40aff001dc2a7f623cd65ba4ebadc2;hp=bff5781fc24f3476d8c125033f5413a13f2d9e89;hpb=afe02ec33981fdc516c888522009d6c074f98560;p=shibboleth%2Fcpp-sp.git diff --git a/shibsp/impl/XMLServiceProvider.cpp b/shibsp/impl/XMLServiceProvider.cpp index bff5781..e6d9da8 100644 --- a/shibsp/impl/XMLServiceProvider.cpp +++ b/shibsp/impl/XMLServiceProvider.cpp @@ -66,6 +66,18 @@ namespace { #pragma warning( disable : 4250 ) #endif + class SHIBSP_DLLLOCAL TokenValidator : public Validator + { + public: + TokenValidator(const Application& app, time_t ts=0, const RoleDescriptor* role=NULL) : m_app(app), m_ts(ts), m_role(role) {} + void validate(const XMLObject*) const; + + private: + const Application& m_app; + time_t m_ts; + const RoleDescriptor* m_role; + }; + static vector g_noHandlers; // Application configuration wrapper @@ -89,7 +101,6 @@ namespace { const char* getHash() const {return m_hash.c_str();} MetadataProvider* getMetadataProvider() const; TrustEngine* getTrustEngine() const; - const vector& getAudiences() const; const PropertySet* getCredentialUse(const EntityDescriptor* provider) const; const Handler* getDefaultSessionInitiator() const; @@ -98,7 +109,14 @@ namespace { const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const; const vector& getAssertionConsumerServicesByBinding(const XMLCh* binding) const; const Handler* getHandler(const char* path) const; - + + const vector& getAudiences() const; + Validator* getTokenValidator(time_t ts=0, const opensaml::saml2md::RoleDescriptor* role=NULL) const { + return new TokenValidator(*this, ts, role); + } + + void validator(const XMLObject* xmlObject) const; + // Provides filter to exclude special config elements. short acceptNode(const DOMNode* node) const; @@ -327,6 +345,122 @@ namespace shibsp { } }; +void TokenValidator::validate(const XMLObject* xmlObject) const +{ +#ifdef _DEBUG + xmltooling::NDC ndc("validate"); +#endif + Category& log=Category::getInstance(SHIBSP_LOGCAT".Application"); + + const opensaml::RootObject* root = NULL; + const opensaml::saml2::Assertion* token2 = dynamic_cast(xmlObject); + if (token2) { + const opensaml::saml2::Conditions* conds = token2->getConditions(); + // First verify the time conditions, using the specified timestamp, if non-zero. + if (m_ts>0 && conds) { + unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs; + time_t t=conds->getNotBeforeEpoch(); + if (m_ts+skew < t) + throw ValidationException("Assertion is not yet valid."); + t=conds->getNotOnOrAfterEpoch(); + if (t <= m_ts-skew) + throw ValidationException("Assertion is no longer valid."); + } + + // Now we process conditions. Only audience restrictions at the moment. + const vector& convec = conds->getConditions(); + for (vector::const_iterator c = convec.begin(); c!=convec.end(); ++c) { + const opensaml::saml2::AudienceRestriction* ac=dynamic_cast(*c); + if (!ac) { + log.error("unrecognized Condition in assertion (%s)", + (*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()); + throw ValidationException("Assertion contains an unrecognized condition."); + } + + bool found = false; + const vector& auds1 = ac->getAudiences(); + const vector& auds2 = m_app.getAudiences(); + for (vector::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) { + for (vector::const_iterator a2 = auds2.begin(); !found && a2!=auds2.end(); ++a2) { + found = XMLString::equals((*a)->getAudienceURI(), *a2); + } + } + + if (!found) { + ostringstream os; + os << *ac; + log.error("unacceptable AudienceRestriction in assertion (%s)", os.str().c_str()); + throw ValidationException("Assertion contains an unacceptable AudienceRestriction."); + } + } + + root = token2; + } + else { + const opensaml::saml1::Assertion* token1 = dynamic_cast(xmlObject); + if (token1) { + const opensaml::saml1::Conditions* conds = token1->getConditions(); + // First verify the time conditions, using the specified timestamp, if non-zero. + if (m_ts>0 && conds) { + unsigned int skew = XMLToolingConfig::getConfig().clock_skew_secs; + time_t t=conds->getNotBeforeEpoch(); + if (m_ts+skew < t) + throw ValidationException("Assertion is not yet valid."); + t=conds->getNotOnOrAfterEpoch(); + if (t <= m_ts-skew) + throw ValidationException("Assertion is no longer valid."); + } + + // Now we process conditions. Only audience restrictions at the moment. + const vector& convec = conds->getConditions(); + for (vector::const_iterator c = convec.begin(); c!=convec.end(); ++c) { + const opensaml::saml1::AudienceRestrictionCondition* ac=dynamic_cast(*c); + if (!ac) { + log.error("unrecognized Condition in assertion (%s)", + (*c)->getSchemaType() ? (*c)->getSchemaType()->toString().c_str() : (*c)->getElementQName().toString().c_str()); + throw ValidationException("Assertion contains an unrecognized condition."); + } + + bool found = false; + const vector& auds1 = ac->getAudiences(); + const vector& auds2 = m_app.getAudiences(); + for (vector::const_iterator a = auds1.begin(); !found && a!=auds1.end(); ++a) { + for (vector::const_iterator a2 = auds2.begin(); !found && a2!=auds2.end(); ++a2) { + found = XMLString::equals((*a)->getAudienceURI(), *a2); + } + } + + if (!found) { + ostringstream os; + os << *ac; + log.error("unacceptable AudienceRestrictionCondition in assertion (%s)", os.str().c_str()); + throw ValidationException("Assertion contains an unacceptable AudienceRestrictionCondition."); + } + } + + root = token1; + } + else { + throw ValidationException("Unknown object type passed to token validator."); + } + } + + if (!m_role || !m_app.getTrustEngine()) { + log.warn("no issuer role or TrustEngine provided, so no signature validation performed"); + return; + } + + const PropertySet* policy=m_app.getServiceProvider().getPolicySettings(m_app.getString("policyId").second); + pair signedAssertions=policy ? policy->getBool("signedAssertions") : make_pair(false,false); + + if (root->getSignature()) { + if (!m_app.getTrustEngine()->validate(*(root->getSignature()),*m_role)) + throw ValidationException("Assertion signature did not validate."); + } + else if (signedAssertions.first && signedAssertions.second) + throw ValidationException("Assertion was unsigned, violating policy."); +} + XMLApplication::XMLApplication( const ServiceProvider* sp, const DOMElement* e, @@ -466,7 +600,7 @@ XMLApplication::XMLApplication( // Always include our own providerId as an audience. m_audiences.push_back(getXMLString("providerId").second); - if (conf.isEnabled(SPConfig::AttributeResolver)) { + if (conf.isEnabled(SPConfig::AttributeResolution)) { // TODO }