From 5d7bff8c9b4a048d34dda50c40ed355cf4dd84de Mon Sep 17 00:00:00 2001 From: cantor Date: Mon, 17 Sep 2007 02:06:13 +0000 Subject: [PATCH] Refactor message extraction into decoders and clients. Remove security checks from SOAP clients. git-svn-id: https://svn.middleware.georgetown.edu/cpp-opensaml2/trunk@307 fb386ef7-a10c-0410-8ebf-fd3f8e989ab0 --- saml/Makefile.am | 6 +- saml/binding/MessageDecoder.h | 15 +++ saml/binding/SecurityPolicy.h | 21 ++-- saml/binding/SecurityPolicyRule.h | 16 --- saml/binding/impl/ClientCertAuthRule.cpp | 8 +- saml/binding/impl/MessageFlowRule.cpp | 6 +- saml/binding/impl/NullSecurityRule.cpp | 4 +- saml/binding/impl/SOAPClient.cpp | 19 ++- saml/binding/impl/SecurityPolicy.cpp | 10 +- saml/binding/impl/SimpleSigningRule.cpp | 8 +- saml/binding/impl/XMLSigningRule.cpp | 8 +- saml/saml.vcproj | 12 +- saml/saml1/binding/SAML1MessageDecoder.h | 52 ++++++++ saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp | 12 +- saml/saml1/binding/impl/SAML1MessageDecoder.cpp | 110 +++++++++++++++++ saml/saml1/binding/impl/SAML1MessageRule.cpp | 136 --------------------- saml/saml1/binding/impl/SAML1POSTDecoder.cpp | 19 +-- saml/saml1/binding/impl/SAML1SOAPClient.cpp | 21 ++-- saml/saml1/binding/impl/SAML1SOAPDecoder.cpp | 22 ++-- saml/saml2/binding/SAML2MessageDecoder.h | 52 ++++++++ saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp | 17 ++- ...AML2MessageRule.cpp => SAML2MessageDecoder.cpp} | 40 ++---- saml/saml2/binding/impl/SAML2POSTDecoder.cpp | 9 +- saml/saml2/binding/impl/SAML2RedirectDecoder.cpp | 9 +- saml/saml2/binding/impl/SAML2SOAPClient.cpp | 25 ++-- saml/saml2/binding/impl/SAML2SOAPDecoder.cpp | 10 +- samltest/binding.h | 21 +--- samltest/saml1/binding/SAML1ArtifactTest.h | 6 +- samltest/saml1/binding/SAML1POSTTest.h | 4 +- samltest/saml2/binding/SAML2ArtifactTest.h | 6 +- samltest/saml2/binding/SAML2POSTTest.h | 8 +- samltest/saml2/binding/SAML2RedirectTest.h | 4 +- 32 files changed, 388 insertions(+), 328 deletions(-) create mode 100644 saml/saml1/binding/SAML1MessageDecoder.h create mode 100644 saml/saml1/binding/impl/SAML1MessageDecoder.cpp delete mode 100644 saml/saml1/binding/impl/SAML1MessageRule.cpp create mode 100644 saml/saml2/binding/SAML2MessageDecoder.h rename saml/saml2/binding/impl/{SAML2MessageRule.cpp => SAML2MessageDecoder.cpp} (77%) diff --git a/saml/Makefile.am b/saml/Makefile.am index cc42f95..5b934a9 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -64,6 +64,7 @@ saml1coreinclude_HEADERS = \ saml1bindinclude_HEADERS = \ saml1/binding/SAMLArtifactType0001.h \ saml1/binding/SAMLArtifactType0002.h \ + saml1/binding/SAML1MessageDecoder.h \ saml1/binding/SAML1SOAPClient.h saml1profinclude_HEADERS = \ @@ -77,6 +78,7 @@ saml2coreinclude_HEADERS = \ saml2bindinclude_HEADERS = \ saml2/binding/SAML2Artifact.h \ saml2/binding/SAML2ArtifactType0004.h \ + saml2/binding/SAML2MessageDecoder.h \ saml2/binding/SAML2Redirect.h \ saml2/binding/SAML2SOAPClient.h @@ -120,12 +122,12 @@ libsaml_la_SOURCES = \ saml1/binding/impl/SAMLArtifactType0002.cpp \ saml1/binding/impl/SAML1ArtifactDecoder.cpp \ saml1/binding/impl/SAML1ArtifactEncoder.cpp \ + saml1/binding/impl/SAML1MessageDecoder.cpp \ saml1/binding/impl/SAML1POSTDecoder.cpp \ saml1/binding/impl/SAML1POSTEncoder.cpp \ saml1/binding/impl/SAML1SOAPDecoder.cpp \ saml1/binding/impl/SAML1SOAPEncoder.cpp \ saml1/binding/impl/SAML1SOAPClient.cpp \ - saml1/binding/impl/SAML1MessageRule.cpp \ saml1/profile/AssertionValidator.cpp \ saml1/profile/BrowserSSOProfileValidator.cpp \ saml2/core/impl/Assertions.cpp \ @@ -147,6 +149,7 @@ libsaml_la_SOURCES = \ saml2/binding/impl/SAML2ArtifactType0004.cpp \ saml2/binding/impl/SAML2ArtifactDecoder.cpp \ saml2/binding/impl/SAML2ArtifactEncoder.cpp \ + saml2/binding/impl/SAML2MessageDecoder.cpp \ saml2/binding/impl/SAML2POSTDecoder.cpp \ saml2/binding/impl/SAML2POSTEncoder.cpp \ saml2/binding/impl/SAML2Redirect.cpp \ @@ -155,7 +158,6 @@ libsaml_la_SOURCES = \ saml2/binding/impl/SAML2SOAPDecoder.cpp \ saml2/binding/impl/SAML2SOAPEncoder.cpp \ saml2/binding/impl/SAML2SOAPClient.cpp \ - saml2/binding/impl/SAML2MessageRule.cpp \ saml2/profile/Assertion20Validator.cpp \ saml2/profile/BrowserSSOProfile20Validator.cpp \ encryption/EncryptedKeyResolver.cpp \ diff --git a/saml/binding/MessageDecoder.h b/saml/binding/MessageDecoder.h index d3fcc9e..746e8a1 100644 --- a/saml/binding/MessageDecoder.h +++ b/saml/binding/MessageDecoder.h @@ -152,6 +152,21 @@ namespace opensaml { /** Pointer to an ArtifactResolver implementation. */ const ArtifactResolver* m_artifactResolver; + + /** + * Extracts policy-relevant message details. + * + * @param message the incoming message + * @param request the protocol request + * @param protocol the protocol family in use + * @param policy SecurityPolicy to provide various components and track message data + */ + virtual void extractMessageDetails ( + const xmltooling::XMLObject& message, + const xmltooling::GenericRequest& genericRequest, + const XMLCh* protocol, + SecurityPolicy& policy + ) const=0; }; /** diff --git a/saml/binding/SecurityPolicy.h b/saml/binding/SecurityPolicy.h index 5f75c34..5f696a9 100644 --- a/saml/binding/SecurityPolicy.h +++ b/saml/binding/SecurityPolicy.h @@ -75,7 +75,7 @@ namespace opensaml { const xmltooling::QName* role=NULL, const xmltooling::TrustEngine* trustEngine=NULL, bool validate=true - ) : m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), m_secure(false), + ) : m_messageID(NULL), m_issueInstant(0), m_issuer(NULL), m_issuerRole(NULL), m_authenticated(false), m_matchingPolicy(NULL), m_metadata(metadataProvider), m_role(NULL), m_trust(trustEngine), m_validate(validate) { if (role) m_role = new xmltooling::QName(*role); @@ -175,12 +175,11 @@ namespace opensaml { * * @param message the incoming message * @param request the protocol request - * @param protocol the protocol family in use * * @throws BindingException raised if the message/request is invalid according to the supplied rules */ void evaluate( - const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request=NULL, const XMLCh* protocol=NULL + const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request=NULL ); /** @@ -230,12 +229,12 @@ namespace opensaml { } /** - * Returns the security status as determined by the registered policies. + * Returns the authentication status of the message as determined by the registered policies. * * @return true iff a SecurityPolicyRule has indicated the issuer/message has been authenticated */ - bool isSecure() const { - return m_secure; + bool isAuthenticated() const { + return m_authenticated; } /** @@ -279,12 +278,12 @@ namespace opensaml { void setIssuerMetadata(const saml2md::RoleDescriptor* issuerRole); /** - * Sets the security status as determined by the registered policies. + * Sets the authentication status of the message as determined by the registered policies. * - * @param secure indicates whether the issuer/message has been authenticated + * @param auth indicates whether the issuer/message has been authenticated */ - void setSecure(bool secure) { - m_secure = secure; + void setAuthenticated(bool auth) { + m_authenticated = auth; } /** Allows override of rules for comparing saml2:Issuer information. */ @@ -353,7 +352,7 @@ namespace opensaml { time_t m_issueInstant; saml2::Issuer* m_issuer; const saml2md::RoleDescriptor* m_issuerRole; - bool m_secure; + bool m_authenticated; // components governing policy rules IssuerMatchingPolicy* m_matchingPolicy; diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h index 095e115..f8d11e8 100644 --- a/saml/binding/SecurityPolicyRule.h +++ b/saml/binding/SecurityPolicyRule.h @@ -57,13 +57,11 @@ namespace opensaml { * * @param message the incoming message * @param request the protocol request - * @param protocol the protocol family in use * @param policy SecurityPolicy to provide various components and track message data */ virtual void evaluate( const xmltooling::XMLObject& message, const xmltooling::GenericRequest* request, - const XMLCh* protocol, SecurityPolicy& policy ) const=0; }; @@ -74,20 +72,6 @@ namespace opensaml { void SAML_API registerSecurityPolicyRules(); /** - * SecurityPolicyRule for processing SAML 1.x messages. - * - * Extracts message ID, timestamp, and issuer information. - */ - #define SAML1MESSAGE_POLICY_RULE "SAML1Message" - - /** - * SecurityPolicyRule for processing SAML 2.0 messages. - * - * Extracts message ID, timestamp, and issuer information. - */ - #define SAML2MESSAGE_POLICY_RULE "SAML2Message" - - /** * SecurityPolicyRule for TLS client certificate authentication. * * Evaluates client certificates against the issuer's metadata. diff --git a/saml/binding/impl/ClientCertAuthRule.cpp b/saml/binding/impl/ClientCertAuthRule.cpp index f736092..262d2a7 100644 --- a/saml/binding/impl/ClientCertAuthRule.cpp +++ b/saml/binding/impl/ClientCertAuthRule.cpp @@ -47,7 +47,7 @@ namespace opensaml { const char* getType() const { return CLIENTCERTAUTH_POLICY_RULE; } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; + void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; }; SecurityPolicyRule* SAML_DLLLOCAL ClientCertAuthRuleFactory(const DOMElement* const & e) @@ -56,9 +56,7 @@ namespace opensaml { } }; -void ClientCertAuthRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy - ) const +void ClientCertAuthRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth"); @@ -92,5 +90,5 @@ void ClientCertAuthRule::evaluate( } log.debug("client certificate verified against message issuer"); - policy.setSecure(true); + policy.setAuthenticated(true); } diff --git a/saml/binding/impl/MessageFlowRule.cpp b/saml/binding/impl/MessageFlowRule.cpp index a2e1ff6..2d78a4a 100644 --- a/saml/binding/impl/MessageFlowRule.cpp +++ b/saml/binding/impl/MessageFlowRule.cpp @@ -43,7 +43,7 @@ namespace opensaml { const char* getType() const { return MESSAGEFLOW_POLICY_RULE; } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; + void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; private: bool m_checkReplay; @@ -72,9 +72,7 @@ MessageFlowRule::MessageFlowRule(const DOMElement* e) } } -void MessageFlowRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy - ) 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 (replay checking %s, expiration %lu)", m_checkReplay ? "on" : "off", m_expires); diff --git a/saml/binding/impl/NullSecurityRule.cpp b/saml/binding/impl/NullSecurityRule.cpp index 7d984ab..74c3fd6 100644 --- a/saml/binding/impl/NullSecurityRule.cpp +++ b/saml/binding/impl/NullSecurityRule.cpp @@ -40,9 +40,9 @@ namespace opensaml { const char* getType() const { return NULLSECURITY_POLICY_RULE; } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const { + void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { m_log.warn("security enforced using NULL policy rule, be sure you know what you're doing"); - policy.setSecure(true); + policy.setAuthenticated(true); } private: diff --git a/saml/binding/impl/SOAPClient.cpp b/saml/binding/impl/SOAPClient.cpp index 73081ec..e67dbac 100644 --- a/saml/binding/impl/SOAPClient.cpp +++ b/saml/binding/impl/SOAPClient.cpp @@ -51,7 +51,14 @@ void SOAPClient::send(const soap11::Envelope& env, const char* from, MetadataCre else m_policy.setRole(&role); - auto_ptr_char pn(dynamic_cast(m_peer->getParent())->getEntityID()); + // Establish the "expected" issuer identity. + const XMLCh* entityID = dynamic_cast(m_peer->getParent())->getEntityID(); + m_policy.setIssuer(entityID); + if (!m_policy.getIssuerMetadata()) + m_policy.setIssuerMetadata(m_peer); + + // Call the base class. + auto_ptr_char pn(entityID); soap11::SOAPClient::send(env, SOAPTransport::Address(from, pn.get(), endpoint)); } @@ -76,12 +83,12 @@ soap11::Envelope* SOAPClient::receive() { auto_ptr env(soap11::SOAPClient::receive()); if (env.get()) { - if (m_peer && m_transport->isSecure()) { - // Set issuer based on peer identity. - m_policy.setIssuer(dynamic_cast(m_peer->getParent())->getEntityID()); - m_policy.setIssuerMetadata(m_peer); - m_policy.setSecure(true); + if (m_peer && m_transport->isAuthenticated()) { + // Set flag based on peer identity. + m_policy.setAuthenticated(true); } + + // Run policy against SOAP layer. m_policy.evaluate(*(env.get())); } return env.release(); diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp index 343687d..2bae01d 100644 --- a/saml/binding/impl/SecurityPolicy.cpp +++ b/saml/binding/impl/SecurityPolicy.cpp @@ -35,8 +35,6 @@ namespace opensaml { SAML_DLLLOCAL PluginManager::Factory ClientCertAuthRuleFactory; SAML_DLLLOCAL PluginManager::Factory MessageFlowRuleFactory; SAML_DLLLOCAL PluginManager::Factory NullSecurityRuleFactory; - SAML_DLLLOCAL PluginManager::Factory SAML1MessageRuleFactory; - SAML_DLLLOCAL PluginManager::Factory SAML2MessageRuleFactory; SAML_DLLLOCAL PluginManager::Factory SimpleSigningRuleFactory; SAML_DLLLOCAL PluginManager::Factory XMLSigningRuleFactory; }; @@ -47,8 +45,6 @@ void SAML_API opensaml::registerSecurityPolicyRules() conf.SecurityPolicyRuleManager.registerFactory(CLIENTCERTAUTH_POLICY_RULE, ClientCertAuthRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(MESSAGEFLOW_POLICY_RULE, MessageFlowRuleFactory); conf.SecurityPolicyRuleManager.registerFactory(NULLSECURITY_POLICY_RULE, NullSecurityRuleFactory); - 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); } @@ -69,14 +65,14 @@ void SecurityPolicy::reset(bool messageOnly) delete m_issuer; m_issuer=NULL; m_issuerRole=NULL; - m_secure=false; + m_authenticated=false; } } -void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol) +void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request) { for (vector::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) - (*i)->evaluate(message,request,protocol,*this); + (*i)->evaluate(message,request,*this); } void SecurityPolicy::setIssuer(const Issuer* issuer) diff --git a/saml/binding/impl/SimpleSigningRule.cpp b/saml/binding/impl/SimpleSigningRule.cpp index 9255cef..bca976d 100644 --- a/saml/binding/impl/SimpleSigningRule.cpp +++ b/saml/binding/impl/SimpleSigningRule.cpp @@ -52,7 +52,7 @@ namespace opensaml { const char* getType() const { return SIMPLESIGNING_POLICY_RULE; } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; + void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; private: // Appends a raw parameter=value pair to the string. @@ -92,9 +92,7 @@ SimpleSigningRule::SimpleSigningRule(const DOMElement* e) : m_errorsFatal(false) } } -void SimpleSigningRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy - ) const +void SimpleSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SimpleSigning"); @@ -209,5 +207,5 @@ void SimpleSigningRule::evaluate( } log.debug("signature verified against message issuer"); - policy.setSecure(true); + policy.setAuthenticated(true); } diff --git a/saml/binding/impl/XMLSigningRule.cpp b/saml/binding/impl/XMLSigningRule.cpp index 9fe67c1..b76e2b6 100644 --- a/saml/binding/impl/XMLSigningRule.cpp +++ b/saml/binding/impl/XMLSigningRule.cpp @@ -50,7 +50,7 @@ namespace opensaml { const char* getType() const { return XMLSIGNING_POLICY_RULE; } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; + void evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const; private: bool m_errorsFatal; @@ -72,9 +72,7 @@ XMLSigningRule::XMLSigningRule(const DOMElement* e) : m_errorsFatal(false) } } -void XMLSigningRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy - ) const +void XMLSigningRule::evaluate(const XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const { Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.XMLSigning"); @@ -116,5 +114,5 @@ void XMLSigningRule::evaluate( } log.debug("signature verified against message issuer"); - policy.setSecure(true); + policy.setAuthenticated(true); } diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 72a4a19..d37a29e 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -240,7 +240,7 @@ > + + @@ -799,6 +803,10 @@ > + + diff --git a/saml/saml1/binding/SAML1MessageDecoder.h b/saml/saml1/binding/SAML1MessageDecoder.h new file mode 100644 index 0000000..d84338c --- /dev/null +++ b/saml/saml1/binding/SAML1MessageDecoder.h @@ -0,0 +1,52 @@ +/* + * Copyright 2001-2007 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/SAML1MessageDecoder.h + * + * Base class for SAML 1.x MessageDecoders. + */ + +#ifndef __saml1_msgdecoder_h__ +#define __saml1_msgdecoder_h__ + +#include + +namespace opensaml { + + namespace saml1p { + + /** + * Base class for SAML 1.x MessageDecoders. + */ + class SAML_API SAML1MessageDecoder : public MessageDecoder + { + protected: + SAML1MessageDecoder() {} + virtual ~SAML1MessageDecoder() {} + + public: + void extractMessageDetails ( + const xmltooling::XMLObject& message, + const xmltooling::GenericRequest& genericRequest, + const XMLCh* protocol, + SecurityPolicy& policy + ) const; + }; + }; +}; + +#endif /* __saml1_msgdecoder_h__ */ diff --git a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp index aa5c478..87b6f8c 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp @@ -22,8 +22,8 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" #include "binding/SAMLArtifact.h" +#include "saml1/binding/SAML1MessageDecoder.h" #include "saml1/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" @@ -42,7 +42,7 @@ using namespace std; namespace opensaml { namespace saml1p { - class SAML_DLLLOCAL SAML1ArtifactDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML1ArtifactDecoder : public SAML1MessageDecoder { public: SAML1ArtifactDecoder() {} @@ -134,12 +134,6 @@ XMLObject* SAML1ArtifactDecoder::decode( 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); if (!roledesc) @@ -149,6 +143,8 @@ XMLObject* SAML1ArtifactDecoder::decode( for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup()); throw BindingException("Unable to find compatible metadata role for artifact issuer."); } + // Set Issuer for the policy. + policy.setIssuer(provider->getEntityID()); policy.setIssuerMetadata(roledesc); try { diff --git a/saml/saml1/binding/impl/SAML1MessageDecoder.cpp b/saml/saml1/binding/impl/SAML1MessageDecoder.cpp new file mode 100644 index 0000000..7a59796 --- /dev/null +++ b/saml/saml1/binding/impl/SAML1MessageDecoder.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2001-2007 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. + */ + +/** + * SAML1MessageDecoder.cpp + * + * Base class for SAML 1.x MessageDecoders. + */ + +#include "internal.h" +#include "exceptions.h" +#include "saml1/binding/SAML1MessageDecoder.h" +#include "saml1/core/Assertions.h" +#include "saml1/core/Protocols.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" + +#include + +using namespace opensaml::saml2md; +using namespace opensaml::saml1p; +using namespace opensaml::saml1; +using namespace opensaml; +using namespace xmltooling::logging; +using namespace xmltooling; +using namespace std; + +void SAML1MessageDecoder::extractMessageDetails( + const XMLObject& message, const GenericRequest& req, const XMLCh* protocol, SecurityPolicy& policy + ) const +{ + // Only handle SAML 1.x protocol messages. + const QName& q = message.getElementQName(); + if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1P_NS)) + return; + + Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1"); + + const Request* request=NULL; + const Response* response=NULL; + if (XMLString::equals(q.getLocalPart(), Request::LOCAL_NAME)) + request = dynamic_cast(&message); + if (!request && XMLString::equals(q.getLocalPart(), Response::LOCAL_NAME)) + response = dynamic_cast(&message); + + if (!request && !response) { + log.warn("decoder cannot extract details from non-SAML 1.x protocol message"); + return; + } + + const RootObject* root = request ? static_cast(request) : static_cast(response); + + // Extract message details. + policy.setMessageID(root->getID()); + policy.setIssueInstant(root->getIssueInstantEpoch()); + + if (request) { + log.warn("issuer identity not extracted, only responses with assertions carry issuer information in standard SAML 1.x"); + return; + } + + log.debug("extracting issuer from SAML 1.x Response"); + const vector& assertions = response->getAssertions(); + if (assertions.empty()) { + log.warn("issuer identity not extracted from response (no assertions were present)"); + return; + } + + const XMLCh* issuer = assertions.front()->getIssuer(); + policy.setIssuer(issuer); + if (log.isDebugEnabled()) { + auto_ptr_char iname(issuer); + log.debug("response from (%s)", iname.get()); + } + + if (policy.getIssuerMetadata()) { + log.debug("metadata for issuer already set, leaving in place"); + return; + } + + if (policy.getMetadataProvider() && policy.getRole()) { + log.debug("searching metadata for response issuer..."); + const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(issuer); + if (entity) { + log.debug("matched response issuer against metadata, searching for applicable role..."); + const RoleDescriptor* roledesc=entity->getRoleDescriptor(*policy.getRole(), protocol); + if (roledesc) + policy.setIssuerMetadata(roledesc); + else if (log.isWarnEnabled()) + log.warn("unable to find compatible role (%s) in metadata", policy.getRole()->toString().c_str()); + } + else if (log.isWarnEnabled()) { + auto_ptr_char iname(issuer); + log.warn("no metadata found, can't establish identity of issuer (%s)", iname.get()); + } + } +} diff --git a/saml/saml1/binding/impl/SAML1MessageRule.cpp b/saml/saml1/binding/impl/SAML1MessageRule.cpp deleted file mode 100644 index 309f175..0000000 --- a/saml/saml1/binding/impl/SAML1MessageRule.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2001-2007 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 "binding/SecurityPolicyRule.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::logging; -using namespace xmltooling; -using namespace std; - -namespace opensaml { - - class SAML_DLLLOCAL SAML1MessageRule : public SecurityPolicyRule - { - public: - SAML1MessageRule(const DOMElement* e) {} - virtual ~SAML1MessageRule() {} - - const char* getType() const { - return SAML1MESSAGE_POLICY_RULE; - } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; - }; - - SecurityPolicyRule* SAML_DLLLOCAL SAML1MessageRuleFactory(const DOMElement* const & e) - { - return new SAML1MessageRule(e); - } -}; - -void SAML1MessageRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy - ) const -{ - // Only handle SAML 1.x messages. - const QName& q = message.getElementQName(); - if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1P_NS) && - !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1_NS)) - return; - - Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML1Message"); - - try { - const RootObject& samlRoot = dynamic_cast(message); - policy.setMessageID(samlRoot.getID()); - policy.setIssueInstant(samlRoot.getIssueInstantEpoch()); - - log.debug("extracting issuer from message"); - - const saml1::Assertion* a = NULL; - - // Handle assertions directly. - if (XMLString::equals(q.getLocalPart(), saml1::Assertion::LOCAL_NAME)) - a = dynamic_cast(&samlRoot); - - // Only samlp:Response is known to carry issuer (via payload) in standard SAML 1.x. - if (!a && XMLString::equals(q.getLocalPart(), Response::LOCAL_NAME)) { - // Should be a samlp:Response. - const vector& assertions = dynamic_cast(samlRoot).getAssertions(); - if (!assertions.empty()) - a = assertions.front(); - } - - if (a) { - policy.setIssuer(a->getIssuer()); - } - else { - log.warn("issuer identity not extracted"); - return; - } - - if (log.isDebugEnabled()) { - auto_ptr_char iname(a->getIssuer()); - log.debug("message from (%s)", iname.get()); - } - - if (policy.getIssuerMetadata()) { - log.debug("metadata for issuer already set, leaving in place"); - return; - } - - if (policy.getMetadataProvider() && policy.getRole()) { - log.debug("searching metadata for message issuer..."); - const EntityDescriptor* entity = policy.getMetadataProvider()->getEntityDescriptor(a->getIssuer()); - if (!entity) { - auto_ptr_char temp(a->getIssuer()); - 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 a454a6f..92a28b7 100644 --- a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" +#include "saml1/binding/SAML1MessageDecoder.h" #include "saml1/core/Assertions.h" #include "saml1/core/Protocols.h" #include "saml2/metadata/Metadata.h" @@ -44,7 +44,7 @@ using namespace std; namespace opensaml { namespace saml1p { - class SAML_DLLLOCAL SAML1POSTDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML1POSTDecoder : public SAML1MessageDecoder { public: SAML1POSTDecoder() {} @@ -108,15 +108,18 @@ XMLObject* SAML1POSTDecoder::decode( throw BindingException("Decoded message was not a SAML 1.x Response."); if (!policy.getValidating()) - SchemaValidators.validate(xmlObject.get()); - - // Run through the policy. + SchemaValidators.validate(response); + pair minor = response->getMinorVersion(); - policy.evaluate( + extractMessageDetails( *response, - &genericRequest, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + genericRequest, + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM, + policy ); + + // Run through the policy. + policy.evaluate(*response,&genericRequest); // Check recipient URL. auto_ptr_char recipient(response->getRecipient()); diff --git a/saml/saml1/binding/impl/SAML1SOAPClient.cpp b/saml/saml1/binding/impl/SAML1SOAPClient.cpp index 9a6527b..7f8b319 100644 --- a/saml/saml1/binding/impl/SAML1SOAPClient.cpp +++ b/saml/saml1/binding/impl/SAML1SOAPClient.cpp @@ -62,20 +62,13 @@ Response* SAML1SOAPClient::receiveSAML() throw SecurityPolicyException("InResponseTo attribute did not correlate with the Request ID."); m_soaper.getPolicy().reset(true); - pair minor = response->getMinorVersion(); - m_soaper.getPolicy().evaluate( - *response, - NULL, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM - ); - - if (!m_soaper.getPolicy().isSecure()) { - SecurityPolicyException ex("Security policy could not authenticate the message."); - if (m_soaper.getPolicy().getIssuerMetadata()) - annotateException(&ex, m_soaper.getPolicy().getIssuerMetadata()); // throws it - else - ex.raise(); - } + + // Extract Response details and run policy against it. + // We don't pull Issuer out of any assertions because some profiles may permit + // alternate issuers at that layer. + m_soaper.getPolicy().setMessageID(response->getResponseID()); + m_soaper.getPolicy().setIssueInstant(response->getIssueInstantEpoch()); + m_soaper.getPolicy().evaluate(*response); // Check Status. Status* status = response->getStatus(); diff --git a/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp b/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp index 4d88e7d..971d700 100644 --- a/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" +#include "saml1/binding/SAML1MessageDecoder.h" #include "saml1/core/Protocols.h" #include @@ -39,7 +39,7 @@ using namespace std; namespace opensaml { namespace saml1p { - class SAML_DLLLOCAL SAML1SOAPDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML1SOAPDecoder : public SAML1MessageDecoder { public: SAML1SOAPDecoder() {} @@ -106,17 +106,23 @@ XMLObject* SAML1SOAPDecoder::decode( if (request) { // Run through the policy at two layers. pair minor = request->getMinorVersion(); - policy.evaluate( + extractMessageDetails( *env, - &genericRequest, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + genericRequest, + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM, + policy ); + policy.evaluate(*env,&genericRequest); + + // Reset, extract, and run again. policy.reset(true); - policy.evaluate( + extractMessageDetails( *request, - &genericRequest, - (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM + genericRequest, + (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM, + policy ); + policy.evaluate(*request,&genericRequest); xmlObject.release(); body->detach(); // frees Envelope request->detach(); // frees Body diff --git a/saml/saml2/binding/SAML2MessageDecoder.h b/saml/saml2/binding/SAML2MessageDecoder.h new file mode 100644 index 0000000..a81cfcb --- /dev/null +++ b/saml/saml2/binding/SAML2MessageDecoder.h @@ -0,0 +1,52 @@ +/* + * Copyright 2001-2007 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/SAML2MessageDecoder.h + * + * Base class for SAML 2.0 MessageDecoders. + */ + +#ifndef __saml2_msgdecoder_h__ +#define __saml2_msgdecoder_h__ + +#include + +namespace opensaml { + + namespace saml2p { + + /** + * Base class for SAML 2.0 MessageDecoders. + */ + class SAML_API SAML2MessageDecoder : public MessageDecoder + { + protected: + SAML2MessageDecoder() {} + virtual ~SAML2MessageDecoder() {} + + public: + void extractMessageDetails ( + const xmltooling::XMLObject& message, + const xmltooling::GenericRequest& genericRequest, + const XMLCh* protocol, + SecurityPolicy& policy + ) const; + }; + }; +}; + +#endif /* __saml2_msgdecoder_h__ */ diff --git a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp index ae7545a..1bb7af2 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp @@ -22,8 +22,8 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" #include "saml2/binding/SAML2Artifact.h" +#include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" @@ -43,7 +43,7 @@ using namespace std; namespace opensaml { namespace saml2p { - class SAML_DLLLOCAL SAML2ArtifactDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML2ArtifactDecoder : public SAML2MessageDecoder { public: SAML2ArtifactDecoder() {} @@ -133,18 +133,14 @@ XMLObject* SAML2ArtifactDecoder::decode( 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()); throw BindingException("Unable to find compatible metadata role for artifact issuer."); } + // Set issuer into policy. + policy.setIssuer(provider->getEntityID()); policy.setIssuerMetadata(roledesc); log.debug("calling ArtifactResolver..."); @@ -156,9 +152,10 @@ XMLObject* SAML2ArtifactDecoder::decode( // Reset only the message state. policy.reset(true); - // Extract payload and check that message. + // Now extract details from the payload and check that message. XMLObject* payload = response->getPayload(); - policy.evaluate(*payload, &genericRequest, samlconstants::SAML20P_NS); + extractMessageDetails(*payload, genericRequest, samlconstants::SAML20P_NS, policy); + policy.evaluate(*payload, &genericRequest); // Return the payload only. response.release(); diff --git a/saml/saml2/binding/impl/SAML2MessageRule.cpp b/saml/saml2/binding/impl/SAML2MessageDecoder.cpp similarity index 77% rename from saml/saml2/binding/impl/SAML2MessageRule.cpp rename to saml/saml2/binding/impl/SAML2MessageDecoder.cpp index 39dca01..d9d21fd 100644 --- a/saml/saml2/binding/impl/SAML2MessageRule.cpp +++ b/saml/saml2/binding/impl/SAML2MessageDecoder.cpp @@ -15,14 +15,14 @@ */ /** - * SAML2MessageRule.cpp + * SAML2MessageDecoder.cpp * - * SAML 2.0 message extraction rule + * Base class for SAML 2.0 MessageDecoders. */ #include "internal.h" #include "exceptions.h" -#include "binding/SecurityPolicyRule.h" +#include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" @@ -38,43 +38,23 @@ using namespace xmltooling::logging; using namespace xmltooling; using namespace std; -namespace opensaml { - class SAML_DLLLOCAL SAML2MessageRule : public SecurityPolicyRule - { - public: - SAML2MessageRule(const DOMElement* e) {} - virtual ~SAML2MessageRule() {} - - const char* getType() const { - return SAML2MESSAGE_POLICY_RULE; - } - void evaluate(const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy) const; - }; - - SecurityPolicyRule* SAML_DLLLOCAL SAML2MessageRuleFactory(const DOMElement* const & e) - { - return new SAML2MessageRule(e); - } -}; - -void SAML2MessageRule::evaluate( - const XMLObject& message, const GenericRequest* request, const XMLCh* protocol, SecurityPolicy& policy +void SAML2MessageDecoder::extractMessageDetails( + const XMLObject& message, const GenericRequest& request, const XMLCh* protocol, SecurityPolicy& policy ) const { // Only handle SAML 2.0 messages. const QName& q = message.getElementQName(); - if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20P_NS)&& - !XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20_NS)) + if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML20P_NS)) return; - Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.SAML2Message"); - + Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2"); + try { const saml2::RootObject& samlRoot = dynamic_cast(message); policy.setMessageID(samlRoot.getID()); policy.setIssueInstant(samlRoot.getIssueInstantEpoch()); - log.debug("extracting issuer from message"); + log.debug("extracting issuer from SAML 2.0 protocol message"); const Issuer* issuer = samlRoot.getIssuer(); if (issuer) { policy.setIssuer(issuer); @@ -129,6 +109,6 @@ void SAML2MessageRule::evaluate( } catch (bad_cast&) { // Just trap it. - log.warn("caught a bad_cast while examining message"); + log.warn("caught a bad_cast while extracting message details"); } } diff --git a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp index 8595e7e..5438199 100644 --- a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" +#include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" @@ -43,7 +43,7 @@ using namespace std; namespace opensaml { namespace saml2p { - class SAML_DLLLOCAL SAML2POSTDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML2POSTDecoder : public SAML2MessageDecoder { public: SAML2POSTDecoder() {} @@ -121,10 +121,11 @@ XMLObject* SAML2POSTDecoder::decode( } if (!policy.getValidating()) - SchemaValidators.validate(xmlObject.get()); + SchemaValidators.validate(root); // Run through the policy. - policy.evaluate(*root, &genericRequest, samlconstants::SAML20P_NS); + extractMessageDetails(*root, genericRequest, samlconstants::SAML20P_NS, policy); + policy.evaluate(*root, &genericRequest); // Check destination URL. auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); diff --git a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp index a5e599d..b43589c 100644 --- a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" +#include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/binding/SAML2Redirect.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" @@ -45,7 +45,7 @@ using namespace std; namespace opensaml { namespace saml2p { - class SAML_DLLLOCAL SAML2RedirectDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML2RedirectDecoder : public SAML2MessageDecoder { public: SAML2RedirectDecoder() {} @@ -135,10 +135,11 @@ XMLObject* SAML2RedirectDecoder::decode( } if (!policy.getValidating()) - SchemaValidators.validate(xmlObject.get()); + SchemaValidators.validate(root); // Run through the policy. - policy.evaluate(*root, &genericRequest, samlconstants::SAML20P_NS); + extractMessageDetails(*root, genericRequest, samlconstants::SAML20P_NS, policy); + policy.evaluate(*root, &genericRequest); // Check destination URL. auto_ptr_char dest(request ? request->getDestination() : response->getDestination()); diff --git a/saml/saml2/binding/impl/SAML2SOAPClient.cpp b/saml/saml2/binding/impl/SAML2SOAPClient.cpp index 626b607..7c94c5d 100644 --- a/saml/saml2/binding/impl/SAML2SOAPClient.cpp +++ b/saml/saml2/binding/impl/SAML2SOAPClient.cpp @@ -25,10 +25,12 @@ #include "saml2/binding/SAML2SOAPClient.h" #include "saml2/core/Protocols.h" #include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" #include #include +using namespace opensaml::saml2; using namespace opensaml::saml2p; using namespace opensaml::saml2md; using namespace opensaml; @@ -56,17 +58,24 @@ StatusResponseType* SAML2SOAPClient::receiveSAML() // Check for SAML Response. StatusResponseType* response = dynamic_cast(body->getUnknownXMLObjects().front()); if (response) { - // Check InResponseTo. if (m_correlate && response->getInResponseTo() && !XMLString::equals(m_correlate, response->getInResponseTo())) throw SecurityPolicyException("InResponseTo attribute did not correlate with the Request ID."); - m_soaper.getPolicy().reset(true); - m_soaper.getPolicy().evaluate(*response, NULL, samlconstants::SAML20P_NS); - if (!m_soaper.getPolicy().isSecure()) { - SecurityPolicyException ex("Security policy could not authenticate the message."); - annotateException(&ex, m_soaper.getPolicy().getIssuerMetadata(), response->getStatus()); // throws it - } + SecurityPolicy& policy = m_soaper.getPolicy(); + policy.reset(true); + + // Extract Response details. + policy.setMessageID(response->getID()); + policy.setIssueInstant(response->getIssueInstantEpoch()); + + // Extract and re-verify Issuer if present. + const Issuer* issuer = response->getIssuer(); + if (issuer) + policy.setIssuer(issuer); // This will throw if it conflicts with the known peer identity. + + // Now run the policy. + policy.evaluate(*response); // Check Status. Status* status = response->getStatus(); @@ -74,7 +83,7 @@ StatusResponseType* SAML2SOAPClient::receiveSAML() const XMLCh* code = status->getStatusCode() ? status->getStatusCode()->getValue() : NULL; if (code && !XMLString::equals(code,StatusCode::SUCCESS) && handleError(*status)) { BindingException ex("SAML response contained an error."); - annotateException(&ex, m_soaper.getPolicy().getIssuerMetadata(), status); // throws it + annotateException(&ex, policy.getIssuerMetadata(), status); // throws it } } diff --git a/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp b/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp index 8879499..8325d33 100644 --- a/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "exceptions.h" -#include "binding/MessageDecoder.h" +#include "saml2/binding/SAML2MessageDecoder.h" #include "saml2/core/Protocols.h" #include @@ -39,7 +39,7 @@ using namespace std; namespace opensaml { namespace saml2p { - class SAML_DLLLOCAL SAML2SOAPDecoder : public MessageDecoder + class SAML_DLLLOCAL SAML2SOAPDecoder : public SAML2MessageDecoder { public: SAML2SOAPDecoder() {} @@ -105,9 +105,11 @@ XMLObject* SAML2SOAPDecoder::decode( RequestAbstractType* request = dynamic_cast(body->getUnknownXMLObjects().front()); if (request) { // Run through the policy at two layers. - policy.evaluate(*env, &genericRequest, samlconstants::SAML20P_NS); + extractMessageDetails(*env, genericRequest, samlconstants::SAML20P_NS, policy); + policy.evaluate(*env, &genericRequest); policy.reset(true); - policy.evaluate(*request, &genericRequest, samlconstants::SAML20P_NS); + extractMessageDetails(*request, genericRequest, samlconstants::SAML20P_NS, policy); + policy.evaluate(*request, &genericRequest); xmlObject.release(); body->detach(); // frees Envelope request->detach(); // frees Body diff --git a/samltest/binding.h b/samltest/binding.h index cdaa3bc..3564bb1 100644 --- a/samltest/binding.h +++ b/samltest/binding.h @@ -41,8 +41,7 @@ protected: map m_headers; string m_method,m_url,m_query; vector m_clientCerts; - vector m_rules1; - vector m_rules2; + vector m_rules; public: void setUp() { @@ -81,15 +80,9 @@ public: m_trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE, 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)); + 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)); } catch (XMLToolingException& ex) { TS_TRACE(ex.what()); @@ -100,10 +93,8 @@ public: } void tearDown() { - 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(); + for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup()); + m_rules.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 5f2dfca..ae593b1 100644 --- a/samltest/saml1/binding/SAML1ArtifactTest.h +++ b/samltest/saml1/binding/SAML1ArtifactTest.h @@ -40,7 +40,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules1.begin(), m_rules1.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml1/binding/SAML1Assertion.xml"; @@ -83,7 +83,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); @@ -132,7 +132,7 @@ public: TSM_ASSERT("Retrieved credential was null", cred!=NULL); response->marshall((DOMDocument*)NULL,&sigs,cred); SchemaValidators.validate(response.get()); - policy.evaluate(*(response.get()), this, samlconstants::SAML11_PROTOCOL_ENUM); + policy.evaluate(*(response.get()), this); return response.release(); } diff --git a/samltest/saml1/binding/SAML1POSTTest.h b/samltest/saml1/binding/SAML1POSTTest.h index 9750b3d..2621fa2 100644 --- a/samltest/saml1/binding/SAML1POSTTest.h +++ b/samltest/saml1/binding/SAML1POSTTest.h @@ -35,7 +35,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules1.begin(), m_rules1.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml1/binding/SAML1Response.xml"; @@ -90,7 +90,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); diff --git a/samltest/saml2/binding/SAML2ArtifactTest.h b/samltest/saml2/binding/SAML2ArtifactTest.h index 329af90..46c33b0 100644 --- a/samltest/saml2/binding/SAML2ArtifactTest.h +++ b/samltest/saml2/binding/SAML2ArtifactTest.h @@ -39,7 +39,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules2.begin(), m_rules2.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -85,7 +85,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); @@ -135,7 +135,7 @@ public: sc->setValue(StatusCode::SUCCESS); response->marshall(); SchemaValidators.validate(response.get()); - policy.evaluate(*(response.get()), this, samlconstants::SAML20P_NS); + policy.evaluate(*(response.get()), this); return response.release(); } }; diff --git a/samltest/saml2/binding/SAML2POSTTest.h b/samltest/saml2/binding/SAML2POSTTest.h index bbdd504..1b4a05f 100644 --- a/samltest/saml2/binding/SAML2POSTTest.h +++ b/samltest/saml2/binding/SAML2POSTTest.h @@ -35,7 +35,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules2.begin(), m_rules2.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -89,7 +89,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); @@ -108,7 +108,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules2.begin(), m_rules2.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -162,7 +162,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); diff --git a/samltest/saml2/binding/SAML2RedirectTest.h b/samltest/saml2/binding/SAML2RedirectTest.h index 80dce5f..8a78a0e 100644 --- a/samltest/saml2/binding/SAML2RedirectTest.h +++ b/samltest/saml2/binding/SAML2RedirectTest.h @@ -35,7 +35,7 @@ public: try { QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME); SecurityPolicy policy(m_metadata, &idprole, m_trust, false); - policy.getRules().assign(m_rules2.begin(), m_rules2.end()); + policy.getRules().assign(m_rules.begin(), m_rules.end()); // Read message to use from file. string path = data_path + "saml2/binding/SAML2Response.xml"; @@ -81,7 +81,7 @@ public: // Test the results. TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state"); TSM_ASSERT("SAML Response not decoded successfully.", response.get()); - TSM_ASSERT("Message was not verified.", policy.isSecure()); + TSM_ASSERT("Message was not verified.", policy.isAuthenticated()); auto_ptr_char entityID(policy.getIssuer()->getName()); TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/")); TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1); -- 2.1.4