X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=shibsp%2Fhandler%2Fimpl%2FSAML2Consumer.cpp;h=532c0ac9ee83756c9da6ad35eb86acfc19cdd3e2;hb=a5b1914f888d2ac8992cc4985d65e9d727aa8df4;hp=0a2ebd8abb276d3aaaad686bbe9382524f4c0a53;hpb=8cfb88bff921f1830d05045bf266b88f8d49abd7;p=shibboleth%2Fsp.git diff --git a/shibsp/handler/impl/SAML2Consumer.cpp b/shibsp/handler/impl/SAML2Consumer.cpp index 0a2ebd8..532c0ac 100644 --- a/shibsp/handler/impl/SAML2Consumer.cpp +++ b/shibsp/handler/impl/SAML2Consumer.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2001-2007 Internet2 - * + * Copyright 2001-2009 Internet2 + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,8 +16,8 @@ /** * SAML2Consumer.cpp - * - * SAML 2.0 assertion consumer service + * + * SAML 2.0 assertion consumer service */ #include "internal.h" @@ -29,10 +29,11 @@ # include "ServiceProvider.h" # include "SessionCache.h" # include "attribute/resolver/ResolutionContext.h" +# include # include -# include # include # include +# include using namespace opensaml::saml2; using namespace opensaml::saml2p; using namespace opensaml::saml2md; @@ -52,15 +53,24 @@ namespace shibsp { #pragma warning( push ) #pragma warning( disable : 4250 ) #endif - + class SHIBSP_DLLLOCAL SAML2Consumer : public AssertionConsumerService { public: SAML2Consumer(const DOMElement* e, const char* appId) : AssertionConsumerService(e, appId, Category::getInstance(SHIBSP_LOGCAT".SSO.SAML2")) { +#ifndef SHIBSP_LITE + m_ssoRule = NULL; + if (SPConfig::getConfig().isEnabled(SPConfig::OutOfProcess)) + m_ssoRule = SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(BEARER_POLICY_RULE, e); +#endif } - virtual ~SAML2Consumer() {} - + virtual ~SAML2Consumer() { +#ifndef SHIBSP_LITE + delete m_ssoRule; +#endif + } + #ifndef SHIBSP_LITE void generateMetadata(SPSSODescriptor& role, const char* handlerURL) const { AssertionConsumerService::generateMetadata(role, handlerURL); @@ -76,6 +86,8 @@ namespace shibsp { const PropertySet* settings, const XMLObject& xmlObject ) const; + + SecurityPolicyRule* m_ssoRule; #endif }; @@ -87,7 +99,19 @@ namespace shibsp { { return new SAML2Consumer(p.first, p.second); } - + +#ifndef SHIBSP_LITE + class SHIBSP_DLLLOCAL _rulenamed : std::unary_function + { + public: + _rulenamed(const char* name) : m_name(name) {} + bool operator()(const SecurityPolicyRule* rule) const { + return rule ? !strcmp(m_name, rule->getType()) : false; + } + private: + const char* m_name; + }; +#endif }; #ifndef SHIBSP_LITE @@ -109,7 +133,7 @@ void SAML2Consumer::implementProtocol( bool alreadySecured = policy.isAuthenticated(); // Check for errors...this will throw if it's not a successful message. - checkError(&xmlObject); + checkError(&xmlObject, policy.getIssuerMetadata()); const Response* response = dynamic_cast(&xmlObject); if (!response) @@ -140,9 +164,6 @@ void SAML2Consumer::implementProtocol( flag = application.getRelyingParty(entity)->getBool("requireSignedAssertions"); } - time_t now = time(NULL); - string dest = httpRequest.getRequestURL(); - // authnskew allows rejection of SSO if AuthnInstant is too old. const PropertySet* sessionProps = application.getPropertySet("Sessions"); pair authnskew = sessionProps ? sessionProps->getUnsignedInt("maxTimeSinceAuthn") : pair(false,0); @@ -150,6 +171,14 @@ void SAML2Consumer::implementProtocol( // Saves off error messages potentially helpful for users. string contextualError; + // Ensure the Bearer rule is in the policy set. + if (find_if(policy.getRules(), _rulenamed(BEARER_POLICY_RULE)) == NULL) + policy.getRules().push_back(m_ssoRule); + + // Populate recipient as audience. + policy.getAudiences().push_back(application.getRelyingParty(entity)->getXMLString("entityID").second); + + time_t now = time(NULL); for (vector::const_iterator a = assertions.begin(); a!=assertions.end(); ++a) { try { // Skip unsigned assertion? @@ -164,9 +193,10 @@ void SAML2Consumer::implementProtocol( extractMessageDetails(*(*a), samlconstants::SAML20P_NS, policy); // Run the policy over the assertion. Handles replay, freshness, and - // signature verification, assuming the relevant rules are configured. - policy.evaluate(*(*a)); - + // signature verification, assuming the relevant rules are configured, + // along with condition and profile enforcement. + policy.evaluate(*(*a), &httpRequest); + // If no security is in place now, we kick it. if (!alreadySecured && !policy.isAuthenticated()) throw SecurityPolicyException("Unable to establish security of incoming assertion."); @@ -179,14 +209,14 @@ void SAML2Consumer::implementProtocol( throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy."); } - // Now do profile and core semantic validation to ensure we can use it for SSO. - BrowserSSOProfileValidator ssoValidator( - application.getRelyingParty(entity)->getXMLString("entityID").second, application.getAudiences(), now, dest.substr(0,dest.find('?')).c_str() - ); - ssoValidator.validateAssertion(*(*a)); - // Address checking. - checkAddress(application, httpRequest, ssoValidator.getAddress()); + SubjectConfirmationData* subcondata = dynamic_cast( + dynamic_cast(policy).getSubjectConfirmation()->getSubjectConfirmationData() + ); + if (subcondata && subcondata->getAddress()) { + auto_ptr_char boundip(subcondata->getAddress()); + checkAddress(application, httpRequest, boundip.get()); + } // Track it as a valid token. tokens.push_back(*a); @@ -241,10 +271,6 @@ void SAML2Consumer::implementProtocol( continue; try { - // Skip unsigned assertion? - if (!decrypted->getSignature() && flag.first && flag.second) - throw SecurityPolicyException("The incoming assertion was unsigned, violating local security policy."); - // We clear the security flag, so we can tell whether the token was secured on its own. policy.setAuthenticated(false); policy.reset(true); @@ -253,24 +279,33 @@ void SAML2Consumer::implementProtocol( extractMessageDetails(*decrypted, samlconstants::SAML20P_NS, policy); // Run the policy over the assertion. Handles replay, freshness, and - // signature verification, assuming the relevant rules are configured. + // signature verification, assuming the relevant rules are configured, + // along with condition and profile enforcement. // We have to marshall the object first to ensure signatures can be checked. if (!decrypted->getDOM()) decrypted->marshall(); - policy.evaluate(*decrypted); - + policy.evaluate(*decrypted, &httpRequest); + // If no security is in place now, we kick it. if (!alreadySecured && !policy.isAuthenticated()) throw SecurityPolicyException("Unable to establish security of incoming assertion."); - // Now do profile and core semantic validation to ensure we can use it for SSO. - BrowserSSOProfileValidator ssoValidator( - application.getRelyingParty(entity)->getXMLString("entityID").second, application.getAudiences(), now, dest.substr(0,dest.find('?')).c_str() - ); - ssoValidator.validateAssertion(*decrypted); + // If we hadn't established Issuer yet, redo the signedAssertions check. + if (!entity && policy.getIssuerMetadata()) { + entity = dynamic_cast(policy.getIssuerMetadata()->getParent()); + flag = application.getRelyingParty(entity)->getBool("requireSignedAssertions"); + if (!decrypted->getSignature() && flag.first && flag.second) + throw SecurityPolicyException("The decrypted assertion was unsigned, violating local security policy."); + } // Address checking. - checkAddress(application, httpRequest, ssoValidator.getAddress()); + SubjectConfirmationData* subcondata = dynamic_cast( + dynamic_cast(policy).getSubjectConfirmation()->getSubjectConfirmationData() + ); + if (subcondata && subcondata->getAddress()) { + auto_ptr_char boundip(subcondata->getAddress()); + checkAddress(application, httpRequest, boundip.get()); + } // Track it as a valid token. tokens.push_back(decrypted); @@ -341,7 +376,8 @@ void SAML2Consumer::implementProtocol( // Now we have to extract the authentication details for session setup. // Session expiration for SAML 2.0 is jointly IdP- and SP-driven. - time_t sessionExp = ssoStatement->getSessionNotOnOrAfter() ? ssoStatement->getSessionNotOnOrAfterEpoch() : 0; + time_t sessionExp = ssoStatement->getSessionNotOnOrAfter() ? + (ssoStatement->getSessionNotOnOrAfterEpoch() + XMLToolingConfig::getConfig().clock_skew_secs) : 0; pair lifetime = sessionProps ? sessionProps->getUnsignedInt("lifetime") : pair(true,28800); if (!lifetime.first || lifetime.second == 0) lifetime.second = 28800;