From 89f7a67207019e004799798858375de7e0be8cda Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 9 Nov 2006 05:15:55 +0000 Subject: [PATCH] Factor out issuer/protocol extraction. --- saml/binding/MessageFlowRule.h | 3 +- saml/binding/SecurityPolicy.h | 54 +++++++++++++++++++++---- saml/binding/SecurityPolicyRule.h | 25 +++++++++++- saml/binding/SimpleSigningRule.h | 17 +------- saml/binding/XMLSigningRule.h | 17 +------- saml/binding/impl/MessageFlowRule.cpp | 3 +- saml/binding/impl/SecurityPolicy.cpp | 72 +++++++++++++++++++++++++++++++-- saml/binding/impl/SimpleSigningRule.cpp | 32 ++------------- saml/binding/impl/XMLSigningRule.cpp | 65 ++--------------------------- 9 files changed, 153 insertions(+), 135 deletions(-) diff --git a/saml/binding/MessageFlowRule.h b/saml/binding/MessageFlowRule.h index 632f305..d9fdeed 100644 --- a/saml/binding/MessageFlowRule.h +++ b/saml/binding/MessageFlowRule.h @@ -41,7 +41,8 @@ namespace opensaml { const xmltooling::XMLObject& message, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, - const TrustEngine* trustEngine + const TrustEngine* trustEngine, + const MessageExtractor& extractor ) const; /** diff --git a/saml/binding/SecurityPolicy.h b/saml/binding/SecurityPolicy.h index 81f990e..fcf3151 100644 --- a/saml/binding/SecurityPolicy.h +++ b/saml/binding/SecurityPolicy.h @@ -62,12 +62,13 @@ namespace opensaml { const saml2md::MetadataProvider* metadataProvider=NULL, const xmltooling::QName* role=NULL, const TrustEngine* trustEngine=NULL - ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_metadata(metadataProvider), - m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) { + ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_extractor(NULL), + m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) { } /** - * Constructor for policy using existing rules. + * Constructor for policy using existing rules. The lifetime of the policy rules + * must be at least as long as the policy object. * * @param rules reference to array of policy rules to use * @param metadataProvider locked MetadataProvider instance @@ -79,8 +80,8 @@ namespace opensaml { const saml2md::MetadataProvider* metadataProvider=NULL, const xmltooling::QName* role=NULL, const TrustEngine* trustEngine=NULL - ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_rules(rules), m_metadata(metadataProvider), - m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) { + ) : m_issuer(NULL), m_issuerRole(NULL), m_matchingPolicy(NULL), m_extractor(NULL), m_rules(rules), + m_metadata(metadataProvider), m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) { } virtual ~SecurityPolicy(); @@ -113,6 +114,16 @@ namespace opensaml { } /** + * Adds a SecurityPolicyRule to the policy. The lifetime of the policy rule + * must be at least as long as the policy object. + * + * @param rule SecurityPolicyRule to add + */ + void addRule(const SecurityPolicyRule* rule) { + m_rules.push_back(rule); + } + + /** * Sets a locked MetadataProvider for the policy. * * @param metadata a locked MetadataProvider or NULL @@ -210,8 +221,8 @@ namespace opensaml { * * @return the effective IssuerMatchingPolicy */ - const IssuerMatchingPolicy* getIssuerMatchingPolicy() const { - return m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching; + const IssuerMatchingPolicy& getIssuerMatchingPolicy() const { + return m_matchingPolicy ? *m_matchingPolicy : m_defaultMatching; } /** @@ -222,20 +233,47 @@ namespace opensaml { * * @param matchingPolicy the IssuerMatchingPolicy to use */ - void getIssuerMatchingPolicy(IssuerMatchingPolicy* matchingPolicy) { + void setIssuerMatchingPolicy(IssuerMatchingPolicy* matchingPolicy) { delete m_matchingPolicy; m_matchingPolicy = matchingPolicy; } + /** + * Returns the MessageExtractor in effect. + * + * @return the effective MessageExtractor + */ + const SecurityPolicyRule::MessageExtractor& getMessageExtractor() const { + return m_extractor ? *m_extractor : m_defaultExtractor; + } + + /** + * Sets the MessageExtractor in effect. Setting no extractor will + * cause the default extractor to be used. + * + *

The extractor will be freed by the SecurityPolicy. + * + * @param extractor the MessageExtractor to use + */ + void setMessageExtractor(SecurityPolicyRule::MessageExtractor* extractor) { + delete m_extractor; + m_extractor = extractor; + } + protected: /** A shared matching object that just supports the default matching rules. */ static IssuerMatchingPolicy m_defaultMatching; + /** A shared extractor object that just supports the default SAML message types. */ + static SecurityPolicyRule::MessageExtractor m_defaultExtractor; + private: saml2::Issuer* m_issuer; const saml2md::RoleDescriptor* m_issuerRole; IssuerMatchingPolicy* m_matchingPolicy; + SecurityPolicyRule::MessageExtractor* m_extractor; + std::vector m_rules; const saml2md::MetadataProvider* m_metadata; xmltooling::QName m_role; diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h index 0222017..9a1b49f 100644 --- a/saml/binding/SecurityPolicyRule.h +++ b/saml/binding/SecurityPolicyRule.h @@ -52,6 +52,27 @@ namespace opensaml { public: virtual ~SecurityPolicyRule() {} + /** Allows override of code for extracting saml2:Issuer and protocol information. */ + class SAML_API MessageExtractor { + MAKE_NONCOPYABLE(MessageExtractor); + public: + MessageExtractor() {} + virtual ~MessageExtractor() {} + + /** + * Examines the message and/or its contents and extracts the issuer's claimed + * identity along with a protocol identifier. Conventions may be needed + * to properly encode non-SAML2 issuer information into a compatible form. + * + *

The caller is responsible for freeing the Issuer object. + * + * @param message message to examine + * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant. + * @throws std::bad_cast thrown if the message is not of an expected type + */ + virtual std::pair getIssuerAndProtocol(const xmltooling::XMLObject& message) const; + }; + /** * Evaluates the rule against the given request and message. If an Issuer is * returned, the caller is responsible for freeing the Issuer object. @@ -61,6 +82,7 @@ namespace opensaml { * @param metadataProvider locked MetadataProvider instance to authenticate the message * @param role identifies the role (generally IdP or SP) of the peer who issued the message * @param trustEngine TrustEngine to authenticate the message + * @param extractor MessageExtractor to use in examining message * @return the identity of the message issuer, in two forms, or NULL * * @throws BindingException thrown if the request/message do not meet the requirements of this rule @@ -70,7 +92,8 @@ namespace opensaml { const xmltooling::XMLObject& message, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, - const TrustEngine* trustEngine + const TrustEngine* trustEngine, + const MessageExtractor& extractor ) const=0; }; diff --git a/saml/binding/SimpleSigningRule.h b/saml/binding/SimpleSigningRule.h index 5a2659c..a4d79e2 100644 --- a/saml/binding/SimpleSigningRule.h +++ b/saml/binding/SimpleSigningRule.h @@ -42,22 +42,9 @@ namespace opensaml { const xmltooling::XMLObject& message, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, - const TrustEngine* trustEngine + const TrustEngine* trustEngine, + const MessageExtractor& extractor ) const; - - protected: - /** - * Examines the message and/or its contents and extracts the issuer's claimed - * identity along with a protocol identifier. The two together can be used to - * locate metadata to use in validating the signature. Conventions may be needed - * to properly encode non-SAML2 issuer information into a compatible form. - * - *

The caller is responsible for freeing the Issuer object. - * - * @param message message to examine - * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant. - */ - virtual std::pair getIssuerAndProtocol(const xmltooling::XMLObject& message) const; }; }; diff --git a/saml/binding/XMLSigningRule.h b/saml/binding/XMLSigningRule.h index f4ff85e..29816b7 100644 --- a/saml/binding/XMLSigningRule.h +++ b/saml/binding/XMLSigningRule.h @@ -41,22 +41,9 @@ namespace opensaml { const xmltooling::XMLObject& message, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, - const TrustEngine* trustEngine + const TrustEngine* trustEngine, + const MessageExtractor& extractor ) const; - - protected: - /** - * Examines the message and/or its contents and extracts the issuer's claimed - * identity along with a protocol identifier. The two together can be used to - * locate metadata to use in validating the signature. Conventions may be needed - * to properly encode non-SAML2 issuer information into a compatible form. - * - *

The caller is responsible for freeing the Issuer object. - * - * @param message message to examine - * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant. - */ - virtual std::pair getIssuerAndProtocol(const xmltooling::XMLObject& message) const; }; }; diff --git a/saml/binding/impl/MessageFlowRule.cpp b/saml/binding/impl/MessageFlowRule.cpp index 001f84e..5c30951 100644 --- a/saml/binding/impl/MessageFlowRule.cpp +++ b/saml/binding/impl/MessageFlowRule.cpp @@ -62,7 +62,8 @@ pair MessageFlowRule::evaluate( const XMLObject& message, const saml2md::MetadataProvider* metadataProvider, const QName* role, - const opensaml::TrustEngine* trustEngine + const opensaml::TrustEngine* trustEngine, + const MessageExtractor& extractor ) const { try { diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp index 437241a..2edad23 100644 --- a/saml/binding/impl/SecurityPolicy.cpp +++ b/saml/binding/impl/SecurityPolicy.cpp @@ -23,7 +23,10 @@ #include "internal.h" #include "exceptions.h" #include "binding/SecurityPolicy.h" +#include "saml1/core/Assertions.h" +#include "saml1/core/Protocols.h" #include "saml2/core/Assertions.h" +#include "saml2/core/Protocols.h" using namespace opensaml::saml2md; using namespace opensaml::saml2; @@ -47,8 +50,11 @@ void SAML_API opensaml::registerSecurityPolicyRules() SecurityPolicy::IssuerMatchingPolicy SecurityPolicy::m_defaultMatching; +SecurityPolicyRule::MessageExtractor SecurityPolicy::m_defaultExtractor; + SecurityPolicy::~SecurityPolicy() { + delete m_extractor; delete m_matchingPolicy; delete m_issuer; } @@ -58,12 +64,13 @@ void SecurityPolicy::evaluate(const GenericRequest& request, const XMLObject& me for (vector::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) { // Run the rule... - pair ident = (*i)->evaluate(request,message,m_metadata,&m_role,m_trust); + pair ident = + (*i)->evaluate(request,message,m_metadata,&m_role,m_trust,getMessageExtractor()); // Make sure returned issuer doesn't conflict. if (ident.first) { - if (!(m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching)->issuerMatches(ident.first, m_issuer)) { + if (!getIssuerMatchingPolicy().issuerMatches(ident.first, m_issuer)) { delete ident.first; throw BindingException("Policy rules returned differing Issuers."); } @@ -81,7 +88,7 @@ void SecurityPolicy::evaluate(const GenericRequest& request, const XMLObject& me void SecurityPolicy::setIssuer(saml2::Issuer* issuer) { - if (!((m_matchingPolicy ? m_matchingPolicy : &m_defaultMatching))->issuerMatches(issuer, m_issuer)) { + if (!getIssuerMatchingPolicy().issuerMatches(issuer, m_issuer)) { delete issuer; throw BindingException("Externally provided Issuer conflicts with policy results."); } @@ -125,3 +132,62 @@ bool SecurityPolicy::IssuerMatchingPolicy::issuerMatches(const Issuer* issuer1, return true; } + + +pair SecurityPolicyRule::MessageExtractor::getIssuerAndProtocol(const XMLObject& message) const +{ + // We just let any bad casts throw here. + + saml2::Issuer* issuer; + + // Shortcuts some of the casting. + const XMLCh* ns = message.getElementQName().getNamespaceURI(); + if (ns) { + if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) { + // 2.0 namespace should be castable to a specialized 2.0 root. + const saml2::RootObject& root = dynamic_cast(message); + issuer = root.getIssuer(); + if (issuer && issuer->getName()) { + return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); + } + + // No issuer in the message, so we have to try the Response approach. + const vector& assertions = dynamic_cast(message).getAssertions(); + if (!assertions.empty()) { + issuer = assertions.front()->getIssuer(); + if (issuer && issuer->getName()) + return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); + } + } + else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) { + // Should be a samlp:Response, at least in OpenSAML. + const vector& assertions = dynamic_cast(message).getAssertions(); + if (!assertions.empty()) { + const saml1::Assertion* a = assertions.front(); + if (a->getIssuer()) { + issuer = saml2::IssuerBuilder::buildIssuer(); + issuer->setName(a->getIssuer()); + pair minor = a->getMinorVersion(); + return make_pair( + issuer, + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + ); + } + } + } + else if (XMLString::equals(ns, samlconstants::SAML1_NS)) { + // Should be a saml:Assertion. + const saml1::Assertion& a = dynamic_cast(message); + if (a.getIssuer()) { + issuer = saml2::IssuerBuilder::buildIssuer(); + issuer->setName(a.getIssuer()); + pair minor = a.getMinorVersion(); + return make_pair( + issuer, + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + ); + } + } + } + return pair(NULL,NULL); +} diff --git a/saml/binding/impl/SimpleSigningRule.cpp b/saml/binding/impl/SimpleSigningRule.cpp index 481223d..44c6e9c 100644 --- a/saml/binding/impl/SimpleSigningRule.cpp +++ b/saml/binding/impl/SimpleSigningRule.cpp @@ -74,7 +74,8 @@ pair SimpleSigningRule::evaluate( const XMLObject& message, const MetadataProvider* metadataProvider, const QName* role, - const opensaml::TrustEngine* trustEngine + const opensaml::TrustEngine* trustEngine, + const MessageExtractor& extractor ) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning"); @@ -101,7 +102,7 @@ pair SimpleSigningRule::evaluate( try { log.debug("extracting issuer from message"); - pair issuerInfo = getIssuerAndProtocol(message); + pair issuerInfo = extractor.getIssuerAndProtocol(message); auto_ptr issuer(issuerInfo.first); if (!issuerInfo.first || !issuerInfo.second || @@ -194,30 +195,3 @@ pair SimpleSigningRule::evaluate( } return ret; } - -pair SimpleSigningRule::getIssuerAndProtocol(const XMLObject& message) const -{ - // We just let any bad casts throw here. - - // Shortcuts some of the casting. - const XMLCh* ns = message.getElementQName().getNamespaceURI(); - if (ns) { - if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) { - // 2.0 namespace should be castable to a specialized 2.0 root. - const saml2::RootObject& root = dynamic_cast(message); - saml2::Issuer* issuer = root.getIssuer(); - if (issuer && issuer->getName()) { - return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); - } - - // No issuer in the message, so we have to try the Response approach. - const vector& assertions = dynamic_cast(message).getAssertions(); - if (!assertions.empty()) { - issuer = assertions.front()->getIssuer(); - if (issuer && issuer->getName()) - return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); - } - } - } - return pair(NULL,NULL); -} diff --git a/saml/binding/impl/XMLSigningRule.cpp b/saml/binding/impl/XMLSigningRule.cpp index cad0e6d..a63c18c 100644 --- a/saml/binding/impl/XMLSigningRule.cpp +++ b/saml/binding/impl/XMLSigningRule.cpp @@ -24,8 +24,6 @@ #include "exceptions.h" #include "RootObject.h" #include "binding/XMLSigningRule.h" -#include "saml1/core/Assertions.h" -#include "saml1/core/Protocols.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" @@ -53,7 +51,8 @@ pair XMLSigningRule::evaluate( const XMLObject& message, const MetadataProvider* metadataProvider, const QName* role, - const opensaml::TrustEngine* trustEngine + const opensaml::TrustEngine* trustEngine, + const MessageExtractor& extractor ) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning"); @@ -74,7 +73,7 @@ pair XMLSigningRule::evaluate( } log.debug("extracting issuer from message"); - pair issuerInfo = getIssuerAndProtocol(message); + pair issuerInfo = extractor.getIssuerAndProtocol(message); auto_ptr issuer(issuerInfo.first); if (!issuerInfo.first || !issuerInfo.second || @@ -117,61 +116,3 @@ pair XMLSigningRule::evaluate( } return ret; } - -pair XMLSigningRule::getIssuerAndProtocol(const XMLObject& message) const -{ - // We just let any bad casts throw here. - - saml2::Issuer* issuer; - - // Shortcuts some of the casting. - const XMLCh* ns = message.getElementQName().getNamespaceURI(); - if (ns) { - if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) { - // 2.0 namespace should be castable to a specialized 2.0 root. - const saml2::RootObject& root = dynamic_cast(message); - issuer = root.getIssuer(); - if (issuer && issuer->getName()) { - return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); - } - - // No issuer in the message, so we have to try the Response approach. - const vector& assertions = dynamic_cast(message).getAssertions(); - if (!assertions.empty()) { - issuer = assertions.front()->getIssuer(); - if (issuer && issuer->getName()) - return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS); - } - } - else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) { - // Should be a samlp:Response, at least in OpenSAML. - const vector& assertions = dynamic_cast(message).getAssertions(); - if (!assertions.empty()) { - const saml1::Assertion* a = assertions.front(); - if (a->getIssuer()) { - issuer = saml2::IssuerBuilder::buildIssuer(); - issuer->setName(a->getIssuer()); - pair minor = a->getMinorVersion(); - return make_pair( - issuer, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM - ); - } - } - } - else if (XMLString::equals(ns, samlconstants::SAML1_NS)) { - // Should be a saml:Assertion. - const saml1::Assertion& a = dynamic_cast(message); - if (a.getIssuer()) { - issuer = saml2::IssuerBuilder::buildIssuer(); - issuer->setName(a.getIssuer()); - pair minor = a.getMinorVersion(); - return make_pair( - issuer, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM - ); - } - } - } - return pair(NULL,NULL); -} -- 2.1.4