Add policy rules for SAML 1 SSO and SAML 2 Bearer confirmation, with unit tests.
authorScott Cantor <cantor.2@osu.edu>
Mon, 23 Feb 2009 21:52:59 +0000 (21:52 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 23 Feb 2009 21:52:59 +0000 (21:52 +0000)
18 files changed:
.cproject
saml/Makefile.am
saml/binding/SecurityPolicy.h
saml/binding/SecurityPolicyRule.h
saml/binding/impl/SecurityPolicy.cpp
saml/saml.vcproj
saml/saml1/profile/impl/AssertionValidator.cpp [moved from saml/saml1/profile/AssertionValidator.cpp with 100% similarity]
saml/saml1/profile/impl/BrowserSSOProfileValidator.cpp [moved from saml/saml1/profile/BrowserSSOProfileValidator.cpp with 95% similarity]
saml/saml1/profile/impl/SAML1BrowserSSORule.cpp [new file with mode: 0644]
saml/saml2/profile/BrowserSSOProfileValidator.h
saml/saml2/profile/impl/Assertion20Validator.cpp [moved from saml/saml2/profile/Assertion20Validator.cpp with 100% similarity]
saml/saml2/profile/impl/BearerConfirmationRule.cpp [new file with mode: 0644]
saml/saml2/profile/impl/BrowserSSOProfile20Validator.cpp [moved from saml/saml2/profile/BrowserSSOProfile20Validator.cpp with 100% similarity]
saml/saml2/profile/impl/SAML2AssertionPolicy.cpp [moved from saml/saml2/profile/SAML2AssertionPolicy.cpp with 100% similarity]
samltest/data/saml1/profile/SAML1Assertion.xml
samltest/data/saml2/profile/SAML2Assertion.xml
samltest/saml1/profile/SAML1PolicyTest.h
samltest/saml2/profile/SAML2PolicyTest.h

index b224a74..55b779c 100644 (file)
--- a/.cproject
+++ b/.cproject
@@ -63,6 +63,7 @@
 \r
 \r
 \r
+\r
 <storageModule moduleId="org.eclipse.cdt.core.pathentry">\r
 <pathentry kind="mac" name="_MSC_VER" path="" value=""/>\r
 <pathentry kind="mac" name="WIN32" path="" value=""/>\r
@@ -79,7 +80,7 @@
 <pathentry kind="out" path="saml/Debug"/>\r
 <pathentry kind="out" path="samltest/Debug"/>\r
 <pathentry kind="con" path="org.eclipse.cdt.make.core.DISCOVERED_SCANNER_INFO"/>\r
-<pathentry excluding="util/|saml1/|signature/|saml2/|encryption/|security/|security/impl/|saml1/binding/|saml1/binding/impl/|saml2/binding/|saml2/binding/impl/|binding/|binding/impl/|zlib/|saml1/profile/|saml1/profile/impl/|saml2/profile/|saml2/profile/impl/|profile|profile/impl/" kind="src" path="saml"/>\r
+<pathentry excluding="util/|saml1/|signature/|saml2/|encryption/|security/|security/impl/|saml1/binding/|saml1/binding/impl/|saml2/binding/|saml2/binding/impl/|binding/|binding/impl/|zlib/|saml1/profile/|saml1/profile/impl/|saml2/profile/|saml2/profile/impl/|profile|profile/impl/|saml1/profile/impl/|saml2/profile/impl/" kind="src" path="saml"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/binding"/>\r
 <pathentry kind="src" path="saml/binding/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/profile"/>\r
@@ -89,6 +90,7 @@
 <pathentry excluding="impl/" kind="src" path="saml/saml1/binding"/>\r
 <pathentry kind="src" path="saml/saml1/binding/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/saml1/profile"/>\r
+<pathentry kind="src" path="saml/saml1/profile/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/saml2/core"/>\r
 <pathentry kind="src" path="saml/saml2/core/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/saml2/binding"/>\r
@@ -96,6 +98,7 @@
 <pathentry excluding="impl/" kind="src" path="saml/saml2/metadata"/>\r
 <pathentry kind="src" path="saml/saml2/metadata/impl"/>\r
 <pathentry excluding="impl/" kind="src" path="saml/saml2/profile"/>\r
+<pathentry kind="src" path="saml/saml2/profile/impl"/>\r
 <pathentry kind="src" path="saml/encryption"/>\r
 <pathentry kind="src" path="saml/signature"/>\r
 <pathentry kind="src" path="saml/util"/>\r
index eb19340..4d859d6 100644 (file)
@@ -132,8 +132,9 @@ libsaml_la_SOURCES = \
        saml1/binding/impl/SAML1SOAPDecoder.cpp \
        saml1/binding/impl/SAML1SOAPEncoder.cpp \
        saml1/binding/impl/SAML1SOAPClient.cpp \
-       saml1/profile/AssertionValidator.cpp \
-       saml1/profile/BrowserSSOProfileValidator.cpp \
+       saml1/profile/impl/AssertionValidator.cpp \
+       saml1/profile/impl/BrowserSSOProfileValidator.cpp \
+       saml1/profile/impl/SAML1BrowserSSORule.cpp \
        saml2/core/impl/Assertions.cpp \
        saml2/core/impl/Assertions20Impl.cpp \
        saml2/core/impl/Assertions20SchemaValidators.cpp \
@@ -166,9 +167,10 @@ libsaml_la_SOURCES = \
        saml2/binding/impl/SAML2SOAPDecoder.cpp \
        saml2/binding/impl/SAML2SOAPEncoder.cpp \
        saml2/binding/impl/SAML2SOAPClient.cpp \
-       saml2/profile/Assertion20Validator.cpp \
-       saml2/profile/BrowserSSOProfile20Validator.cpp \
-       saml2/profile/SAML2AssertionPolicy.cpp \
+       saml2/profile/impl/Assertion20Validator.cpp \
+       saml2/profile/impl/BrowserSSOProfile20Validator.cpp \
+    saml2/profile/impl/BearerConfirmationRule.cpp \
+       saml2/profile/impl/SAML2AssertionPolicy.cpp \
        encryption/EncryptedKeyResolver.cpp \
        signature/ContentReference.cpp \
        signature/SignatureProfileValidator.cpp \
index 2dd16c2..6a5aac7 100644 (file)
@@ -160,6 +160,16 @@ namespace opensaml {
         }
 
         /**
+         * Returns the message identifier to which the message being evaluated
+         * is a response.
+         *
+         * @return correlated message identifier
+         */
+        const XMLCh* getCorrelationID() const {
+            return m_correlationID;
+        }
+
+        /**
          * Gets a mutable array of installed policy rules.
          *
          * <p>If adding rules, their lifetime must be at least as long as the policy object.
@@ -242,6 +252,16 @@ namespace opensaml {
         }
 
         /**
+         * Sets the message identifier to which the message being evaluated
+         * is a response.
+         *
+         * @param correlationID correlated message identifier
+         */
+        void setCorrelationID(const XMLCh* correlationID) {
+            m_correlationID = correlationID;
+        }
+
+        /**
          * Evaluates the policy against the given request and message,
          * possibly populating message information in the policy object.
          *
@@ -450,6 +470,7 @@ namespace opensaml {
 
         // contextual information
         mutable time_t m_ts;
+        const XMLCh* m_correlationID;
         std::vector<const XMLCh*> m_audiences;
     };
 
index 003e7ec..f4b746d 100644 (file)
@@ -135,6 +135,24 @@ namespace opensaml {
      * over the message. The transport layer is not considered.
      */
     #define XMLSIGNING_POLICY_RULE      "XMLSigning"
+
+    /**
+     * SecurityPolicyRule for SAML 1.x Browser SSO profile validation.
+     *
+     * Enforces presence of time conditions and proper subject confirmation.
+     */
+    #define SAML1BROWSERSSO_POLICY_RULE "SAML1BrowserSSO"
+
+    /**
+     * SecurityPolicyRule for SAML 2.0 bearer SubjectConfirmation.
+     *
+     * <p>Optionally enforces message delivery requirements based on SubjectConfirmationData.
+     *
+     * <p>The XML attributes "checkValidity", "checkRecipient", and "checkCorrelation" can be set
+     * "false" to disable checks of NotBefore/NotOnOrAfter, Recipient, and InResponseTo confirmation
+     * data respectively.
+     */
+    #define BEARER_POLICY_RULE "Bearer"
 };
 
 #endif /* __saml_secrule_h__ */
index bae5447..6603e3b 100644 (file)
@@ -40,6 +40,14 @@ namespace opensaml {
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory NullSecurityRuleFactory;
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory SimpleSigningRuleFactory;
     SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory XMLSigningRuleFactory;
+
+    namespace saml1 {
+        SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory BrowserSSORuleFactory;
+    }
+
+    namespace saml2 {
+        SAML_DLLLOCAL PluginManager<SecurityPolicyRule,string,const DOMElement*>::Factory BearerConfirmationRuleFactory;
+    }
 };
 
 void SAML_API opensaml::registerSecurityPolicyRules()
@@ -53,6 +61,8 @@ void SAML_API opensaml::registerSecurityPolicyRules()
     conf.SecurityPolicyRuleManager.registerFactory(NULLSECURITY_POLICY_RULE, NullSecurityRuleFactory);
     conf.SecurityPolicyRuleManager.registerFactory(SIMPLESIGNING_POLICY_RULE, SimpleSigningRuleFactory);
     conf.SecurityPolicyRuleManager.registerFactory(XMLSIGNING_POLICY_RULE, XMLSigningRuleFactory);
+    conf.SecurityPolicyRuleManager.registerFactory(SAML1BROWSERSSO_POLICY_RULE, saml1::BrowserSSORuleFactory);
+    conf.SecurityPolicyRuleManager.registerFactory(BEARER_POLICY_RULE, saml2::BearerConfirmationRuleFactory);
 }
 
 SecurityPolicy::IssuerMatchingPolicy SecurityPolicy::m_defaultMatching;
@@ -74,7 +84,8 @@ SecurityPolicy::SecurityPolicy(
         m_trust(trustEngine),
         m_validate(validate),
         m_entityOnly(true),
-        m_ts(0)
+        m_ts(0),
+        m_correlationID(NULL)
 {
     if (role)
         m_role = new xmltooling::QName(*role);
index ab67f1f..58783f5 100644 (file)
                                <Filter\r
                                        Name="profile"\r
                                        >\r
-                                       <File\r
-                                               RelativePath=".\saml1\profile\AssertionValidator.cpp"\r
-                                               >\r
-                                       </File>\r
-                                       <File\r
-                                               RelativePath=".\saml1\profile\BrowserSSOProfileValidator.cpp"\r
+                                       <Filter\r
+                                               Name="impl"\r
                                                >\r
-                                       </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml1\profile\impl\AssertionValidator.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml1\profile\impl\BrowserSSOProfileValidator.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml1\profile\impl\SAML1BrowserSSORule.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                       </Filter>\r
                                </Filter>\r
                        </Filter>\r
                        <Filter\r
                                <Filter\r
                                        Name="profile"\r
                                        >\r
-                                       <File\r
-                                               RelativePath=".\saml2\profile\Assertion20Validator.cpp"\r
-                                               >\r
-                                               <FileConfiguration\r
-                                                       Name="Debug|Win32"\r
-                                                       >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Debug|x64"\r
-                                                       >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Release|Win32"\r
-                                                       >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Release|x64"\r
-                                                       >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                       </File>\r
-                                       <File\r
-                                               RelativePath=".\saml2\profile\BrowserSSOProfile20Validator.cpp"\r
+                                       <Filter\r
+                                               Name="impl"\r
                                                >\r
-                                               <FileConfiguration\r
-                                                       Name="Debug|Win32"\r
+                                               <File\r
+                                                       RelativePath=".\saml2\profile\impl\Assertion20Validator.cpp"\r
                                                        >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Debug|x64"\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml2\profile\impl\BearerConfirmationRule.cpp"\r
                                                        >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Release|Win32"\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml2\profile\impl\BrowserSSOProfile20Validator.cpp"\r
                                                        >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                               <FileConfiguration\r
-                                                       Name="Release|x64"\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml2\profile\impl\SAML2AssertionPolicy.cpp"\r
                                                        >\r
-                                                       <Tool\r
-                                                               Name="VCCLCompilerTool"\r
-                                                               ObjectFile="$(IntDir)\$(InputName)1.obj"\r
-                                                               XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"\r
-                                                       />\r
-                                               </FileConfiguration>\r
-                                       </File>\r
-                                       <File\r
-                                               RelativePath=".\saml2\profile\SAML2AssertionPolicy.cpp"\r
-                                               >\r
-                                       </File>\r
+                                               </File>\r
+                                       </Filter>\r
                                </Filter>\r
                        </Filter>\r
                        <Filter\r
@@ -1,6 +1,6 @@
 /*
  *  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
@@ -16,7 +16,7 @@
 
 /**
  * BrowserSSOProfileValidator.cpp
- * 
+ *
  * SAML 1.x Browser SSO Profile Assertion Validator
  */
 
@@ -75,8 +75,6 @@ void BrowserSSOProfileValidator::validateAssertion(const Assertion& assertion) c
     for_each(authn.begin(), authn.end(), _checkMethod());
     const vector<AttributeStatement*>& attr = assertion.getAttributeStatements();
     for_each(attr.begin(), attr.end(), _checkMethod());
-    const vector<SubjectStatement*>& sub = assertion.getSubjectStatements();
-    for_each(sub.begin(), sub.end(), _checkMethod());
 
     // Pass up for additional checking.
     AssertionValidator::validateAssertion(assertion);
diff --git a/saml/saml1/profile/impl/SAML1BrowserSSORule.cpp b/saml/saml1/profile/impl/SAML1BrowserSSORule.cpp
new file mode 100644 (file)
index 0000000..1b1cc4f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  Copyright 2009 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     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.
+ */
+
+/**
+ * SAML1BrowserSSORule.cpp
+ *
+ * SAML 1.x Browser SSO Profile SecurityPolicyRule
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/SecurityPolicyRule.h"
+#include "saml1/core/Assertions.h"
+
+#include <xmltooling/logging.h>
+
+using namespace opensaml::saml1;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+    namespace saml1 {
+
+        class SAML_DLLLOCAL BrowserSSORule : public opensaml::SecurityPolicyRule
+        {
+        public:
+            BrowserSSORule(const DOMElement* e) {}
+
+            virtual ~BrowserSSORule() {
+            }
+            const char* getType() const {
+                return SAML1BROWSERSSO_POLICY_RULE;
+            }
+            bool evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const;
+        };
+
+        opensaml::SecurityPolicyRule* SAML_DLLLOCAL BrowserSSORuleFactory(const DOMElement* const & e)
+        {
+            return new BrowserSSORule(e);
+        }
+
+        class SAML_DLLLOCAL _checkMethod : public unary_function<const SubjectStatement*,void>,
+            public unary_function<const ConfirmationMethod*,bool>
+        {
+        public:
+            void operator()(const SubjectStatement* s) const {
+                const Subject* sub = s->getSubject();
+                if (s) {
+                    const SubjectConfirmation* sc = sub->getSubjectConfirmation();
+                    if (sc) {
+                        const vector<ConfirmationMethod*>& methods = sc->getConfirmationMethods();
+                        if (find_if(methods.begin(), methods.end(), _checkMethod())!=methods.end())
+                            return;     // methods checked out
+                    }
+                }
+                throw SecurityPolicyException("Assertion contained a statement without a supported ConfirmationMethod.");
+            }
+
+            bool operator()(const ConfirmationMethod* cm) const {
+                const XMLCh* m = cm->getMethod();
+                return (XMLString::equals(m,SubjectConfirmation::BEARER) ||
+                    XMLString::equals(m,SubjectConfirmation::ARTIFACT) ||
+                    XMLString::equals(m,SubjectConfirmation::ARTIFACT01));
+            }
+        };
+    };
+};
+
+bool BrowserSSORule::evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const
+{
+    const Assertion* a=dynamic_cast<const Assertion*>(&message);
+    if (!a)
+        return false;
+
+    // Make sure the assertion is bounded.
+    const Conditions* conds = a->getConditions();
+    if (!conds || !conds->getNotBefore() || !conds->getNotOnOrAfter())
+        throw SecurityPolicyException("Browser SSO assertions MUST contain NotBefore/NotOnOrAfter attributes.");
+
+    // Each statement MUST have proper confirmation requirements.
+    const vector<AuthenticationStatement*>& authn = a->getAuthenticationStatements();
+    for_each(authn.begin(), authn.end(), _checkMethod());
+    const vector<AttributeStatement*>& attr = a->getAttributeStatements();
+    for_each(attr.begin(), attr.end(), _checkMethod());
+
+    return true;
+}
index 460c99d..9af864c 100644 (file)
@@ -34,8 +34,7 @@ namespace opensaml {
          * SAML 2.0 Browser SSO Profile Assertion Validator
          *
          * <p>In addition to standard core requirements for validity, SSO assertions
-         * <strong>MUST</strong> have NotBefore/NotOnOrAfter attributes and each subject statement
-         * <strong>MUST</strong> be confirmable via bearer method.
+         * <strong>MUST</strong> be bearer-confirmable.
          */
         class SAML_API BrowserSSOProfileValidator : public AssertionValidator
         {
diff --git a/saml/saml2/profile/impl/BearerConfirmationRule.cpp b/saml/saml2/profile/impl/BearerConfirmationRule.cpp
new file mode 100644 (file)
index 0000000..b197226
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  Copyright 2009 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     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.
+ */
+
+/**
+ * BearerConfirmationRule.cpp
+ *
+ * SAML 2.0 Bearer SubjectConfirmation SecurityPolicyRule
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/SecurityPolicyRule.h"
+#include "saml2/core/Assertions.h"
+#include "saml2/profile/SAML2AssertionPolicy.h"
+
+#include <xmltooling/logging.h>
+#include <xmltooling/io/HTTPRequest.h>
+
+using namespace opensaml::saml2;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2 {
+
+        class SAML_DLLLOCAL BearerConfirmationRule : public opensaml::SecurityPolicyRule
+        {
+        public:
+            BearerConfirmationRule(const DOMElement* e);
+
+            virtual ~BearerConfirmationRule() {
+            }
+            const char* getType() const {
+                return BEARER_POLICY_RULE;
+            }
+            bool evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const;
+        
+        private:
+            bool m_validity, m_recipient, m_correlation, m_fatal;
+        };
+
+        opensaml::SecurityPolicyRule* SAML_DLLLOCAL BearerConfirmationRuleFactory(const DOMElement* const & e)
+        {
+            return new BearerConfirmationRule(e);
+        }
+        
+        static const XMLCh checkValidity[] =    UNICODE_LITERAL_13(c,h,e,c,k,V,a,l,i,d,i,t,y);
+        static const XMLCh checkRecipient[] =   UNICODE_LITERAL_14(c,h,e,c,k,R,e,c,i,p,i,e,n,t);
+        static const XMLCh checkCorrelation[] = UNICODE_LITERAL_16(c,h,e,c,k,C,o,r,r,e,l,a,t,i,o,n);
+        static const XMLCh missingFatal[] =     UNICODE_LITERAL_12(m,i,s,s,i,n,g,F,a,t,a,l);
+    };
+};
+
+BearerConfirmationRule::BearerConfirmationRule(const DOMElement* e) : m_validity(true), m_recipient(true), m_correlation(true), m_fatal(true)
+{
+    const XMLCh* flag = e ? e->getAttributeNS(NULL, checkValidity) : NULL;
+    m_validity = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
+    flag = e ? e->getAttributeNS(NULL, checkRecipient) : NULL;
+    m_recipient = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
+    flag = e ? e->getAttributeNS(NULL, checkCorrelation) : NULL;
+    m_correlation = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
+    flag = e ? e->getAttributeNS(NULL, missingFatal) : NULL;
+    m_fatal = (!flag || (*flag != chLatin_f && *flag != chDigit_0));
+}
+
+bool BearerConfirmationRule::evaluate(const XMLObject& message, const GenericRequest* request, opensaml::SecurityPolicy& policy) const
+{
+    const Assertion* a=dynamic_cast<const Assertion*>(&message);
+    if (!a)
+        return false;
+
+    logging::Category& log = logging::Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.BearerConfirmation");
+
+    const char* msg=NULL;
+    const Subject* subject = a->getSubject();
+    if (subject) {
+        const vector<SubjectConfirmation*>& confs = subject->getSubjectConfirmations();
+        for (vector<SubjectConfirmation*>::const_iterator sc = confs.begin(); sc!=confs.end(); ++sc) {
+            if (XMLString::equals((*sc)->getMethod(), SubjectConfirmation::BEARER)) {
+
+                const SubjectConfirmationDataType* data = dynamic_cast<const SubjectConfirmationDataType*>((*sc)->getSubjectConfirmationData());
+
+                if (m_recipient) {
+                    const HTTPRequest* httpRequest = dynamic_cast<const HTTPRequest*>(request);
+                    if (httpRequest && httpRequest->getRequestURL()) {
+                        string dest = httpRequest->getRequestURL();
+                        auto_ptr_XMLCh destination(dest.substr(0,dest.find('?')).c_str());
+                        if (!XMLString::equals(destination.get(), data ? data->getRecipient() : NULL)) {
+                            msg = "bearer confirmation failed with recipient mismatch";
+                            continue;
+                        }
+                    }
+                }
+
+                if (m_correlation && policy.getCorrelationID()) {
+                    if (!XMLString::equals(policy.getCorrelationID(), data ? data->getInResponseTo() : NULL)) {
+                        msg = "bearer confirmation failed with request correlation mismatch";
+                        continue;
+                    }
+                }
+
+                if (m_validity) {
+                    if (!data || !data->getNotOnOrAfter()) {
+                        msg = "bearer SubjectConfirmationData missing NotOnOrAfter attribute";
+                        continue;
+                    }
+                    else if (data->getNotOnOrAfterEpoch() <= policy.getTime() - XMLToolingConfig::getConfig().clock_skew_secs) {
+                        msg = "bearer confirmation has expired";
+                        continue;
+                    }
+
+                    if (data && data->getNotBefore() && policy.getTime() + XMLToolingConfig::getConfig().clock_skew_secs < data->getNotBeforeEpoch()) {
+                        msg = "bearer confirmation not yet valid";
+                        continue;
+                    }
+                }
+
+                SAML2AssertionPolicy* saml2policy = dynamic_cast<SAML2AssertionPolicy*>(&policy);
+                if (saml2policy)
+                    saml2policy->setSubjectConfirmation(*sc);
+                log.debug("assertion satisfied bearer confirmation requirements");
+                return true;
+            }
+        }
+    }
+
+    log.error(msg);
+    if (m_fatal)
+        throw SecurityPolicyException("Unable to locate satisfiable bearer SubjectConfirmation in assertion.");
+    return false;
+}
index 01d7d96..81fc080 100644 (file)
@@ -7,6 +7,11 @@ IssueInstant="1970-01-02T01:01:02.100Z" Issuer="https://idp.example.org/" MajorV
         <saml:DoNotCacheCondition/>
     </saml:Conditions>
     <saml:AuthenticationStatement AuthenticationInstant="1970-01-02T01:01:02.100Z" AuthenticationMethod="method">
-        <saml:Subject><saml:NameIdentifier>John Doe</saml:NameIdentifier></saml:Subject>
+        <saml:Subject>
+            <saml:NameIdentifier>John Doe</saml:NameIdentifier>
+            <saml:SubjectConfirmation>
+                <saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
+            </saml:SubjectConfirmation>
+        </saml:Subject>
     </saml:AuthenticationStatement>
 </saml:Assertion>
index 758e79e..e423ec1 100644 (file)
@@ -1,6 +1,11 @@
 <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="aident" IssueInstant="1970-01-02T01:01:02.100Z" Version="2.0">
     <saml:Issuer>https://idp.example.org/</saml:Issuer>
-    <saml:Subject><saml:NameID>John Doe</saml:NameID></saml:Subject>
+    <saml:Subject>
+        <saml:NameID>John Doe</saml:NameID>
+        <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+            <saml:SubjectConfirmationData NotOnOrAfter="2030-01-02T01:01:02.100Z"/>
+        </saml:SubjectConfirmation>
+    </saml:Subject>
     <saml:Conditions NotBefore="2008-01-02T01:01:02.100Z" NotOnOrAfter="2030-01-02T01:01:02.100Z">
         <saml:AudienceRestriction>
             <saml:Audience>https://sp.example.org</saml:Audience>
index 49554e5..3ea4593 100644 (file)
@@ -24,18 +24,18 @@ using namespace opensaml;
 
 class SAML1PolicyTest : public CxxTest::TestSuite {
     SecurityPolicy* m_policy;
-    SecurityPolicyRule* m_rule;
+    vector<SecurityPolicyRule*> m_rules;
 public:
     void setUp() {
         m_policy = NULL;
-        m_rule = NULL;
-        m_rule = SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL);
+        m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL));
+        m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SAML1BROWSERSSO_POLICY_RULE, NULL));
         m_policy = new SecurityPolicy();
-        m_policy->getRules().push_back(m_rule);
+        m_policy->getRules().assign(m_rules.begin(), m_rules.end());
     }
 
     void tearDown() {
-        delete m_rule;
+        for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());
         delete m_policy;
     }
 
index 3f3b958..c5b80e0 100644 (file)
@@ -24,18 +24,18 @@ using namespace opensaml;
 
 class SAML2PolicyTest : public CxxTest::TestSuite {
     SecurityPolicy* m_policy;
-    SecurityPolicyRule* m_rule;
+    vector<SecurityPolicyRule*> m_rules;
 public:
     void setUp() {
         m_policy = NULL;
-        m_rule = NULL;
-        m_rule = SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL);
+        m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(CONDITIONS_POLICY_RULE, NULL));
+        m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(BEARER_POLICY_RULE, NULL));
         m_policy = new SecurityPolicy();
-        m_policy->getRules().push_back(m_rule);
+        m_policy->getRules().assign(m_rules.begin(), m_rules.end());
     }
 
     void tearDown() {
-        delete m_rule;
+        for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());
         delete m_policy;
     }
 
@@ -51,10 +51,18 @@ public:
                 );
             janitor.release();
 
+            auto_ptr_XMLCh requestID("_12345");
+            m_policy->setCorrelationID(requestID.get());
+
             TSM_ASSERT_THROWS("Policy should have tripped on AudienceRestriction", m_policy->evaluate(*assertion.get()), SecurityPolicyException);
 
             auto_ptr_XMLCh recipient("https://sp.example.org");
             m_policy->getAudiences().push_back(recipient.get());
+            TSM_ASSERT_THROWS("Policy should have tripped on InResponseTo correlation", m_policy->evaluate(*assertion.get()), SecurityPolicyException);
+
+            dynamic_cast<saml2::SubjectConfirmationData*>(
+                assertion->getSubject()->getSubjectConfirmations().front()->getSubjectConfirmationData()
+                )->setInResponseTo(requestID.get());
             m_policy->evaluate(*assertion.get());
         }
         catch (exception& ex) {