From 3e40c0e62375c069e7860a87ca4f65fb2003f018 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Tue, 12 Dec 2006 02:02:09 +0000 Subject: [PATCH] Policy rule redesign for factor out issuer handling. --- saml/Makefile.am | 8 +- saml/SAMLConfig.cpp | 1 + saml/binding/ClientCertAuthRule.h | 22 +-- saml/binding/MessageFlowRule.h | 23 +-- saml/binding/SecurityPolicy.h | 103 ++++++++++-- saml/binding/SecurityPolicyRule.h | 46 +++--- saml/binding/SimpleSigningRule.h | 25 +-- saml/binding/XMLSigningRule.h | 25 +-- saml/binding/impl/ClientCertAuthRule.cpp | 95 +++-------- saml/binding/impl/MessageFlowRule.cpp | 46 ++---- saml/binding/impl/SecurityPolicy.cpp | 50 +++--- saml/binding/impl/SimpleSigningRule.cpp | 198 ++++++++--------------- saml/binding/impl/XMLSigningRule.cpp | 144 ++++------------- saml/saml.vcproj | 16 ++ saml/saml1/binding/SAML1MessageRule.h | 40 +++++ saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp | 13 +- saml/saml1/binding/impl/SAML1MessageRule.cpp | 120 ++++++++++++++ saml/saml1/binding/impl/SAML1POSTDecoder.cpp | 61 ++----- saml/saml2/binding/SAML2MessageRule.h | 40 +++++ saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp | 40 ++--- saml/saml2/binding/impl/SAML2MessageRule.cpp | 123 ++++++++++++++ saml/saml2/binding/impl/SAML2POSTDecoder.cpp | 67 ++------ saml/saml2/binding/impl/SAML2RedirectDecoder.cpp | 55 ++----- saml/util/SAMLConstants.h | 2 + samltest/binding.h | 22 ++- samltest/saml1/binding/SAML1ArtifactTest.h | 3 +- samltest/saml1/binding/SAML1POSTTest.h | 3 +- samltest/saml2/binding/SAML2ArtifactTest.h | 3 +- samltest/saml2/binding/SAML2POSTTest.h | 6 +- samltest/saml2/binding/SAML2RedirectTest.h | 3 +- 30 files changed, 711 insertions(+), 692 deletions(-) create mode 100644 saml/saml1/binding/SAML1MessageRule.h create mode 100644 saml/saml1/binding/impl/SAML1MessageRule.cpp create mode 100644 saml/saml2/binding/SAML2MessageRule.h create mode 100644 saml/saml2/binding/impl/SAML2MessageRule.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index ccb114f..8dcd88e 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -74,7 +74,8 @@ saml1bindinclude_HEADERS = \ saml1/binding/SAML1POSTEncoder.h \ saml1/binding/SAML1SOAPDecoder.h \ saml1/binding/SAML1SOAPEncoder.h \ - saml1/binding/SAML1SOAPClient.h + saml1/binding/SAML1SOAPClient.h \ + saml1/binding/SAML1MessageRule.h saml2coreinclude_HEADERS = \ saml2/core/Assertions.h \ @@ -92,7 +93,8 @@ saml2bindinclude_HEADERS = \ saml2/binding/SAML2RedirectEncoder.h \ saml2/binding/SAML2SOAPDecoder.h \ saml2/binding/SAML2SOAPEncoder.h \ - saml2/binding/SAML2SOAPClient.h + saml2/binding/SAML2SOAPClient.h \ + saml1/binding/SAML2MessageRule.h saml2mdinclude_HEADERS = \ saml2/metadata/AbstractMetadataProvider.h \ @@ -132,6 +134,7 @@ libsaml_la_SOURCES = \ saml1/binding/impl/SAML1SOAPDecoder.cpp \ saml1/binding/impl/SAML1SOAPEncoder.cpp \ saml1/binding/impl/SAML1SOAPClient.cpp \ + saml1/binding/impl/SAML1MessageRule.cpp \ saml2/core/impl/Assertions20Impl.cpp \ saml2/core/impl/Assertions20SchemaValidators.cpp \ saml2/core/impl/Protocols20Impl.cpp \ @@ -158,6 +161,7 @@ libsaml_la_SOURCES = \ saml2/binding/impl/SAML2SOAPDecoder.cpp \ saml2/binding/impl/SAML2SOAPEncoder.cpp \ saml2/binding/impl/SAML2SOAPClient.cpp \ + saml2/binding/impl/SAML2MessageRule.cpp \ encryption/EncryptedKeyResolver.cpp \ signature/ContentReference.cpp \ signature/SignatureProfileValidator.cpp \ diff --git a/saml/SAMLConfig.cpp b/saml/SAMLConfig.cpp index cfecf0c..48a8175 100644 --- a/saml/SAMLConfig.cpp +++ b/saml/SAMLConfig.cpp @@ -28,6 +28,7 @@ #include "binding/MessageDecoder.h" #include "binding/MessageEncoder.h" #include "binding/SAMLArtifact.h" +#include "binding/SecurityPolicyRule.h" #include "binding/URLEncoder.h" #include "saml1/core/Assertions.h" #include "saml1/core/Protocols.h" diff --git a/saml/binding/ClientCertAuthRule.h b/saml/binding/ClientCertAuthRule.h index edd9b99..737e52b 100644 --- a/saml/binding/ClientCertAuthRule.h +++ b/saml/binding/ClientCertAuthRule.h @@ -33,26 +33,6 @@ namespace opensaml { ClientCertAuthRule(const DOMElement* e) {} virtual ~ClientCertAuthRule() {} - std::pair evaluate( - const xmltooling::XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const xmltooling::QName* role, - const xmltooling::TrustEngine* trustEngine - ) 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; + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; }; }; diff --git a/saml/binding/MessageFlowRule.h b/saml/binding/MessageFlowRule.h index 885b82a..accd60c 100644 --- a/saml/binding/MessageFlowRule.h +++ b/saml/binding/MessageFlowRule.h @@ -27,8 +27,8 @@ namespace opensaml { /** * SAML replay and freshness checking SecurityPolicyRule * - * Subclasses can provide support for additional message types - * by overriding the main method and then calling the check method. + * Some form of message rule to extract ID and timestamp must be + * run prior to this rule. */ class SAML_API MessageFlowRule : public SecurityPolicyRule { @@ -36,13 +36,7 @@ namespace opensaml { MessageFlowRule(const DOMElement* e); virtual ~MessageFlowRule() {} - std::pair evaluate( - const xmltooling::XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const xmltooling::QName* role, - const xmltooling::TrustEngine* trustEngine - ) const; + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; /** * Controls whether rule executes replay checking. @@ -61,17 +55,6 @@ namespace opensaml { void setExpires(time_t expires) { m_expires = expires; } - - protected: - /** - * Performs the check. - * - * @param id message identifier - * @param issueInstant timestamp of protocol message - * - * @exception BindingException raised if a check fails - */ - void check(const XMLCh* id, time_t issueInstant) const; private: bool m_checkReplay; diff --git a/saml/binding/SecurityPolicy.h b/saml/binding/SecurityPolicy.h index 96fdffe..a9ab6e0 100644 --- a/saml/binding/SecurityPolicy.h +++ b/saml/binding/SecurityPolicy.h @@ -23,8 +23,12 @@ #ifndef __saml_secpol_h__ #define __saml_secpol_h__ -#include +#include + +#include #include +#include +#include #if defined (_MSC_VER) #pragma warning( push ) @@ -33,10 +37,16 @@ namespace opensaml { + namespace saml2 { + class SAML_API Issuer; + }; namespace saml2md { class SAML_API MetadataProvider; + class SAML_API RoleDescriptor; }; + class SAML_API SecurityPolicyRule; + /** * A policy used to verify the security of an incoming message. * @@ -53,7 +63,7 @@ namespace opensaml { public: /** * Constructor for policy. - * + * * @param metadataProvider locked MetadataProvider instance * @param role identifies the role (generally IdP or SP) of the policy peer * @param trustEngine TrustEngine to authenticate policy peer @@ -62,8 +72,10 @@ namespace opensaml { const saml2md::MetadataProvider* metadataProvider=NULL, const xmltooling::QName* role=NULL, const xmltooling::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_messageQName(NULL), m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), + m_matchingPolicy(NULL), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine) { + if (role) + m_role = new xmltooling::QName(*role); } /** @@ -80,8 +92,10 @@ namespace opensaml { const saml2md::MetadataProvider* metadataProvider=NULL, const xmltooling::QName* role=NULL, const xmltooling::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_messageQName(NULL), m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), + m_matchingPolicy(NULL), m_rules(rules), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine) { + if (role) + m_role = new xmltooling::QName(*role); } virtual ~SecurityPolicy(); @@ -101,7 +115,7 @@ namespace opensaml { * @return the peer role element/type, or an empty QName */ const xmltooling::QName* getRole() const { - return &m_role; + return m_role; } /** @@ -138,7 +152,8 @@ namespace opensaml { * @param role the peer role element/type or NULL */ void setRole(const xmltooling::QName* role) { - m_role = (role ? *role : xmltooling::QName()); + delete m_role; + m_role = role ? new xmltooling::QName(*role) : NULL; } /** @@ -152,7 +167,7 @@ namespace opensaml { /** * Evaluates the policy against the given request and message, - * possibly populating issuer information in the policy object. + * possibly populating message information in the policy object. * * @param message the incoming message * @param request the protocol request @@ -162,6 +177,38 @@ namespace opensaml { void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request=NULL); /** + * Resets the policy object and clears any per-message state. + */ + void reset(); + + /** + * Returns the message element/type as determined by the registered policies. + * + * @return message element/type as determined by the registered policies + */ + const xmltooling::QName* getMessageQName() const { + return m_messageQName; + } + + /** + * Returns the message identifier as determined by the registered policies. + * + * @return message identifier as determined by the registered policies + */ + const XMLCh* getMessageID() const { + return m_messageID; + } + + /** + * Returns the message timestamp as determined by the registered policies. + * + * @return message timestamp as determined by the registered policies + */ + time_t getIssueInstant() const { + return m_issueInstant; + } + + /** * Gets the issuer of the message as determined by the registered policies. * * @return issuer of the message as determined by the registered policies @@ -180,7 +227,36 @@ namespace opensaml { } /** - * Sets the issuer of the message as determined by external factors. + * Sets the message element/type as determined by the registered policies. + * + * @param messageQName message element/type + */ + void setMessageQName(const xmltooling::QName* messageQName) { + delete m_messageQName; + m_messageQName = messageQName ? new xmltooling::QName(*messageQName) : NULL; + } + + /** + * Sets the message identifier as determined by the registered policies. + * + * @param id message identifier + */ + void setMessageID(const XMLCh* id) { + XMLString::release(&m_messageID); + m_messageID = XMLString::replicate(id); + } + + /** + * Sets the message timestamp as determined by the registered policies. + * + * @param issueInstant message timestamp + */ + void setIssueInstant(time_t issueInstant) { + m_issueInstant = issueInstant; + } + + /** + * Sets the issuer of the message as determined by the registered policies. * The policy object takes ownership of the Issuer object. * * @param issuer issuer of the message @@ -242,13 +318,18 @@ namespace opensaml { static IssuerMatchingPolicy m_defaultMatching; private: + // information extracted from message + xmltooling::QName* m_messageQName; + XMLCh* m_messageID; + time_t m_issueInstant; saml2::Issuer* m_issuer; const saml2md::RoleDescriptor* m_issuerRole; + // components governing policy rules IssuerMatchingPolicy* m_matchingPolicy; std::vector m_rules; const saml2md::MetadataProvider* m_metadata; - xmltooling::QName m_role; + xmltooling::QName* m_role; const xmltooling::TrustEngine* m_trust; }; diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h index ed31d7c..f15d263 100644 --- a/saml/binding/SecurityPolicyRule.h +++ b/saml/binding/SecurityPolicyRule.h @@ -23,18 +23,9 @@ #ifndef __saml_secrule_h__ #define __saml_secrule_h__ -#include -#include -#include +#include namespace opensaml { - namespace saml2 { - class SAML_API Issuer; - }; - namespace saml2md { - class SAML_API MetadataProvider; - class SAML_API RoleDescriptor; - }; /** * A rule that a protocol request and message must meet in order to be valid and secure. @@ -55,22 +46,14 @@ namespace opensaml { * Evaluates the rule against the given request and message. If an Issuer is * returned, the caller is responsible for freeing the Issuer object. * - * @param message the incoming message - * @param request the protocol request - * @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 + * @param message the incoming message + * @param request the protocol request + * @param policy SecurityPolicy to provide various components and track message data * * @throws BindingException thrown if the request/message do not meet the requirements of this rule */ - virtual std::pair evaluate( - const xmltooling::XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const xmltooling::QName* role, - const xmltooling::TrustEngine* trustEngine + virtual void evaluate( + const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy ) const=0; }; @@ -80,10 +63,23 @@ namespace opensaml { void SAML_API registerSecurityPolicyRules(); /** + * SecurityPolicyRule for processing SAML 1.x messages. + * + * Extracts message ID, timestamp, and issuer information. + */ + #define SAML1MESSAGE_POLICY_RULE "org.opensaml.saml1.binding.SAML1MessageRule" + + /** + * SecurityPolicyRule for processing SAML 2.0 messages. + * + * Extracts message ID, timestamp, and issuer information. + */ + #define SAML2MESSAGE_POLICY_RULE "org.opensaml.saml2.binding.SAML2MessageRule" + + /** * SecurityPolicyRule for TLS client certificate authentication. * - * Requires that messages carry information about the issuer, and then - * evaluates the claimed certificates against the issuer's metadata. + * Evaluates client certificates against the issuer's metadata. */ #define CLIENTCERTAUTH_POLICY_RULE "org.opensaml.binding.ClientCertAuthRule" diff --git a/saml/binding/SimpleSigningRule.h b/saml/binding/SimpleSigningRule.h index bceac07..ac82b33 100644 --- a/saml/binding/SimpleSigningRule.h +++ b/saml/binding/SimpleSigningRule.h @@ -27,9 +27,6 @@ namespace opensaml { /** * Blob-oriented signature checking SecurityPolicyRule for * bindings that support non-XML signature techniques. - * - * Subclasses can provide support for additional message types - * by overriding the issuer derivation method. */ class SAML_API SimpleSigningRule : public SecurityPolicyRule { @@ -37,27 +34,7 @@ namespace opensaml { SimpleSigningRule(const DOMElement* e) {} virtual ~SimpleSigningRule() {} - std::pair evaluate( - const xmltooling::XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const xmltooling::QName* role, - const xmltooling::TrustEngine* trustEngine - ) 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; + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; }; }; diff --git a/saml/binding/XMLSigningRule.h b/saml/binding/XMLSigningRule.h index d2c3580..0469914 100644 --- a/saml/binding/XMLSigningRule.h +++ b/saml/binding/XMLSigningRule.h @@ -26,9 +26,6 @@ namespace opensaml { /** * XML Signature checking SecurityPolicyRule - * - * Subclasses can provide support for additional message types - * by overriding the issuer derivation method. */ class SAML_API XMLSigningRule : public SecurityPolicyRule { @@ -36,27 +33,7 @@ namespace opensaml { XMLSigningRule(const DOMElement* e) {} virtual ~XMLSigningRule() {} - std::pair evaluate( - const xmltooling::XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const xmltooling::QName* role, - const xmltooling::TrustEngine* trustEngine - ) 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; + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; }; }; diff --git a/saml/binding/impl/ClientCertAuthRule.cpp b/saml/binding/impl/ClientCertAuthRule.cpp index f13e25e..6337b19 100644 --- a/saml/binding/impl/ClientCertAuthRule.cpp +++ b/saml/binding/impl/ClientCertAuthRule.cpp @@ -27,7 +27,6 @@ #include "saml2/metadata/MetadataProvider.h" #include -#include #include #include @@ -44,95 +43,37 @@ namespace opensaml { } }; -pair ClientCertAuthRule::evaluate( - const XMLObject& message, - const GenericRequest* request, - const MetadataProvider* metadataProvider, - const QName* role, - const TrustEngine* trustEngine - ) const +void ClientCertAuthRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth"); log.debug("evaluating client certificate authentication policy"); - pair ret = pair(NULL,NULL); if (!request) { log.debug("ignoring message, no protocol request available"); - return ret; - } - + return; + } + else if (!policy.getIssuerMetadata()) { + log.debug("ignoring message, no issuer metadata supplied"); + return; + } + const X509TrustEngine* x509trust; - if (!metadataProvider || !role || !(x509trust=dynamic_cast(trustEngine))) { - log.debug("ignoring message, no metadata or X509TrustEngine supplied"); - return ret; + if (!(x509trust=dynamic_cast(policy.getTrustEngine()))) { + log.debug("ignoring message, no X509TrustEngine supplied"); + return; } const std::vector& chain = request->getClientCertificates(); if (chain.empty()) { log.debug("ignoring message, no client certificates in request"); - return ret; + return; } - try { - log.debug("extracting issuer from message"); - pair issuerInfo = getIssuerAndProtocol(message); - - auto_ptr issuer(issuerInfo.first); - if (!issuerInfo.first || !issuerInfo.second || - (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) { - log.warn("issuer identity not estabished, or was not an entityID"); - return ret; - } - - log.debug("searching metadata for message issuer..."); - const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName()); - if (!entity) { - auto_ptr_char temp(issuer->getName()); - log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); - return ret; - } - - log.debug("matched message issuer against metadata, searching for applicable role..."); - const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); - if (!roledesc) { - log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); - return ret; - } - - if (!x509trust->validate(chain.front(), chain, *roledesc, true, metadataProvider->getKeyResolver())) { - log.error("unable to verify certificate chain with supplied trust engine"); - return ret; - } - - if (log.isDebugEnabled()) { - auto_ptr_char iname(entity->getEntityID()); - log.debug("message from (%s), signature verified", iname.get()); - } - - ret.first = issuer.release(); - ret.second = roledesc; + if (!x509trust->validate(chain.front(), chain, *(policy.getIssuerMetadata()), true, + policy.getMetadataProvider()->getKeyResolver())) { + log.error("unable to verify certificate chain with supplied trust engine"); + return; } - catch (bad_cast&) { - // Just trap it. - log.warn("caught a bad_cast while extracting issuer"); - } - return ret; -} - -pair ClientCertAuthRule::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)) { - // 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); - } - } - return pair(NULL,NULL); + + log.debug("client certificate verified against message issuer"); } diff --git a/saml/binding/impl/MessageFlowRule.cpp b/saml/binding/impl/MessageFlowRule.cpp index f7412c2..ce04682 100644 --- a/saml/binding/impl/MessageFlowRule.cpp +++ b/saml/binding/impl/MessageFlowRule.cpp @@ -22,13 +22,11 @@ #include "internal.h" #include "exceptions.h" -#include "RootObject.h" #include "binding/MessageFlowRule.h" -#include "util/SAMLConstants.h" -#include -#include #include +#include +#include using namespace opensaml; using namespace xmltooling; @@ -58,37 +56,16 @@ MessageFlowRule::MessageFlowRule(const DOMElement* e) } } -pair MessageFlowRule::evaluate( - const XMLObject& message, - const GenericRequest* request, - const saml2md::MetadataProvider* metadataProvider, - const QName* role, - const TrustEngine* trustEngine - ) const +void MessageFlowRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageFlow"); - log.debug("evaluating message flow policy"); + log.debug("evaluating message flow policy (replay checking %s, expiration %lu)", m_checkReplay ? "on" : "off", m_expires); - try { - const XMLCh* ns = message.getElementQName().getNamespaceURI(); - if (ns && (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML1P_NS))) { - const RootObject& obj = dynamic_cast(message); - check(obj.getID(), obj.getIssueInstantEpoch()); - } - else { - log.debug("ignoring unrecognized message type"); - } - } - catch (bad_cast&) { - log.warn("caught a bad_cast while extracting issuer"); + time_t issueInstant = policy.getIssueInstant(); + if (issueInstant == 0) { + log.error("unknown message timestamp"); + throw BindingException("Message rejected, no timestamp available."); } - return pair(NULL,NULL); -} - -void MessageFlowRule::check(const XMLCh* id, time_t issueInstant) const -{ - Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageFlow"); - log.debug("evaluating message flow policy (replay checking %s, expiration %lu)", m_checkReplay ? "on" : "off", m_expires); time_t skew = XMLToolingConfig::getConfig().clock_skew_secs; time_t now = time(NULL); @@ -105,12 +82,13 @@ void MessageFlowRule::check(const XMLCh* id, time_t issueInstant) const // Check replay. if (m_checkReplay) { + const XMLCh* id = policy.getMessageID(); ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache(); if (!replayCache) - throw BindingException("No ReplayCache instance available."); + throw BindingException("Message rejected, no ReplayCache instance available."); else if (!id) - throw BindingException("Message did not contain an identifier."); - auto_ptr_char temp(id); + throw BindingException("Message rejected, did not contain an identifier."); + auto_ptr_char temp(id); if (!replayCache->check("SAML", temp.get(), issueInstant + skew + m_expires)) { log.error("replay detected of message ID (%s)", temp.get()); throw BindingException("Rejecting replayed message ID ($1).", params(1,temp.get())); diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp index 350057e..4091df7 100644 --- a/saml/binding/impl/SecurityPolicy.cpp +++ b/saml/binding/impl/SecurityPolicy.cpp @@ -22,11 +22,8 @@ #include "internal.h" #include "exceptions.h" -#include "binding/SecurityPolicy.h" -#include "saml1/core/Assertions.h" -#include "saml1/core/Protocols.h" +#include "binding/SecurityPolicyRule.h" #include "saml2/core/Assertions.h" -#include "saml2/core/Protocols.h" using namespace opensaml::saml2md; using namespace opensaml::saml2; @@ -37,6 +34,8 @@ using namespace std; namespace opensaml { SAML_DLLLOCAL PluginManager::Factory ClientCertAuthRuleFactory; SAML_DLLLOCAL PluginManager::Factory MessageFlowRuleFactory; + SAML_DLLLOCAL PluginManager::Factory SAML1MessageRuleFactory; + SAML_DLLLOCAL PluginManager::Factory SAML2MessageRuleFactory; SAML_DLLLOCAL PluginManager::Factory SimpleSigningRuleFactory; SAML_DLLLOCAL PluginManager::Factory XMLSigningRuleFactory; }; @@ -46,6 +45,8 @@ void SAML_API opensaml::registerSecurityPolicyRules() SAMLConfig& conf=SAMLConfig::getConfig(); conf.SecurityPolicyRuleManager.registerFactory(CLIENTCERTAUTH_POLICY_RULE, ClientCertAuthRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(MESSAGEFLOW_POLICY_RULE, MessageFlowRuleFactory); + conf.SecurityPolicyRuleManager.registerFactory(SAML1MESSAGE_POLICY_RULE, SAML1MessageRuleFactory); + conf.SecurityPolicyRuleManager.registerFactory(SAML2MESSAGE_POLICY_RULE, SAML2MessageRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(SIMPLESIGNING_POLICY_RULE, SimpleSigningRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(XMLSIGNING_POLICY_RULE, XMLSigningRuleFactory); } @@ -54,41 +55,32 @@ SecurityPolicy::IssuerMatchingPolicy SecurityPolicy::m_defaultMatching; SecurityPolicy::~SecurityPolicy() { - delete m_matchingPolicy; + reset(); +} + +void SecurityPolicy::reset() +{ + delete m_messageQName; + XMLString::release(&m_messageID); delete m_issuer; + m_messageQName=NULL; + m_messageID=NULL; + m_issueInstant=0; + m_issuer=NULL; + m_issuerRole=NULL; } void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request) { - for (vector::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) { - - // Run the rule... - pair ident = (*i)->evaluate(message,request,m_metadata,&m_role,m_trust); - - // Make sure returned issuer doesn't conflict. - - if (ident.first) { - if (!getIssuerMatchingPolicy().issuerMatches(ident.first, m_issuer)) { - delete ident.first; - throw BindingException("Policy rules returned differing Issuers."); - } - delete m_issuer; - m_issuer=ident.first; - } - - if (ident.second) { - if (m_issuerRole && ident.second!=m_issuerRole) - throw BindingException("Policy rules returned differing issuer RoleDescriptors."); - m_issuerRole=ident.second; - } - } + for (vector::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) + (*i)->evaluate(message,request,*this); } void SecurityPolicy::setIssuer(saml2::Issuer* issuer) { if (!getIssuerMatchingPolicy().issuerMatches(issuer, m_issuer)) { delete issuer; - throw BindingException("Externally provided Issuer conflicts with policy results."); + throw BindingException("A rule supplied an Issuer that conflicts with previous results."); } delete m_issuer; @@ -98,7 +90,7 @@ void SecurityPolicy::setIssuer(saml2::Issuer* issuer) void SecurityPolicy::setIssuerMetadata(const RoleDescriptor* issuerRole) { if (issuerRole && m_issuerRole && issuerRole!=m_issuerRole) - throw BindingException("Externally provided RoleDescriptor conflicts with policy results."); + throw BindingException("A rule supplied a RoleDescriptor that conflicts with previous results."); m_issuerRole=issuerRole; } diff --git a/saml/binding/impl/SimpleSigningRule.cpp b/saml/binding/impl/SimpleSigningRule.cpp index 7f1ea7f..394802b 100644 --- a/saml/binding/impl/SimpleSigningRule.cpp +++ b/saml/binding/impl/SimpleSigningRule.cpp @@ -24,16 +24,11 @@ #include "exceptions.h" #include "binding/HTTPRequest.h" #include "binding/SimpleSigningRule.h" -#include "saml2/core/Protocols.h" +#include "saml2/core/Assertions.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" #include -#include -#include -#include -#include -#include using namespace opensaml::saml2md; using namespace opensaml; @@ -67,159 +62,94 @@ namespace opensaml { }; -pair SimpleSigningRule::evaluate( - const XMLObject& message, - const GenericRequest* request, - const MetadataProvider* metadataProvider, - const QName* role, - const TrustEngine* trustEngine - ) const +void SimpleSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning"); log.debug("evaluating simple signing policy"); - pair ret = pair(NULL,NULL); - + if (!policy.getIssuerMetadata()) { + log.debug("ignoring message, no issuer metadata supplied"); + return; + } + else if (!policy.getTrustEngine()) { + log.debug("ignoring message, no TrustEngine supplied"); + return; + } + const HTTPRequest* httpRequest = dynamic_cast(request); if (!request || !httpRequest) { log.debug("ignoring message, no HTTP protocol request available"); - return ret; + return; } - if (!metadataProvider || !role || !trustEngine) { - log.debug("ignoring message, no metadata supplied"); - return ret; - } - const char* signature = request->getParameter("Signature"); if (!signature) { log.debug("ignoring unsigned message"); - return ret; + return; } const char* sigAlgorithm = request->getParameter("SigAlg"); if (!sigAlgorithm) { log.error("SigAlg parameter not found, no way to verify the signature"); - return ret; + return; } - try { - log.debug("extracting issuer from message"); - pair issuerInfo = getIssuerAndProtocol(message); - - auto_ptr issuer(issuerInfo.first); - if (!issuerInfo.first || !issuerInfo.second || - (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) { - log.warn("issuer identity not estabished, or was not an entityID"); - return ret; - } - - log.debug("searching metadata for message issuer..."); - const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName()); - if (!entity) { - auto_ptr_char temp(issuer->getName()); - log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); - return ret; - } - - log.debug("matched message issuer against metadata, searching for applicable role..."); - const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); - if (!roledesc) { - log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); - return ret; - } - - string input; - const char* pch; - if (!strcmp(httpRequest->getMethod(), "GET")) { - // We have to construct a string containing the signature input by accessing the - // request directly. We can't use the decoded parameters because we need the raw - // data and URL-encoding isn't canonical. - pch = httpRequest->getQueryString(); - if (!appendParameter(input, pch, "SAMLRequest=")) - appendParameter(input, pch, "SAMLResponse="); - appendParameter(input, pch, "RelayState="); - appendParameter(input, pch, "SigAlg="); - } + string input; + const char* pch; + if (!strcmp(httpRequest->getMethod(), "GET")) { + // We have to construct a string containing the signature input by accessing the + // request directly. We can't use the decoded parameters because we need the raw + // data and URL-encoding isn't canonical. + pch = httpRequest->getQueryString(); + if (!appendParameter(input, pch, "SAMLRequest=")) + appendParameter(input, pch, "SAMLResponse="); + appendParameter(input, pch, "RelayState="); + appendParameter(input, pch, "SigAlg="); + } + else { + // With POST, the input string is concatenated from the decoded form controls. + // GET should be this way too, but I messed up the spec, sorry. + pch = httpRequest->getParameter("SAMLRequest"); + if (pch) + input = string("SAMLRequest=") + pch; else { - // With POST, the input string is concatenated from the decoded form controls. - // GET should be this way too, but I messed up the spec, sorry. - pch = httpRequest->getParameter("SAMLRequest"); - if (pch) - input = string("SAMLRequest=") + pch; - else { - pch = httpRequest->getParameter("SAMLResponse"); - input = string("SAMLResponse=") + pch; - } - pch = httpRequest->getParameter("RelayState"); - if (pch) - input = input + "&RelayState=" + pch; - input = input + "&SigAlg=" + sigAlgorithm; + pch = httpRequest->getParameter("SAMLResponse"); + input = string("SAMLResponse=") + pch; } + pch = httpRequest->getParameter("RelayState"); + if (pch) + input = input + "&RelayState=" + pch; + input = input + "&SigAlg=" + sigAlgorithm; + } - // Check for KeyInfo, but defensively (we might be able to run without it). - KeyInfo* keyInfo=NULL; - pch = request->getParameter("KeyInfo"); - if (pch) { - try { - istringstream kstrm(pch); - DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(kstrm); - XercesJanitor janitor(doc); - XMLObject* kxml = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true); - janitor.release(); - if (!(keyInfo=dynamic_cast(kxml))) - delete kxml; - } - catch (XMLToolingException& ex) { - log.warn("Failed to load KeyInfo from message: %s", ex.what()); - } - } - - auto_ptr kjanitor(keyInfo); - auto_ptr_XMLCh alg(sigAlgorithm); - - if (!trustEngine->validate(alg.get(), signature, keyInfo, input.c_str(), input.length(), *roledesc, metadataProvider->getKeyResolver())) { - log.error("unable to verify signature on message with supplied trust engine"); - return ret; + // Check for KeyInfo, but defensively (we might be able to run without it). + KeyInfo* keyInfo=NULL; + pch = request->getParameter("KeyInfo"); + if (pch) { + try { + istringstream kstrm(pch); + DOMDocument* doc = XMLToolingConfig::getConfig().getParser().parse(kstrm); + XercesJanitor janitor(doc); + XMLObject* kxml = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true); + janitor.release(); + if (!(keyInfo=dynamic_cast(kxml))) + delete kxml; } - - if (log.isDebugEnabled()) { - auto_ptr_char iname(entity->getEntityID()); - log.debug("message from (%s), signature verified", iname.get()); + catch (XMLToolingException& ex) { + log.warn("Failed to load KeyInfo from message: %s", ex.what()); } - - ret.first = issuer.release(); - ret.second = roledesc; } - catch (bad_cast&) { - // Just trap it. - log.warn("caught a bad_cast while extracting issuer"); + + auto_ptr kjanitor(keyInfo); + auto_ptr_XMLCh alg(sigAlgorithm); + + if (!policy.getTrustEngine()->validate( + alg.get(), signature, keyInfo, input.c_str(), input.length(), + *(policy.getIssuerMetadata()), policy.getMetadataProvider()->getKeyResolver() + )) { + log.error("unable to verify message signature with supplied trust engine"); + return; } - 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)) { - // 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); + log.debug("signature verified against message issuer"); } diff --git a/saml/binding/impl/XMLSigningRule.cpp b/saml/binding/impl/XMLSigningRule.cpp index 56c2250..029f14c 100644 --- a/saml/binding/impl/XMLSigningRule.cpp +++ b/saml/binding/impl/XMLSigningRule.cpp @@ -23,15 +23,11 @@ #include "internal.h" #include "exceptions.h" #include "binding/XMLSigningRule.h" -#include "saml1/core/Assertions.h" -#include "saml1/core/Protocols.h" -#include "saml2/core/Protocols.h" +#include "saml2/core/Assertions.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" #include "signature/SignatureProfileValidator.h" -#include -#include #include using namespace opensaml::saml2md; @@ -47,128 +43,42 @@ namespace opensaml { } }; -pair XMLSigningRule::evaluate( - const XMLObject& message, - const GenericRequest* request, - const MetadataProvider* metadataProvider, - const QName* role, - const TrustEngine* trustEngine - ) const +void XMLSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning"); log.debug("evaluating message signing policy"); - pair ret = pair(NULL,NULL); + if (!policy.getIssuerMetadata()) { + log.debug("ignoring message, no issuer metadata supplied"); + return; + } + else if (!policy.getTrustEngine()) { + log.debug("ignoring message, no TrustEngine supplied"); + return; + } - if (!metadataProvider || !role || !trustEngine) { - log.debug("ignoring message, no metadata or trust information supplied"); - return ret; + const SignableObject* signable = dynamic_cast(&message); + if (!signable || !signable->getSignature()) { + log.debug("ignoring unsigned or unrecognized message"); + return; } + log.debug("validating signature profile"); try { - const SignableObject* signable = dynamic_cast(&message); - if (!signable || !signable->getSignature()) { - log.debug("ignoring unsigned or unrecognized message"); - return ret; - } - - log.debug("validating signature profile"); - try { - SignatureProfileValidator sigval; - sigval.validate(signable->getSignature()); - } - catch (ValidationException& ve) { - log.error("signature profile failed to validate: %s", ve.what()); - return ret; - } - - - log.debug("extracting issuer from message"); - pair issuerInfo = getIssuerAndProtocol(message); - - auto_ptr issuer(issuerInfo.first); - if (!issuerInfo.first || !issuerInfo.second || - (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) { - log.warn("issuer identity not estabished, or was not an entityID"); - return ret; - } - - log.debug("searching metadata for message issuer..."); - const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName()); - if (!entity) { - auto_ptr_char temp(issuer->getName()); - log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); - return ret; - } - - log.debug("matched message issuer against metadata, searching for applicable role..."); - const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second); - if (!roledesc) { - log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str()); - return ret; - } - - if (!trustEngine->validate(*(signable->getSignature()), *roledesc, metadataProvider->getKeyResolver())) { - log.error("unable to verify signature on message with supplied trust engine"); - return ret; - } - - if (log.isDebugEnabled()) { - auto_ptr_char iname(entity->getEntityID()); - log.debug("message from (%s), signature verified", iname.get()); - } - - ret.first = issuer.release(); - ret.second = roledesc; + SignatureProfileValidator sigval; + sigval.validate(signable->getSignature()); } - catch (bad_cast&) { - // Just trap it. - log.warn("caught a bad_cast while extracting issuer"); + catch (ValidationException& ve) { + log.error("signature profile failed to validate: %s", ve.what()); + return; } - 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 - ); - } - } - } + if (!policy.getTrustEngine()->validate( + *(signable->getSignature()), *(policy.getIssuerMetadata()), policy.getMetadataProvider()->getKeyResolver() + )) { + log.error("unable to verify message signature with supplied trust engine"); + return; } - return pair(NULL,NULL); + + log.debug("signature verified against message issuer"); } diff --git a/saml/saml.vcproj b/saml/saml.vcproj index b7d12cb..2d13c5a 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -241,6 +241,10 @@ > + + @@ -417,6 +421,10 @@ + + @@ -620,6 +628,10 @@ > + + @@ -732,6 +744,10 @@ > + + diff --git a/saml/saml1/binding/SAML1MessageRule.h b/saml/saml1/binding/SAML1MessageRule.h new file mode 100644 index 0000000..0027921 --- /dev/null +++ b/saml/saml1/binding/SAML1MessageRule.h @@ -0,0 +1,40 @@ +/* + * Copyright 2001-2006 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file saml/saml1/binding/SAML1MessageRule.h + * + * SAML 1.x message extraction rule + */ + +#include + + +namespace opensaml { + namespace saml1p { + /** + * SAML 1.x message extraction rule + */ + class SAML_API SAML1MessageRule : public SecurityPolicyRule + { + public: + SAML1MessageRule(const DOMElement* e) {} + virtual ~SAML1MessageRule() {} + + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; + }; + }; +}; diff --git a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp index bc0f0e6..23a9505 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp @@ -123,6 +123,12 @@ XMLObject* SAML1ArtifactDecoder::decode( auto_ptr_char issuer(provider->getEntityID()); log.debug("lookup succeeded, artifact issued by (%s)", issuer.get()); } + + // Mock up an Issuer object for the policy. + auto_ptr issuer(saml2::IssuerBuilder::buildIssuer()); + issuer->setName(provider->getEntityID()); + policy.setIssuer(issuer.get()); + issuer.release(); // owned by policy now log.debug("attempting to find artifact issuing role..."); const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML11_PROTOCOL_ENUM); @@ -131,9 +137,9 @@ XMLObject* SAML1ArtifactDecoder::decode( if (!roledesc || !dynamic_cast(roledesc)) { log.error("unable to find compatible SAML role (%s) in metadata", policy.getRole()->toString().c_str()); for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup()); - BindingException ex("Unable to find compatible metadata role for artifact issuer."); - annotateException(&ex,provider); // throws it + throw BindingException("Unable to find compatible metadata role for artifact issuer."); } + policy.setIssuerMetadata(roledesc); try { auto_ptr response( @@ -145,9 +151,8 @@ XMLObject* SAML1ArtifactDecoder::decode( for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup()); return response.release(); } - catch (XMLToolingException& ex) { + catch (XMLToolingException&) { for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup()); - annotateException(&ex,roledesc,false); throw; } } diff --git a/saml/saml1/binding/impl/SAML1MessageRule.cpp b/saml/saml1/binding/impl/SAML1MessageRule.cpp new file mode 100644 index 0000000..3d70d87 --- /dev/null +++ b/saml/saml1/binding/impl/SAML1MessageRule.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2001-2006 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * SAML1MessageRule.cpp + * + * SAML 1.x message extraction rule + */ + +#include "internal.h" +#include "exceptions.h" +#include "RootObject.h" +#include "saml1/binding/SAML1MessageRule.h" +#include "saml1/core/Assertions.h" +#include "saml1/core/Protocols.h" +#include "saml2/core/Assertions.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" +#include "util/SAMLConstants.h" + +#include + +using namespace opensaml::saml2md; +using namespace opensaml::saml1p; +using namespace opensaml; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace opensaml { + SecurityPolicyRule* SAML_DLLLOCAL SAML1MessageRuleFactory(const DOMElement* const & e) + { + return new SAML1MessageRule(e); + } +}; + +void SAML1MessageRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const +{ + Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML1Message"); + + const QName& q = message.getElementQName(); + policy.setMessageQName(&q); + + try { + const RootObject& samlRoot = dynamic_cast(message); + policy.setMessageID(samlRoot.getID()); + policy.setIssueInstant(samlRoot.getIssueInstantEpoch()); + + if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1P_NS)) { + log.warn("not a SAML 1.x protocol message"); + throw BindingException("Message was not a recognized SAML 1.x protocol element."); + } + + log.debug("extracting issuer from message"); + + // Only samlp:Response is known to carry issuer (via payload) in standard SAML 1.x. + const XMLCh* protocol = NULL; + if (XMLString::equals(q.getLocalPart(), Response::LOCAL_NAME)) { + // Should be a samlp:Response. + const vector& assertions = dynamic_cast(samlRoot).getAssertions(); + if (!assertions.empty()) { + const saml1::Assertion* a = assertions.front(); + if (a->getIssuer()) { + auto_ptr issuer(saml2::IssuerBuilder::buildIssuer()); + issuer->setName(a->getIssuer()); + policy.setIssuer(issuer.get()); + issuer.release(); // owned by policy now + pair minor = a->getMinorVersion(); + protocol = (minor.first && minor.second==0) ? + samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM; + } + } + } + + if (!protocol) { + log.warn("issuer identity not extracted"); + return; + } + + if (log.isDebugEnabled()) { + auto_ptr_char iname(policy.getIssuer()->getName()); + log.debug("message from (%s)", iname.get()); + } + + if (policy.getMetadataProvider() && policy.getRole()) { + log.debug("searching metadata for message issuer..."); + const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(policy.getIssuer()->getName()); + if (!entity) { + auto_ptr_char temp(policy.getIssuer()->getName()); + log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); + return; + } + + log.debug("matched message issuer against metadata, searching for applicable role..."); + const RoleDescriptor* roledesc=entity->getRoleDescriptor(*policy.getRole(), protocol); + if (!roledesc) { + log.warn("unable to find compatible role (%s) in metadata", policy.getRole()->toString().c_str()); + return; + } + policy.setIssuerMetadata(roledesc); + } + } + catch (bad_cast&) { + // Just trap it. + log.warn("caught a bad_cast while examining message"); + } +} diff --git a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp index fd3258a..1c7e539 100644 --- a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -97,52 +97,23 @@ XMLObject* SAML1POSTDecoder::decode( if (!response) throw BindingException("Decoded message was not a SAML 1.x Response."); - try { - if (!m_validate) - SchemaValidators.validate(xmlObject.get()); - - // Check recipient URL. - auto_ptr_char recipient(response->getRecipient()); - 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."); - } - else if (!recipient2 || !*recipient2 || strcmp(recipient.get(),recipient2)) { - log.error("POST targeted at (%s), but delivered to (%s)", recipient.get(), recipient2 ? recipient2 : "none"); - throw BindingException("SAML message delivered with POST to incorrect server URL."); - } - - // Run through the policy. - policy.evaluate(*response, &genericRequest); + if (!m_validate) + SchemaValidators.validate(xmlObject.get()); + + // Check recipient URL. + auto_ptr_char recipient(response->getRecipient()); + 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."); } - 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() || !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 + else if (!recipient2 || !*recipient2 || strcmp(recipient.get(),recipient2)) { + log.error("POST targeted at (%s), but delivered to (%s)", recipient.get(), recipient2 ? recipient2 : "none"); + throw BindingException("SAML message delivered with POST to incorrect server URL."); } + + // Run through the policy. + policy.evaluate(*response, &genericRequest); - xmlObject.release(); - return response; + return xmlObject.release(); } diff --git a/saml/saml2/binding/SAML2MessageRule.h b/saml/saml2/binding/SAML2MessageRule.h new file mode 100644 index 0000000..20e785e --- /dev/null +++ b/saml/saml2/binding/SAML2MessageRule.h @@ -0,0 +1,40 @@ +/* + * Copyright 2001-2006 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file saml/saml2/binding/SAML2MessageRule.h + * + * SAML 2.0 message extraction rule + */ + +#include + + +namespace opensaml { + namespace saml2p { + /** + * SAML 2.0 message extraction rule + */ + class SAML_API SAML2MessageRule : public SecurityPolicyRule + { + public: + SAML2MessageRule(const DOMElement* e) {} + virtual ~SAML2MessageRule() {} + + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; + }; + }; +}; diff --git a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp index c309162..db3e4b7 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp @@ -124,33 +124,33 @@ XMLObject* SAML2ArtifactDecoder::decode( auto_ptr_char issuer(provider->getEntityID()); log.debug("lookup succeeded, artifact issued by (%s)", issuer.get()); } + + // Mock up an Issuer object for the policy. + auto_ptr issuer(IssuerBuilder::buildIssuer()); + issuer->setName(provider->getEntityID()); + policy.setIssuer(issuer.get()); + issuer.release(); // owned by policy now log.debug("attempting to find artifact issuing role..."); const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML20P_NS); if (!roledesc || !dynamic_cast(roledesc)) { log.error("unable to find compatible SAML role (%s) in metadata", policy.getRole()->toString().c_str()); - BindingException ex("Unable to find compatible metadata role for artifact issuer."); - annotateException(&ex,provider); // throws it + throw BindingException("Unable to find compatible metadata role for artifact issuer."); } + policy.setIssuerMetadata(roledesc); - try { - auto_ptr response( - m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast(*roledesc), policy) - ); - - policy.evaluate(*(response.get()), &genericRequest); + auto_ptr response( + m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast(*roledesc), policy) + ); + + policy.evaluate(*(response.get()), &genericRequest); - // Extract payload and check that message. - XMLObject* payload = response->getPayload(); - policy.evaluate(*payload, &genericRequest); + // Extract payload and check that message. + XMLObject* payload = response->getPayload(); + policy.evaluate(*payload, &genericRequest); - // Return the payload only. - response.release(); - payload->detach(); - return payload; - } - catch (XMLToolingException& ex) { - annotateException(&ex,roledesc,false); - throw; - } + // Return the payload only. + response.release(); + payload->detach(); + return payload; } diff --git a/saml/saml2/binding/impl/SAML2MessageRule.cpp b/saml/saml2/binding/impl/SAML2MessageRule.cpp new file mode 100644 index 0000000..fe604c2 --- /dev/null +++ b/saml/saml2/binding/impl/SAML2MessageRule.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2001-2006 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * SAML1MessageRule.cpp + * + * SAML 1.x message extraction rule + */ + +#include "internal.h" +#include "exceptions.h" +#include "saml2/binding/SAML2MessageRule.h" +#include "saml2/core/Protocols.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" +#include "util/SAMLConstants.h" + +#include + +using namespace opensaml::saml2md; +using namespace opensaml::saml2p; +using namespace opensaml::saml2; +using namespace opensaml; +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace opensaml { + SecurityPolicyRule* SAML_DLLLOCAL SAML2MessageRuleFactory(const DOMElement* const & e) + { + return new SAML2MessageRule(e); + } +}; + +void SAML2MessageRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const +{ + Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML2Message"); + + const QName& q = message.getElementQName(); + policy.setMessageQName(&q); + + try { + const opensaml::RootObject& samlRoot = dynamic_cast(message); + policy.setMessageID(samlRoot.getID()); + policy.setIssueInstant(samlRoot.getIssueInstantEpoch()); + + if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20P_NS)) { + log.warn("not a SAML 2.0 protocol message"); + throw BindingException("Message was not a recognized SAML 2.0 protocol element."); + } + + log.debug("extracting issuer from message"); + const saml2::RootObject& saml2Root = dynamic_cast(samlRoot); + Issuer* issuer = saml2Root.getIssuer(); + if (issuer && issuer->getName()) { + auto_ptr copy(issuer->cloneIssuer()); + policy.setIssuer(copy.get()); + copy.release(); + } + else { + // No issuer in the message, so we have to try the Response approach. + const vector& assertions = dynamic_cast(saml2Root).getAssertions(); + if (!assertions.empty()) { + issuer = assertions.front()->getIssuer(); + if (issuer && issuer->getName()) { + auto_ptr copy(issuer->cloneIssuer()); + policy.setIssuer(copy.get()); + copy.release(); + } + } + } + + if (!policy.getIssuer()) { + log.warn("issuer identity not extracted"); + return; + } + + if (log.isDebugEnabled()) { + auto_ptr_char iname(policy.getIssuer()->getName()); + log.debug("message from (%s)", iname.get()); + } + + if (policy.getMetadataProvider() && policy.getRole()) { + if (policy.getIssuer()->getFormat() && !XMLString::equals(policy.getIssuer()->getFormat(), saml2::NameIDType::ENTITY)) { + log.warn("non-system entity issuer, skipping metadata lookup"); + return; + } + + log.debug("searching metadata for message issuer..."); + const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(policy.getIssuer()->getName()); + if (!entity) { + auto_ptr_char temp(policy.getIssuer()->getName()); + log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get()); + return; + } + + log.debug("matched message issuer against metadata, searching for applicable role..."); + const RoleDescriptor* roledesc=entity->getRoleDescriptor(*policy.getRole(), samlconstants::SAML20P_NS); + if (!roledesc) { + log.warn("unable to find compatible role (%s) in metadata", policy.getRole()->toString().c_str()); + return; + } + policy.setIssuerMetadata(roledesc); + } + } + catch (bad_cast&) { + // Just trap it. + log.warn("caught a bad_cast while examining message"); + } +} diff --git a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp index 8b953e3..49919b3 100644 --- a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp @@ -111,59 +111,22 @@ XMLObject* SAML2POSTDecoder::decode( root = static_cast(request); } - try { - if (!m_validate) - SchemaValidators.validate(xmlObject.get()); - - // Check destination URL. - auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); - const char* dest2 = httpRequest->getRequestURL(); - if ((root->getSignature() || httpRequest->getParameter("Signature")) && !dest.get() || !*(dest.get())) { - log.error("signed SAML message missing Destination attribute"); - throw BindingException("Signed SAML message missing Destination attribute identifying intended destination."); - } - else if (dest.get() && (!dest2 || !*dest2 || strcmp(dest.get(),dest2))) { - log.error("POST targeted at (%s), but delivered to (%s)", dest.get(), dest2 ? dest2 : "none"); - throw BindingException("SAML message delivered with POST to incorrect server URL."); - } - - // Run through the policy. - policy.evaluate(*root, &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 - - const Issuer* claimedIssuer = root->getIssuer(); - if (!claimedIssuer) { - // Check for assertions. - const Response* assbag = dynamic_cast(response); - if (assbag) { - const vector& assertions=assbag->getAssertions(); - if (!assertions.empty()) - claimedIssuer = assertions.front()->getIssuer(); - } - } + if (!m_validate) + SchemaValidators.validate(xmlObject.get()); - if (!claimedIssuer || !claimedIssuer->getName()) - throw; - const EntityDescriptor* provider=NULL; - if (!policy.getMetadataProvider() || - !(provider=policy.getMetadataProvider()->getEntityDescriptor(claimedIssuer->getName(), false))) { - // Just record it. - auto_ptr_char iname(claimedIssuer->getName()); - if (iname.get()) - ex.addProperty("entityID", iname.get()); - throw; - } - - if (policy.getRole()) { - const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML20P_NS); - if (roledesc) annotateException(&ex,roledesc); // throws it - } - annotateException(&ex,provider); // throws it + // Check destination URL. + auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); + const char* dest2 = httpRequest->getRequestURL(); + if ((root->getSignature() || httpRequest->getParameter("Signature")) && !dest.get() || !*(dest.get())) { + log.error("signed SAML message missing Destination attribute"); + throw BindingException("Signed SAML message missing Destination attribute identifying intended destination."); } - + else if (dest.get() && (!dest2 || !*dest2 || strcmp(dest.get(),dest2))) { + log.error("POST targeted at (%s), but delivered to (%s)", dest.get(), dest2 ? dest2 : "none"); + throw BindingException("SAML message delivered with POST to incorrect server URL."); + } + + // Run through the policy. + policy.evaluate(*root, &genericRequest); return xmlObject.release(); } diff --git a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp index d2abd41..de2c66b 100644 --- a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp @@ -125,50 +125,23 @@ XMLObject* SAML2RedirectDecoder::decode( root = static_cast(request); } + if (!m_validate) + SchemaValidators.validate(xmlObject.get()); - try { - if (!m_validate) - SchemaValidators.validate(xmlObject.get()); - - // Check destination URL. - auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); - const char* dest2 = httpRequest->getRequestURL(); - if ((root->getSignature() || httpRequest->getParameter("Signature")) && !dest.get() || !*(dest.get())) { - log.error("signed SAML message missing Destination attribute"); - throw BindingException("Signed SAML message missing Destination attribute identifying intended destination."); - } - else if (dest.get() && (!dest2 || !*dest2 || strcmp(dest.get(),dest2))) { - log.error("Redirect targeted at (%s), but delivered to (%s)", dest.get(), dest2 ? dest2 : "none"); - throw BindingException("SAML message delivered with Redirect to incorrect server URL."); - } - - // Run through the policy. - policy.evaluate(*root, &genericRequest); + // Check destination URL. + auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); + const char* dest2 = httpRequest->getRequestURL(); + if ((root->getSignature() || httpRequest->getParameter("Signature")) && !dest.get() || !*(dest.get())) { + log.error("signed SAML message missing Destination attribute"); + throw BindingException("Signed SAML message missing Destination attribute identifying intended destination."); } - 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 - - const Issuer* claimedIssuer = root->getIssuer(); - if (!claimedIssuer || !claimedIssuer->getName()) - throw; - const EntityDescriptor* provider=NULL; - if (!policy.getMetadataProvider() || - !(provider=policy.getMetadataProvider()->getEntityDescriptor(claimedIssuer->getName(), false))) { - // Just record it. - auto_ptr_char iname(claimedIssuer->getName()); - if (iname.get()) - ex.addProperty("entityID", iname.get()); - throw; - } - - if (policy.getRole()) { - const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML20P_NS); - if (roledesc) annotateException(&ex,roledesc); // throws it - } - annotateException(&ex,provider); // throws it + else if (dest.get() && (!dest2 || !*dest2 || strcmp(dest.get(),dest2))) { + log.error("Redirect targeted at (%s), but delivered to (%s)", dest.get(), dest2 ? dest2 : "none"); + throw BindingException("SAML message delivered with Redirect to incorrect server URL."); } + // Run through the policy. + policy.evaluate(*root, &genericRequest); + return xmlObject.release(); } diff --git a/saml/util/SAMLConstants.h b/saml/util/SAMLConstants.h index edb7207..50c63e0 100644 --- a/saml/util/SAMLConstants.h +++ b/saml/util/SAMLConstants.h @@ -105,8 +105,10 @@ namespace samlconstants { /** SAML 1.x Metadata Profile QName prefix ("saml1md") */ extern SAML_API const XMLCh SAML1MD_PREFIX[]; +#ifndef SAML10_PROTOCOL_ENUM /** SAML 1.0 Protocol Enumeration constant ("urn:oasis:names:tc:SAML:1.0:protocol") */ #define SAML10_PROTOCOL_ENUM SAML1P_NS +#endif /** SAML 1.1 Protocol Enumeration constant ("urn:oasis:names:tc:SAML:1.1:protocol") */ extern SAML_API const XMLCh SAML11_PROTOCOL_ENUM[]; diff --git a/samltest/binding.h b/samltest/binding.h index b412be8..fea95fb 100644 --- a/samltest/binding.h +++ b/samltest/binding.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,8 @@ protected: map m_headers; string m_method,m_url,m_query; vector m_clientCerts; - vector m_rules; + vector m_rules1; + vector m_rules2; public: void setUp() { @@ -78,9 +80,15 @@ public: m_trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE, NULL); - m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL)); - m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL)); - m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL)); + m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SAML1MESSAGE_POLICY_RULE,NULL)); + m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL)); + m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL)); + m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL)); + + m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SAML2MESSAGE_POLICY_RULE,NULL)); + m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL)); + m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL)); + m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL)); } catch (XMLToolingException& ex) { TS_TRACE(ex.what()); @@ -91,8 +99,10 @@ public: } void tearDown() { - for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup()); - m_rules.clear(); + for_each(m_rules1.begin(), m_rules1.end(), xmltooling::cleanup()); + m_rules1.clear(); + for_each(m_rules2.begin(), m_rules2.end(), xmltooling::cleanup()); + m_rules2.clear(); delete m_creds; delete m_metadata; delete m_trust; diff --git a/samltest/saml1/binding/SAML1ArtifactTest.h b/samltest/saml1/binding/SAML1ArtifactTest.h index 30f4dc9..38a95fe 100644 --- a/samltest/saml1/binding/SAML1ArtifactTest.h +++ b/samltest/saml1/binding/SAML1ArtifactTest.h @@ -51,7 +51,7 @@ public: void testSAML1Artifact() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules1, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml1/binding/SAML1Assertion.xml"; @@ -89,6 +89,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { diff --git a/samltest/saml1/binding/SAML1POSTTest.h b/samltest/saml1/binding/SAML1POSTTest.h index 61ae72d..5808169 100644 --- a/samltest/saml1/binding/SAML1POSTTest.h +++ b/samltest/saml1/binding/SAML1POSTTest.h @@ -34,7 +34,7 @@ public: void testSAML1POST() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules1, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml1/binding/SAML1Response.xml"; @@ -84,6 +84,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { diff --git a/samltest/saml2/binding/SAML2ArtifactTest.h b/samltest/saml2/binding/SAML2ArtifactTest.h index 5e3a408..dc968ef 100644 --- a/samltest/saml2/binding/SAML2ArtifactTest.h +++ b/samltest/saml2/binding/SAML2ArtifactTest.h @@ -38,7 +38,7 @@ public: void testSAML2Artifact() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -79,6 +79,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { diff --git a/samltest/saml2/binding/SAML2POSTTest.h b/samltest/saml2/binding/SAML2POSTTest.h index ada0f3e..ec94a04 100644 --- a/samltest/saml2/binding/SAML2POSTTest.h +++ b/samltest/saml2/binding/SAML2POSTTest.h @@ -34,7 +34,7 @@ public: void testSAML2POST() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -84,6 +84,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { @@ -95,7 +96,7 @@ public: void testSAML2POSTSimpleSign() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -145,6 +146,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { diff --git a/samltest/saml2/binding/SAML2RedirectTest.h b/samltest/saml2/binding/SAML2RedirectTest.h index 92d9741..96c0504 100644 --- a/samltest/saml2/binding/SAML2RedirectTest.h +++ b/samltest/saml2/binding/SAML2RedirectTest.h @@ -34,7 +34,7 @@ public: void testSAML2Redirect() { try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); - SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust); + SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -74,6 +74,7 @@ public: TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); // Trigger a replay. + policy.reset(); TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException); } catch (XMLToolingException& ex) { -- 2.1.4