Policy rule redesign for factor out issuer handling.
authorScott Cantor <cantor.2@osu.edu>
Tue, 12 Dec 2006 02:02:09 +0000 (02:02 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 12 Dec 2006 02:02:09 +0000 (02:02 +0000)
30 files changed:
saml/Makefile.am
saml/SAMLConfig.cpp
saml/binding/ClientCertAuthRule.h
saml/binding/MessageFlowRule.h
saml/binding/SecurityPolicy.h
saml/binding/SecurityPolicyRule.h
saml/binding/SimpleSigningRule.h
saml/binding/XMLSigningRule.h
saml/binding/impl/ClientCertAuthRule.cpp
saml/binding/impl/MessageFlowRule.cpp
saml/binding/impl/SecurityPolicy.cpp
saml/binding/impl/SimpleSigningRule.cpp
saml/binding/impl/XMLSigningRule.cpp
saml/saml.vcproj
saml/saml1/binding/SAML1MessageRule.h [new file with mode: 0644]
saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp
saml/saml1/binding/impl/SAML1MessageRule.cpp [new file with mode: 0644]
saml/saml1/binding/impl/SAML1POSTDecoder.cpp
saml/saml2/binding/SAML2MessageRule.h [new file with mode: 0644]
saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp
saml/saml2/binding/impl/SAML2MessageRule.cpp [new file with mode: 0644]
saml/saml2/binding/impl/SAML2POSTDecoder.cpp
saml/saml2/binding/impl/SAML2RedirectDecoder.cpp
saml/util/SAMLConstants.h
samltest/binding.h
samltest/saml1/binding/SAML1ArtifactTest.h
samltest/saml1/binding/SAML1POSTTest.h
samltest/saml2/binding/SAML2ArtifactTest.h
samltest/saml2/binding/SAML2POSTTest.h
samltest/saml2/binding/SAML2RedirectTest.h

index ccb114f..8dcd88e 100644 (file)
@@ -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 \
index cfecf0c..48a8175 100644 (file)
@@ -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"
index edd9b99..737e52b 100644 (file)
@@ -33,26 +33,6 @@ namespace opensaml {
         ClientCertAuthRule(const DOMElement* e) {}
         virtual ~ClientCertAuthRule() {}
         
-        std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> 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. 
-         * 
-         * <p>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<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
+        void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
     };
 };
index 885b82a..accd60c 100644 (file)
@@ -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<saml2::Issuer*,const saml2md::RoleDescriptor*> 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;
index 96fdffe..a9ab6e0 100644 (file)
 #ifndef __saml_secpol_h__
 #define __saml_secpol_h__
 
-#include <saml/binding/SecurityPolicyRule.h>
+#include <saml/binding/GenericRequest.h>
+
+#include <ctime>
 #include <vector>
+#include <xmltooling/XMLObject.h>
+#include <xmltooling/security/TrustEngine.h>
 
 #if defined (_MSC_VER)
     #pragma warning( push )
 
 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<const SecurityPolicyRule*> m_rules;
         const saml2md::MetadataProvider* m_metadata;
-        xmltooling::QName m_role;
+        xmltooling::QName* m_role;
         const xmltooling::TrustEngine* m_trust;
     };
 
index ed31d7c..f15d263 100644 (file)
 #ifndef __saml_secrule_h__
 #define __saml_secrule_h__
 
-#include <saml/binding/GenericRequest.h>
-#include <xmltooling/XMLObject.h>
-#include <xmltooling/security/TrustEngine.h>
+#include <saml/binding/SecurityPolicy.h>
 
 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<saml2::Issuer*,const saml2md::RoleDescriptor*> 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"
 
index bceac07..ac82b33 100644 (file)
@@ -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<saml2::Issuer*,const saml2md::RoleDescriptor*> 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. 
-         * 
-         * <p>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<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
+        void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
     };
     
 };
index d2c3580..0469914 100644 (file)
@@ -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<saml2::Issuer*,const saml2md::RoleDescriptor*> 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. 
-         * 
-         * <p>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<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
+        void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request, SecurityPolicy& policy) const;
     };
     
 };
index f13e25e..6337b19 100644 (file)
@@ -27,7 +27,6 @@
 #include "saml2/metadata/MetadataProvider.h"
 
 #include <xmltooling/security/X509TrustEngine.h>
-#include <xmltooling/util/NDC.h>
 #include <xmltooling/util/ReplayCache.h>
 #include <log4cpp/Category.hh>
 
@@ -44,95 +43,37 @@ namespace opensaml {
     }
 };
 
-pair<saml2::Issuer*,const RoleDescriptor*> 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<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(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<const X509TrustEngine*>(trustEngine))) {
-        log.debug("ignoring message, no metadata or X509TrustEngine supplied");
-        return ret;
+    if (!(x509trust=dynamic_cast<const X509TrustEngine*>(policy.getTrustEngine()))) {
+        log.debug("ignoring message, no X509TrustEngine supplied");
+        return;
     }
     
     const std::vector<XSECCryptoX509*>& 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<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
-        
-        auto_ptr<saml2::Issuer> 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<saml2::Issuer*,const XMLCh*> 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<const saml2::RootObject&>(message);
-            saml2::Issuer* issuer = root.getIssuer();
-            if (issuer && issuer->getName())
-                return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
-        }
-    }
-    return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+    
+    log.debug("client certificate verified against message issuer");
 }
index f7412c2..ce04682 100644 (file)
 
 #include "internal.h"
 #include "exceptions.h"
-#include "RootObject.h"
 #include "binding/MessageFlowRule.h"
-#include "util/SAMLConstants.h"
 
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReplayCache.h>
 #include <log4cpp/Category.hh>
+#include <xmltooling/util/ReplayCache.h>
+#include <xercesc/util/XMLUniDefs.hpp>
 
 using namespace opensaml;
 using namespace xmltooling;
@@ -58,37 +56,16 @@ MessageFlowRule::MessageFlowRule(const DOMElement* e)
     }
 }
 
-pair<saml2::Issuer*,const saml2md::RoleDescriptor*> 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<const RootObject&>(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<saml2::Issuer*,const saml2md::RoleDescriptor*>(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()));
index 350057e..4091df7 100644 (file)
 
 #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<SecurityPolicyRule,const DOMElement*>::Factory ClientCertAuthRuleFactory;
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory MessageFlowRuleFactory;
+    SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory SAML1MessageRuleFactory;
+    SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory SAML2MessageRuleFactory;
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory SimpleSigningRuleFactory;
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::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 SecurityPolicyRule*>::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) {
-
-        // Run the rule...
-        pair<Issuer*,const RoleDescriptor*> 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 SecurityPolicyRule*>::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;
 }
 
index 7f1ea7f..394802b 100644 (file)
 #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 <log4cpp/Category.hh>
-#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReplayCache.h>
-#include <xsec/enc/XSECCryptoException.hpp>
-#include <xsec/enc/XSECCryptoProvider.hpp>
-#include <xsec/framework/XSECException.hpp>
 
 using namespace opensaml::saml2md;
 using namespace opensaml;
@@ -67,159 +62,94 @@ namespace opensaml {
 };
 
 
-pair<saml2::Issuer*,const RoleDescriptor*> 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<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(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<const HTTPRequest*>(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<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
-        
-        auto_ptr<saml2::Issuer> 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<DOMDocument> janitor(doc);
-                XMLObject* kxml = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true);
-                janitor.release();
-                if (!(keyInfo=dynamic_cast<KeyInfo*>(kxml)))
-                    delete kxml;
-            }
-            catch (XMLToolingException& ex) {
-                log.warn("Failed to load KeyInfo from message: %s", ex.what());
-            }
-        }
-        
-        auto_ptr<KeyInfo> 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<DOMDocument> janitor(doc);
+            XMLObject* kxml = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true);
+            janitor.release();
+            if (!(keyInfo=dynamic_cast<KeyInfo*>(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<KeyInfo> 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<saml2::Issuer*,const XMLCh*> 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<const saml2::RootObject&>(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<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
-            if (!assertions.empty()) {
-                issuer = assertions.front()->getIssuer();
-                if (issuer && issuer->getName())
-                    return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
-            }
-        }
-    }
-    return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+    log.debug("signature verified against message issuer");
 }
index 56c2250..029f14c 100644 (file)
 #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 <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReplayCache.h>
 #include <log4cpp/Category.hh>
 
 using namespace opensaml::saml2md;
@@ -47,128 +43,42 @@ namespace opensaml {
     }
 };
 
-pair<saml2::Issuer*,const RoleDescriptor*> 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<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(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<const SignableObject*>(&message);
+    if (!signable || !signable->getSignature()) {
+        log.debug("ignoring unsigned or unrecognized message");
+        return;
     }
     
+    log.debug("validating signature profile");
     try {
-        const SignableObject* signable = dynamic_cast<const SignableObject*>(&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<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
-        
-        auto_ptr<saml2::Issuer> 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<saml2::Issuer*,const XMLCh*> 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<const saml2::RootObject&>(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<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(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<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(message).getAssertions();
-            if (!assertions.empty()) {
-                const saml1::Assertion* a = assertions.front();
-                if (a->getIssuer()) {
-                    issuer = saml2::IssuerBuilder::buildIssuer();
-                    issuer->setName(a->getIssuer());
-                    pair<bool,int> 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<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+
+    log.debug("signature verified against message issuer");
 }
index b7d12cb..2d13c5a 100644 (file)
                                                        >\r
                                                </File>\r
                                                <File\r
+                                                       RelativePath=".\saml1\binding\impl\SAML1MessageRule.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml1\binding\impl\SAML1POSTDecoder.cpp"\r
                                                        >\r
                                                </File>\r
                                                        </FileConfiguration>\r
                                                </File>\r
                                                <File\r
+                                                       RelativePath=".\saml2\binding\impl\SAML2MessageRule.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml2\binding\impl\SAML2POSTDecoder.cpp"\r
                                                        >\r
                                                </File>\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1MessageRule.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml1\binding\SAML1POSTDecoder.h"\r
                                                >\r
                                        </File>\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\saml2\binding\SAML2MessageRule.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml2\binding\SAML2POSTDecoder.h"\r
                                                >\r
                                        </File>\r
diff --git a/saml/saml1/binding/SAML1MessageRule.h b/saml/saml1/binding/SAML1MessageRule.h
new file mode 100644 (file)
index 0000000..0027921
--- /dev/null
@@ -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 <saml/binding/SecurityPolicyRule.h>
+
+
+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;
+        };
+    };
+};
index bc0f0e6..23a9505 100644 (file)
@@ -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<saml2::Issuer> 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<const IDPSSODescriptor*>(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<SAMLArtifact>());
-        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> response(
@@ -145,9 +151,8 @@ XMLObject* SAML1ArtifactDecoder::decode(
         for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
         return response.release();
     }
-    catch (XMLToolingException& ex) {
+    catch (XMLToolingException&) {
         for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
-        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 (file)
index 0000000..3d70d87
--- /dev/null
@@ -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 <log4cpp/Category.hh>
+
+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<const RootObject&>(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<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(samlRoot).getAssertions();
+            if (!assertions.empty()) {
+                const saml1::Assertion* a = assertions.front();
+                if (a->getIssuer()) {
+                    auto_ptr<saml2::Issuer> issuer(saml2::IssuerBuilder::buildIssuer());
+                    issuer->setName(a->getIssuer());
+                    policy.setIssuer(issuer.get());
+                    issuer.release();   // owned by policy now
+                    pair<bool,int> 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");
+    }
+}
index fd3258a..1c7e539 100644 (file)
@@ -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<Assertion*>& assertions=const_cast<const Response*>(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<bool,int> 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 (file)
index 0000000..20e785e
--- /dev/null
@@ -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 <saml/binding/SecurityPolicyRule.h>
+
+
+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;
+        };
+    };
+};
index c309162..db3e4b7 100644 (file)
@@ -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> 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<const SSODescriptorType*>(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<ArtifactResponse> response(
-            m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*roledesc), policy)
-            );
-        
-        policy.evaluate(*(response.get()), &genericRequest);
+    auto_ptr<ArtifactResponse> response(
+        m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*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 (file)
index 0000000..fe604c2
--- /dev/null
@@ -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 <log4cpp/Category.hh>
+
+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<const opensaml::RootObject&>(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<const saml2::RootObject&>(samlRoot);
+        Issuer* issuer = saml2Root.getIssuer();
+        if (issuer && issuer->getName()) {
+            auto_ptr<Issuer> 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<Assertion*>& assertions = dynamic_cast<const Response&>(saml2Root).getAssertions();
+            if (!assertions.empty()) {
+                issuer = assertions.front()->getIssuer();
+                if (issuer && issuer->getName()) {
+                    auto_ptr<Issuer> 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");
+    }
+}
index 8b953e3..49919b3 100644 (file)
@@ -111,59 +111,22 @@ XMLObject* SAML2POSTDecoder::decode(
         root = static_cast<saml2::RootObject*>(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*>(response);
-            if (assbag) {
-                const vector<Assertion*>& 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();
 }
index d2abd41..de2c66b 100644 (file)
@@ -125,50 +125,23 @@ XMLObject* SAML2RedirectDecoder::decode(
         root = static_cast<saml2::RootObject*>(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();
 }
index edb7207..50c63e0 100644 (file)
@@ -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[];
index b412be8..fea95fb 100644 (file)
@@ -21,6 +21,7 @@
 #include <saml/binding/HTTPResponse.h>\r
 #include <saml/binding/MessageDecoder.h>\r
 #include <saml/binding/MessageEncoder.h>\r
+#include <saml/binding/SecurityPolicyRule.h>\r
 #include <saml/binding/URLEncoder.h>\r
 #include <saml/saml2/metadata/Metadata.h>\r
 #include <saml/saml2/metadata/MetadataProvider.h>\r
@@ -39,7 +40,8 @@ protected:
     map<string,string> m_headers;\r
     string m_method,m_url,m_query;\r
     vector<XSECCryptoX509*> m_clientCerts;\r
-    vector<const SecurityPolicyRule*> m_rules;\r
+    vector<const SecurityPolicyRule*> m_rules1;\r
+    vector<const SecurityPolicyRule*> m_rules2;\r
 \r
 public:\r
     void setUp() {\r
@@ -78,9 +80,15 @@ public:
                 \r
             m_trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE, NULL);\r
 \r
-            m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL));\r
-            m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL));\r
-            m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL));\r
+            m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SAML1MESSAGE_POLICY_RULE,NULL));\r
+            m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL));\r
+            m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL));\r
+            m_rules1.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL));\r
+\r
+            m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SAML2MESSAGE_POLICY_RULE,NULL));\r
+            m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL));\r
+            m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL));\r
+            m_rules2.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL));\r
         }\r
         catch (XMLToolingException& ex) {\r
             TS_TRACE(ex.what());\r
@@ -91,8 +99,10 @@ public:
     }\r
     \r
     void tearDown() {\r
-        for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
-        m_rules.clear();\r
+        for_each(m_rules1.begin(), m_rules1.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+        m_rules1.clear();\r
+        for_each(m_rules2.begin(), m_rules2.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+        m_rules2.clear();\r
         delete m_creds;\r
         delete m_metadata;\r
         delete m_trust;\r
index 30f4dc9..38a95fe 100644 (file)
@@ -51,7 +51,7 @@ public:
     void testSAML1Artifact() {\r
         try {\r
             QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
-            SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);\r
+            SecurityPolicy policy(m_rules1, m_metadata, &idprole, m_trust);\r
 \r
             // Read message to use from file.\r
             string path = data_path + "saml1/binding/SAML1Assertion.xml";\r
@@ -89,6 +89,7 @@ public:
             TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);\r
 \r
             // Trigger a replay.\r
+            policy.reset();\r
             TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);\r
         }\r
         catch (XMLToolingException& ex) {\r
index 61ae72d..5808169 100644 (file)
@@ -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();\r
             TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);
         }
         catch (XMLToolingException& ex) {
index 5e3a408..dc968ef 100644 (file)
@@ -38,7 +38,7 @@ public:
     void testSAML2Artifact() {\r
         try {\r
             QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
-            SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);\r
+            SecurityPolicy policy(m_rules2, m_metadata, &idprole, m_trust);\r
 \r
             // Read message to use from file.\r
             string path = data_path + "saml2/binding/SAML2Response.xml";\r
@@ -79,6 +79,7 @@ public:
             TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);\r
 \r
             // Trigger a replay.\r
+            policy.reset();\r
             TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);\r
         }\r
         catch (XMLToolingException& ex) {\r
index ada0f3e..ec94a04 100644 (file)
@@ -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();\r
             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();\r
             TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);
         }
         catch (XMLToolingException& ex) {
index 92d9741..96c0504 100644 (file)
@@ -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();\r
             TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);
         }
         catch (XMLToolingException& ex) {